diff --git a/Android.mk b/Android.mk index 6b3b77a984ad39a202c5e2322e5505b4144640a9..18051aaa8a86a40040b8e352350626dd3f13a406 100644 --- a/Android.mk +++ b/Android.mk @@ -30,6 +30,7 @@ framework-res-source-path := APPS/framework-res_intermediates/src # ============================================================ include $(CLEAR_VARS) +# FRAMEWORKS_BASE_SUBDIRS comes from build/core/pathmap.mk LOCAL_SRC_FILES := $(call find-other-java-files,$(FRAMEWORKS_BASE_SUBDIRS)) # The following filters out code we are temporarily not including at all. @@ -66,6 +67,7 @@ LOCAL_SRC_FILES += \ core/java/android/app/ITransientNotification.aidl \ core/java/android/app/IWallpaperService.aidl \ core/java/android/app/IWallpaperServiceCallback.aidl \ + core/java/android/bluetooth/IBluetoothA2dp.aidl \ core/java/android/bluetooth/IBluetoothDevice.aidl \ core/java/android/bluetooth/IBluetoothDeviceCallback.aidl \ core/java/android/bluetooth/IBluetoothHeadset.aidl \ @@ -96,6 +98,14 @@ LOCAL_SRC_FILES += \ core/java/android/view/IWindowManager.aidl \ core/java/android/view/IWindowSession.aidl \ core/java/com/android/internal/app/IBatteryStats.aidl \ + core/java/com/android/internal/view/IInputContext.aidl \ + core/java/com/android/internal/view/IInputContextCallback.aidl \ + core/java/com/android/internal/view/IInputMethod.aidl \ + core/java/com/android/internal/view/IInputMethodCallback.aidl \ + core/java/com/android/internal/view/IInputMethodClient.aidl \ + core/java/com/android/internal/view/IInputMethodManager.aidl \ + core/java/com/android/internal/view/IInputMethodSession.aidl \ + im/java/android/im/IImPlugin.aidl \ location/java/android/location/IGpsStatusListener.aidl \ location/java/android/location/ILocationListener.aidl \ location/java/android/location/ILocationManager.aidl \ @@ -110,6 +120,7 @@ LOCAL_SRC_FILES += \ telephony/java/com/android/internal/telephony/gsm/ISms.aidl \ wifi/java/android/net/wifi/IWifiManager.aidl +# FRAMEWORKS_BASE_JAVA_SRC_DIRS comes from build/core/pathmap.mk LOCAL_AIDL_INCLUDES += $(FRAMEWORKS_BASE_JAVA_SRC_DIRS) LOCAL_INTERMEDIATE_SOURCES := \ @@ -126,6 +137,8 @@ LOCAL_MODULE_CLASS := JAVA_LIBRARIES # List of classes and interfaces which should be loaded by the Zygote. LOCAL_JAVA_RESOURCE_FILES += $(LOCAL_PATH)/preloaded-classes +#LOCAL_JARJAR_RULES := $(LOCAL_PATH)/jarjar-rules.txt + LOCAL_DX_FLAGS := --core-library include $(BUILD_JAVA_LIBRARY) @@ -134,7 +147,7 @@ include $(BUILD_JAVA_LIBRARY) # the source for this library. framework_res_R_stamp := \ $(call intermediates-dir-for,APPS,framework-res,,COMMON)/src/R.stamp -$(full_classes_jar): $(framework_res_R_stamp) +$(full_classes_compiled_jar): $(framework_res_R_stamp) # Make sure that framework-res is installed when framework is. $(LOCAL_INSTALLED_MODULE): | $(dir $(LOCAL_INSTALLED_MODULE))framework-res.apk @@ -159,9 +172,16 @@ aidl_files := \ frameworks/base/core/java/android/view/MotionEvent.aidl \ frameworks/base/core/java/android/view/Surface.aidl \ frameworks/base/core/java/android/view/WindowManager.aidl \ + frameworks/base/core/java/com/android/internal/view/IInputContext.aidl \ + frameworks/base/core/java/com/android/internal/view/IInputMethod.aidl \ + frameworks/base/core/java/com/android/internal/view/IInputMethodCallback.aidl \ + frameworks/base/core/java/com/android/internal/view/IInputMethodClient.aidl \ + frameworks/base/core/java/com/android/internal/view/IInputMethodManager.aidl \ + frameworks/base/core/java/com/android/internal/view/IInputMethodSession.aidl \ frameworks/base/graphics/java/android/graphics/Bitmap.aidl \ frameworks/base/graphics/java/android/graphics/Rect.aidl \ frameworks/base/graphics/java/android/graphics/Region.aidl \ + frameworks/base/im/java/android/im/IImPlugin.aidl \ frameworks/base/location/java/android/location/Criteria.aidl \ frameworks/base/location/java/android/location/Location.aidl \ frameworks/base/telephony/java/android/telephony/ServiceState.aidl \ @@ -261,10 +281,16 @@ framework_docs_LOCAL_JAVA_LIBRARIES := \ framework_docs_LOCAL_MODULE_CLASS := JAVA_LIBRARIES framework_docs_LOCAL_DROIDDOC_HTML_DIR := docs/html framework_docs_LOCAL_DROIDDOC_OPTIONS := \ - -error 1 -error 2 -error 3 -error 4 -error 6 -error 8 \ - -overview $(LOCAL_PATH)/core/java/overview.html \ - -hdf android.buglink 1 \ - -hdf android.whichdoc framework + -error 1 -error 2 -warning 3 -error 4 -error 6 -error 8 \ + -overview $(LOCAL_PATH)/core/java/overview.html + +framework_docs_LOCAL_ADDITIONAL_JAVA_DIR:=$(call intermediates-dir-for,JAVA_LIBRARIES,framework) + +web_docs_sample_code_flags := \ + -hdf android.hasSamples 1 \ + -samplecode samples/ApiDemos guide/samples/ApiDemos "API Demos" \ + -samplecode samples/LunarLander guide/samples/LunarLander "Lunar Lander" \ + -samplecode samples/NotePad guide/samples/NotePad "Note Pad" sample_dir := development/samples @@ -278,7 +304,7 @@ web_docs_sample_code_flags := \ guide/samples/NotePad "Note Pad" -# ==== static html ================================== +# ==== static html in the sdk ================================== include $(CLEAR_VARS) LOCAL_SRC_FILES:=$(framework_docs_LOCAL_SRC_FILES) @@ -287,19 +313,23 @@ LOCAL_JAVA_LIBRARIES:=$(framework_docs_LOCAL_JAVA_LIBRARIES) LOCAL_MODULE_CLASS:=$(framework_docs_LOCAL_MODULE_CLASS) LOCAL_DROIDDOC_SOURCE_PATH:=$(framework_docs_LOCAL_DROIDDOC_SOURCE_PATH) LOCAL_DROIDDOC_HTML_DIR:=$(framework_docs_LOCAL_DROIDDOC_HTML_DIR) -LOCAL_MODULE:=framework +LOCAL_ADDITIONAL_JAVA_DIR:=$(framework_docs_LOCAL_ADDITIONAL_JAVA_DIR) -framework_keep_file := $(OUT_DOCS)/$(LOCAL_MODULE)-keep.txt +LOCAL_MODULE := offline-sdk LOCAL_DROIDDOC_OPTIONS:=\ $(framework_docs_LOCAL_DROIDDOC_OPTIONS) \ -title "Android SDK" \ - -keeplist $(framework_keep_file) \ -proofread $(OUT_DOCS)/$(LOCAL_MODULE)-proofread.txt \ -todo $(OUT_DOCS)/$(LOCAL_MODULE)-docs-todo.html \ -stubs $(TARGET_OUT_COMMON_INTERMEDIATES)/JAVA_LIBRARIES/android_stubs_current_intermediates/src \ -apixml $(INTERNAL_PLATFORM_API_FILE) \ -sdkvalues $(OUT_DOCS) \ + -warning 3 \ + -hdf android.whichdoc offline + +LOCAL_DROIDDOC_CUSTOM_TEMPLATE_DIR:=build/tools/droiddoc/templates-sdk +LOCAL_DROIDDOC_CUSTOM_ASSET_DIR:=assets-sdk include $(BUILD_DROIDDOC) @@ -311,34 +341,37 @@ $(static_doc_index_redirect): \ $(full_target): $(static_doc_index_redirect) $(full_target): $(framework_built) -$(framework_keep_file): $(full_target) $(INTERNAL_PLATFORM_API_FILE): $(full_target) $(call dist-for-goals,sdk,$(INTERNAL_PLATFORM_API_FILE)) -# ==== codesite ezt templates ======================= +# ==== docs for the web (on the google app engine server) ======================= include $(CLEAR_VARS) LOCAL_SRC_FILES:=$(framework_docs_LOCAL_SRC_FILES) LOCAL_INTERMEDIATE_SOURCES:=$(framework_docs_LOCAL_INTERMEDIATE_SOURCES) -LOCAL_JAVA_LIBRARIES:=$(framework_docs_LOCAL_JAVA_LIBRARIES) framework +LOCAL_STATIC_JAVA_LIBRARIES:=$(framework_docs_LOCAL_STATIC_JAVA_LIBRARIES) +LOCAL_JAVA_LIBRARIES:=$(framework_docs_LOCAL_JAVA_LIBRARIES) LOCAL_MODULE_CLASS:=$(framework_docs_LOCAL_MODULE_CLASS) LOCAL_DROIDDOC_SOURCE_PATH:=$(framework_docs_LOCAL_DROIDDOC_SOURCE_PATH) LOCAL_DROIDDOC_HTML_DIR:=$(framework_docs_LOCAL_DROIDDOC_HTML_DIR) -LOCAL_ADDITIONAL_JAVA_DIR:=$(call intermediates-dir-for,JAVA_LIBRARIES,framework) +LOCAL_ADDITIONAL_JAVA_DIR:=$(framework_docs_LOCAL_ADDITIONAL_JAVA_DIR) -LOCAL_MODULE:=codesite -LOCAL_DROIDDOC_OPTIONS:=\ - $(framework_docs_LOCAL_DROIDDOC_OPTIONS) \ - $(web_docs_sample_code_flags) \ - -toroot /android/ +LOCAL_MODULE := online-sdk + +LOCAL_DROIDDOC_OPTIONS:= \ + $(framework_docs_LOCAL_DROIDDOC_OPTIONS) \ + $(web_docs_sample_code_flags) \ + -toroot / \ + -hdf android.whichdoc online -LOCAL_DROIDDOC_CUSTOM_TEMPLATE_DIR:=$(SRC_DROIDDOC_DIR)/templates-codesite -LOCAL_DROIDDOC_CUSTOM_ASSET_DIR:=assets-google +LOCAL_DROIDDOC_CUSTOM_TEMPLATE_DIR:=build/tools/droiddoc/templates-sdk +LOCAL_DROIDDOC_CUSTOM_ASSET_DIR:=assets-sdk include $(BUILD_DROIDDOC) -# ==== docs for the web (on the google app engine server) ======================= + +# ==== docs that have all of the stuff that's @hidden ======================= include $(CLEAR_VARS) LOCAL_SRC_FILES:=$(framework_docs_LOCAL_SRC_FILES) @@ -349,18 +382,17 @@ LOCAL_DROIDDOC_SOURCE_PATH:=$(framework_docs_LOCAL_DROIDDOC_SOURCE_PATH) LOCAL_DROIDDOC_HTML_DIR:=$(framework_docs_LOCAL_DROIDDOC_HTML_DIR) LOCAL_ADDITIONAL_JAVA_DIR:=$(call intermediates-dir-for,JAVA_LIBRARIES,framework) -LOCAL_MODULE:=gae +LOCAL_MODULE := hidden LOCAL_DROIDDOC_OPTIONS:=\ - $(framework_docs_LOCAL_DROIDDOC_OPTIONS) \ - $(web_docs_sample_code_flags) \ - -toroot /gae/ + $(framework_docs_LOCAL_DROIDDOC_OPTIONS) \ + -title "Android SDK - Including hidden APIs." +# -hidden -LOCAL_DROIDDOC_CUSTOM_TEMPLATE_DIR:=$(SRC_DROIDDOC_DIR)/templates -LOCAL_DROIDDOC_CUSTOM_ASSET_DIR:=assets +LOCAL_DROIDDOC_CUSTOM_TEMPLATE_DIR:=build/tools/droiddoc/templates-sdk +LOCAL_DROIDDOC_CUSTOM_ASSET_DIR:=assets-sdk include $(BUILD_DROIDDOC) - # Build ext.jar # ============================================================ @@ -385,24 +417,8 @@ LOCAL_MODULE := ext include $(BUILD_JAVA_LIBRARY) -# ==== the documentation =================================== -include $(CLEAR_VARS) - -LOCAL_SRC_FILES := $(ext_src_files) docs/overview-ext.html - -LOCAL_NO_STANDARD_LIBRARIES := true -LOCAL_JAVA_LIBRARIES := core - -LOCAL_MODULE := ext -LOCAL_MODULE_CLASS := JAVA_LIBRARIES -LOCAL_DROIDDOC_OPTIONS := -overview $(LOCAL_PATH)/docs/overview-ext.html - -include $(BUILD_DROIDDOC) - # Include subdirectory makefiles # ============================================================ -ifneq ($(SDK_ONLY),true) - include $(call first-makefiles-under,$(LOCAL_PATH)) -endif +include $(call first-makefiles-under,$(LOCAL_PATH)) diff --git a/api/1.xml b/api/1.xml new file mode 100644 index 0000000000000000000000000000000000000000..b196ac776ed9932ba7a4b3d3a57e30d688b201c9 --- /dev/null +++ b/api/1.xml @@ -0,0 +1,311265 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/api/2.xml b/api/2.xml new file mode 100644 index 0000000000000000000000000000000000000000..b9736fe735974f778e74bfb6cf6a1facf7603e31 --- /dev/null +++ b/api/2.xml @@ -0,0 +1,311400 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/api/3.xml b/api/3.xml new file mode 100644 index 0000000000000000000000000000000000000000..e13cfdecf9601c5fb7bb383d9186a59e0b0881a2 --- /dev/null +++ b/api/3.xml @@ -0,0 +1,311400 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/api/current.xml b/api/current.xml new file mode 100644 index 0000000000000000000000000000000000000000..880b6e82136cb8408a86a48decd10305c81261e6 --- /dev/null +++ b/api/current.xml @@ -0,0 +1,325107 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/awt/java/awt/AWTEvent.java b/awt/java/awt/AWTEvent.java index 1ed9a374facd46a443b4daebd437a5717630b846..a8dc83aafe5ff21b9be7c789128917cd9be99229 100644 --- a/awt/java/awt/AWTEvent.java +++ b/awt/java/awt/AWTEvent.java @@ -18,6 +18,7 @@ * @author Dmitry A. Durnev, Michael Danilov * @version $Revision$ */ + package java.awt; import java.util.EventObject; @@ -27,190 +28,252 @@ import java.util.EventListener; import java.awt.event.*; /** - * The abstract AWT events is base class for all AWT events. - * This class and its subclasses supercede the original java.awt.Event class. + * The abstract class AWTEvent is the base class for all AWT events. This class + * and its subclasses supersede the original java.awt.Event class. + * + * @since Android 1.0 */ public abstract class AWTEvent extends EventObject { - - /** The Constant serialVersionUID. */ + + /** + * The Constant serialVersionUID. + */ private static final long serialVersionUID = -1825314779160409405L; - /** The Constant COMPONENT_EVENT_MASK indicates the event relates to a component. */ + /** + * The Constant COMPONENT_EVENT_MASK indicates the event relates to a + * component. + */ public static final long COMPONENT_EVENT_MASK = 1; - /** The Constant CONTAINER_EVENT_MASK indicates the event relates to a container. */ + /** + * The Constant CONTAINER_EVENT_MASK indicates the event relates to a + * container. + */ public static final long CONTAINER_EVENT_MASK = 2; - /** The Constant FOCUS_EVENT_MASK indicates the event relates to the focus. */ + /** + * The Constant FOCUS_EVENT_MASK indicates the event relates to the focus. + */ public static final long FOCUS_EVENT_MASK = 4; - /** The Constant KEY_EVENT_MASK indicates the event relates to a key. */ + /** + * The Constant KEY_EVENT_MASK indicates the event relates to a key. + */ public static final long KEY_EVENT_MASK = 8; - /** The Constant MOUSE_EVENT_MASK indicates the event relates to the mouse. */ + /** + * The Constant MOUSE_EVENT_MASK indicates the event relates to the mouse. + */ public static final long MOUSE_EVENT_MASK = 16; - /** The Constant MOUSE_MOTION_EVENT_MASK indicates the event relates to a mouse motion. */ + /** + * The Constant MOUSE_MOTION_EVENT_MASK indicates the event relates to a + * mouse motion. + */ public static final long MOUSE_MOTION_EVENT_MASK = 32; - /** The Constant WINDOW_EVENT_MASK indicates the event relates to a window. */ + /** + * The Constant WINDOW_EVENT_MASK indicates the event relates to a window. + */ public static final long WINDOW_EVENT_MASK = 64; - /** The Constant ACTION_EVENT_MASK indicates the event relates to an action. */ + /** + * The Constant ACTION_EVENT_MASK indicates the event relates to an action. + */ public static final long ACTION_EVENT_MASK = 128; - /** The Constant ADJUSTMENT_EVENT_MASK indicates the event relates to an adjustment. */ + /** + * The Constant ADJUSTMENT_EVENT_MASK indicates the event relates to an + * adjustment. + */ public static final long ADJUSTMENT_EVENT_MASK = 256; - /** The Constant ITEM_EVENT_MASK indicates the event relates to an item. */ + /** + * The Constant ITEM_EVENT_MASK indicates the event relates to an item. + */ public static final long ITEM_EVENT_MASK = 512; - /** The Constant TEXT_EVENT_MASK indicates the event relates to text. */ + /** + * The Constant TEXT_EVENT_MASK indicates the event relates to text. + */ public static final long TEXT_EVENT_MASK = 1024; - /** The Constant INPUT_METHOD_EVENT_MASK indicates the event relates to an input method. */ + /** + * The Constant INPUT_METHOD_EVENT_MASK indicates the event relates to an + * input method. + */ public static final long INPUT_METHOD_EVENT_MASK = 2048; - /** The Constant PAINT_EVENT_MASK indicates the event relates to a paint method. */ + /** + * The Constant PAINT_EVENT_MASK indicates the event relates to a paint + * method. + */ public static final long PAINT_EVENT_MASK = 8192; - /** The Constant INVOCATION_EVENT_MASK indicates the event relates to a method invocation. */ + /** + * The Constant INVOCATION_EVENT_MASK indicates the event relates to a + * method invocation. + */ public static final long INVOCATION_EVENT_MASK = 16384; - /** The Constant HIERARCHY_EVENT_MASK indicates the event relates to a hierarchy. */ + /** + * The Constant HIERARCHY_EVENT_MASK indicates the event relates to a + * hierarchy. + */ public static final long HIERARCHY_EVENT_MASK = 32768; - /** - * The Constant HIERARCHY_BOUNDS_EVENT_MASK indicates the event relates to hierarchy bounds. + /** + * The Constant HIERARCHY_BOUNDS_EVENT_MASK indicates the event relates to + * hierarchy bounds. */ public static final long HIERARCHY_BOUNDS_EVENT_MASK = 65536; - /** The Constant MOUSE_WHEEL_EVENT_MASK indicates the event relates to the mouse wheel. */ + /** + * The Constant MOUSE_WHEEL_EVENT_MASK indicates the event relates to the + * mouse wheel. + */ public static final long MOUSE_WHEEL_EVENT_MASK = 131072; - /** The Constant WINDOW_STATE_EVENT_MASK indicates the event relates to a window state. */ + /** + * The Constant WINDOW_STATE_EVENT_MASK indicates the event relates to a + * window state. + */ public static final long WINDOW_STATE_EVENT_MASK = 262144; - /** The Constant WINDOW_FOCUS_EVENT_MASK indicates the event relates to a window focus. */ + /** + * The Constant WINDOW_FOCUS_EVENT_MASK indicates the event relates to a + * window focus. + */ public static final long WINDOW_FOCUS_EVENT_MASK = 524288; - /** The Constant RESERVED_ID_MAX indicates the maximum value for reserved - * AWT event IDs. + /** + * The Constant RESERVED_ID_MAX indicates the maximum value for reserved AWT + * event IDs. */ public static final int RESERVED_ID_MAX = 1999; - /** The Constant eventsMap. */ + /** + * The Constant eventsMap. + */ private static final Hashtable eventsMap = new Hashtable(); - /** The converter. */ + /** + * The converter. + */ private static EventConverter converter; - /** The ID of the event. */ + /** + * The ID of the event. + */ protected int id; - /** - * The consumed indicates whether or not the event is sent back down to - * the peer once the source has processed it (false means it's sent to the peer, + /** + * The consumed indicates whether or not the event is sent back down to the + * peer once the source has processed it (false means it's sent to the peer, * true means it's not). - */ + */ protected boolean consumed; - /** The dispatched by kfm. */ + /** + * The dispatched by kfm. + */ boolean dispatchedByKFM; - - /** The is posted. */ + + /** + * The is posted. + */ transient boolean isPosted; static { - eventsMap.put(new Integer(KeyEvent.KEY_TYPED), - new EventDescriptor(KEY_EVENT_MASK, KeyListener.class)); - eventsMap.put(new Integer(KeyEvent.KEY_PRESSED), - new EventDescriptor(KEY_EVENT_MASK, KeyListener.class)); - eventsMap.put(new Integer(KeyEvent.KEY_RELEASED), - new EventDescriptor(KEY_EVENT_MASK, KeyListener.class)); - eventsMap.put(new Integer(MouseEvent.MOUSE_CLICKED), - new EventDescriptor(MOUSE_EVENT_MASK, MouseListener.class)); - eventsMap.put(new Integer(MouseEvent.MOUSE_PRESSED), - new EventDescriptor(MOUSE_EVENT_MASK, MouseListener.class)); - eventsMap.put(new Integer(MouseEvent.MOUSE_RELEASED), - new EventDescriptor(MOUSE_EVENT_MASK, MouseListener.class)); - eventsMap.put(new Integer(MouseEvent.MOUSE_MOVED), - new EventDescriptor(MOUSE_MOTION_EVENT_MASK, MouseMotionListener.class)); - eventsMap.put(new Integer(MouseEvent.MOUSE_ENTERED), - new EventDescriptor(MOUSE_EVENT_MASK, MouseListener.class)); - eventsMap.put(new Integer(MouseEvent.MOUSE_EXITED), - new EventDescriptor(MOUSE_EVENT_MASK, MouseListener.class)); - eventsMap.put(new Integer(MouseEvent.MOUSE_DRAGGED), - new EventDescriptor(MOUSE_MOTION_EVENT_MASK, MouseMotionListener.class)); - eventsMap.put(new Integer(MouseEvent.MOUSE_WHEEL), - new EventDescriptor(MOUSE_WHEEL_EVENT_MASK, MouseWheelListener.class)); - eventsMap.put(new Integer(ComponentEvent.COMPONENT_MOVED), - new EventDescriptor(COMPONENT_EVENT_MASK, ComponentListener.class)); - eventsMap.put(new Integer(ComponentEvent.COMPONENT_RESIZED), - new EventDescriptor(COMPONENT_EVENT_MASK, ComponentListener.class)); - eventsMap.put(new Integer(ComponentEvent.COMPONENT_SHOWN), - new EventDescriptor(COMPONENT_EVENT_MASK, ComponentListener.class)); - eventsMap.put(new Integer(ComponentEvent.COMPONENT_HIDDEN), - new EventDescriptor(COMPONENT_EVENT_MASK, ComponentListener.class)); - eventsMap.put(new Integer(FocusEvent.FOCUS_GAINED), - new EventDescriptor(FOCUS_EVENT_MASK, FocusListener.class)); - eventsMap.put(new Integer(FocusEvent.FOCUS_LOST), - new EventDescriptor(FOCUS_EVENT_MASK, FocusListener.class)); - eventsMap.put(new Integer(PaintEvent.PAINT), - new EventDescriptor(PAINT_EVENT_MASK, null)); - eventsMap.put(new Integer(PaintEvent.UPDATE), - new EventDescriptor(PAINT_EVENT_MASK, null)); - eventsMap.put(new Integer(WindowEvent.WINDOW_OPENED), - new EventDescriptor(WINDOW_EVENT_MASK, WindowListener.class)); - eventsMap.put(new Integer(WindowEvent.WINDOW_CLOSING), - new EventDescriptor(WINDOW_EVENT_MASK, WindowListener.class)); - eventsMap.put(new Integer(WindowEvent.WINDOW_CLOSED), - new EventDescriptor(WINDOW_EVENT_MASK, WindowListener.class)); - eventsMap.put(new Integer(WindowEvent.WINDOW_DEICONIFIED), - new EventDescriptor(WINDOW_EVENT_MASK, WindowListener.class)); - eventsMap.put(new Integer(WindowEvent.WINDOW_ICONIFIED), - new EventDescriptor(WINDOW_EVENT_MASK, WindowListener.class)); - eventsMap.put(new Integer(WindowEvent.WINDOW_STATE_CHANGED), - new EventDescriptor(WINDOW_STATE_EVENT_MASK, WindowStateListener.class)); - eventsMap.put(new Integer(WindowEvent.WINDOW_LOST_FOCUS), - new EventDescriptor(WINDOW_FOCUS_EVENT_MASK, WindowFocusListener.class)); - eventsMap.put(new Integer(WindowEvent.WINDOW_GAINED_FOCUS), - new EventDescriptor(WINDOW_FOCUS_EVENT_MASK, WindowFocusListener.class)); - eventsMap.put(new Integer(WindowEvent.WINDOW_DEACTIVATED), - new EventDescriptor(WINDOW_EVENT_MASK, WindowListener.class)); - eventsMap.put(new Integer(WindowEvent.WINDOW_ACTIVATED), - new EventDescriptor(WINDOW_EVENT_MASK, WindowListener.class)); - eventsMap.put(new Integer(HierarchyEvent.HIERARCHY_CHANGED), - new EventDescriptor(HIERARCHY_EVENT_MASK, HierarchyListener.class)); - eventsMap.put(new Integer(HierarchyEvent.ANCESTOR_MOVED), - new EventDescriptor(HIERARCHY_BOUNDS_EVENT_MASK, HierarchyBoundsListener.class)); - eventsMap.put(new Integer(HierarchyEvent.ANCESTOR_RESIZED), - new EventDescriptor(HIERARCHY_BOUNDS_EVENT_MASK, HierarchyBoundsListener.class)); - eventsMap.put(new Integer(ContainerEvent.COMPONENT_ADDED), - new EventDescriptor(CONTAINER_EVENT_MASK, ContainerListener.class)); - eventsMap.put(new Integer(ContainerEvent.COMPONENT_REMOVED), - new EventDescriptor(CONTAINER_EVENT_MASK, ContainerListener.class)); - eventsMap.put(new Integer(InputMethodEvent.INPUT_METHOD_TEXT_CHANGED), - new EventDescriptor(INPUT_METHOD_EVENT_MASK, InputMethodListener.class)); - eventsMap.put(new Integer(InputMethodEvent.CARET_POSITION_CHANGED), - new EventDescriptor(INPUT_METHOD_EVENT_MASK, InputMethodListener.class)); - eventsMap.put(new Integer(InvocationEvent.INVOCATION_DEFAULT), - new EventDescriptor(INVOCATION_EVENT_MASK, null)); - eventsMap.put(new Integer(ItemEvent.ITEM_STATE_CHANGED), - new EventDescriptor(ITEM_EVENT_MASK, ItemListener.class)); - eventsMap.put(new Integer(TextEvent.TEXT_VALUE_CHANGED), - new EventDescriptor(TEXT_EVENT_MASK, TextListener.class)); - eventsMap.put(new Integer(ActionEvent.ACTION_PERFORMED), - new EventDescriptor(ACTION_EVENT_MASK, ActionListener.class)); - eventsMap.put(new Integer(AdjustmentEvent.ADJUSTMENT_VALUE_CHANGED), - new EventDescriptor(ADJUSTMENT_EVENT_MASK, AdjustmentListener.class)); + eventsMap.put(new Integer(KeyEvent.KEY_TYPED), new EventDescriptor(KEY_EVENT_MASK, + KeyListener.class)); + eventsMap.put(new Integer(KeyEvent.KEY_PRESSED), new EventDescriptor(KEY_EVENT_MASK, + KeyListener.class)); + eventsMap.put(new Integer(KeyEvent.KEY_RELEASED), new EventDescriptor(KEY_EVENT_MASK, + KeyListener.class)); + eventsMap.put(new Integer(MouseEvent.MOUSE_CLICKED), new EventDescriptor(MOUSE_EVENT_MASK, + MouseListener.class)); + eventsMap.put(new Integer(MouseEvent.MOUSE_PRESSED), new EventDescriptor(MOUSE_EVENT_MASK, + MouseListener.class)); + eventsMap.put(new Integer(MouseEvent.MOUSE_RELEASED), new EventDescriptor(MOUSE_EVENT_MASK, + MouseListener.class)); + eventsMap.put(new Integer(MouseEvent.MOUSE_MOVED), new EventDescriptor( + MOUSE_MOTION_EVENT_MASK, MouseMotionListener.class)); + eventsMap.put(new Integer(MouseEvent.MOUSE_ENTERED), new EventDescriptor(MOUSE_EVENT_MASK, + MouseListener.class)); + eventsMap.put(new Integer(MouseEvent.MOUSE_EXITED), new EventDescriptor(MOUSE_EVENT_MASK, + MouseListener.class)); + eventsMap.put(new Integer(MouseEvent.MOUSE_DRAGGED), new EventDescriptor( + MOUSE_MOTION_EVENT_MASK, MouseMotionListener.class)); + eventsMap.put(new Integer(MouseEvent.MOUSE_WHEEL), new EventDescriptor( + MOUSE_WHEEL_EVENT_MASK, MouseWheelListener.class)); + eventsMap.put(new Integer(ComponentEvent.COMPONENT_MOVED), new EventDescriptor( + COMPONENT_EVENT_MASK, ComponentListener.class)); + eventsMap.put(new Integer(ComponentEvent.COMPONENT_RESIZED), new EventDescriptor( + COMPONENT_EVENT_MASK, ComponentListener.class)); + eventsMap.put(new Integer(ComponentEvent.COMPONENT_SHOWN), new EventDescriptor( + COMPONENT_EVENT_MASK, ComponentListener.class)); + eventsMap.put(new Integer(ComponentEvent.COMPONENT_HIDDEN), new EventDescriptor( + COMPONENT_EVENT_MASK, ComponentListener.class)); + eventsMap.put(new Integer(FocusEvent.FOCUS_GAINED), new EventDescriptor(FOCUS_EVENT_MASK, + FocusListener.class)); + eventsMap.put(new Integer(FocusEvent.FOCUS_LOST), new EventDescriptor(FOCUS_EVENT_MASK, + FocusListener.class)); + eventsMap.put(new Integer(PaintEvent.PAINT), new EventDescriptor(PAINT_EVENT_MASK, null)); + eventsMap.put(new Integer(PaintEvent.UPDATE), new EventDescriptor(PAINT_EVENT_MASK, null)); + eventsMap.put(new Integer(WindowEvent.WINDOW_OPENED), new EventDescriptor( + WINDOW_EVENT_MASK, WindowListener.class)); + eventsMap.put(new Integer(WindowEvent.WINDOW_CLOSING), new EventDescriptor( + WINDOW_EVENT_MASK, WindowListener.class)); + eventsMap.put(new Integer(WindowEvent.WINDOW_CLOSED), new EventDescriptor( + WINDOW_EVENT_MASK, WindowListener.class)); + eventsMap.put(new Integer(WindowEvent.WINDOW_DEICONIFIED), new EventDescriptor( + WINDOW_EVENT_MASK, WindowListener.class)); + eventsMap.put(new Integer(WindowEvent.WINDOW_ICONIFIED), new EventDescriptor( + WINDOW_EVENT_MASK, WindowListener.class)); + eventsMap.put(new Integer(WindowEvent.WINDOW_STATE_CHANGED), new EventDescriptor( + WINDOW_STATE_EVENT_MASK, WindowStateListener.class)); + eventsMap.put(new Integer(WindowEvent.WINDOW_LOST_FOCUS), new EventDescriptor( + WINDOW_FOCUS_EVENT_MASK, WindowFocusListener.class)); + eventsMap.put(new Integer(WindowEvent.WINDOW_GAINED_FOCUS), new EventDescriptor( + WINDOW_FOCUS_EVENT_MASK, WindowFocusListener.class)); + eventsMap.put(new Integer(WindowEvent.WINDOW_DEACTIVATED), new EventDescriptor( + WINDOW_EVENT_MASK, WindowListener.class)); + eventsMap.put(new Integer(WindowEvent.WINDOW_ACTIVATED), new EventDescriptor( + WINDOW_EVENT_MASK, WindowListener.class)); + eventsMap.put(new Integer(HierarchyEvent.HIERARCHY_CHANGED), new EventDescriptor( + HIERARCHY_EVENT_MASK, HierarchyListener.class)); + eventsMap.put(new Integer(HierarchyEvent.ANCESTOR_MOVED), new EventDescriptor( + HIERARCHY_BOUNDS_EVENT_MASK, HierarchyBoundsListener.class)); + eventsMap.put(new Integer(HierarchyEvent.ANCESTOR_RESIZED), new EventDescriptor( + HIERARCHY_BOUNDS_EVENT_MASK, HierarchyBoundsListener.class)); + eventsMap.put(new Integer(ContainerEvent.COMPONENT_ADDED), new EventDescriptor( + CONTAINER_EVENT_MASK, ContainerListener.class)); + eventsMap.put(new Integer(ContainerEvent.COMPONENT_REMOVED), new EventDescriptor( + CONTAINER_EVENT_MASK, ContainerListener.class)); + eventsMap.put(new Integer(InputMethodEvent.INPUT_METHOD_TEXT_CHANGED), new EventDescriptor( + INPUT_METHOD_EVENT_MASK, InputMethodListener.class)); + eventsMap.put(new Integer(InputMethodEvent.CARET_POSITION_CHANGED), new EventDescriptor( + INPUT_METHOD_EVENT_MASK, InputMethodListener.class)); + eventsMap.put(new Integer(InvocationEvent.INVOCATION_DEFAULT), new EventDescriptor( + INVOCATION_EVENT_MASK, null)); + eventsMap.put(new Integer(ItemEvent.ITEM_STATE_CHANGED), new EventDescriptor( + ITEM_EVENT_MASK, ItemListener.class)); + eventsMap.put(new Integer(TextEvent.TEXT_VALUE_CHANGED), new EventDescriptor( + TEXT_EVENT_MASK, TextListener.class)); + eventsMap.put(new Integer(ActionEvent.ACTION_PERFORMED), new EventDescriptor( + ACTION_EVENT_MASK, ActionListener.class)); + eventsMap.put(new Integer(AdjustmentEvent.ADJUSTMENT_VALUE_CHANGED), new EventDescriptor( + ADJUSTMENT_EVENT_MASK, AdjustmentListener.class)); converter = new EventConverter(); } - + /** * Instantiates a new AWT event from the specified Event object. * - * @param event the Event object. + * @param event + * the Event object. */ public AWTEvent(Event event) { this(event.target, event.id); @@ -219,8 +282,10 @@ public abstract class AWTEvent extends EventObject { /** * Instantiates a new AWT event with the specified object and type. * - * @param source the source Object. - * @param id the event's type. + * @param source + * the source Object. + * @param id + * the event's type. */ public AWTEvent(Object source, int id) { super(source); @@ -240,7 +305,8 @@ public abstract class AWTEvent extends EventObject { /** * Sets a new source for the AWTEvent. * - * @param newSource the new source Object for the AWTEvent. + * @param newSource + * the new source Object for the AWTEvent. */ public void setSource(Object newSource) { source = newSource; @@ -253,33 +319,32 @@ public abstract class AWTEvent extends EventObject { */ @Override public String toString() { - /* The format is based on 1.5 release behavior - * which can be revealed by the following code: - * - * AWTEvent event = new AWTEvent(new Component(){}, 1){}; - * System.out.println(event); + /* + * The format is based on 1.5 release behavior which can be revealed by + * the following code: AWTEvent event = new AWTEvent(new Component(){}, + * 1){}; System.out.println(event); */ String name = ""; //$NON-NLS-1$ - + if (source instanceof Component && (source != null)) { - Component comp = (Component) getSource(); + Component comp = (Component)getSource(); name = comp.getName(); if (name == null) { name = ""; //$NON-NLS-1$ } } - + return (getClass().getName() + "[" + paramString() + "]" //$NON-NLS-1$ //$NON-NLS-2$ + " on " + (name.length() > 0 ? name : source)); //$NON-NLS-1$ } /** - * Returns a string representation of the AWTEvent state. - * + * Returns a string representation of the AWTEvent state. + * * @return a string representation of the AWTEvent state. */ public String paramString() { - //nothing to implement: all event types must override this method + // nothing to implement: all event types must override this method return ""; //$NON-NLS-1$ } @@ -296,73 +361,77 @@ public abstract class AWTEvent extends EventObject { * Consumes the AWTEvent. */ protected void consume() { - consumed = true; + consumed = true; } /** * Convert AWTEvent object to a corresponding (deprecated) Event object. * - * @return new Event object which is a converted AWTEvent object or null - * if the conversion is not possible + * @return new Event object which is a converted AWTEvent object or null if + * the conversion is not possible */ Event getEvent() { - + if (id == ActionEvent.ACTION_PERFORMED) { - ActionEvent ae = (ActionEvent) this; + ActionEvent ae = (ActionEvent)this; return converter.convertActionEvent(ae); } else if (id == AdjustmentEvent.ADJUSTMENT_VALUE_CHANGED) { - AdjustmentEvent ae = (AdjustmentEvent) this; + AdjustmentEvent ae = (AdjustmentEvent)this; return converter.convertAdjustmentEvent(ae); -//???AWT -// } else if (id == ComponentEvent.COMPONENT_MOVED -// && source instanceof Window) { -// //the only type of Component events is COMPONENT_MOVED on window -// ComponentEvent ce = (ComponentEvent) this; -// return converter.convertComponentEvent(ce); + // ???AWT + // } else if (id == ComponentEvent.COMPONENT_MOVED + // && source instanceof Window) { + // //the only type of Component events is COMPONENT_MOVED on window + // ComponentEvent ce = (ComponentEvent) this; + // return converter.convertComponentEvent(ce); } else if (id >= FocusEvent.FOCUS_FIRST && id <= FocusEvent.FOCUS_LAST) { - //nothing to convert + // nothing to convert -//???AWT -// } else if (id == ItemEvent.ITEM_STATE_CHANGED) { -// ItemEvent ie = (ItemEvent) this; -// return converter.convertItemEvent(ie); + // ???AWT + // } else if (id == ItemEvent.ITEM_STATE_CHANGED) { + // ItemEvent ie = (ItemEvent) this; + // return converter.convertItemEvent(ie); } else if (id == KeyEvent.KEY_PRESSED || id == KeyEvent.KEY_RELEASED) { - KeyEvent ke = (KeyEvent) this; + KeyEvent ke = (KeyEvent)this; return converter.convertKeyEvent(ke); } else if (id >= MouseEvent.MOUSE_FIRST && id <= MouseEvent.MOUSE_LAST) { - MouseEvent me = (MouseEvent) this; + MouseEvent me = (MouseEvent)this; return converter.convertMouseEvent(me); - } else if (id == WindowEvent.WINDOW_CLOSING - || id == WindowEvent.WINDOW_ICONIFIED + } else if (id == WindowEvent.WINDOW_CLOSING || id == WindowEvent.WINDOW_ICONIFIED || id == WindowEvent.WINDOW_DEICONIFIED) { - //nothing to convert + // nothing to convert } else { return null; } return new Event(source, id, null); } - /** - * The Class EventDescriptor. + * The class EventDescriptor. */ static final class EventDescriptor { - /** The event mask. */ + /** + * The event mask. + */ final long eventMask; - /** The listener type. */ + /** + * The listener type. + */ final Class listenerType; /** * Instantiates a new event descriptor. * - * @param eventMask the event mask - * @param listenerType the listener type + * @param eventMask + * the event mask. + * @param listenerType + * the listener type. */ EventDescriptor(long eventMask, Class listenerType) { this.eventMask = eventMask; @@ -370,24 +439,28 @@ public abstract class AWTEvent extends EventObject { } } - + /** - * The Class EventTypeLookup. + * The class EventTypeLookup. */ static final class EventTypeLookup { - - /** The last event. */ + + /** + * The last event. + */ private AWTEvent lastEvent = null; - - /** The last event descriptor. */ + + /** + * The last event descriptor. + */ private EventDescriptor lastEventDescriptor = null; /** * Gets the event descriptor. * - * @param event the event - * - * @return the event descriptor + * @param event + * the event. + * @return the event descriptor. */ EventDescriptor getEventDescriptor(AWTEvent event) { synchronized (this) { @@ -403,9 +476,9 @@ public abstract class AWTEvent extends EventObject { /** * Gets the event mask. * - * @param event the event - * - * @return the event mask + * @param event + * the event. + * @return the event mask. */ long getEventMask(AWTEvent event) { final EventDescriptor ed = getEventDescriptor(event); @@ -414,65 +487,62 @@ public abstract class AWTEvent extends EventObject { } /** - * The Class EventConverter. + * The class EventConverter. */ static final class EventConverter { - - /** The Constant OLD_MOD_MASK. */ - static final int OLD_MOD_MASK = Event.ALT_MASK | Event.CTRL_MASK - | Event.META_MASK | Event.SHIFT_MASK; + + /** + * The constant OLD_MOD_MASK. + */ + static final int OLD_MOD_MASK = Event.ALT_MASK | Event.CTRL_MASK | Event.META_MASK + | Event.SHIFT_MASK; /** * Convert action event. * - * @param ae the ae - * - * @return the event + * @param ae + * the ae. + * @return the event. */ Event convertActionEvent(ActionEvent ae) { Event evt = new Event(ae.getSource(), ae.getID(), ae.getActionCommand()); evt.when = ae.getWhen(); evt.modifiers = ae.getModifiers() & OLD_MOD_MASK; - /* if (source instanceof Button) { - arg = ((Button) source).getLabel(); - } else if (source instanceof Checkbox) { - arg = new Boolean(((Checkbox) source).getState()); - } else if (source instanceof CheckboxMenuItem) { - arg = ((CheckboxMenuItem) source).getLabel(); - } else if (source instanceof Choice) { - arg = ((Choice) source).getSelectedItem(); - } else if (source instanceof List) { - arg = ((List) source).getSelectedItem(); - } else if (source instanceof MenuItem) { - arg = ((MenuItem) source).getLabel(); - } else if (source instanceof TextField) { - arg = ((TextField) source).getText(); - } -*/ + /* + * if (source instanceof Button) { arg = ((Button) + * source).getLabel(); } else if (source instanceof Checkbox) { arg + * = new Boolean(((Checkbox) source).getState()); } else if (source + * instanceof CheckboxMenuItem) { arg = ((CheckboxMenuItem) + * source).getLabel(); } else if (source instanceof Choice) { arg = + * ((Choice) source).getSelectedItem(); } else if (source instanceof + * List) { arg = ((List) source).getSelectedItem(); } else if + * (source instanceof MenuItem) { arg = ((MenuItem) + * source).getLabel(); } else if (source instanceof TextField) { arg + * = ((TextField) source).getText(); } + */ return evt; } - /** * Convert adjustment event. * - * @param ae the ae - * - * @return the event + * @param ae + * the ae. + * @return the event. */ Event convertAdjustmentEvent(AdjustmentEvent ae) { - //TODO: Event.SCROLL_BEGIN/SCROLL_END - return new Event(ae.source, ae.id + ae.getAdjustmentType() - 1, - new Integer(ae.getValue())); + // TODO: Event.SCROLL_BEGIN/SCROLL_END + return new Event(ae.source, ae.id + ae.getAdjustmentType() - 1, new Integer(ae + .getValue())); } /** * Convert component event. * - * @param ce the ce - * - * @return the event + * @param ce + * the ce. + * @return the event. */ Event convertComponentEvent(ComponentEvent ce) { Component comp = ce.getComponent(); @@ -482,35 +552,27 @@ public abstract class AWTEvent extends EventObject { return evt; } - //???AWT + // ???AWT /* - Event convertItemEvent(ItemEvent ie) { - int oldId = ie.id + ie.getStateChange() - 1; - Object source = ie.source; - int idx = -1; - if (source instanceof List) { - List list = (List) source; - idx = list.getSelectedIndex(); - } - else if (source instanceof Choice) { - Choice choice = (Choice) source; - idx = choice.getSelectedIndex(); - } - Object arg = idx >= 0 ? new Integer(idx) : null; - return new Event(source, oldId, arg); - } - */ - + * Event convertItemEvent(ItemEvent ie) { int oldId = ie.id + + * ie.getStateChange() - 1; Object source = ie.source; int idx = -1; if + * (source instanceof List) { List list = (List) source; idx = + * list.getSelectedIndex(); } else if (source instanceof Choice) { + * Choice choice = (Choice) source; idx = choice.getSelectedIndex(); } + * Object arg = idx >= 0 ? new Integer(idx) : null; return new + * Event(source, oldId, arg); } + */ + /** * Convert key event. * - * @param ke the ke - * - * @return the event + * @param ke + * the ke. + * @return the event. */ Event convertKeyEvent(KeyEvent ke) { int oldId = ke.id; - //leave only old Event's modifiers + // leave only old Event's modifiers int mod = ke.getModifiers() & OLD_MOD_MASK; Component comp = ke.getComponent(); @@ -518,7 +580,7 @@ public abstract class AWTEvent extends EventObject { int keyCode = ke.getKeyCode(); int key = convertKey(keyChar, keyCode); if (key >= Event.HOME && key <= Event.INSERT) { - oldId += 2; //non-ASCII key -> action key + oldId += 2; // non-ASCII key -> action key } return new Event(comp, ke.getWhen(), oldId, 0, 0, key, mod); } @@ -526,9 +588,9 @@ public abstract class AWTEvent extends EventObject { /** * Convert mouse event. * - * @param me the me - * - * @return the event + * @param me + * the me. + * @return the event. */ Event convertMouseEvent(MouseEvent me) { int id = me.id; @@ -537,7 +599,7 @@ public abstract class AWTEvent extends EventObject { evt.x = me.getX(); evt.y = me.getY(); int mod = me.getModifiers(); - //in Event modifiers mean button number for mouse events: + // in Event modifiers mean button number for mouse events: evt.modifiers = mod & (Event.ALT_MASK | Event.META_MASK); if (id == MouseEvent.MOUSE_PRESSED) { evt.clickCount = me.getClickCount(); @@ -546,68 +608,69 @@ public abstract class AWTEvent extends EventObject { } return null; } - + /** * Convert key. * - * @param keyChar the key char - * @param keyCode the key code - * - * @return the int + * @param keyChar + * the key char. + * @param keyCode + * the key code. + * @return the int. */ int convertKey(char keyChar, int keyCode) { int key; - //F1 - F12 + // F1 - F12 if (keyCode >= KeyEvent.VK_F1 && keyCode <= KeyEvent.VK_F12) { key = Event.F1 + keyCode - KeyEvent.VK_F1; } else { switch (keyCode) { - default: //non-action key - key = keyChar; - break; - //action keys: - case KeyEvent.VK_HOME: - key = Event.HOME; - break; - case KeyEvent.VK_END: - key = Event.END; - break; - case KeyEvent.VK_PAGE_UP: - key = Event.PGUP; - break; - case KeyEvent.VK_PAGE_DOWN: - key = Event.PGDN; - break; - case KeyEvent.VK_UP: - key = Event.UP; - break; - case KeyEvent.VK_DOWN: - key = Event.DOWN; - break; - case KeyEvent.VK_LEFT: - key = Event.LEFT; - break; - case KeyEvent.VK_RIGHT: - key = Event.RIGHT; - break; - case KeyEvent.VK_PRINTSCREEN: - key = Event.PRINT_SCREEN; - break; - case KeyEvent.VK_SCROLL_LOCK: - key = Event.SCROLL_LOCK; - break; - case KeyEvent.VK_CAPS_LOCK: - key = Event.CAPS_LOCK; - break; - case KeyEvent.VK_NUM_LOCK: - key = Event.NUM_LOCK; - break; - case KeyEvent.VK_PAUSE: - key = Event.PAUSE; - break; - case KeyEvent.VK_INSERT: - key = Event.INSERT; - break; + default: // non-action key + key = keyChar; + break; + // action keys: + case KeyEvent.VK_HOME: + key = Event.HOME; + break; + case KeyEvent.VK_END: + key = Event.END; + break; + case KeyEvent.VK_PAGE_UP: + key = Event.PGUP; + break; + case KeyEvent.VK_PAGE_DOWN: + key = Event.PGDN; + break; + case KeyEvent.VK_UP: + key = Event.UP; + break; + case KeyEvent.VK_DOWN: + key = Event.DOWN; + break; + case KeyEvent.VK_LEFT: + key = Event.LEFT; + break; + case KeyEvent.VK_RIGHT: + key = Event.RIGHT; + break; + case KeyEvent.VK_PRINTSCREEN: + key = Event.PRINT_SCREEN; + break; + case KeyEvent.VK_SCROLL_LOCK: + key = Event.SCROLL_LOCK; + break; + case KeyEvent.VK_CAPS_LOCK: + key = Event.CAPS_LOCK; + break; + case KeyEvent.VK_NUM_LOCK: + key = Event.NUM_LOCK; + break; + case KeyEvent.VK_PAUSE: + key = Event.PAUSE; + break; + case KeyEvent.VK_INSERT: + key = Event.INSERT; + break; } } return key; diff --git a/awt/java/awt/AWTException.java b/awt/java/awt/AWTException.java index 70ce6e175d9f75058d853a099b43fc6d5da6fb32..6590b73d1dff95dc21c42ae48f242bfa133df724 100644 --- a/awt/java/awt/AWTException.java +++ b/awt/java/awt/AWTException.java @@ -18,26 +18,30 @@ * @author Michael Danilov * @version $Revision$ */ -package java.awt; +package java.awt; /** - * The AWTException class is used to provide notification and information - * about AWT errors. + * The AWTException class is used to provide notification and information about + * AWT errors. + * + * @since Android 1.0 */ public class AWTException extends Exception { - - /** The Constant serialVersionUID. */ + + /** + * The Constant serialVersionUID. + */ private static final long serialVersionUID = -1900414231151323879L; /** * Instantiates a new AWT exception with the specified message. * - * @param msg the specific message for current exception. + * @param msg + * the specific message for current exception. */ public AWTException(String msg) { super(msg); } } - diff --git a/awt/java/awt/AWTKeyStroke.java b/awt/java/awt/AWTKeyStroke.java index 5e7de4e3fcdc1975a8aecb545db863f40ac8f144..f01f6f00ec94e444f162555806bb8de45063b0b5 100644 --- a/awt/java/awt/AWTKeyStroke.java +++ b/awt/java/awt/AWTKeyStroke.java @@ -18,7 +18,9 @@ * @author Dmitry A. Durnev * @version $Revision$ */ + package java.awt; + import java.awt.event.InputEvent; import java.awt.event.KeyEvent; import java.io.ObjectStreamException; @@ -36,7 +38,7 @@ import org.apache.harmony.awt.internal.nls.Messages; * The AWTKeyStroke holds all of the information for the complete act of * typing a character. This includes the events that are generated when * the key is pressed, released, or typed (pressed and released generating - * a unicode character result) which are associated with the event + * a Unicode character result) which are associated with the event * objects KeyEvent.KEY_PRESSED, KeyEvent.KEY_RELEASED, or KeyEvent.KEY_TYPED. * It also holds information about which modifiers (such as control or * shift) were used in conjunction with the keystroke. The following masks @@ -57,19 +59,41 @@ import org.apache.harmony.awt.internal.nls.Messages; * The AWTKeyStroke is unique, and applications should not create their own * instances of AWTKeyStroke. All applications should use getAWTKeyStroke * methods for obtaining instances of AWTKeyStroke. + * + * @since Android 1.0 */ public class AWTKeyStroke implements Serializable { - - /** The Constant serialVersionUID. */ + + /** + * The Constant serialVersionUID. + */ private static final long serialVersionUID = -6430539691155161871L; - /** The Constant cache. */ - private static final Map cache = new HashMap(); //Map - - /** The Constant keyEventTypesMap. */ - private static final Map keyEventTypesMap = new HashMap(); //Map + /** + * The Constant cache. + */ + private static final Map cache = new HashMap(); // Map - private static Constructor subConstructor; + // < + // AWTKeyStroke + // , + // ? + // extends + // AWTKeyStroke + // > + + /** + * The Constant keyEventTypesMap. + */ + private static final Map keyEventTypesMap = new HashMap(); // Map + + // < + // int + // , + // String + // > + + private static Constructor subConstructor; static { keyEventTypesMap.put(new Integer(KeyEvent.KEY_PRESSED), "pressed"); //$NON-NLS-1$ @@ -77,53 +101,66 @@ public class AWTKeyStroke implements Serializable { keyEventTypesMap.put(new Integer(KeyEvent.KEY_TYPED), "typed"); //$NON-NLS-1$ } - /** The key char. */ + /** + * The key char. + */ private char keyChar; - - /** The key code. */ + + /** + * The key code. + */ private int keyCode; - - /** The modifiers. */ + + /** + * The modifiers. + */ private int modifiers; - - /** The on key release. */ + + /** + * The on key release. + */ private boolean onKeyRelease; - + /** - * Instantiates a new AWTKeyStroke. - * getAWTKeyStroke method should be used by applications code. - * - * @param keyChar the key char - * @param keyCode the key code - * @param modifiers the modifiers - * @param onKeyRelease true if AWTKeyStroke is for a key release, overwise false. - */ - protected AWTKeyStroke(char keyChar, int keyCode, int modifiers, - boolean onKeyRelease) - { - setAWTKeyStroke(keyChar, keyCode, modifiers, onKeyRelease); + * Instantiates a new AWTKeyStroke. getAWTKeyStroke method should be used by + * applications code. + * + * @param keyChar + * the key char. + * @param keyCode + * the key code. + * @param modifiers + * the modifiers. + * @param onKeyRelease + * true if AWTKeyStroke is for a key release, false otherwise. + */ + protected AWTKeyStroke(char keyChar, int keyCode, int modifiers, boolean onKeyRelease) { + setAWTKeyStroke(keyChar, keyCode, modifiers, onKeyRelease); } - /** Sets the awt key stroke. - * - * @param keyChar the key char - * @param keyCode the key code - * @param modifiers the modifiers - * @param onKeyRelease the on key release - */ - private void setAWTKeyStroke( char keyChar, int keyCode, int modifiers, - boolean onKeyRelease) - { + /** + * Sets the AWT key stroke. + * + * @param keyChar + * the key char. + * @param keyCode + * the key code. + * @param modifiers + * the modifiers. + * @param onKeyRelease + * the on key release. + */ + private void setAWTKeyStroke(char keyChar, int keyCode, int modifiers, boolean onKeyRelease) { this.keyChar = keyChar; this.keyCode = keyCode; this.modifiers = modifiers; this.onKeyRelease = onKeyRelease; } - + /** * Instantiates a new AWTKeyStroke with default parameters: - * KeyEvent.CHAR_UNDEFINED key char, KeyEvent.VK_UNDEFINED key code, - * without modifiers and false key realised value. + * KeyEvent.CHAR_UNDEFINED key char, KeyEvent.VK_UNDEFINED key code, without + * modifiers and false key realized value. */ protected AWTKeyStroke() { this(KeyEvent.CHAR_UNDEFINED, KeyEvent.VK_UNDEFINED, 0, false); @@ -132,42 +169,44 @@ public class AWTKeyStroke implements Serializable { /** * Returns the unique number value for AWTKeyStroke object. * - * @return the int unique value of the AWTKeyStroke object. + * @return the integer unique value of the AWTKeyStroke object. */ @Override public int hashCode() { - return modifiers + ( keyCode != KeyEvent.VK_UNDEFINED ? - keyCode : keyChar) + (onKeyRelease ? -1 : 0); + return modifiers + (keyCode != KeyEvent.VK_UNDEFINED ? keyCode : keyChar) + + (onKeyRelease ? -1 : 0); } /** * Gets the set of modifiers for the AWTKeyStroke object. * - * @return the int value which contains modifiers. + * @return the integer value which contains modifiers. */ public final int getModifiers() { return modifiers; } /** - * Compares the AWTKeyStroke object to the specified object. + * Compares this AWTKeyStroke object to the specified object. * - * @return true, if objects are identical, overwise false. + * @param anObject + * the specified AWTKeyStroke object to compare with this + * instance. + * @return true if objects are identical, false otherwise. */ @Override public final boolean equals(Object anObject) { if (anObject instanceof AWTKeyStroke) { AWTKeyStroke key = (AWTKeyStroke)anObject; - return ((key.keyCode == keyCode) && (key.keyChar == keyChar) && - (key.modifiers == modifiers) && - (key.onKeyRelease == onKeyRelease)); + return ((key.keyCode == keyCode) && (key.keyChar == keyChar) + && (key.modifiers == modifiers) && (key.onKeyRelease == onKeyRelease)); } return false; } /** - * Returns the string representation of the AWTKeyStroke. - * This string should contain key stroke properties. + * Returns the string representation of the AWTKeyStroke. This string should + * contain key stroke properties. * * @return the string representation of the AWTKeyStroke. */ @@ -175,9 +214,10 @@ public class AWTKeyStroke implements Serializable { public String toString() { int type = getKeyEventType(); return InputEvent.getModifiersExText(getModifiers()) + " " + //$NON-NLS-1$ - keyEventTypesMap.get(new Integer(type)) + " " + //$NON-NLS-1$ - (type == KeyEvent.KEY_TYPED ? new String(new char[] {keyChar}) : - KeyEvent.getKeyText(keyCode)); + keyEventTypesMap.get(new Integer(type)) + " " + //$NON-NLS-1$ + (type == KeyEvent.KEY_TYPED ? new String(new char[] { + keyChar + }) : KeyEvent.getKeyText(keyCode)); } /** @@ -201,16 +241,18 @@ public class AWTKeyStroke implements Serializable { /** * Gets the AWT key stroke. * - * @param keyChar the key char - * @param keyCode the key code - * @param modifiers the modifiers - * @param onKeyRelease the on key release - * - * @return the AWT key stroke + * @param keyChar + * the key char. + * @param keyCode + * the key code. + * @param modifiers + * the modifiers. + * @param onKeyRelease + * the on key release. + * @return the AWT key stroke. */ - private static AWTKeyStroke getAWTKeyStroke(char keyChar, int keyCode, - int modifiers, - boolean onKeyRelease) { + private static AWTKeyStroke getAWTKeyStroke(char keyChar, int keyCode, int modifiers, + boolean onKeyRelease) { AWTKeyStroke key = newInstance(keyChar, keyCode, modifiers, onKeyRelease); AWTKeyStroke value = cache.get(key); @@ -224,28 +266,30 @@ public class AWTKeyStroke implements Serializable { /** * New instance. * - * @param keyChar the key char - * @param keyCode the key code - * @param modifiers the modifiers - * @param onKeyRelease the on key release - * - * @return the AWT key stroke + * @param keyChar + * the key char. + * @param keyCode + * the key code. + * @param modifiers + * the modifiers. + * @param onKeyRelease + * the on key release. + * @return the AWT key stroke. */ - private static AWTKeyStroke newInstance(char keyChar, int keyCode, - int modifiers, - boolean onKeyRelease) { + private static AWTKeyStroke newInstance(char keyChar, int keyCode, int modifiers, + boolean onKeyRelease) { AWTKeyStroke key; - //???AWT -// if (subConstructor == null) { - key = new AWTKeyStroke(); - //???AWT -// } else { -// try { -// key = (AWTKeyStroke) subConstructor.newInstance(); -// } catch (Exception e) { -// throw new RuntimeException(e); -// } -// } + // ???AWT + // if (subConstructor == null) { + key = new AWTKeyStroke(); + // ???AWT + // } else { + // try { + // key = (AWTKeyStroke) subConstructor.newInstance(); + // } catch (Exception e) { + // throw new RuntimeException(e); + // } + // } int allModifiers = getAllModifiers(modifiers); key.setAWTKeyStroke(keyChar, keyCode, allModifiers, onKeyRelease); return key; @@ -254,21 +298,22 @@ public class AWTKeyStroke implements Serializable { /** * Adds the mask. * - * @param mod the mod - * @param mask the mask - * - * @return the int + * @param mod + * the mod. + * @param mask + * the mask. + * @return the int. */ private static int addMask(int mod, int mask) { return ((mod & mask) != 0) ? (mod | mask) : mod; } /** - * return all (old & new) modifiers corresponding to. - * - * @param mod old or new modifiers + * Return all (old & new) modifiers corresponding to. * - * @return old and new modifiers together + * @param mod + * old or new modifiers. + * @return old and new modifiers together. */ static int getAllModifiers(int mod) { int allMod = mod; @@ -289,27 +334,23 @@ public class AWTKeyStroke implements Serializable { } /** - * Returns an instance of AWTKeyStroke for parsed string. - * - * The string must have the following syntax: + * Returns an instance of AWTKeyStroke for parsed string. The string must + * have the following syntax: *

* <modifiers>* (<typedID> | <pressedReleasedID>) *

- * modifiers := shift | control | ctrl | meta | alt | altGraph - *
- * typedID := typed - *
- * typedKey := string of length 1 giving the Unicode character. - *
- * pressedReleasedID := (pressed | released) - *
+ * modifiers := shift | control | ctrl | meta | alt | altGraph
+ * typedID := typed
+ * typedKey := string of length 1 giving the Unicode character.
+ * pressedReleasedID := (pressed | released)
* key := KeyEvent key code name, i.e. the name following "VK_". *

- * @param s the String which contains key stroke parameters. * + * @param s + * the String which contains key stroke parameters. * @return the AWTKeyStroke for string. - * - * @throws IllegalArgumentException if string has incorrect format or null. + * @throws IllegalArgumentException + * if string has incorrect format or null. */ public static AWTKeyStroke getAWTKeyStroke(String s) { if (s == null) { @@ -351,16 +392,15 @@ public class AWTKeyStroke implements Serializable { throw new IllegalArgumentException(Messages.getString("awt.66")); //$NON-NLS-1$ } - return getAWTKeyStroke(keyChar, keyCode, modifiers, - release == Boolean.TRUE); + return getAWTKeyStroke(keyChar, keyCode, modifiers, release == Boolean.TRUE); } /** * Gets the next token. * - * @param tokenizer the tokenizer - * - * @return the next token + * @param tokenizer + * the tokenizer. + * @return the next token. */ private static String getNextToken(StringTokenizer tokenizer) { try { @@ -374,9 +414,9 @@ public class AWTKeyStroke implements Serializable { /** * Gets the key code. * - * @param s the s - * - * @return the key code + * @param s + * the s. + * @return the key code. */ static int getKeyCode(String s) { try { @@ -394,8 +434,8 @@ public class AWTKeyStroke implements Serializable { /** * Gets an instance of the AWTKeyStroke for specified character. * - * @param keyChar the keyboard character value. - * + * @param keyChar + * the keyboard character value. * @return a AWTKeyStroke for specified character. */ public static AWTKeyStroke getAWTKeyStroke(char keyChar) { @@ -403,120 +443,121 @@ public class AWTKeyStroke implements Serializable { } /** - * Returns an instance of AWTKeyStroke for a given key code, set - * of modifiers, and specified key released flag value. - * The key codes are defined in java.awt.event.KeyEvent class. - * The set of modifiers is given as a bitwise combination - * of masks taken from the following list: + * Returns an instance of AWTKeyStroke for a given key code, set of + * modifiers, and specified key released flag value. The key codes are + * defined in java.awt.event.KeyEvent class. The set of modifiers is given + * as a bitwise combination of masks taken from the following list: *

    - *
  • java.awt.event.InputEvent.ALT_GRAPH_DOWN_MASK
  • - *
  • java.awt.event.InputEvent.ALT_DOWN_MASK
  • - *
  • java.awt.event.InputEvent.CTRL_DOWN_MASK
  • - *
  • java.awt.event.InputEvent.META_DOWN_MASK
  • - *
  • java.awt.event.InputEvent.SHIFT_DOWN_MASK
  • - *
  • java.awt.event.InputEvent.ALT_GRAPH_MASK
  • - *
  • java.awt.event.InputEvent.ALT_MASK
  • - *
  • java.awt.event.InputEvent.CTRL_MASK
  • - *
  • java.awt.event.InputEvent.META_MASK
  • - *
  • java.awt.event.InputEvent.SHIFT_MASK
  • + *
  • java.awt.event.InputEvent.ALT_GRAPH_DOWN_MASK
  • + * java.awt.event.InputEvent.ALT_DOWN_MASK
  • + * java.awt.event.InputEvent.CTRL_DOWN_MASK
  • + * java.awt.event.InputEvent.META_DOWN_MASK
  • + * java.awt.event.InputEvent.SHIFT_DOWN_MASK
  • + * java.awt.event.InputEvent.ALT_GRAPH_MASK
  • + * java.awt.event.InputEvent.ALT_MASK
  • + * java.awt.event.InputEvent.CTRL_MASK
  • + * java.awt.event.InputEvent.META_MASK
  • + * java.awt.event.InputEvent.SHIFT_MASK
  • *
- *
- * - * @param keyCode the specified key code of keyboard. - * @param modifiers the bit set of modifiers. + *
* + * @param keyCode + * the specified key code of keyboard. + * @param modifiers + * the bit set of modifiers. + * @param onKeyRelease + * the value which represents whether this AWTKeyStroke shall + * represents a key release. * @return the AWTKeyStroke. */ - public static AWTKeyStroke getAWTKeyStroke(int keyCode, int modifiers, - boolean onKeyRelease) { - return getAWTKeyStroke(KeyEvent.CHAR_UNDEFINED, keyCode, modifiers, - onKeyRelease); + public static AWTKeyStroke getAWTKeyStroke(int keyCode, int modifiers, boolean onKeyRelease) { + return getAWTKeyStroke(KeyEvent.CHAR_UNDEFINED, keyCode, modifiers, onKeyRelease); } /** - * Returns AWTKeyStroke for a specified character and set of modifiers. - * The set of modifiers is given as a bitwise combination - * of masks taken from the following list: + * Returns AWTKeyStroke for a specified character and set of modifiers. The + * set of modifiers is given as a bitwise combination of masks taken from + * the following list: *
    - *
  • java.awt.event.InputEvent.ALT_GRAPH_DOWN_MASK
  • - *
  • java.awt.event.InputEvent.ALT_DOWN_MASK
  • - *
  • java.awt.event.InputEvent.CTRL_DOWN_MASK
  • - *
  • java.awt.event.InputEvent.META_DOWN_MASK
  • - *
  • java.awt.event.InputEvent.SHIFT_DOWN_MASK
  • - *
  • java.awt.event.InputEvent.ALT_GRAPH_MASK
  • - *
  • java.awt.event.InputEvent.ALT_MASK
  • - *
  • java.awt.event.InputEvent.CTRL_MASK
  • - *
  • java.awt.event.InputEvent.META_MASK
  • - *
  • java.awt.event.InputEvent.SHIFT_MASK
  • + *
  • java.awt.event.InputEvent.ALT_GRAPH_DOWN_MASK
  • + * java.awt.event.InputEvent.ALT_DOWN_MASK
  • + * java.awt.event.InputEvent.CTRL_DOWN_MASK
  • + * java.awt.event.InputEvent.META_DOWN_MASK
  • + * java.awt.event.InputEvent.SHIFT_DOWN_MASK
  • + * java.awt.event.InputEvent.ALT_GRAPH_MASK
  • + * java.awt.event.InputEvent.ALT_MASK
  • + * java.awt.event.InputEvent.CTRL_MASK
  • + * java.awt.event.InputEvent.META_MASK
  • + * java.awt.event.InputEvent.SHIFT_MASK
  • *
* - * @param keyChar the Character object which represents keyboard character value. - * @param modifiers the bit set of modifiers. - * + * @param keyChar + * the Character object which represents keyboard character + * value. + * @param modifiers + * the bit set of modifiers. * @return the AWTKeyStroke object. - * - * @throws IllegalArgumentException if keyChar value is null. + * @throws IllegalArgumentException + * if keyChar value is null. */ public static AWTKeyStroke getAWTKeyStroke(Character keyChar, int modifiers) { if (keyChar == null) { // awt.01='{0}' parameter is null throw new IllegalArgumentException(Messages.getString("awt.01", "keyChar")); //$NON-NLS-1$ //$NON-NLS-2$ } - return getAWTKeyStroke(keyChar.charValue(), KeyEvent.VK_UNDEFINED, - modifiers, false); + return getAWTKeyStroke(keyChar.charValue(), KeyEvent.VK_UNDEFINED, modifiers, false); } /** - * Returns an instance of AWTKeyStroke for a specified key code and - * set of modifiers. - * The key codes are defined in java.awt.event.KeyEvent class. - * The set of modifiers is given as a bitwise combination - * of masks taken from the following list: + * Returns an instance of AWTKeyStroke for a specified key code and set of + * modifiers. The key codes are defined in java.awt.event.KeyEvent class. + * The set of modifiers is given as a bitwise combination of masks taken + * from the following list: *
    - *
  • java.awt.event.InputEvent.ALT_GRAPH_DOWN_MASK
  • - *
  • java.awt.event.InputEvent.ALT_DOWN_MASK
  • - *
  • java.awt.event.InputEvent.CTRL_DOWN_MASK
  • - *
  • java.awt.event.InputEvent.META_DOWN_MASK
  • - *
  • java.awt.event.InputEvent.SHIFT_DOWN_MASK
  • - *
  • java.awt.event.InputEvent.ALT_GRAPH_MASK
  • - *
  • java.awt.event.InputEvent.ALT_MASK
  • - *
  • java.awt.event.InputEvent.CTRL_MASK
  • - *
  • java.awt.event.InputEvent.META_MASK
  • - *
  • java.awt.event.InputEvent.SHIFT_MASK
  • + *
  • java.awt.event.InputEvent.ALT_GRAPH_DOWN_MASK
  • + * java.awt.event.InputEvent.ALT_DOWN_MASK
  • + * java.awt.event.InputEvent.CTRL_DOWN_MASK
  • + * java.awt.event.InputEvent.META_DOWN_MASK
  • + * java.awt.event.InputEvent.SHIFT_DOWN_MASK
  • + * java.awt.event.InputEvent.ALT_GRAPH_MASK
  • + * java.awt.event.InputEvent.ALT_MASK
  • + * java.awt.event.InputEvent.CTRL_MASK
  • + * java.awt.event.InputEvent.META_MASK
  • + * java.awt.event.InputEvent.SHIFT_MASK
  • *
- * - * @param keyCode the specified key code of keyboard. - * @param modifiers the bit set of modifiers. * - * @return the AWTKeyStroke + * @param keyCode + * the specified key code of keyboard. + * @param modifiers + * the bit set of modifiers. + * @return the AWTKeyStroke. */ public static AWTKeyStroke getAWTKeyStroke(int keyCode, int modifiers) { return getAWTKeyStroke(keyCode, modifiers, false); } /** - * Gets the AWTKeyStroke for a key event. This method obtains the key char + * Gets the AWTKeyStroke for a key event. This method obtains the key char * and key code from the specified key event. * - * @param anEvent the key event which identifies the desired AWTKeyStroke. - * + * @param anEvent + * the key event which identifies the desired AWTKeyStroke. * @return the AWTKeyStroke for the key event. */ public static AWTKeyStroke getAWTKeyStrokeForEvent(KeyEvent anEvent) { int id = anEvent.getID(); char undef = KeyEvent.CHAR_UNDEFINED; - char keyChar = (id == KeyEvent.KEY_TYPED ? anEvent.getKeyChar() : - undef); - int keyCode = (keyChar == undef ? anEvent.getKeyCode() : - KeyEvent.VK_UNDEFINED); + char keyChar = (id == KeyEvent.KEY_TYPED ? anEvent.getKeyChar() : undef); + int keyCode = (keyChar == undef ? anEvent.getKeyCode() : KeyEvent.VK_UNDEFINED); return getAWTKeyStroke(keyChar, keyCode, anEvent.getModifiersEx(), - id == KeyEvent.KEY_RELEASED); + id == KeyEvent.KEY_RELEASED); } /** * Gets the key event type for the AWTKeyStroke object. * - * @return the key event type: KeyEvent.KEY_PRESSED, KeyEvent.KEY_TYPED, or KeyEvent.KEY_RELEASED + * @return the key event type: KeyEvent.KEY_PRESSED, KeyEvent.KEY_TYPED, or + * KeyEvent.KEY_RELEASED. */ public final int getKeyEventType() { if (keyCode == KeyEvent.VK_UNDEFINED) { @@ -526,11 +567,11 @@ public class AWTKeyStroke implements Serializable { } /** - * Retuns true if the key event is associated with the AWTKeyStroke is - * KEY_RELEASED, overwise false. + * Returns true if the key event is associated with the AWTKeyStroke is + * KEY_RELEASED, false otherwise. * - * @return true, if if the key event associated with the AWTKeyStroke is - * KEY_RELEASED, overwise false. + * @return true, if if the key event associated with the AWTKeyStroke is + * KEY_RELEASED, false otherwise. */ public final boolean isOnKeyRelease() { return onKeyRelease; @@ -539,50 +580,44 @@ public class AWTKeyStroke implements Serializable { /** * Read resolve. * - * @return the object - * - * @throws ObjectStreamException the object stream exception + * @return the object. + * @throws ObjectStreamException + * the object stream exception. */ protected Object readResolve() throws ObjectStreamException { - return getAWTKeyStroke(this.keyChar, this.keyCode, - this.modifiers, this.onKeyRelease); + return getAWTKeyStroke(this.keyChar, this.keyCode, this.modifiers, this.onKeyRelease); } /** * Register subclass. * - * @param subclass the subclass + * @param subclass + * the subclass. */ protected static void registerSubclass(Class subclass) { - //???AWT + // ???AWT /* - if (subclass == null) { - // awt.01='{0}' parameter is null - throw new IllegalArgumentException(Messages.getString("awt.01", "subclass")); //$NON-NLS-1$ //$NON-NLS-2$ - } - if (! AWTKeyStroke.class.isAssignableFrom(subclass)) { - // awt.67=subclass is not derived from AWTKeyStroke - throw new ClassCastException(Messages.getString("awt.67")); //$NON-NLS-1$ - } - try { - subConstructor = subclass.getDeclaredConstructor(); - subConstructor.setAccessible(true); - } catch (SecurityException e) { - throw new RuntimeException(e); - } catch (NoSuchMethodException e) { - // awt.68=subclass could not be instantiated - throw new IllegalArgumentException(Messages.getString("awt.68")); //$NON-NLS-1$ - } - cache.clear(); //flush the cache - */ + * if (subclass == null) { // awt.01='{0}' parameter is null throw new + * IllegalArgumentException(Messages.getString("awt.01", "subclass")); + * //$NON-NLS-1$ //$NON-NLS-2$ } if (! + * AWTKeyStroke.class.isAssignableFrom(subclass)) { // awt.67=subclass + * is not derived from AWTKeyStroke throw new + * ClassCastException(Messages.getString("awt.67")); //$NON-NLS-1$ } try + * { subConstructor = subclass.getDeclaredConstructor(); + * subConstructor.setAccessible(true); } catch (SecurityException e) { + * throw new RuntimeException(e); } catch (NoSuchMethodException e) { // + * awt.68=subclass could not be instantiated throw new + * IllegalArgumentException(Messages.getString("awt.68")); //$NON-NLS-1$ + * } cache.clear(); //flush the cache + */ } /** * Parses the modifier. * - * @param strMod the str mod - * - * @return the long + * @param strMod + * the str mod. + * @return the long. */ private static long parseModifier(String strMod) { long modifiers = 0l; @@ -609,9 +644,9 @@ public class AWTKeyStroke implements Serializable { /** * Parses the typed id. * - * @param strTyped the str typed - * - * @return true, if successful + * @param strTyped + * the str typed. + * @return true, if successful. */ private static boolean parseTypedID(String strTyped) { if (strTyped.equals("typed")) { //$NON-NLS-1$ @@ -624,9 +659,9 @@ public class AWTKeyStroke implements Serializable { /** * Parses the typed key. * - * @param strChar the str char - * - * @return the char + * @param strChar + * the str char. + * @return the char. */ private static char parseTypedKey(String strChar) { char keyChar = KeyEvent.CHAR_UNDEFINED; @@ -642,9 +677,9 @@ public class AWTKeyStroke implements Serializable { /** * Parses the pressed released id. * - * @param str the str - * - * @return the boolean + * @param str + * the str. + * @return the boolean. */ private static Boolean parsePressedReleasedID(String str) { @@ -659,9 +694,9 @@ public class AWTKeyStroke implements Serializable { /** * Parses the key. * - * @param strCode the str code - * - * @return the int + * @param strCode + * the str code. + * @return the int. */ private static int parseKey(String strCode) { int keyCode = KeyEvent.VK_UNDEFINED; @@ -675,4 +710,3 @@ public class AWTKeyStroke implements Serializable { return keyCode; } } - diff --git a/awt/java/awt/AWTPermission.java b/awt/java/awt/AWTPermission.java index 25326abb1a6b2100a4d61bf65410505b2dd7f7c9..4bd835777d612f467977863a5b7d0f9b2b055097 100644 --- a/awt/java/awt/AWTPermission.java +++ b/awt/java/awt/AWTPermission.java @@ -18,24 +18,31 @@ * @author Pavel Dolgov * @version $Revision$ */ + package java.awt; import java.security.BasicPermission; /** - * The AWTPermission specifies the name of the permission and the - * corresponding action list. + * The AWTPermission specifies the name of the permission and the corresponding + * action list. + * + * @since Android 1.0 */ public final class AWTPermission extends BasicPermission { - - /** The Constant serialVersionUID. */ + + /** + * The Constant serialVersionUID. + */ private static final long serialVersionUID = 8890392402588814465L; /** * Instantiates a new AWTPermission with defined name and actions. * - * @param name the name of a new AWTPermission. - * @param actions the actions of a new AWTPermission. + * @param name + * the name of a new AWTPermission. + * @param actions + * the actions of a new AWTPermission. */ public AWTPermission(String name, String actions) { super(name, actions); @@ -44,11 +51,11 @@ public final class AWTPermission extends BasicPermission { /** * Instantiates a new AWT permission with the defined name. * - * @param name the name of a new AWTPermission. + * @param name + * the name of a new AWTPermission. */ public AWTPermission(String name) { super(name); } } - diff --git a/awt/java/awt/ActiveEvent.java b/awt/java/awt/ActiveEvent.java index 41337524a6028927729db5f332e35863dd1c209b..704462390a017c83ecd8d4818071529c8dab0311 100644 --- a/awt/java/awt/ActiveEvent.java +++ b/awt/java/awt/ActiveEvent.java @@ -18,18 +18,21 @@ * @author Michael Danilov * @version $Revision$ */ + package java.awt; /** - * This interface defines events that know how to dispatch themselves. - * Such event can be placed upon the event queue and its dispatch method - * will be called when the event is dispatched. + * This interface defines events that know how to dispatch themselves. Such + * event can be placed upon the event queue and its dispatch method will be + * called when the event is dispatched. + * + * @since Android 1.0 */ public interface ActiveEvent { /** - * Dispatches the event to the listeners of the event's source, - * or does whatever it is this event is supposed to do. + * Dispatches the event to the listeners of the event's source, or does + * whatever it is this event is supposed to do. */ public void dispatch(); diff --git a/awt/java/awt/Adjustable.java b/awt/java/awt/Adjustable.java index 3241cad1dbeba35432f3dc5decb6cc8a9821e6cb..baf80f7c7c6fdb0b8d58927038af4384751e6d1d 100644 --- a/awt/java/awt/Adjustable.java +++ b/awt/java/awt/Adjustable.java @@ -18,32 +18,35 @@ * @author Pavel Dolgov * @version $Revision$ */ + package java.awt; import java.awt.event.AdjustmentListener; /** - * The Adjustable interface represents an adjustable numeric value - * contained within a bounded range of values, such as the current - * location in scrollable region or the value of a gauge. + * The Adjustable interface represents an adjustable numeric value contained + * within a bounded range of values, such as the current location in scrollable + * region or the value of a gauge. + * + * @since Android 1.0 */ public interface Adjustable { - /** - * The Constant HORIZONTAL indicates that the Adjustable's orientation - * is horizontal. + /** + * The Constant HORIZONTAL indicates that the Adjustable's orientation is + * horizontal. */ public static final int HORIZONTAL = 0; - /** - * The Constant VERTICAL indicates that the Adjustable's orientation - * is vertical. + /** + * The Constant VERTICAL indicates that the Adjustable's orientation is + * vertical. */ public static final int VERTICAL = 1; - /** - * The Constant NO_ORIENTATION indicates that the Adjustable - * has no orientation. + /** + * The Constant NO_ORIENTATION indicates that the Adjustable has no + * orientation. */ public static final int NO_ORIENTATION = 2; @@ -57,14 +60,16 @@ public interface Adjustable { /** * Sets the value to the Adjustable object. * - * @param a0 the new value of the Adjustable object. + * @param a0 + * the new value of the Adjustable object. */ public void setValue(int a0); /** * Adds the AdjustmentListener to current Adjustment. * - * @param a0 the AdjustmentListener object. + * @param a0 + * the AdjustmentListener object. */ public void addAdjustmentListener(AdjustmentListener a0); @@ -85,7 +90,7 @@ public interface Adjustable { /** * Gets the minimum value of the Adjustable. * - * @return the minimum value of the Adjustable. + * @return the minimum value of the Adjustable. */ public int getMinimum(); @@ -113,44 +118,49 @@ public interface Adjustable { /** * Removes the adjustment listener of the Adjustable. * - * @param a0 the specified AdjustmentListener to be removed. + * @param a0 + * the specified AdjustmentListener to be removed. */ public void removeAdjustmentListener(AdjustmentListener a0); /** * Sets the block increment for the Adjustable. * - * @param a0 the new block increment. + * @param a0 + * the new block increment. */ public void setBlockIncrement(int a0); /** * Sets the maximum value of the Adjustable. * - * @param a0 the new maximum of the Adjustable. + * @param a0 + * the new maximum of the Adjustable. */ public void setMaximum(int a0); /** * Sets the minimum value of the Adjustable. * - * @param a0 the new minimum of the Adjustable. + * @param a0 + * the new minimum of the Adjustable. */ public void setMinimum(int a0); /** * Sets the unit increment of the Adjustable. * - * @param a0 the new unit increment of the Adjustable. + * @param a0 + * the new unit increment of the Adjustable. */ public void setUnitIncrement(int a0); /** * Sets the visible amount of the Adjustable. * - * @param a0 the new visible amount of the Adjustable. + * @param a0 + * the new visible amount of the Adjustable. */ public void setVisibleAmount(int a0); } - diff --git a/awt/java/awt/AlphaComposite.java b/awt/java/awt/AlphaComposite.java index d26753c316a766c9d7ff6fd29890b8fbd5e97bfc..8389eb4621fe21be31d0997fd4a60161a104cf10 100644 --- a/awt/java/awt/AlphaComposite.java +++ b/awt/java/awt/AlphaComposite.java @@ -18,6 +18,7 @@ * @author Igor V. Stolyarov * @version $Revision$ */ + package java.awt; import java.awt.Composite; @@ -28,148 +29,181 @@ import java.awt.image.ColorModel; import org.apache.harmony.awt.gl.ICompositeContext; import org.apache.harmony.awt.internal.nls.Messages; - /** - * The AlphaComposite class defines a basic alpha compositing rules for - * combining source and destination colors to achieve blending and - * transparency effects with graphics and images. + * The AlphaComposite class defines a basic alpha compositing rules for + * combining source and destination colors to achieve blending and transparency + * effects with graphics and images. + * + * @since Android 1.0 */ public final class AlphaComposite implements Composite { - /** - * The Constant CLEAR indicates that both the color and the alpha of - * the destination are cleared (Porter-Duff Clear rule). + /** + * The Constant CLEAR indicates that both the color and the alpha of the + * destination are cleared (Porter-Duff Clear rule). */ public static final int CLEAR = 1; - /** - * The Constant SRC indicates that the source is copied to the destination + /** + * The Constant SRC indicates that the source is copied to the destination * (Porter-Duff Source rule). */ public static final int SRC = 2; - /** The Constant DST indicates that the destination is left untouched + /** + * The Constant DST indicates that the destination is left untouched * (Porter-Duff Destination rule). */ public static final int DST = 9; - /** - * The Constant SRC_OVER indicates that the source is composited over - * the destination (Porter-Duff Source Over Destination rule). + /** + * The Constant SRC_OVER indicates that the source is composited over the + * destination (Porter-Duff Source Over Destination rule). */ public static final int SRC_OVER = 3; /** - * The Constant DST_OVER indicates that The destination is composited over - * the source and the result replaces the destination - * (Porter-Duff Destination Over Source rule). + * The Constant DST_OVER indicates that The destination is composited over + * the source and the result replaces the destination (Porter-Duff + * Destination Over Source rule). */ public static final int DST_OVER = 4; /** - * The Constant SRC_IN indicates that the part of the source lying - * inside of the destination replaces the destination (Porter-Duff - * Source In Destination rule). + * The Constant SRC_IN indicates that the part of the source lying inside of + * the destination replaces the destination (Porter-Duff Source In + * Destination rule). */ public static final int SRC_IN = 5; - /** - * The Constant DST_IN indicates that the part of the destination - * lying inside of the source replaces the destination - * (Porter-Duff Destination In Source rule). + /** + * The Constant DST_IN indicates that the part of the destination lying + * inside of the source replaces the destination (Porter-Duff Destination In + * Source rule). */ public static final int DST_IN = 6; /** - * The Constant SRC_OUT indicates that the part of the source lying - * outside of the destination replaces the destination (Porter-Duff - * Source Held Out By Destination rule). + * The Constant SRC_OUT indicates that the part of the source lying outside + * of the destination replaces the destination (Porter-Duff Source Held Out + * By Destination rule). */ public static final int SRC_OUT = 7; - /** - * The Constant DST_OUT indicates that the part of the destination - * lying outside of the source replaces the destination (Porter-Duff - * Destination Held Out By Source rule). + /** + * The Constant DST_OUT indicates that the part of the destination lying + * outside of the source replaces the destination (Porter-Duff Destination + * Held Out By Source rule). */ public static final int DST_OUT = 8; - /** - * The Constant SRC_ATOP indicates that the part of the source lying - * inside of the destination is composited onto the destination - * (Porter-Duff Source Atop Destination rule). + /** + * The Constant SRC_ATOP indicates that the part of the source lying inside + * of the destination is composited onto the destination (Porter-Duff Source + * Atop Destination rule). */ public static final int SRC_ATOP = 10; - /** - * The Constant DST_ATOP indicates that the part of the destination - * lying inside of the source is composited over the source and replaces - * the destination (Porter-Duff Destination Atop Source rule). + /** + * The Constant DST_ATOP indicates that the part of the destination lying + * inside of the source is composited over the source and replaces the + * destination (Porter-Duff Destination Atop Source rule). */ public static final int DST_ATOP = 11; /** - * The Constant XOR indicates that the part of the source that lies - * outside of the destination is combined with the part of the destination - * that lies outside of the source (Porter-Duff Source Xor Destination rule). + * The Constant XOR indicates that the part of the source that lies outside + * of the destination is combined with the part of the destination that lies + * outside of the source (Porter-Duff Source Xor Destination rule). */ public static final int XOR = 12; - /** AlphaComposite object with the opaque CLEAR rule and an alpha of 1.0f. */ + /** + * AlphaComposite object with the opaque CLEAR rule and an alpha of 1.0f. + */ public static final AlphaComposite Clear = new AlphaComposite(CLEAR); - /** AlphaComposite object with the opaque SRC rule and an alpha of 1.0f. */ + /** + * AlphaComposite object with the opaque SRC rule and an alpha of 1.0f. + */ public static final AlphaComposite Src = new AlphaComposite(SRC); - /** AlphaComposite object with the opaque DST rule and an alpha of 1.0f. */ + /** + * AlphaComposite object with the opaque DST rule and an alpha of 1.0f. + */ public static final AlphaComposite Dst = new AlphaComposite(DST); - /** AlphaComposite object with the opaque SRC_OVER rule and an alpha of 1.0f. */ + /** + * AlphaComposite object with the opaque SRC_OVER rule and an alpha of 1.0f. + */ public static final AlphaComposite SrcOver = new AlphaComposite(SRC_OVER); - /** AlphaComposite object with the opaque DST_OVER rule and an alpha of 1.0f. */ + /** + * AlphaComposite object with the opaque DST_OVER rule and an alpha of 1.0f. + */ public static final AlphaComposite DstOver = new AlphaComposite(DST_OVER); - /** AlphaComposite object with the opaque SRC_IN rule and an alpha of 1.0f. */ + /** + * AlphaComposite object with the opaque SRC_IN rule and an alpha of 1.0f. + */ public static final AlphaComposite SrcIn = new AlphaComposite(SRC_IN); - /** AlphaComposite object with the opaque DST_IN rule and an alpha of 1.0f. */ + /** + * AlphaComposite object with the opaque DST_IN rule and an alpha of 1.0f. + */ public static final AlphaComposite DstIn = new AlphaComposite(DST_IN); - /** AlphaComposite object with the opaque SRC_OUT rule and an alpha of 1.0f. */ + /** + * AlphaComposite object with the opaque SRC_OUT rule and an alpha of 1.0f. + */ public static final AlphaComposite SrcOut = new AlphaComposite(SRC_OUT); - /** AlphaComposite object with the opaque DST_OUT rule and an alpha of 1.0f. */ + /** + * AlphaComposite object with the opaque DST_OUT rule and an alpha of 1.0f. + */ public static final AlphaComposite DstOut = new AlphaComposite(DST_OUT); - /** AlphaComposite object with the opaque SRC_ATOP rule and an alpha of 1.0f. */ + /** + * AlphaComposite object with the opaque SRC_ATOP rule and an alpha of 1.0f. + */ public static final AlphaComposite SrcAtop = new AlphaComposite(SRC_ATOP); - /** AlphaComposite object with the opaque DST_ATOP rule and an alpha of 1.0f. */ + /** + * AlphaComposite object with the opaque DST_ATOP rule and an alpha of 1.0f. + */ public static final AlphaComposite DstAtop = new AlphaComposite(DST_ATOP); - /** AlphaComposite object with the opaque XOR rule and an alpha of 1.0f. */ + /** + * AlphaComposite object with the opaque XOR rule and an alpha of 1.0f. + */ public static final AlphaComposite Xor = new AlphaComposite(XOR); - /** The rule. */ + /** + * The rule. + */ private int rule; - - /** The alpha. */ + + /** + * The alpha. + */ private float alpha; /** - * Instantiates a new alpha composite. - * Creates a context for the compositing operation. The context contains state that is used in performing the compositing operation. + * Instantiates a new alpha composite. Creates a context for the compositing + * operation. The context contains state that is used in performing the + * compositing operation. * - * @param rule the rule - * @param alpha the alpha + * @param rule + * the rule. + * @param alpha + * the alpha. */ - private AlphaComposite(int rule, float alpha){ - if(rule < CLEAR || rule > XOR) { + private AlphaComposite(int rule, float alpha) { + if (rule < CLEAR || rule > XOR) { // awt.11D=Unknown rule throw new IllegalArgumentException(Messages.getString("awt.11D")); //$NON-NLS-1$ } - if(alpha < 0.0f || alpha > 1.0f) { + if (alpha < 0.0f || alpha > 1.0f) { // awt.11E=Wrong alpha value throw new IllegalArgumentException(Messages.getString("awt.11E")); //$NON-NLS-1$ } @@ -181,41 +215,44 @@ public final class AlphaComposite implements Composite { /** * Instantiates a new alpha composite. * - * @param rule the rule + * @param rule + * the rule. */ - private AlphaComposite(int rule){ + private AlphaComposite(int rule) { this(rule, 1.0f); } /** * Creates a CompositeContext object with the specified source ColorModel, - * destination ColorModel and RenderingHints parameters for a composing + * destination ColorModel and RenderingHints parameters for a composing * operation. * - * @param srcColorModel the source's ColorModel. - * @param dstColorModel the destination's ColorModel. - * @param hints the RenderingHints object. - * - * @return the CompositeContext object. - * - * @see java.awt.Composite#createContext(java.awt.image.ColorModel, java.awt.image.ColorModel, java.awt.RenderingHints) + * @param srcColorModel + * the source's ColorModel. + * @param dstColorModel + * the destination's ColorModel. + * @param hints + * the RenderingHints object. + * @return the CompositeContext object. + * @see java.awt.Composite#createContext(java.awt.image.ColorModel, + * java.awt.image.ColorModel, java.awt.RenderingHints) */ - public CompositeContext createContext(ColorModel srcColorModel, - ColorModel dstColorModel, RenderingHints hints) { + public CompositeContext createContext(ColorModel srcColorModel, ColorModel dstColorModel, + RenderingHints hints) { return new ICompositeContext(this, srcColorModel, dstColorModel); } /** * Compares the AlphaComposite object with the specified object. * - * @param obj the Object to be compared. - * + * @param obj + * the Object to be compared. * @return true, if the AlphaComposite object is equal to the specified - * object. + * object. */ @Override public boolean equals(Object obj) { - if(!(obj instanceof AlphaComposite)) { + if (!(obj instanceof AlphaComposite)) { return false; } AlphaComposite other = (AlphaComposite)obj; @@ -247,11 +284,11 @@ public final class AlphaComposite implements Composite { } /** - * Gets the alpha value of this AlphaComposite object; returns 1.0 if - * this AlphaComposite object doesn't have alpha value. + * Gets the alpha value of this AlphaComposite object; returns 1.0 if this + * AlphaComposite object doesn't have alpha value. * - * @return the alpha value of this AlphaComposite object or 1.0 if - * this AlphaComposite object doesn't have alpha value. + * @return the alpha value of this AlphaComposite object or 1.0 if this + * AlphaComposite object doesn't have alpha value. */ public float getAlpha() { return alpha; @@ -260,13 +297,14 @@ public final class AlphaComposite implements Composite { /** * Gets the AlphaComposite instance with the specified rule and alpha value. * - * @param rule the compositing rule. - * @param alpha the alpha value. - * - * @return AlphaComposite instance. + * @param rule + * the compositing rule. + * @param alpha + * the alpha value. + * @return the AlphaComposite instance. */ public static AlphaComposite getInstance(int rule, float alpha) { - if(alpha == 1.0f) { + if (alpha == 1.0f) { return getInstance(rule); } return new AlphaComposite(rule, alpha); @@ -275,41 +313,40 @@ public final class AlphaComposite implements Composite { /** * Gets the AlphaComposite instance with the specified rule. * - * @param rule the compositing rule. - * - * @return AlphaComposite instance. + * @param rule + * the compositing rule. + * @return the AlphaComposite instance. */ public static AlphaComposite getInstance(int rule) { - switch(rule){ - case CLEAR: - return Clear; - case SRC: - return Src; - case DST: - return Dst; - case SRC_OVER: - return SrcOver; - case DST_OVER: - return DstOver; - case SRC_IN: - return SrcIn; - case DST_IN: - return DstIn; - case SRC_OUT: - return SrcOut; - case DST_OUT: - return DstOut; - case SRC_ATOP: - return SrcAtop; - case DST_ATOP: - return DstAtop; - case XOR: - return Xor; - default: - // awt.11D=Unknown rule - throw new IllegalArgumentException(Messages.getString("awt.11D")); //$NON-NLS-1$ + switch (rule) { + case CLEAR: + return Clear; + case SRC: + return Src; + case DST: + return Dst; + case SRC_OVER: + return SrcOver; + case DST_OVER: + return DstOver; + case SRC_IN: + return SrcIn; + case DST_IN: + return DstIn; + case SRC_OUT: + return SrcOut; + case DST_OUT: + return DstOut; + case SRC_ATOP: + return SrcAtop; + case DST_ATOP: + return DstAtop; + case XOR: + return Xor; + default: + // awt.11D=Unknown rule + throw new IllegalArgumentException(Messages.getString("awt.11D")); //$NON-NLS-1$ } } } - diff --git a/awt/java/awt/BasicStroke.java b/awt/java/awt/BasicStroke.java index 955dc6b3331dc58d90fcd51425957d92cc1441b8..245781570a73b0fe0f1ba62bdb4e2fcc50bf6e81 100644 --- a/awt/java/awt/BasicStroke.java +++ b/awt/java/awt/BasicStroke.java @@ -18,6 +18,7 @@ * @author Denis M. Kishenko * @version $Revision$ */ + package java.awt; import java.awt.geom.GeneralPath; @@ -27,139 +28,188 @@ import org.apache.harmony.awt.internal.nls.Messages; import org.apache.harmony.misc.HashCode; /** - * The BasicStroke class specifies a set of rendering attributes for the outlines - * of graphics primitives. The BasicStroke attributes describe the shape of the - * pen which draws the outline of a Shape and the decorations applied at the ends - * and joins of path segments of the Shape. The BasicStroke has the following - * rendering attributes: + * The BasicStroke class specifies a set of rendering attributes for the + * outlines of graphics primitives. The BasicStroke attributes describe the + * shape of the pen which draws the outline of a Shape and the decorations + * applied at the ends and joins of path segments of the Shape. The BasicStroke + * has the following rendering attributes: *

*

    - *
  • line width -the pen width which draws the outlines.
  • - *
  • end caps - indicates the decoration applied to the ends of unclosed - * subpaths and dash segments. The BasicStroke defines three different decorations: - * CAP_BUTT, CAP_ROUND, and CAP_SQUARE.
  • - *
  • line joins - indicates the decoration applied at the intersection of - * two path segments and at the intersection of the endpoints of a subpath. - * The BasicStroke defines three decorations: JOIN_BEVEL, JOIN_MITER, - * and JOIN_ROUND.
  • - *
  • miter limit - the limit to trim a line join that has a JOIN_MITER + *
  • line width -the pen width which draws the outlines.
  • + *
  • end caps - indicates the decoration applied to the ends of unclosed + * subpaths and dash segments. The BasicStroke defines three different + * decorations: CAP_BUTT, CAP_ROUND, and CAP_SQUARE.
  • + *
  • line joins - indicates the decoration applied at the intersection of two + * path segments and at the intersection of the endpoints of a subpath. The + * BasicStroke defines three decorations: JOIN_BEVEL, JOIN_MITER, and + * JOIN_ROUND.
  • + *
  • miter limit - the limit to trim a line join that has a JOIN_MITER * decoration.
  • - *
  • dash attributes - the definition of how to make a dash pattern by - * alternating between opaque and transparent sections
  • + *
  • dash attributes - the definition of how to make a dash pattern by + * alternating between opaque and transparent sections
  • *
+ *

+ * + * @since Android 1.0 */ public class BasicStroke implements Stroke { - /** - * The Constant CAP_BUTT indicates the ends of unclosed subpaths - * and dash segments have no added decoration. + /** + * The Constant CAP_BUTT indicates the ends of unclosed subpaths and dash + * segments have no added decoration. */ public static final int CAP_BUTT = 0; - - /** - * The Constant CAP_ROUND indicates the ends of unclosed subpaths - * and dash segments have a round decoration. + + /** + * The Constant CAP_ROUND indicates the ends of unclosed subpaths and dash + * segments have a round decoration. */ public static final int CAP_ROUND = 1; - - /** - * The Constant CAP_SQUARE indicates the ends of unclosed subpaths - * and dash segments have a square projection. + + /** + * The Constant CAP_SQUARE indicates the ends of unclosed subpaths and dash + * segments have a square projection. */ public static final int CAP_SQUARE = 2; - /** - * The Constant JOIN_MITER indicates that path segments are joined by + /** + * The Constant JOIN_MITER indicates that path segments are joined by * extending their outside edges until they meet. */ public static final int JOIN_MITER = 0; - - /** - * The Constant JOIN_ROUND indicates that path segments are joined by + + /** + * The Constant JOIN_ROUND indicates that path segments are joined by * rounding off the corner at a radius of half the line width. */ public static final int JOIN_ROUND = 1; - - /** - * The Constant JOIN_BEVEL indicates that path segments are joined by - * connecting the outer corners of their wide outlines with - * a straight segment. + + /** + * The Constant JOIN_BEVEL indicates that path segments are joined by + * connecting the outer corners of their wide outlines with a straight + * segment. */ public static final int JOIN_BEVEL = 2; - - /** Constants for calculating. */ - static final int MAX_LEVEL = 20; // Maximal deepness of curve subdivision - - /** The Constant CURVE_DELTA. */ - static final double CURVE_DELTA = 2.0; // Width tolerance - - /** The Constant CORNER_ANGLE. */ + + /** + * Constants for calculating. + */ + static final int MAX_LEVEL = 20; // Maximal deepness of curve subdivision + + /** + * The Constant CURVE_DELTA. + */ + static final double CURVE_DELTA = 2.0; // Width tolerance + + /** + * The Constant CORNER_ANGLE. + */ static final double CORNER_ANGLE = 4.0; // Minimum corner angle - - /** The Constant CORNER_ZERO. */ + + /** + * The Constant CORNER_ZERO. + */ static final double CORNER_ZERO = 0.01; // Zero angle - - /** The Constant CUBIC_ARC. */ + + /** + * The Constant CUBIC_ARC. + */ static final double CUBIC_ARC = 4.0 / 3.0 * (Math.sqrt(2.0) - 1); - /** Stroke width. */ + /** + * Stroke width. + */ float width; - - /** Stroke cap type. */ + + /** + * Stroke cap type. + */ int cap; - - /** Stroke join type. */ + + /** + * Stroke join type. + */ int join; - - /** Stroke miter limit. */ + + /** + * Stroke miter limit. + */ float miterLimit; - - /** Stroke dashes array. */ + + /** + * Stroke dashes array. + */ float dash[]; - - /** Stroke dash phase. */ + + /** + * Stroke dash phase. + */ float dashPhase; - /** The temporary pre-calculated values. */ + /** + * The temporary pre-calculated values. + */ double curveDelta; - - /** The corner delta. */ + + /** + * The corner delta. + */ double cornerDelta; - - /** The zero delta. */ + + /** + * The zero delta. + */ double zeroDelta; - /** The w2. */ + /** + * The w2. + */ double w2; - - /** The fmy. */ + + /** + * The fmy. + */ double fmx, fmy; - - /** The smy. */ + + /** + * The smy. + */ double scx, scy, smx, smy; - - /** The cy. */ + + /** + * The cy. + */ double mx, my, cx, cy; - /** The temporary indicators. */ + /** + * The temporary indicators. + */ boolean isMove; - - /** The is first. */ + + /** + * The is first. + */ boolean isFirst; - - /** The check move. */ + + /** + * The check move. + */ boolean checkMove; - - /** The temporary and destination work paths. */ + + /** + * The temporary and destination work paths. + */ BufferedPath dst, lp, rp, sp; - - /** Stroke dasher class. */ + + /** + * Stroke dasher class. + */ Dasher dasher; /** - * Instantiates a new BasicStroke with default width, cap, join, limit, - * dash attributes parameters. The default parameters are a solid line of - * width 1.0, CAP_SQUARE, JOIN_MITER, a miter limit of 10.0, null dash attributes, + * Instantiates a new BasicStroke with default width, cap, join, limit, dash + * attributes parameters. The default parameters are a solid line of width + * 1.0, CAP_SQUARE, JOIN_MITER, a miter limit of 10.0, null dash attributes, * and a dash phase of 0.0f. */ public BasicStroke() { @@ -167,17 +217,24 @@ public class BasicStroke implements Stroke { } /** - * Instantiates a new BasicStroke with the specified width, - * caps, joins, limit, dash attributes, dash phase parameters. + * Instantiates a new BasicStroke with the specified width, caps, joins, + * limit, dash attributes, dash phase parameters. * - * @param width the width of BasikStroke. - * @param cap the end decoration of BasikStroke. - * @param join the join segments decoration. - * @param miterLimit the limit to trim the miter join. - * @param dash the array with the dashing pattern. - * @param dashPhase the offset to start the dashing pattern. - */ - public BasicStroke(float width, int cap, int join, float miterLimit, float[] dash, float dashPhase) { + * @param width + * the width of BasikStroke. + * @param cap + * the end decoration of BasikStroke. + * @param join + * the join segments decoration. + * @param miterLimit + * the limit to trim the miter join. + * @param dash + * the array with the dashing pattern. + * @param dashPhase + * the offset to start the dashing pattern. + */ + public BasicStroke(float width, int cap, int join, float miterLimit, float[] dash, + float dashPhase) { if (width < 0.0f) { // awt.133=Negative width throw new IllegalArgumentException(Messages.getString("awt.133")); //$NON-NLS-1$ @@ -204,7 +261,7 @@ public class BasicStroke implements Stroke { throw new IllegalArgumentException(Messages.getString("awt.138")); //$NON-NLS-1$ } ZERO: { - for(int i = 0; i < dash.length; i++) { + for (int i = 0; i < dash.length; i++) { if (dash[i] < 0.0) { // awt.139=Negative dash[{0}] throw new IllegalArgumentException(Messages.getString("awt.139", i)); //$NON-NLS-1$ @@ -226,35 +283,43 @@ public class BasicStroke implements Stroke { } /** - * Instantiates a new BasicStroke with specified width, cap, join, limit - * and default dash attributes parameters. + * Instantiates a new BasicStroke with specified width, cap, join, limit and + * default dash attributes parameters. * - * @param width the width of BasikStroke. - * @param cap the end decoration of BasikStroke. - * @param join the join segments decoration. - * @param miterLimit the limit to trim the miter join. + * @param width + * the width of BasikStroke. + * @param cap + * the end decoration of BasikStroke. + * @param join + * the join segments decoration. + * @param miterLimit + * the limit to trim the miter join. */ public BasicStroke(float width, int cap, int join, float miterLimit) { this(width, cap, join, miterLimit, null, 0.0f); } /** - * Instantiates a new BasicStroke with specified width, cap, join - * and default limit and dash attributes parameters. + * Instantiates a new BasicStroke with specified width, cap, join and + * default limit and dash attributes parameters. * - * @param width the width of BasikStroke. - * @param cap the end decoration of BasikStroke. - * @param join the join segments decoration. + * @param width + * the width of BasikStroke. + * @param cap + * the end decoration of BasikStroke. + * @param join + * the join segments decoration. */ public BasicStroke(float width, int cap, int join) { this(width, cap, join, 10.0f, null, 0.0f); } /** - * Instantiates a new BasicStroke with specified width and default cap, join, - * limit, dash attributes parameters. + * Instantiates a new BasicStroke with specified width and default cap, + * join, limit, dash attributes parameters. * - * @param width the width of BasicStroke. + * @param width + * the width of BasicStroke. */ public BasicStroke(float width) { this(width, CAP_SQUARE, JOIN_MITER, 10.0f, null, 0.0f); @@ -288,7 +353,8 @@ public class BasicStroke implements Stroke { } /** - * Gets the miter limit of the BasicStroke (the limit to trim the miter join). + * Gets the miter limit of the BasicStroke (the limit to trim the miter + * join). * * @return the miter limit of the BasicStroke. */ @@ -338,10 +404,10 @@ public class BasicStroke implements Stroke { /** * Compares this BasicStroke object with the specified Object. * - * @param obj the Object to be compared. - * - * @return true, if the Object is a BasicStroke with the same data - * values as this BasicStroke; false otherwise. + * @param obj + * the Object to be compared. + * @return true, if the Object is a BasicStroke with the same data values as + * this BasicStroke; false otherwise. */ @Override public boolean equals(Object obj) { @@ -350,13 +416,9 @@ public class BasicStroke implements Stroke { } if (obj instanceof BasicStroke) { BasicStroke bs = (BasicStroke)obj; - return - bs.width == width && - bs.cap == cap && - bs.join == join && - bs.miterLimit == miterLimit && - bs.dashPhase == dashPhase && - java.util.Arrays.equals(bs.dash, dash); + return bs.width == width && bs.cap == cap && bs.join == join + && bs.miterLimit == miterLimit && bs.dashPhase == dashPhase + && java.util.Arrays.equals(bs.dash, dash); } return false; } @@ -364,9 +426,9 @@ public class BasicStroke implements Stroke { /** * Calculates allowable curve derivation. * - * @param width the width - * - * @return the curve delta + * @param width + * the width. + * @return the curve delta. */ double getCurveDelta(double width) { double a = width + CURVE_DELTA; @@ -378,9 +440,9 @@ public class BasicStroke implements Stroke { /** * Calculates the value to detect a small angle. * - * @param width the width - * - * @return the corner delta + * @param width + * the width. + * @return the corner delta. */ double getCornerDelta(double width) { return width * width * Math.sin(Math.PI * CORNER_ANGLE / 180.0); @@ -389,22 +451,21 @@ public class BasicStroke implements Stroke { /** * Calculates value to detect a zero angle. * - * @param width the width - * - * @return the zero delta + * @param width + * the width. + * @return the zero delta. */ double getZeroDelta(double width) { return width * width * Math.sin(Math.PI * CORNER_ZERO / 180.0); } /** - * Creates a Shape from the outline of the specified shape - * drawn with this BasicStroke. - * - * @param s the specified Shape to be stroked. + * Creates a Shape from the outline of the specified shape drawn with this + * BasicStroke. * + * @param s + * the specified Shape to be stroked. * @return the Shape of the stroked outline. - * * @see java.awt.Stroke#createStrokedShape(java.awt.Shape) */ public Shape createStrokedShape(Shape s) { @@ -429,7 +490,8 @@ public class BasicStroke implements Stroke { /** * Generates a shape with a solid (not dashed) outline. * - * @param p - the PathIterator of source shape + * @param p + * the PathIterator of source shape. */ void createSolidShape(PathIterator p) { double coords[] = new double[6]; @@ -439,36 +501,37 @@ public class BasicStroke implements Stroke { checkMove = true; boolean isClosed = true; - while(!p.isDone()) { - switch(p.currentSegment(coords)) { - case PathIterator.SEG_MOVETO: - if (!isClosed) { - closeSolidShape(); - } - rp.clean(); - mx = cx = coords[0]; - my = cy = coords[1]; - isMove = true; - isClosed = false; - break; - case PathIterator.SEG_LINETO: - addLine(cx, cy, cx = coords[0], cy = coords[1], true); - break; - case PathIterator.SEG_QUADTO: - addQuad(cx, cy, coords[0], coords[1], cx = coords[2], cy = coords[3]); - break; - case PathIterator.SEG_CUBICTO: - addCubic(cx, cy, coords[0], coords[1], coords[2], coords[3], cx = coords[4], cy = coords[5]); - break; - case PathIterator.SEG_CLOSE: - addLine(cx, cy, mx, my, false); - addJoin(lp, mx, my, lp.xMove, lp.yMove, true); - addJoin(rp, mx, my, rp.xMove, rp.yMove, false); - lp.closePath(); - rp.closePath(); - lp.appendReverse(rp); - isClosed = true; - break; + while (!p.isDone()) { + switch (p.currentSegment(coords)) { + case PathIterator.SEG_MOVETO: + if (!isClosed) { + closeSolidShape(); + } + rp.clean(); + mx = cx = coords[0]; + my = cy = coords[1]; + isMove = true; + isClosed = false; + break; + case PathIterator.SEG_LINETO: + addLine(cx, cy, cx = coords[0], cy = coords[1], true); + break; + case PathIterator.SEG_QUADTO: + addQuad(cx, cy, coords[0], coords[1], cx = coords[2], cy = coords[3]); + break; + case PathIterator.SEG_CUBICTO: + addCubic(cx, cy, coords[0], coords[1], coords[2], coords[3], cx = coords[4], + cy = coords[5]); + break; + case PathIterator.SEG_CLOSE: + addLine(cx, cy, mx, my, false); + addJoin(lp, mx, my, lp.xMove, lp.yMove, true); + addJoin(rp, mx, my, rp.xMove, rp.yMove, false); + lp.closePath(); + rp.closePath(); + lp.appendReverse(rp); + isClosed = true; + break; } p.next(); } @@ -492,7 +555,8 @@ public class BasicStroke implements Stroke { /** * Generates dashed stroked shape. * - * @param p - the PathIterator of source shape + * @param p + * the PathIterator of source shape. */ void createDashedShape(PathIterator p) { double coords[] = new double[6]; @@ -502,52 +566,53 @@ public class BasicStroke implements Stroke { checkMove = false; boolean isClosed = true; - while(!p.isDone()) { - switch(p.currentSegment(coords)) { - case PathIterator.SEG_MOVETO: + while (!p.isDone()) { + switch (p.currentSegment(coords)) { + case PathIterator.SEG_MOVETO: - if (!isClosed) { - closeDashedShape(); - } + if (!isClosed) { + closeDashedShape(); + } - dasher = new Dasher(dash, dashPhase); - lp.clean(); - rp.clean(); - sp = null; - isFirst = true; - isMove = true; - isClosed = false; - mx = cx = coords[0]; - my = cy = coords[1]; - break; - case PathIterator.SEG_LINETO: - addDashLine(cx, cy, cx = coords[0], cy = coords[1]); - break; - case PathIterator.SEG_QUADTO: - addDashQuad(cx, cy, coords[0], coords[1], cx = coords[2], cy = coords[3]); - break; - case PathIterator.SEG_CUBICTO: - addDashCubic(cx, cy, coords[0], coords[1], coords[2], coords[3], cx = coords[4], cy = coords[5]); - break; - case PathIterator.SEG_CLOSE: - addDashLine(cx, cy, cx = mx, cy = my); - - if (dasher.isConnected()) { - // Connect current and head segments - addJoin(lp, fmx, fmy, sp.xMove, sp.yMove, true); - lp.join(sp); - addJoin(lp, fmx, fmy, rp.xLast, rp.yLast, true); - lp.combine(rp); - addCap(lp, smx, smy, lp.xMove, lp.yMove); - lp.closePath(); - dst.append(lp); + dasher = new Dasher(dash, dashPhase); + lp.clean(); + rp.clean(); sp = null; - } else { - closeDashedShape(); - } + isFirst = true; + isMove = true; + isClosed = false; + mx = cx = coords[0]; + my = cy = coords[1]; + break; + case PathIterator.SEG_LINETO: + addDashLine(cx, cy, cx = coords[0], cy = coords[1]); + break; + case PathIterator.SEG_QUADTO: + addDashQuad(cx, cy, coords[0], coords[1], cx = coords[2], cy = coords[3]); + break; + case PathIterator.SEG_CUBICTO: + addDashCubic(cx, cy, coords[0], coords[1], coords[2], coords[3], + cx = coords[4], cy = coords[5]); + break; + case PathIterator.SEG_CLOSE: + addDashLine(cx, cy, cx = mx, cy = my); - isClosed = true; - break; + if (dasher.isConnected()) { + // Connect current and head segments + addJoin(lp, fmx, fmy, sp.xMove, sp.yMove, true); + lp.join(sp); + addJoin(lp, fmx, fmy, rp.xLast, rp.yLast, true); + lp.combine(rp); + addCap(lp, smx, smy, lp.xMove, lp.yMove); + lp.closePath(); + dst.append(lp); + sp = null; + } else { + closeDashedShape(); + } + + isClosed = true; + break; } p.next(); } @@ -583,11 +648,16 @@ public class BasicStroke implements Stroke { /** * Adds cap to the work path. * - * @param p - the BufferedPath object of work path - * @param x0 - the x coordinate of the source path - * @param y0 - the y coordinate on the source path - * @param x2 - the x coordinate of the next point on the work path - * @param y2 - the y coordinate of the next point on the work path + * @param p + * the BufferedPath object of work path. + * @param x0 + * the x coordinate of the source path. + * @param y0 + * the y coordinate on the source path. + * @param x2 + * the x coordinate of the next point on the work path. + * @param y2 + * the y coordinate of the next point on the work path. */ void addCap(BufferedPath p, double x0, double y0, double x2, double y2) { double x1 = p.xLast; @@ -597,42 +667,49 @@ public class BasicStroke implements Stroke { double x20 = x2 - x0; double y20 = y2 - y0; - switch(cap) { - case CAP_BUTT: - p.lineTo(x2, y2); - break; - case CAP_ROUND: - double mx = x10 * CUBIC_ARC; - double my = y10 * CUBIC_ARC; - - double x3 = x0 + y10; - double y3 = y0 - x10; - - x10 *= CUBIC_ARC; - y10 *= CUBIC_ARC; - x20 *= CUBIC_ARC; - y20 *= CUBIC_ARC; - - p.cubicTo(x1 + y10, y1 - x10, x3 + mx, y3 + my, x3, y3); - p.cubicTo(x3 - mx, y3 - my, x2 - y20, y2 + x20, x2, y2); - break; - case CAP_SQUARE: - p.lineTo(x1 + y10, y1 - x10); - p.lineTo(x2 - y20, y2 + x20); - p.lineTo(x2, y2); - break; + switch (cap) { + case CAP_BUTT: + p.lineTo(x2, y2); + break; + case CAP_ROUND: + double mx = x10 * CUBIC_ARC; + double my = y10 * CUBIC_ARC; + + double x3 = x0 + y10; + double y3 = y0 - x10; + + x10 *= CUBIC_ARC; + y10 *= CUBIC_ARC; + x20 *= CUBIC_ARC; + y20 *= CUBIC_ARC; + + p.cubicTo(x1 + y10, y1 - x10, x3 + mx, y3 + my, x3, y3); + p.cubicTo(x3 - mx, y3 - my, x2 - y20, y2 + x20, x2, y2); + break; + case CAP_SQUARE: + p.lineTo(x1 + y10, y1 - x10); + p.lineTo(x2 - y20, y2 + x20); + p.lineTo(x2, y2); + break; } } /** * Adds bevel and miter join to the work path. * - * @param p - the BufferedPath object of work path - * @param x0 - the x coordinate of the source path - * @param y0 - the y coordinate on the source path - * @param x2 - the x coordinate of the next point on the work path - * @param y2 - the y coordinate of the next point on the work path - * @param isLeft - the orientation of work path, true if work path lies to the left from source path, false otherwise + * @param p + * the BufferedPath object of work path. + * @param x0 + * the x coordinate of the source path. + * @param y0 + * the y coordinate on the source path. + * @param x2 + * the x coordinate of the next point on the work path. + * @param y2 + * the y coordinate of the next point on the work path. + * @param isLeft + * the orientation of work path, true if work path lies to the + * left from source path, false otherwise. */ void addJoin(BufferedPath p, double x0, double y0, double x2, double y2, boolean isLeft) { double x1 = p.xLast; @@ -667,26 +744,26 @@ public class BasicStroke implements Stroke { p.lineTo(x0, y0); p.lineTo(x2, y2); } else { - switch(join) { - case JOIN_BEVEL: - p.lineTo(x2, y2); - break; - case JOIN_MITER: - double s1 = x1 * x10 + y1 * y10; - double s2 = x2 * x20 + y2 * y20; - double x3 = (s1 * y20 - s2 * y10) / sin0; - double y3 = (s2 * x10 - s1 * x20) / sin0; - double x30 = x3 - x0; - double y30 = y3 - y0; - double miterLength = Math.sqrt(x30 * x30 + y30 * y30); - if (miterLength < miterLimit * w2) { - p.lineTo(x3, y3); - } - p.lineTo(x2, y2); - break; - case JOIN_ROUND: - addRoundJoin(p, x0, y0, x2, y2, isLeft); - break; + switch (join) { + case JOIN_BEVEL: + p.lineTo(x2, y2); + break; + case JOIN_MITER: + double s1 = x1 * x10 + y1 * y10; + double s2 = x2 * x20 + y2 * y20; + double x3 = (s1 * y20 - s2 * y10) / sin0; + double y3 = (s2 * x10 - s1 * x20) / sin0; + double x30 = x3 - x0; + double y30 = y3 - y0; + double miterLength = Math.sqrt(x30 * x30 + y30 * y30); + if (miterLength < miterLimit * w2) { + p.lineTo(x3, y3); + } + p.lineTo(x2, y2); + break; + case JOIN_ROUND: + addRoundJoin(p, x0, y0, x2, y2, isLeft); + break; } } } @@ -694,12 +771,19 @@ public class BasicStroke implements Stroke { /** * Adds round join to the work path. * - * @param p - the BufferedPath object of work path - * @param x0 - the x coordinate of the source path - * @param y0 - the y coordinate on the source path - * @param x2 - the x coordinate of the next point on the work path - * @param y2 - the y coordinate of the next point on the work path - * @param isLeft - the orientation of work path, true if work path lies to the left from source path, false otherwise + * @param p + * the BufferedPath object of work path. + * @param x0 + * the x coordinate of the source path. + * @param y0 + * the y coordinate on the source path. + * @param x2 + * the x coordinate of the next point on the work path. + * @param y2 + * the y coordinate of the next point on the work path. + * @param isLeft + * the orientation of work path, true if work path lies to the + * left from source path, false otherwise. */ void addRoundJoin(BufferedPath p, double x0, double y0, double x2, double y2, boolean isLeft) { double x1 = p.xLast; @@ -763,11 +847,16 @@ public class BasicStroke implements Stroke { /** * Adds solid line segment to the work path. * - * @param x1 - the x coordinate of the start line point - * @param y1 - the y coordinate of the start line point - * @param x2 - the x coordinate of the end line point - * @param y2 - the y coordinate of the end line point - * @param zero - if true it's allowable to add zero length line segment + * @param x1 + * the x coordinate of the start line point. + * @param y1 + * the y coordinate of the start line point. + * @param x2 + * the x coordinate of the end line point. + * @param y2 + * the y coordinate of the end line point. + * @param zero + * if true it's allowable to add zero length line segment. */ void addLine(double x1, double y1, double x2, double y2, boolean zero) { double dx = x2 - x1; @@ -808,12 +897,18 @@ public class BasicStroke implements Stroke { /** * Adds solid quad segment to the work path. * - * @param x1 - the x coordinate of the first control point - * @param y1 - the y coordinate of the first control point - * @param x2 - the x coordinate of the second control point - * @param y2 - the y coordinate of the second control point - * @param x3 - the x coordinate of the third control point - * @param y3 - the y coordinate of the third control point + * @param x1 + * the x coordinate of the first control point. + * @param y1 + * the y coordinate of the first control point. + * @param x2 + * the x coordinate of the second control point. + * @param y2 + * the y coordinate of the second control point. + * @param x3 + * the x coordinate of the third control point. + * @param y3 + * the y coordinate of the third control point. */ void addQuad(double x1, double y1, double x2, double y2, double x3, double y3) { double x21 = x2 - x1; @@ -841,11 +936,11 @@ public class BasicStroke implements Stroke { double w; w = w2 / l21; - double mx1 = - y21 * w; - double my1 = x21 * w; + double mx1 = -y21 * w; + double my1 = x21 * w; w = w2 / l23; - double mx3 = y23 * w; - double my3 = - x23 * w; + double mx3 = y23 * w; + double my3 = -x23 * w; double lx1 = x1 + mx1; double ly1 = y1 + my1; @@ -903,15 +998,23 @@ public class BasicStroke implements Stroke { } /** - * Subdivides solid quad curve to make outline for source quad segment and adds it to work path. + * Subdivides solid quad curve to make outline for source quad segment and + * adds it to work path. * - * @param x1 - the x coordinate of the first control point - * @param y1 - the y coordinate of the first control point - * @param x2 - the x coordinate of the second control point - * @param y2 - the y coordinate of the second control point - * @param x3 - the x coordinate of the third control point - * @param y3 - the y coordinate of the third control point - * @param level - the maximum level of subdivision deepness + * @param x1 + * the x coordinate of the first control point. + * @param y1 + * the y coordinate of the first control point. + * @param x2 + * the x coordinate of the second control point. + * @param y2 + * the y coordinate of the second control point. + * @param x3 + * the x coordinate of the third control point. + * @param y3 + * the y coordinate of the third control point. + * @param level + * the maximum level of subdivision deepness. */ void addSubQuad(double x1, double y1, double x2, double y2, double x3, double y3, int level) { double x21 = x2 - x1; @@ -939,8 +1042,8 @@ public class BasicStroke implements Stroke { double mx2 = (x21 * l23 + x23 * l21) * w; double my2 = (y21 * l23 + y23 * l21) * w; w = w2 / l23; - double mx3 = y23 * w; - double my3 = - x23 * w; + double mx3 = y23 * w; + double my3 = -x23 * w; lp.quadTo(x2 + mx2, y2 + my2, x3 + mx3, y3 + my3); rp.quadTo(x2 - mx2, y2 - my2, x3 - mx3, y3 - my3); } @@ -949,16 +1052,25 @@ public class BasicStroke implements Stroke { /** * Adds solid cubic segment to the work path. * - * @param x1 - the x coordinate of the first control point - * @param y1 - the y coordinate of the first control point - * @param x2 - the x coordinate of the second control point - * @param y2 - the y coordinate of the second control point - * @param x3 - the x coordinate of the third control point - * @param y3 - the y coordinate of the third control point - * @param x4 - the x coordinate of the fours control point - * @param y4 - the y coordinate of the fours control point - */ - void addCubic(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4) { + * @param x1 + * the x coordinate of the first control point. + * @param y1 + * the y coordinate of the first control point. + * @param x2 + * the x coordinate of the second control point. + * @param y2 + * the y coordinate of the second control point. + * @param x3 + * the x coordinate of the third control point. + * @param y3 + * the y coordinate of the third control point. + * @param x4 + * the x coordinate of the fours control point. + * @param y4 + * the y coordinate of the fours control point. + */ + void addCubic(double x1, double y1, double x2, double y2, double x3, double y3, double x4, + double y4) { double x12 = x1 - x2; double y12 = y1 - y2; double x23 = x2 - x3; @@ -997,35 +1109,32 @@ public class BasicStroke implements Stroke { if (l12 == 0.0) { w = w2 / l23; - mx1 = y23 * w; - my1 = - x23 * w; + mx1 = y23 * w; + my1 = -x23 * w; w = w2 / l34; - mx4 = y34 * w; - my4 = - x34 * w; - onLine = - x23 * y34 + y23 * x34 == 0.0; // sin3 - } else - if (l34 == 0.0) { + mx4 = y34 * w; + my4 = -x34 * w; + onLine = -x23 * y34 + y23 * x34 == 0.0; // sin3 + } else if (l34 == 0.0) { w = w2 / l12; - mx1 = y12 * w; - my1 = - x12 * w; + mx1 = y12 * w; + my1 = -x12 * w; w = w2 / l23; - mx4 = y23 * w; - my4 = - x23 * w; - onLine = - x12 * y23 + y12 * x23 == 0.0; // sin2 + mx4 = y23 * w; + my4 = -x23 * w; + onLine = -x12 * y23 + y12 * x23 == 0.0; // sin2 } else { w = w2 / l12; - mx1 = y12 * w; - my1 = - x12 * w; + mx1 = y12 * w; + my1 = -x12 * w; w = w2 / l34; - mx4 = y34 * w; - my4 = - x34 * w; + mx4 = y34 * w; + my4 = -x34 * w; if (l23 == 0.0) { - onLine = - x12 * y34 + y12 * x34 == 0.0; + onLine = -x12 * y34 + y12 * x34 == 0.0; } else { - onLine = - - x12 * y34 + y12 * x34 == 0.0 && - - x12 * y23 + y12 * x23 == 0.0 && // sin2 - - x23 * y34 + y23 * x34 == 0.0; // sin3 + onLine = -x12 * y34 + y12 * x34 == 0.0 && -x12 * y23 + y12 * x23 == 0.0 && // sin2 + -x23 * y34 + y23 * x34 == 0.0; // sin3 } } @@ -1063,8 +1172,7 @@ public class BasicStroke implements Stroke { if (0.0 < t && t < 1.0) { roots[rc++] = t; } - } else - if (d > 0.0) { + } else if (d > 0.0) { d = Math.sqrt(d); double z = l12 + l34 - l23 - l23; double t; @@ -1087,15 +1195,15 @@ public class BasicStroke implements Stroke { } roots[rc++] = 1.0; - double ax = - x34 - x12 + x23 + x23; - double ay = - y34 - y12 + y23 + y23; - double bx = 3.0 * (- x23 + x12); - double by = 3.0 * (- y23 + y12); - double cx = 3.0 * (- x12); - double cy = 3.0 * (- y12); + double ax = -x34 - x12 + x23 + x23; + double ay = -y34 - y12 + y23 + y23; + double bx = 3.0 * (-x23 + x12); + double by = 3.0 * (-y23 + y12); + double cx = 3.0 * (-x12); + double cy = 3.0 * (-y12); double xPrev = x1; double yPrev = y1; - for(int i = 0; i < rc; i++) { + for (int i = 0; i < rc; i++) { double t = roots[i]; double px = t * (t * (t * ax + bx) + cx) + x1; double py = t * (t * (t * ay + by) + cy) + y1; @@ -1109,8 +1217,8 @@ public class BasicStroke implements Stroke { } xPrev = px; yPrev = py; - mx1 = - mx1; - my1 = - my1; + mx1 = -mx1; + my1 = -my1; } } else { lp.cubicTo(x2 + mx1, y2 + my1, x3 + mx4, y3 + my4, x4 + mx4, y4 + my4); @@ -1122,19 +1230,30 @@ public class BasicStroke implements Stroke { } /** - * Subdivides solid cubic curve to make outline for source quad segment and adds it to work path. + * Subdivides solid cubic curve to make outline for source quad segment and + * adds it to work path. * - * @param x1 - the x coordinate of the first control point - * @param y1 - the y coordinate of the first control point - * @param x2 - the x coordinate of the second control point - * @param y2 - the y coordinate of the second control point - * @param x3 - the x coordinate of the third control point - * @param y3 - the y coordinate of the third control point - * @param x4 - the x coordinate of the fours control point - * @param y4 - the y coordinate of the fours control point - * @param level - the maximum level of subdivision deepness - */ - void addSubCubic(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4, int level) { + * @param x1 + * the x coordinate of the first control point. + * @param y1 + * the y coordinate of the first control point. + * @param x2 + * the x coordinate of the second control point. + * @param y2 + * the y coordinate of the second control point. + * @param x3 + * the x coordinate of the third control point. + * @param y3 + * the y coordinate of the third control point. + * @param x4 + * the x coordinate of the fours control point. + * @param y4 + * the y coordinate of the fours control point. + * @param level + * the maximum level of subdivision deepness. + */ + void addSubCubic(double x1, double y1, double x2, double y2, double x3, double y3, double x4, + double y4, int level) { double x12 = x1 - x2; double y12 = y1 - y2; double x23 = x2 - x3; @@ -1142,19 +1261,18 @@ public class BasicStroke implements Stroke { double x34 = x3 - x4; double y34 = y3 - y4; - double cos2 = - x12 * x23 - y12 * y23; - double cos3 = - x23 * x34 - y23 * y34; - double sin2 = - x12 * y23 + y12 * x23; - double sin3 = - x23 * y34 + y23 * x34; - double sin0 = - x12 * y34 + y12 * x34; - double cos0 = - x12 * x34 - y12 * y34; - - if (level < MAX_LEVEL && (sin2 != 0.0 || sin3 != 0.0 || sin0 != 0.0) && - (cos2 >= 0.0 || cos3 >= 0.0 || cos0 >= 0.0 || - (Math.abs(sin2 / cos2) > curveDelta) || - (Math.abs(sin3 / cos3) > curveDelta) || - (Math.abs(sin0 / cos0) > curveDelta))) - { + double cos2 = -x12 * x23 - y12 * y23; + double cos3 = -x23 * x34 - y23 * y34; + double sin2 = -x12 * y23 + y12 * x23; + double sin3 = -x23 * y34 + y23 * x34; + double sin0 = -x12 * y34 + y12 * x34; + double cos0 = -x12 * x34 - y12 * y34; + + if (level < MAX_LEVEL + && (sin2 != 0.0 || sin3 != 0.0 || sin0 != 0.0) + && (cos2 >= 0.0 || cos3 >= 0.0 || cos0 >= 0.0 + || (Math.abs(sin2 / cos2) > curveDelta) + || (Math.abs(sin3 / cos3) > curveDelta) || (Math.abs(sin0 / cos0) > curveDelta))) { double cx = (x2 + x3) / 2.0; double cy = (y2 + y3) / 2.0; double lx2 = (x2 + x1) / 2.0; @@ -1177,27 +1295,26 @@ public class BasicStroke implements Stroke { if (l12 == 0.0) { w = w2 / l23; - mx1 = y23 * w; - my1 = - x23 * w; + mx1 = y23 * w; + my1 = -x23 * w; w = w2 / l34; - mx4 = y34 * w; - my4 = - x34 * w; - } else - if (l34 == 0.0) { + mx4 = y34 * w; + my4 = -x34 * w; + } else if (l34 == 0.0) { w = w2 / l12; - mx1 = y12 * w; - my1 = - x12 * w; + mx1 = y12 * w; + my1 = -x12 * w; w = w2 / l23; - mx4 = y23 * w; - my4 = - x23 * w; + mx4 = y23 * w; + my4 = -x23 * w; } else { // Common case w = w2 / l12; - mx1 = y12 * w; - my1 = - x12 * w; + mx1 = y12 * w; + my1 = -x12 * w; w = w2 / l34; - mx4 = y34 * w; - my4 = - x34 * w; + mx4 = y34 * w; + my4 = -x34 * w; } if (sin2 == 0.0) { @@ -1225,10 +1342,14 @@ public class BasicStroke implements Stroke { /** * Adds dashed line segment to the work path. * - * @param x1 - the x coordinate of the start line point - * @param y1 - the y coordinate of the start line point - * @param x2 - the x coordinate of the end line point - * @param y2 - the y coordinate of the end line point + * @param x1 + * the x coordinate of the start line point. + * @param y1 + * the y coordinate of the start line point. + * @param x2 + * the x coordinate of the end line point. + * @param y2 + * the y coordinate of the end line point. */ void addDashLine(double x1, double y1, double x2, double y2) { double x21 = x2 - x1; @@ -1243,12 +1364,12 @@ public class BasicStroke implements Stroke { double px1, py1; px1 = py1 = 0.0; double w = w2 / l21; - double mx = - y21 * w; - double my = x21 * w; + double mx = -y21 * w; + double my = x21 * w; dasher.init(new DashIterator.Line(l21)); - while(!dasher.eof()) { + while (!dasher.eof()) { double t = dasher.getValue(); scx = x1 + t * x21; scy = y1 + t * y21; @@ -1271,28 +1392,27 @@ public class BasicStroke implements Stroke { addJoin(lp, x1, y1, lx1, ly1, true); addJoin(rp, x1, y1, rx1, ry1, false); } - } else - if (dasher.isContinue()) { - double px2 = scx; - double py2 = scy; - lp.lineTo(px2 + mx, py2 + my); - rp.lineTo(px2 - mx, py2 - my); - if (dasher.close) { - addCap(lp, px2, py2, rp.xLast, rp.yLast); - lp.combine(rp); - if (isFirst) { - isFirst = false; - fmx = smx; - fmy = smy; - sp = lp; - lp = new BufferedPath(); - } else { - addCap(lp, smx, smy, lp.xMove, lp.yMove); - lp.closePath(); - } - isMove = true; + } else if (dasher.isContinue()) { + double px2 = scx; + double py2 = scy; + lp.lineTo(px2 + mx, py2 + my); + rp.lineTo(px2 - mx, py2 - my); + if (dasher.close) { + addCap(lp, px2, py2, rp.xLast, rp.yLast); + lp.combine(rp); + if (isFirst) { + isFirst = false; + fmx = smx; + fmy = smy; + sp = lp; + lp = new BufferedPath(); + } else { + addCap(lp, smx, smy, lp.xMove, lp.yMove); + lp.closePath(); } + isMove = true; } + } dasher.next(); } @@ -1301,12 +1421,18 @@ public class BasicStroke implements Stroke { /** * Adds dashed quad segment to the work path. * - * @param x1 - the x coordinate of the first control point - * @param y1 - the y coordinate of the first control point - * @param x2 - the x coordinate of the second control point - * @param y2 - the y coordinate of the second control point - * @param x3 - the x coordinate of the third control point - * @param y3 - the y coordinate of the third control point + * @param x1 + * the x coordinate of the first control point. + * @param y1 + * the y coordinate of the first control point. + * @param x2 + * the x coordinate of the second control point. + * @param y2 + * the y coordinate of the second control point. + * @param x3 + * the x coordinate of the third control point. + * @param y3 + * the y coordinate of the third control point. */ void addDashQuad(double x1, double y1, double x2, double y2, double x3, double y3) { @@ -1345,7 +1471,7 @@ public class BasicStroke implements Stroke { dasher.init(new DashIterator.Quad(x1, y1, x2, y2, x3, y3)); - while(!dasher.eof()) { + while (!dasher.eof()) { double t = dasher.getValue(); double dx = t * ax + bx; double dy = t * ay + by; @@ -1357,8 +1483,8 @@ public class BasicStroke implements Stroke { dx1 = dx; dy1 = dy; double w = w2 / Math.sqrt(dx1 * dx1 + dy1 * dy1); - double mx1 = - dy1 * w; - double my1 = dx1 * w; + double mx1 = -dy1 * w; + double my1 = dx1 * w; double lx1 = px1 + mx1; double ly1 = py1 + my1; double rx1 = px1 - mx1; @@ -1374,33 +1500,32 @@ public class BasicStroke implements Stroke { addJoin(lp, x1, y1, lx1, ly1, true); addJoin(rp, x1, y1, rx1, ry1, false); } - } else - if (dasher.isContinue()) { - double px3 = scx; - double py3 = scy; - double sx = x2 - x23 * prev; - double sy = y2 - y23 * prev; - double t2 = (t - prev) / (1 - prev); - double px2 = px1 + (sx - px1) * t2; - double py2 = py1 + (sy - py1) * t2; - - addQuad(px1, py1, px2, py2, px3, py3); - if (dasher.isClosed()) { - addCap(lp, px3, py3, rp.xLast, rp.yLast); - lp.combine(rp); - if (isFirst) { - isFirst = false; - fmx = smx; - fmy = smy; - sp = lp; - lp = new BufferedPath(); - } else { - addCap(lp, smx, smy, lp.xMove, lp.yMove); - lp.closePath(); - } - isMove = true; + } else if (dasher.isContinue()) { + double px3 = scx; + double py3 = scy; + double sx = x2 - x23 * prev; + double sy = y2 - y23 * prev; + double t2 = (t - prev) / (1 - prev); + double px2 = px1 + (sx - px1) * t2; + double py2 = py1 + (sy - py1) * t2; + + addQuad(px1, py1, px2, py2, px3, py3); + if (dasher.isClosed()) { + addCap(lp, px3, py3, rp.xLast, rp.yLast); + lp.combine(rp); + if (isFirst) { + isFirst = false; + fmx = smx; + fmy = smy; + sp = lp; + lp = new BufferedPath(); + } else { + addCap(lp, smx, smy, lp.xMove, lp.yMove); + lp.closePath(); } + isMove = true; } + } prev = t; dasher.next(); @@ -1410,16 +1535,25 @@ public class BasicStroke implements Stroke { /** * Adds dashed cubic segment to the work path. * - * @param x1 - the x coordinate of the first control point - * @param y1 - the y coordinate of the first control point - * @param x2 - the x coordinate of the second control point - * @param y2 - the y coordinate of the second control point - * @param x3 - the x coordinate of the third control point - * @param y3 - the y coordinate of the third control point - * @param x4 - the x coordinate of the fours control point - * @param y4 - the y coordinate of the fours control point + * @param x1 + * the x coordinate of the first control point. + * @param y1 + * the y coordinate of the first control point. + * @param x2 + * the x coordinate of the second control point. + * @param y2 + * the y coordinate of the second control point. + * @param x3 + * the x coordinate of the third control point. + * @param y3 + * the y coordinate of the third control point. + * @param x4 + * the x coordinate of the fours control point. + * @param y4 + * the y coordinate of the fours control point. */ - void addDashCubic(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4) { + void addDashCubic(double x1, double y1, double x2, double y2, double x3, double y3, double x4, + double y4) { double x12 = x1 - x2; double y12 = y1 - y2; @@ -1469,7 +1603,7 @@ public class BasicStroke implements Stroke { dasher.init(new DashIterator.Cubic(x1, y1, x2, y2, x3, y3, x4, y4)); - while(!dasher.eof()) { + while (!dasher.eof()) { double t = dasher.getValue(); scx = t * (t * (t * ax + bx) + cx) + dx; @@ -1480,8 +1614,8 @@ public class BasicStroke implements Stroke { double dx1 = t * (t * (ax + ax + ax) + bx + bx) + cx; double dy1 = t * (t * (ay + ay + ay) + by + by) + cy; double w = w2 / Math.sqrt(dx1 * dx1 + dy1 * dy1); - double mx1 = - dy1 * w; - double my1 = dx1 * w; + double mx1 = -dy1 * w; + double my1 = dx1 * w; double lx1 = px1 + mx1; double ly1 = py1 + my1; double rx1 = px1 - mx1; @@ -1497,42 +1631,41 @@ public class BasicStroke implements Stroke { addJoin(lp, x1, y1, lx1, ly1, true); addJoin(rp, x1, y1, rx1, ry1, false); } - } else - if (dasher.isContinue()) { - double sx1 = x2 - x23 * prev; - double sy1 = y2 - y23 * prev; - double sx2 = x3 - x34 * prev; - double sy2 = y3 - y34 * prev; - double sx3 = sx1 + (sx2 - sx1) * prev; - double sy3 = sy1 + (sy2 - sy1) * prev; - double t2 = (t - prev) / (1 - prev); - double sx4 = sx3 + (sx2 - sx3) * t2; - double sy4 = sy3 + (sy2 - sy3) * t2; - - double px4 = scx; - double py4 = scy; - double px2 = px1 + (sx3 - px1) * t2; - double py2 = py1 + (sy3 - py1) * t2; - double px3 = px2 + (sx4 - px2) * t2; - double py3 = py2 + (sy4 - py2) * t2; - - addCubic(px1, py1, px2, py2, px3, py3, px4, py4); - if (dasher.isClosed()) { - addCap(lp, px4, py4, rp.xLast, rp.yLast); - lp.combine(rp); - if (isFirst) { - isFirst = false; - fmx = smx; - fmy = smy; - sp = lp; - lp = new BufferedPath(); - } else { - addCap(lp, smx, smy, lp.xMove, lp.yMove); - lp.closePath(); - } - isMove = true; + } else if (dasher.isContinue()) { + double sx1 = x2 - x23 * prev; + double sy1 = y2 - y23 * prev; + double sx2 = x3 - x34 * prev; + double sy2 = y3 - y34 * prev; + double sx3 = sx1 + (sx2 - sx1) * prev; + double sy3 = sy1 + (sy2 - sy1) * prev; + double t2 = (t - prev) / (1 - prev); + double sx4 = sx3 + (sx2 - sx3) * t2; + double sy4 = sy3 + (sy2 - sy3) * t2; + + double px4 = scx; + double py4 = scy; + double px2 = px1 + (sx3 - px1) * t2; + double py2 = py1 + (sy3 - py1) * t2; + double px3 = px2 + (sx4 - px2) * t2; + double py3 = py2 + (sy4 - py2) * t2; + + addCubic(px1, py1, px2, py2, px3, py3, px4, py4); + if (dasher.isClosed()) { + addCap(lp, px4, py4, rp.xLast, rp.yLast); + lp.combine(rp); + if (isFirst) { + isFirst = false; + fmx = smx; + fmy = smy; + sp = lp; + lp = new BufferedPath(); + } else { + addCap(lp, smx, smy, lp.xMove, lp.yMove); + lp.closePath(); } + isMove = true; } + } prev = t; dasher.next(); @@ -1543,30 +1676,44 @@ public class BasicStroke implements Stroke { * Dasher class provides dashing for particular dash style. */ class Dasher { - - /** The pos. */ + + /** + * The pos. + */ double pos; - - /** The first. */ + + /** + * The first. + */ boolean close, visible, first; - - /** The dash. */ + + /** + * The dash. + */ float dash[]; - - /** The phase. */ + + /** + * The phase. + */ float phase; - - /** The index. */ + + /** + * The index. + */ int index; - - /** The iter. */ + + /** + * The iter. + */ DashIterator iter; - + /** * Instantiates a new dasher. * - * @param dash the dash - * @param phase the phase + * @param dash + * the dash. + * @param phase + * the phase. */ Dasher(float dash[], float phase) { this.dash = dash; @@ -1578,52 +1725,53 @@ public class BasicStroke implements Stroke { visible = !visible; pos -= dash[index]; index = (index + 1) % dash.length; - } + } pos = -pos; first = visible; } - + /** * Inits the. * - * @param iter the iter + * @param iter + * the iter. */ void init(DashIterator iter) { this.iter = iter; close = true; } - + /** * Checks if is open. * - * @return true, if is open + * @return true, if is open. */ boolean isOpen() { return visible && pos < iter.length; } - + /** * Checks if is continue. * - * @return true, if is continue + * @return true, if is continue. */ boolean isContinue() { return !visible && pos > 0; } - + /** * Checks if is closed. * - * @return true, if is closed + * @return true, if is closed. */ boolean isClosed() { return close; } - + /** * Checks if is connected. * - * @return true, if is connected + * @return true, if is connected. */ boolean isConnected() { return first && !close; @@ -1632,7 +1780,7 @@ public class BasicStroke implements Stroke { /** * Eof. * - * @return true, if successful + * @return true, if successful. */ boolean eof() { if (!close) { @@ -1648,7 +1796,7 @@ public class BasicStroke implements Stroke { } return false; } - + /** * Next. */ @@ -1663,17 +1811,17 @@ public class BasicStroke implements Stroke { } visible = !visible; } - + /** * Gets the value. * - * @return the value + * @return the value. */ double getValue() { double t = iter.getNext(pos); return t < 0 ? 0 : (t > 1 ? 1 : t); } - + } /** @@ -1681,7 +1829,9 @@ public class BasicStroke implements Stroke { */ static abstract class DashIterator { - /** The Constant FLATNESS. */ + /** + * The Constant FLATNESS. + */ static final double FLATNESS = 1.0; /** @@ -1692,7 +1842,8 @@ public class BasicStroke implements Stroke { /** * Instantiates a new line. * - * @param len the len + * @param len + * the len. */ Line(double len) { length = len; @@ -1710,36 +1861,56 @@ public class BasicStroke implements Stroke { */ static class Quad extends DashIterator { - /** The val size. */ + /** + * The val size. + */ int valSize; - - /** The val pos. */ + + /** + * The val pos. + */ int valPos; - - /** The cur len. */ + + /** + * The cur len. + */ double curLen; - - /** The prev len. */ + + /** + * The prev len. + */ double prevLen; - - /** The last len. */ + + /** + * The last len. + */ double lastLen; - - /** The values. */ + + /** + * The values. + */ double[] values; - - /** The step. */ + + /** + * The step. + */ double step; /** * Instantiates a new quad. * - * @param x1 the x1 - * @param y1 the y1 - * @param x2 the x2 - * @param y2 the y2 - * @param x3 the x3 - * @param y3 the y3 + * @param x1 + * the x1. + * @param y1 + * the y1. + * @param x2 + * the x2. + * @param y2 + * the y2. + * @param x3 + * the x3. + * @param y3 + * the y3. */ Quad(double x1, double y1, double x2, double y2, double x3, double y3) { @@ -1766,7 +1937,7 @@ public class BasicStroke implements Stroke { double pvx = vx; double pvy = vy; length = 0.0; - for(int i = 0; i < n; i++) { + for (int i = 0; i < n; i++) { vx += dx1; vy += dy1; dx1 += dx2; @@ -1804,40 +1975,63 @@ public class BasicStroke implements Stroke { */ static class Cubic extends DashIterator { - /** The val size. */ + /** + * The val size. + */ int valSize; - - /** The val pos. */ + + /** + * The val pos. + */ int valPos; - - /** The cur len. */ + + /** + * The cur len. + */ double curLen; - - /** The prev len. */ + + /** + * The prev len. + */ double prevLen; - - /** The last len. */ + + /** + * The last len. + */ double lastLen; - - /** The values. */ + + /** + * The values. + */ double[] values; - - /** The step. */ + + /** + * The step. + */ double step; /** * Instantiates a new cubic. * - * @param x1 the x1 - * @param y1 the y1 - * @param x2 the x2 - * @param y2 the y2 - * @param x3 the x3 - * @param y3 the y3 - * @param x4 the x4 - * @param y4 the y4 + * @param x1 + * the x1. + * @param y1 + * the y1. + * @param x2 + * the x2. + * @param y2 + * the y2. + * @param x3 + * the x3. + * @param y3 + * the y3. + * @param x4 + * the x4. + * @param y4 + * the y4. */ - Cubic(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4) { + Cubic(double x1, double y1, double x2, double y2, double x3, double y3, double x4, + double y4) { double nx1 = x1 + x3 - x2 - x2; double ny1 = y1 + y3 - y2 - y2; @@ -1869,7 +2063,7 @@ public class BasicStroke implements Stroke { double pvx = vx; double pvy = vy; length = 0.0; - for(int i = 0; i < n; i++) { + for (int i = 0; i < n; i++) { vx += dx1; vy += dy1; dx1 += dx2; @@ -1904,15 +2098,17 @@ public class BasicStroke implements Stroke { } - /** The length. */ + /** + * The length. + */ double length; /** * Gets the next. * - * @param dashPos the dash pos - * - * @return the next + * @param dashPos + * the dash pos. + * @return the next. */ abstract double getNext(double dashPos); @@ -1923,39 +2119,60 @@ public class BasicStroke implements Stroke { */ static class BufferedPath { - /** The Constant bufCapacity. */ + /** + * The Constant bufCapacity. + */ private static final int bufCapacity = 10; - /** The point shift. */ + /** + * The point shift. + */ static int pointShift[] = { - 2, // MOVETO - 2, // LINETO - 4, // QUADTO - 6, // CUBICTO - 0}; // CLOSE + 2, // MOVETO + 2, // LINETO + 4, // QUADTO + 6, // CUBICTO + 0 + }; // CLOSE - /** The types. */ + /** + * The types. + */ byte[] types; - - /** The points. */ + + /** + * The points. + */ float[] points; - - /** The type size. */ + + /** + * The type size. + */ int typeSize; - - /** The point size. */ + + /** + * The point size. + */ int pointSize; - /** The x last. */ + /** + * The x last. + */ float xLast; - - /** The y last. */ + + /** + * The y last. + */ float yLast; - - /** The x move. */ + + /** + * The x move. + */ float xMove; - - /** The y move. */ + + /** + * The y move. + */ float yMove; /** @@ -1969,8 +2186,10 @@ public class BasicStroke implements Stroke { /** * Check buf. * - * @param typeCount the type count - * @param pointCount the point count + * @param typeCount + * the type count. + * @param pointCount + * the point count. */ void checkBuf(int typeCount, int pointCount) { if (typeSize + typeCount > types.length) { @@ -1988,7 +2207,7 @@ public class BasicStroke implements Stroke { /** * Checks if is empty. * - * @return true, if is empty + * @return true, if is empty. */ boolean isEmpty() { return typeSize == 0; @@ -2005,8 +2224,10 @@ public class BasicStroke implements Stroke { /** * Move to. * - * @param x the x - * @param y the y + * @param x + * the x. + * @param y + * the y. */ void moveTo(double x, double y) { checkBuf(1, 2); @@ -2018,8 +2239,10 @@ public class BasicStroke implements Stroke { /** * Line to. * - * @param x the x - * @param y the y + * @param x + * the x. + * @param y + * the y. */ void lineTo(double x, double y) { checkBuf(1, 2); @@ -2031,10 +2254,14 @@ public class BasicStroke implements Stroke { /** * Quad to. * - * @param x1 the x1 - * @param y1 the y1 - * @param x2 the x2 - * @param y2 the y2 + * @param x1 + * the x1. + * @param y1 + * the y1. + * @param x2 + * the x2. + * @param y2 + * the y2. */ void quadTo(double x1, double y1, double x2, double y2) { checkBuf(1, 4); @@ -2048,12 +2275,18 @@ public class BasicStroke implements Stroke { /** * Cubic to. * - * @param x1 the x1 - * @param y1 the y1 - * @param x2 the x2 - * @param y2 the y2 - * @param x3 the x3 - * @param y3 the y3 + * @param x1 + * the x1. + * @param y1 + * the y1. + * @param x2 + * the x2. + * @param y2 + * the y2. + * @param x3 + * the x3. + * @param y3 + * the y3. */ void cubicTo(double x1, double y1, double x2, double y2, double x3, double y3) { checkBuf(1, 6); @@ -2077,8 +2310,10 @@ public class BasicStroke implements Stroke { /** * Sets the last. * - * @param x the x - * @param y the y + * @param x + * the x. + * @param y + * the y. */ void setLast(double x, double y) { points[pointSize - 2] = xLast = (float)x; @@ -2088,7 +2323,8 @@ public class BasicStroke implements Stroke { /** * Append. * - * @param p the p + * @param p + * the p. */ void append(BufferedPath p) { checkBuf(p.typeSize, p.pointSize); @@ -2103,18 +2339,19 @@ public class BasicStroke implements Stroke { /** * Append reverse. * - * @param p the p + * @param p + * the p. */ void appendReverse(BufferedPath p) { checkBuf(p.typeSize, p.pointSize); // Skip last point, beacause it's the first point of the second path - for(int i = p.pointSize - 2; i >= 0; i -= 2) { + for (int i = p.pointSize - 2; i >= 0; i -= 2) { points[pointSize++] = p.points[i + 0]; points[pointSize++] = p.points[i + 1]; } // Skip first type, beacuse it's always MOVETO int closeIndex = 0; - for(int i = p.typeSize - 1; i >= 0; i--) { + for (int i = p.typeSize - 1; i >= 0; i--) { byte type = p.types[i]; if (type == PathIterator.SEG_MOVETO) { types[closeIndex] = PathIterator.SEG_MOVETO; @@ -2133,7 +2370,8 @@ public class BasicStroke implements Stroke { /** * Join. * - * @param p the p + * @param p + * the p. */ void join(BufferedPath p) { // Skip MOVETO @@ -2149,17 +2387,18 @@ public class BasicStroke implements Stroke { /** * Combine. * - * @param p the p + * @param p + * the p. */ void combine(BufferedPath p) { checkBuf(p.typeSize - 1, p.pointSize - 2); // Skip last point, beacause it's the first point of the second path - for(int i = p.pointSize - 4; i >= 0; i -= 2) { + for (int i = p.pointSize - 4; i >= 0; i -= 2) { points[pointSize++] = p.points[i + 0]; points[pointSize++] = p.points[i + 1]; } // Skip first type, beacuse it's always MOVETO - for(int i = p.typeSize - 1; i >= 1; i--) { + for (int i = p.typeSize - 1; i >= 1; i--) { types[typeSize++] = p.types[i]; } xLast = points[pointSize - 2]; @@ -2169,29 +2408,30 @@ public class BasicStroke implements Stroke { /** * Creates the general path. * - * @return the general path + * @return the general path. */ GeneralPath createGeneralPath() { GeneralPath p = new GeneralPath(); int j = 0; - for(int i = 0; i < typeSize; i++) { + for (int i = 0; i < typeSize; i++) { int type = types[i]; - switch(type){ - case PathIterator.SEG_MOVETO: - p.moveTo(points[j], points[j + 1]); - break; - case PathIterator.SEG_LINETO: - p.lineTo(points[j], points[j + 1]); - break; - case PathIterator.SEG_QUADTO: - p.quadTo(points[j], points[j + 1], points[j + 2], points[j + 3]); - break; - case PathIterator.SEG_CUBICTO: - p.curveTo(points[j], points[j + 1], points[j + 2], points[j + 3], points[j + 4], points[j + 5]); - break; - case PathIterator.SEG_CLOSE: - p.closePath(); - break; + switch (type) { + case PathIterator.SEG_MOVETO: + p.moveTo(points[j], points[j + 1]); + break; + case PathIterator.SEG_LINETO: + p.lineTo(points[j], points[j + 1]); + break; + case PathIterator.SEG_QUADTO: + p.quadTo(points[j], points[j + 1], points[j + 2], points[j + 3]); + break; + case PathIterator.SEG_CUBICTO: + p.curveTo(points[j], points[j + 1], points[j + 2], points[j + 3], + points[j + 4], points[j + 5]); + break; + case PathIterator.SEG_CLOSE: + p.closePath(); + break; } j += pointShift[type]; } @@ -2201,4 +2441,3 @@ public class BasicStroke implements Stroke { } } - diff --git a/awt/java/awt/BufferCapabilities.java b/awt/java/awt/BufferCapabilities.java index 80e8add53f5f4b6499088436e6ba1e284d805b9a..cd5fe7b1c73337c8b0ef83261ea0a1317a832e1d 100644 --- a/awt/java/awt/BufferCapabilities.java +++ b/awt/java/awt/BufferCapabilities.java @@ -18,35 +18,45 @@ * @author Alexey A. Petrenko * @version $Revision$ */ -package java.awt; +package java.awt; /** - * The BufferCapabilities class represents the capabilities - * and other properties of the image buffers. + * The BufferCapabilities class represents the capabilities and other properties + * of the image buffers. + * + * @since Android 1.0 */ public class BufferCapabilities implements Cloneable { - - /** The front buffer capabilities. */ + + /** + * The front buffer capabilities. + */ private final ImageCapabilities frontBufferCapabilities; - - /** The back buffer capabilities. */ + + /** + * The back buffer capabilities. + */ private final ImageCapabilities backBufferCapabilities; - - /** The flip contents. */ + + /** + * The flip contents. + */ private final FlipContents flipContents; /** * Instantiates a new BufferCapabilities object. * - * @param frontBufferCapabilities the front buffer capabilities, - * can not be null. - * @param backBufferCapabilities the the back and intermediate - * buffers capabilities, can not be null. - * @param flipContents the back buffer contents after page flipping, - * null if page flipping is not used. + * @param frontBufferCapabilities + * the front buffer capabilities, can not be null. + * @param backBufferCapabilities + * the the back and intermediate buffers capabilities, can not be + * null. + * @param flipContents + * the back buffer contents after page flipping, null if page + * flipping is not used. */ - public BufferCapabilities(ImageCapabilities frontBufferCapabilities, + public BufferCapabilities(ImageCapabilities frontBufferCapabilities, ImageCapabilities backBufferCapabilities, FlipContents flipContents) { if (frontBufferCapabilities == null || backBufferCapabilities == null) { throw new IllegalArgumentException(); @@ -70,8 +80,8 @@ public class BufferCapabilities implements Cloneable { /** * Gets the image capabilities of the front buffer. * - * @return the ImageCapabilities object represented capabilities - * of the front buffer. + * @return the ImageCapabilities object represented capabilities of the + * front buffer. */ public ImageCapabilities getFrontBufferCapabilities() { return frontBufferCapabilities; @@ -80,15 +90,15 @@ public class BufferCapabilities implements Cloneable { /** * Gets the image capabilities of the back buffer. * - * @return the ImageCapabilities object represented capabilities - * of the back buffer. + * @return the ImageCapabilities object represented capabilities of the back + * buffer. */ public ImageCapabilities getBackBufferCapabilities() { return backBufferCapabilities; } /** - * Gets the flip contents of the back buffer after page-flipping. + * Gets the flip contents of the back buffer after page-flipping. * * @return the FlipContents of the back buffer after page-flipping. */ @@ -99,8 +109,7 @@ public class BufferCapabilities implements Cloneable { /** * Checks if the buffer strategy uses page flipping. * - * @return true, if the buffer strategy uses page flipping, - * false otherwise. + * @return true, if the buffer strategy uses page flipping, false otherwise. */ public boolean isPageFlipping() { return flipContents != null; @@ -110,7 +119,7 @@ public class BufferCapabilities implements Cloneable { * Checks if page flipping is only available in full-screen mode. * * @return true, if page flipping is only available in full-screen mode, - * false otherwise. + * false otherwise. */ public boolean isFullScreenRequired() { return false; @@ -119,39 +128,40 @@ public class BufferCapabilities implements Cloneable { /** * Checks if page flipping can be performed using more than two buffers. * - * @return true, if page flipping can be performed using more than two buffers, - * false otherwise. + * @return true, if page flipping can be performed using more than two + * buffers, false otherwise. */ public boolean isMultiBufferAvailable() { return false; } /** - * The FlipContents class represents a set of possible back buffer contents + * The FlipContents class represents a set of possible back buffer contents * after page-flipping. + * + * @since Android 1.0 */ public static final class FlipContents { - + /** - * The back buffered contents are cleared with the background color + * The back buffered contents are cleared with the background color * after flipping. */ public static final FlipContents BACKGROUND = new FlipContents(); - - /** - * The back buffered contents are copied to the front buffer before + + /** + * The back buffered contents are copied to the front buffer before * flipping. */ public static final FlipContents COPIED = new FlipContents(); - - /** - * The back buffer contents are the prior contents of the - * front buffer. + + /** + * The back buffer contents are the prior contents of the front buffer. */ public static final FlipContents PRIOR = new FlipContents(); - - /** - * The back buffer contents are undefined after flipping + + /** + * The back buffer contents are undefined after flipping */ public static final FlipContents UNDEFINED = new FlipContents(); diff --git a/awt/java/awt/Color.java b/awt/java/awt/Color.java index e1e4178e9992f885ba8d253aa4d17cec71651e77..93c532d784a35af87d5a41dc8dfe6bdd48c5ce90 100644 --- a/awt/java/awt/Color.java +++ b/awt/java/awt/Color.java @@ -18,6 +18,7 @@ * @author Oleg V. Khaschansky * @version $Revision$ */ + package java.awt; import java.awt.color.ColorSpace; @@ -33,155 +34,230 @@ import java.util.Arrays; import org.apache.harmony.awt.internal.nls.Messages; /** - * The Color class defines colors in the default sRGB color - * space or in the specified ColorSpace. Every Color contains alpha value. - * The alpha value defines the transparency of a color and can be represented - * by a float value in the range 0.0 - 1.0 or 0 - 255. - */ + * The Color class defines colors in the default sRGB color space or in the + * specified ColorSpace. Every Color contains alpha value. The alpha value + * defines the transparency of a color and can be represented by a float value + * in the range 0.0 - 1.0 or 0 - 255. + * + * @since Android 1.0 + */ public class Color implements Paint, Serializable { - - /** The Constant serialVersionUID. */ + + /** + * The Constant serialVersionUID. + */ private static final long serialVersionUID = 118526816881161077L; /* - * The values of the following colors are based on 1.5 release behavior which - * can be revealed using the following or similar code: - * Color c = Color.white; - * System.out.println(c); + * The values of the following colors are based on 1.5 release behavior + * which can be revealed using the following or similar code: Color c = + * Color.white; System.out.println(c); */ - /** The color white. */ + /** + * The color white. + */ public static final Color white = new Color(255, 255, 255); - /** The color white. */ + /** + * The color white. + */ public static final Color WHITE = white; - /** The color light gray. */ + /** + * The color light gray. + */ public static final Color lightGray = new Color(192, 192, 192); - /** The color light gray. */ + /** + * The color light gray. + */ public static final Color LIGHT_GRAY = lightGray; - /** The color gray. */ + /** + * The color gray. + */ public static final Color gray = new Color(128, 128, 128); - /** The color gray. */ + /** + * The color gray. + */ public static final Color GRAY = gray; - /** The color dark gray. */ + /** + * The color dark gray. + */ public static final Color darkGray = new Color(64, 64, 64); - /** The color dark gray. */ + /** + * The color dark gray. + */ public static final Color DARK_GRAY = darkGray; - /** The color black. */ + /** + * The color black. + */ public static final Color black = new Color(0, 0, 0); - /** The color black. */ + /** + * The color black. + */ public static final Color BLACK = black; - /** The color red. */ + /** + * The color red. + */ public static final Color red = new Color(255, 0, 0); - /** The color red. */ + /** + * The color red. + */ public static final Color RED = red; - /** The color pink. */ + /** + * The color pink. + */ public static final Color pink = new Color(255, 175, 175); - /** The color pink. */ + /** + * The color pink. + */ public static final Color PINK = pink; - /** The color orange. */ + /** + * The color orange. + */ public static final Color orange = new Color(255, 200, 0); - /** The color orange. */ + /** + * The color orange. + */ public static final Color ORANGE = orange; - /** The color yellow. */ + /** + * The color yellow. + */ public static final Color yellow = new Color(255, 255, 0); - /** The color yellow. */ + /** + * The color yellow. + */ public static final Color YELLOW = yellow; - /** The color green. */ + /** + * The color green. + */ public static final Color green = new Color(0, 255, 0); - /** The color green. */ + /** + * The color green. + */ public static final Color GREEN = green; - /** The color magenta. */ + /** + * The color magenta. + */ public static final Color magenta = new Color(255, 0, 255); - /** The color magenta. */ + /** + * The color magenta. + */ public static final Color MAGENTA = magenta; - /** The color cyan. */ + /** + * The color cyan. + */ public static final Color cyan = new Color(0, 255, 255); - /** The color cyan. */ + /** + * The color cyan. + */ public static final Color CYAN = cyan; - /** The color blue. */ + /** + * The color blue. + */ public static final Color blue = new Color(0, 0, 255); - /** The color blue. */ + /** + * The color blue. + */ public static final Color BLUE = blue; - /** integer RGB value. */ + /** + * integer RGB value. + */ int value; - /** Float sRGB value. */ + /** + * Float sRGB value. + */ private float[] frgbvalue; - /** Color in an arbitrary color space with float components. If null, other value should be used. */ + /** + * Color in an arbitrary color space with float components. If + * null, other value should be used. + */ private float fvalue[]; - /** Float alpha value. If frgbvalue is null, this is not valid data. */ + /** + * Float alpha value. If frgbvalue is null, this is not valid data. + */ private float falpha; - /** The color's color space if applicable. */ + /** + * The color's color space if applicable. + */ private ColorSpace cs; /* - * The value of the SCALE_FACTOR is based on 1.5 release behavior which - * can be revealed using the following code: - * Color c = new Color(100, 100, 100); - * Color bc = c.brighter(); - * System.out.println("Brighter factor: " + ((float)c.getRed())/((float)bc.getRed())); - * Color dc = c.darker(); - * System.out.println("Darker factor: " + ((float)dc.getRed())/((float)c.getRed())); - * The result is the same for brighter and darker methods, so we need only - * one scale factor for both. - */ - /** The Constant SCALE_FACTOR. */ + * The value of the SCALE_FACTOR is based on 1.5 release behavior which can + * be revealed using the following code: Color c = new Color(100, 100, 100); + * Color bc = c.brighter(); System.out.println("Brighter factor: " + + * ((float)c.getRed())/((float)bc.getRed())); Color dc = c.darker(); + * System.out.println("Darker factor: " + + * ((float)dc.getRed())/((float)c.getRed())); The result is the same for + * brighter and darker methods, so we need only one scale factor for both. + */ + /** + * The Constant SCALE_FACTOR. + */ private static final double SCALE_FACTOR = 0.7; - /** The Constant MIN_SCALABLE. */ - private static final int MIN_SCALABLE = 3; // should increase when multiplied by SCALE_FACTOR + /** + * The Constant MIN_SCALABLE. + */ + private static final int MIN_SCALABLE = 3; // should increase when + + // multiplied by SCALE_FACTOR - /** The current paint context. */ + /** + * The current paint context. + */ transient private PaintContext currentPaintContext; /** - * Creates a color in the specified ColorSpace, the specified color - * components and the specified alpha. + * Creates a color in the specified ColorSpace, the specified color + * components and the specified alpha. * - * @param cspace the ColorSpace to be used to define the components. - * @param components the components. - * @param alpha the alpha. + * @param cspace + * the ColorSpace to be used to define the components. + * @param components + * the components. + * @param alpha + * the alpha. */ public Color(ColorSpace cspace, float[] components, float alpha) { int nComps = cspace.getNumComponents(); float comp; fvalue = new float[nComps]; - for(int i=0 ; i 1.0f) { - // awt.107=Color parameter outside of expected range: component {0}. - throw new IllegalArgumentException( - Messages.getString("awt.107", i)); //$NON-NLS-1$ + if (comp < 0.0f || comp > 1.0f) { + // awt.107=Color parameter outside of expected range: component + // {0}. + throw new IllegalArgumentException(Messages.getString("awt.107", i)); //$NON-NLS-1$ } fvalue[i] = components[i]; } @@ -196,22 +272,22 @@ public class Color implements Paint, Serializable { frgbvalue = cs.toRGB(fvalue); - value = ((int)(frgbvalue[2]*255 + 0.5)) | - (((int)(frgbvalue[1]*255 + 0.5)) << 8 ) | - (((int)(frgbvalue[0]*255 + 0.5)) << 16 ) | - (((int)(falpha*255 + 0.5)) << 24 ); + value = ((int)(frgbvalue[2] * 255 + 0.5)) | (((int)(frgbvalue[1] * 255 + 0.5)) << 8) + | (((int)(frgbvalue[0] * 255 + 0.5)) << 16) | (((int)(falpha * 255 + 0.5)) << 24); } /** - * Instantiates a new sRGB color with the specified combined - * RGBA value consisting of the alpha component in bits 24-31, - * the red component in bits 16-23, the green component in bits 8-15, - * and the blue component in bits 0-7. If the hasalpha argument is - * false, the alpha has default value - 255. + * Instantiates a new sRGB color with the specified combined RGBA value + * consisting of the alpha component in bits 24-31, the red component in + * bits 16-23, the green component in bits 8-15, and the blue component in + * bits 0-7. If the hasalpha argument is false, the alpha has default value + * - 255. * - * @param rgba the RGBA components. - * @param hasAlpha alpha parameter is true if alpha bits are valid, - * false otherwise. + * @param rgba + * the RGBA components. + * @param hasAlpha + * the alpha parameter is true if alpha bits are valid, false + * otherwise. */ public Color(int rgba, boolean hasAlpha) { if (!hasAlpha) { @@ -222,13 +298,17 @@ public class Color implements Paint, Serializable { } /** - * Instantiates a new color with the specified red, green, blue and alpha + * Instantiates a new color with the specified red, green, blue and alpha * components. * - * @param r the red component. - * @param g the green component. - * @param b the blue component. - * @param a the alpha component. + * @param r + * the red component. + * @param g + * the green component. + * @param b + * the blue component. + * @param a + * the alpha component. */ public Color(int r, int g, int b, int a) { if ((r & 0xFF) != r || (g & 0xFF) != g || (b & 0xFF) != b || (a & 0xFF) != a) { @@ -239,12 +319,15 @@ public class Color implements Paint, Serializable { } /** - * Instantiates a new opaque sRGB color with the specified red, green, - * and blue values. The Alpha component is set to the default - 1.0. + * Instantiates a new opaque sRGB color with the specified red, green, and + * blue values. The Alpha component is set to the default - 1.0. * - * @param r the red component. - * @param g the green component. - * @param b the blue component. + * @param r + * the red component. + * @param g + * the green component. + * @param b + * the blue component. */ public Color(int r, int g, int b) { if ((r & 0xFF) != r || (g & 0xFF) != g || (b & 0xFF) != b) { @@ -256,31 +339,32 @@ public class Color implements Paint, Serializable { } /** - * Instantiates a new sRGB color with the specified - * RGB value consisting of the red component in bits 16-23, - * the green component in bits 8-15, and the blue component - * in bits 0-7. Alpha has default value - 255. + * Instantiates a new sRGB color with the specified RGB value consisting of + * the red component in bits 16-23, the green component in bits 8-15, and + * the blue component in bits 0-7. Alpha has default value - 255. * - * @param rgb the RGB components. + * @param rgb + * the RGB components. */ public Color(int rgb) { value = rgb | 0xFF000000; } /** - * Instantiates a new color with the specified red, green, blue and alpha + * Instantiates a new color with the specified red, green, blue and alpha * components. * - * @param r the red component. - * @param g the green component. - * @param b the blue component. - * @param a the alpha component. + * @param r + * the red component. + * @param g + * the green component. + * @param b + * the blue component. + * @param a + * the alpha component. */ public Color(float r, float g, float b, float a) { - this((int)(r*255+0.5), - (int)(g*255+0.5), - (int)(b*255+0.5), - (int)(a*255+0.5)); + this((int)(r * 255 + 0.5), (int)(g * 255 + 0.5), (int)(b * 255 + 0.5), (int)(a * 255 + 0.5)); falpha = a; fvalue = new float[3]; fvalue[0] = r; @@ -290,25 +374,23 @@ public class Color implements Paint, Serializable { } /** - * Instantiates a new color with the specified red, green, and blue - * components and default alfa value - 1.0. + * Instantiates a new color with the specified red, green, and blue + * components and default alpha value - 1.0. * - * @param r the red component. - * @param g the green component. - * @param b the blue component. + * @param r + * the red component. + * @param g + * the green component. + * @param b + * the blue component. */ public Color(float r, float g, float b) { this(r, g, b, 1.0f); } - public PaintContext createContext( - ColorModel cm, - Rectangle r, - Rectangle2D r2d, - AffineTransform xform, - RenderingHints rhs - ) { - if(currentPaintContext != null) { + public PaintContext createContext(ColorModel cm, Rectangle r, Rectangle2D r2d, + AffineTransform xform, RenderingHints rhs) { + if (currentPaintContext != null) { return currentPaintContext; } currentPaintContext = new Color.ColorPaintContext(value); @@ -323,15 +405,12 @@ public class Color implements Paint, Serializable { @Override public String toString() { /* - The format of the string is based on 1.5 release behavior which - can be revealed using the following code: - - Color c = new Color(1, 2, 3); - System.out.println(c); - */ - - return getClass().getName() + - "[r=" + getRed() + //$NON-NLS-1$ + * The format of the string is based on 1.5 release behavior which can + * be revealed using the following code: Color c = new Color(1, 2, 3); + * System.out.println(c); + */ + + return getClass().getName() + "[r=" + getRed() + //$NON-NLS-1$ ",g=" + getGreen() + //$NON-NLS-1$ ",b=" + getBlue() + //$NON-NLS-1$ "]"; //$NON-NLS-1$ @@ -340,65 +419,67 @@ public class Color implements Paint, Serializable { /** * Compares the specified Object to the Color. * - * @param obj the Object to be compared. - * - * @return true, if the specified Object is a Color whose - * value is equal to this Color, false otherwise. + * @param obj + * the Object to be compared. + * @return true, if the specified Object is a Color whose value is equal to + * this Color, false otherwise. */ @Override public boolean equals(Object obj) { - if(obj instanceof Color) { + if (obj instanceof Color) { return ((Color)obj).value == this.value; } return false; } /** - * Returns a float array containing the color and alpha components of - * the Color in the specified ColorSpace. - * - * @param colorSpace the specified ColorSpace. - * @param components the results of this method will be written to - * this float array. If null, a float array will be created. + * Returns a float array containing the color and alpha components of the + * Color in the specified ColorSpace. * + * @param colorSpace + * the specified ColorSpace. + * @param components + * the results of this method will be written to this float + * array. If null, a float array will be created. * @return the color and alpha components in a float array. */ public float[] getComponents(ColorSpace colorSpace, float[] components) { int nComps = colorSpace.getNumComponents(); - if(components == null) { - components = new float[nComps+1]; + if (components == null) { + components = new float[nComps + 1]; } getColorComponents(colorSpace, components); - if(frgbvalue != null) { + if (frgbvalue != null) { components[nComps] = falpha; } else { - components[nComps] = getAlpha()/255f; + components[nComps] = getAlpha() / 255f; } return components; } /** - * Returns a float array containing the color components of - * the Color in the specified ColorSpace. - * - * @param colorSpace the specified ColorSpace. - * @param components the results of this method will be written to - * this float array. If null, a float array will be created. + * Returns a float array containing the color components of the Color in the + * specified ColorSpace. * + * @param colorSpace + * the specified ColorSpace. + * @param components + * the results of this method will be written to this float + * array. If null, a float array will be created. * @return the color components in a float array. */ public float[] getColorComponents(ColorSpace colorSpace, float[] components) { float[] cieXYZComponents = getColorSpace().toCIEXYZ(getColorComponents(null)); float[] csComponents = colorSpace.fromCIEXYZ(cieXYZComponents); - if(components == null) { + if (components == null) { return csComponents; } - for(int i=0; i 255) ? 255 : r; } - if(b < MIN_SCALABLE && b != 0) { + if (b < MIN_SCALABLE && b != 0) { b = MIN_SCALABLE; } else { - b = (int) (b/SCALE_FACTOR); + b = (int)(b / SCALE_FACTOR); b = (b > 255) ? 255 : b; } - if(g < MIN_SCALABLE && g != 0) { + if (g < MIN_SCALABLE && g != 0) { g = MIN_SCALABLE; } else { - g = (int) (g/SCALE_FACTOR); + g = (int)(g / SCALE_FACTOR); g = (g > 255) ? 255 : g; } @@ -471,24 +550,24 @@ public class Color implements Paint, Serializable { } /** - * Returns a float array containing the color and alpha components of - * the Color in the default sRGB color space. - * - * @param components the results of this method will be written to - * this float array. A new float array will be created if this - * argument is null. + * Returns a float array containing the color and alpha components of the + * Color in the default sRGB color space. * + * @param components + * the results of this method will be written to this float + * array. A new float array will be created if this argument is + * null. * @return the RGB color and alpha components in a float array. */ public float[] getRGBComponents(float[] components) { - if(components == null) { + if (components == null) { components = new float[4]; } - if(frgbvalue != null) { + if (frgbvalue != null) { components[3] = falpha; } else { - components[3] = getAlpha()/255f; + components[3] = getAlpha() / 255f; } getRGBColorComponents(components); @@ -497,52 +576,52 @@ public class Color implements Paint, Serializable { } /** - * Returns a float array containing the color components of - * the Color in the default sRGB color space. - * - * @param components the results of this method will be written to - * this float array. A new float array will be created if this - * argument is null. + * Returns a float array containing the color components of the Color in the + * default sRGB color space. * + * @param components + * the results of this method will be written to this float + * array. A new float array will be created if this argument is + * null. * @return the RGB color components in a float array. */ public float[] getRGBColorComponents(float[] components) { - if(components == null) { + if (components == null) { components = new float[3]; } - if(frgbvalue != null) { + if (frgbvalue != null) { components[2] = frgbvalue[2]; components[1] = frgbvalue[1]; components[0] = frgbvalue[0]; } else { - components[2] = getBlue()/255f; - components[1] = getGreen()/255f; - components[0] = getRed()/255f; + components[2] = getBlue() / 255f; + components[1] = getGreen() / 255f; + components[0] = getRed() / 255f; } return components; } /** - * Returns a float array which contains the color and alpha components of + * Returns a float array which contains the color and alpha components of * the Color in the ColorSpace of the Color. * - * @param components the results of this method will be written to - * this float array. A new float array will be created if this - * argument is null. - * + * @param components + * the results of this method will be written to this float + * array. A new float array will be created if this argument is + * null. * @return the color and alpha components in a float array. */ public float[] getComponents(float[] components) { - if(fvalue == null) { + if (fvalue == null) { return getRGBComponents(components); } int nColorComps = fvalue.length; - if(components == null) { - components = new float[nColorComps+1]; + if (components == null) { + components = new float[nColorComps + 1]; } getColorComponents(components); @@ -553,25 +632,25 @@ public class Color implements Paint, Serializable { } /** - * Returns a float array which contains the color components of - * the Color in the ColorSpace of the Color. - * - * @param components the results of this method will be written to - * this float array. A new float array will be created if this - * argument is null. + * Returns a float array which contains the color components of the Color in + * the ColorSpace of the Color. * + * @param components + * the results of this method will be written to this float + * array. A new float array will be created if this argument is + * null. * @return the color components in a float array. */ public float[] getColorComponents(float[] components) { - if(fvalue == null) { + if (fvalue == null) { return getRGBColorComponents(components); } - if(components == null) { + if (components == null) { components = new float[fvalue.length]; } - for(int i=0; i, Boolean> childClassesFlags = new Hashtable, Boolean>(); - /** The Constant peer. */ + /** + * The Constant peer. + */ private static final ComponentPeer peer = new ComponentPeer() { }; - /** The Constant incrementalImageUpdate. */ + /** + * The Constant incrementalImageUpdate. + */ private static final boolean incrementalImageUpdate; - /** The toolkit. */ + /** + * The toolkit. + */ final transient Toolkit toolkit = Toolkit.getDefaultToolkit(); - //???AWT + // ???AWT /* - protected abstract class AccessibleAWTComponent extends AccessibleContext implements - Serializable, AccessibleComponent { - private static final long serialVersionUID = 642321655757800191L; - - protected class AccessibleAWTComponentHandler implements ComponentListener { - protected AccessibleAWTComponentHandler() { - } - - public void componentHidden(ComponentEvent e) { - if (behaviour.isLightweight()) { - return; - } - firePropertyChange(AccessibleContext.ACCESSIBLE_STATE_PROPERTY, - AccessibleState.VISIBLE, null); - } - - public void componentMoved(ComponentEvent e) { - } - - public void componentResized(ComponentEvent e) { - } - - public void componentShown(ComponentEvent e) { - if (behaviour.isLightweight()) { - return; - } - firePropertyChange(AccessibleContext.ACCESSIBLE_STATE_PROPERTY, null, - AccessibleState.VISIBLE); - } - } - - protected class AccessibleAWTFocusHandler implements FocusListener { - public void focusGained(FocusEvent e) { - if (behaviour.isLightweight()) { - return; - } - firePropertyChange(AccessibleContext.ACCESSIBLE_STATE_PROPERTY, null, - AccessibleState.FOCUSED); - } - - public void focusLost(FocusEvent e) { - if (behaviour.isLightweight()) { - return; - } - firePropertyChange(AccessibleContext.ACCESSIBLE_STATE_PROPERTY, - AccessibleState.FOCUSED, null); - } - } - - protected ComponentListener accessibleAWTComponentHandler; - - protected FocusListener accessibleAWTFocusHandler; - */ - /* - * Number of registered property change listeners. - */ - /* - int listenersCount; - - public void addFocusListener(FocusListener l) { - Component.this.addFocusListener(l); - } - - @Override - public void addPropertyChangeListener(PropertyChangeListener listener) { - toolkit.lockAWT(); - try { - super.addPropertyChangeListener(listener); - listenersCount++; - if (accessibleAWTComponentHandler == null) { - accessibleAWTComponentHandler = new AccessibleAWTComponentHandler(); - Component.this.addComponentListener(accessibleAWTComponentHandler); - } - if (accessibleAWTFocusHandler == null) { - accessibleAWTFocusHandler = new AccessibleAWTFocusHandler(); - Component.this.addFocusListener(accessibleAWTFocusHandler); - } - } finally { - toolkit.unlockAWT(); - } - } - - public boolean contains(Point p) { - toolkit.lockAWT(); - try { - return Component.this.contains(p); - } finally { - toolkit.unlockAWT(); - } - } - - public Accessible getAccessibleAt(Point arg0) { - toolkit.lockAWT(); - try { - return null; - } finally { - toolkit.unlockAWT(); - } - } - - public Color getBackground() { - toolkit.lockAWT(); - try { - return Component.this.getBackground(); - } finally { - toolkit.unlockAWT(); - } - } - - public Rectangle getBounds() { - toolkit.lockAWT(); - try { - return Component.this.getBounds(); - } finally { - toolkit.unlockAWT(); - } - } - - public Cursor getCursor() { - toolkit.lockAWT(); - try { - return Component.this.getCursor(); - } finally { - toolkit.unlockAWT(); - } - } - - public Font getFont() { - toolkit.lockAWT(); - try { - return Component.this.getFont(); - } finally { - toolkit.unlockAWT(); - } - } - - public FontMetrics getFontMetrics(Font f) { - toolkit.lockAWT(); - try { - return Component.this.getFontMetrics(f); - } finally { - toolkit.unlockAWT(); - } - } - - public Color getForeground() { - toolkit.lockAWT(); - try { - return Component.this.getForeground(); - } finally { - toolkit.unlockAWT(); - } - } - - public Point getLocation() { - toolkit.lockAWT(); - try { - return Component.this.getLocation(); - } finally { - toolkit.unlockAWT(); - } - } - - public Point getLocationOnScreen() { - toolkit.lockAWT(); - try { - return Component.this.getLocationOnScreen(); - } finally { - toolkit.unlockAWT(); - } - } - - public Dimension getSize() { - toolkit.lockAWT(); - try { - return Component.this.getSize(); - } finally { - toolkit.unlockAWT(); - } - } - - public boolean isEnabled() { - toolkit.lockAWT(); - try { - return Component.this.isEnabled(); - } finally { - toolkit.unlockAWT(); - } - } - - public boolean isFocusTraversable() { - toolkit.lockAWT(); - try { - return Component.this.isFocusTraversable(); - } finally { - toolkit.unlockAWT(); - } - } - - public boolean isShowing() { - toolkit.lockAWT(); - try { - return Component.this.isShowing(); - } finally { - toolkit.unlockAWT(); - } - } - - public boolean isVisible() { - toolkit.lockAWT(); - try { - return Component.this.isVisible(); - } finally { - toolkit.unlockAWT(); - } - } - - public void removeFocusListener(FocusListener l) { - Component.this.removeFocusListener(l); - } - - @Override - public void removePropertyChangeListener(PropertyChangeListener listener) { - toolkit.lockAWT(); - try { - super.removePropertyChangeListener(listener); - listenersCount--; - if (listenersCount > 0) { - return; - } - // if there are no more listeners, remove handlers: - Component.this.removeFocusListener(accessibleAWTFocusHandler); - Component.this.removeComponentListener(accessibleAWTComponentHandler); - accessibleAWTComponentHandler = null; - accessibleAWTFocusHandler = null; - } finally { - toolkit.unlockAWT(); - } - } - - public void requestFocus() { - toolkit.lockAWT(); - try { - Component.this.requestFocus(); - } finally { - toolkit.unlockAWT(); - } - } - - public void setBackground(Color color) { - toolkit.lockAWT(); - try { - Component.this.setBackground(color); - } finally { - toolkit.unlockAWT(); - } - } - - public void setBounds(Rectangle r) { - toolkit.lockAWT(); - try { - Component.this.setBounds(r); - } finally { - toolkit.unlockAWT(); - } - } - - public void setCursor(Cursor cursor) { - toolkit.lockAWT(); - try { - Component.this.setCursor(cursor); - } finally { - toolkit.unlockAWT(); - } - } - - public void setEnabled(boolean enabled) { - toolkit.lockAWT(); - try { - Component.this.setEnabled(enabled); - } finally { - toolkit.unlockAWT(); - } - } - - public void setFont(Font f) { - toolkit.lockAWT(); - try { - Component.this.setFont(f); - } finally { - toolkit.unlockAWT(); - } - } - - public void setForeground(Color color) { - toolkit.lockAWT(); - try { - Component.this.setForeground(color); - } finally { - toolkit.unlockAWT(); - } - } - - public void setLocation(Point p) { - toolkit.lockAWT(); - try { - Component.this.setLocation(p); - } finally { - toolkit.unlockAWT(); - } - } - - public void setSize(Dimension size) { - toolkit.lockAWT(); - try { - Component.this.setSize(size); - } finally { - toolkit.unlockAWT(); - } - } - - public void setVisible(boolean visible) { - toolkit.lockAWT(); - try { - Component.this.setVisible(visible); - } finally { - toolkit.unlockAWT(); - } - } - - @Override - public Accessible getAccessibleParent() { - toolkit.lockAWT(); - try { - Accessible aParent = super.getAccessibleParent(); - if (aParent != null) { - return aParent; - } - Container parent = getParent(); - return (parent instanceof Accessible ? (Accessible) parent : null); - } finally { - toolkit.unlockAWT(); - } - } - - @Override - public Accessible getAccessibleChild(int i) { - toolkit.lockAWT(); - try { - return null; - } finally { - toolkit.unlockAWT(); - } - } - - @Override - public int getAccessibleChildrenCount() { - toolkit.lockAWT(); - try { - return 0; - } finally { - toolkit.unlockAWT(); - } - } - - @Override - public AccessibleComponent getAccessibleComponent() { - return this; - } - - @Override - public String getAccessibleDescription() { - return super.getAccessibleDescription(); // why override? - } - - @Override - public int getAccessibleIndexInParent() { - toolkit.lockAWT(); - try { - if (getAccessibleParent() == null) { - return -1; - } - int count = 0; - Container parent = getParent(); - for (int i = 0; i < parent.getComponentCount(); i++) { - Component aComp = parent.getComponent(i); - if (aComp instanceof Accessible) { - if (aComp == Component.this) { - return count; - } - ++count; - } - } - return -1; - } finally { - toolkit.unlockAWT(); - } - } - - @Override - public AccessibleRole getAccessibleRole() { - toolkit.lockAWT(); - try { - return AccessibleRole.AWT_COMPONENT; - } finally { - toolkit.unlockAWT(); - } - } - - @Override - public AccessibleStateSet getAccessibleStateSet() { - toolkit.lockAWT(); - try { - AccessibleStateSet set = new AccessibleStateSet(); - if (isEnabled()) { - set.add(AccessibleState.ENABLED); - } - if (isFocusable()) { - set.add(AccessibleState.FOCUSABLE); - } - if (hasFocus()) { - set.add(AccessibleState.FOCUSED); - } - if (isOpaque()) { - set.add(AccessibleState.OPAQUE); - } - if (isShowing()) { - set.add(AccessibleState.SHOWING); - } - if (isVisible()) { - set.add(AccessibleState.VISIBLE); - } - return set; - } finally { - toolkit.unlockAWT(); - } - } - - @Override - public Locale getLocale() throws IllegalComponentStateException { - toolkit.lockAWT(); - try { - return Component.this.getLocale(); - } finally { - toolkit.unlockAWT(); - } - } - } - */ - /** - * The BltBufferStrategy class provides opportunity of blitting - * offscreen surfaces to a component. For more information on - * blitting, see Bit blit. + * protected abstract class AccessibleAWTComponent extends AccessibleContext + * implements Serializable, AccessibleComponent { private static final long + * serialVersionUID = 642321655757800191L; protected class + * AccessibleAWTComponentHandler implements ComponentListener { protected + * AccessibleAWTComponentHandler() { } public void + * componentHidden(ComponentEvent e) { if (behaviour.isLightweight()) { + * return; } firePropertyChange(AccessibleContext.ACCESSIBLE_STATE_PROPERTY, + * AccessibleState.VISIBLE, null); } public void + * componentMoved(ComponentEvent e) { } public void + * componentResized(ComponentEvent e) { } public void + * componentShown(ComponentEvent e) { if (behaviour.isLightweight()) { + * return; } firePropertyChange(AccessibleContext.ACCESSIBLE_STATE_PROPERTY, + * null, AccessibleState.VISIBLE); } } protected class + * AccessibleAWTFocusHandler implements FocusListener { public void + * focusGained(FocusEvent e) { if (behaviour.isLightweight()) { return; } + * firePropertyChange(AccessibleContext.ACCESSIBLE_STATE_PROPERTY, null, + * AccessibleState.FOCUSED); } public void focusLost(FocusEvent e) { if + * (behaviour.isLightweight()) { return; } + * firePropertyChange(AccessibleContext.ACCESSIBLE_STATE_PROPERTY, + * AccessibleState.FOCUSED, null); } } protected ComponentListener + * accessibleAWTComponentHandler; protected FocusListener + * accessibleAWTFocusHandler; + */ + /* + * Number of registered property change listeners. + */ + /* + * int listenersCount; public void addFocusListener(FocusListener l) { + * Component.this.addFocusListener(l); } + * @Override public void addPropertyChangeListener(PropertyChangeListener + * listener) { toolkit.lockAWT(); try { + * super.addPropertyChangeListener(listener); listenersCount++; if + * (accessibleAWTComponentHandler == null) { accessibleAWTComponentHandler = + * new AccessibleAWTComponentHandler(); + * Component.this.addComponentListener(accessibleAWTComponentHandler); } if + * (accessibleAWTFocusHandler == null) { accessibleAWTFocusHandler = new + * AccessibleAWTFocusHandler(); + * Component.this.addFocusListener(accessibleAWTFocusHandler); } } finally { + * toolkit.unlockAWT(); } } public boolean contains(Point p) { + * toolkit.lockAWT(); try { return Component.this.contains(p); } finally { + * toolkit.unlockAWT(); } } public Accessible getAccessibleAt(Point arg0) { + * toolkit.lockAWT(); try { return null; } finally { toolkit.unlockAWT(); } + * } public Color getBackground() { toolkit.lockAWT(); try { return + * Component.this.getBackground(); } finally { toolkit.unlockAWT(); } } + * public Rectangle getBounds() { toolkit.lockAWT(); try { return + * Component.this.getBounds(); } finally { toolkit.unlockAWT(); } } public + * Cursor getCursor() { toolkit.lockAWT(); try { return + * Component.this.getCursor(); } finally { toolkit.unlockAWT(); } } public + * Font getFont() { toolkit.lockAWT(); try { return + * Component.this.getFont(); } finally { toolkit.unlockAWT(); } } public + * FontMetrics getFontMetrics(Font f) { toolkit.lockAWT(); try { return + * Component.this.getFontMetrics(f); } finally { toolkit.unlockAWT(); } } + * public Color getForeground() { toolkit.lockAWT(); try { return + * Component.this.getForeground(); } finally { toolkit.unlockAWT(); } } + * public Point getLocation() { toolkit.lockAWT(); try { return + * Component.this.getLocation(); } finally { toolkit.unlockAWT(); } } public + * Point getLocationOnScreen() { toolkit.lockAWT(); try { return + * Component.this.getLocationOnScreen(); } finally { toolkit.unlockAWT(); } + * } public Dimension getSize() { toolkit.lockAWT(); try { return + * Component.this.getSize(); } finally { toolkit.unlockAWT(); } } public + * boolean isEnabled() { toolkit.lockAWT(); try { return + * Component.this.isEnabled(); } finally { toolkit.unlockAWT(); } } public + * boolean isFocusTraversable() { toolkit.lockAWT(); try { return + * Component.this.isFocusTraversable(); } finally { toolkit.unlockAWT(); } } + * public boolean isShowing() { toolkit.lockAWT(); try { return + * Component.this.isShowing(); } finally { toolkit.unlockAWT(); } } public + * boolean isVisible() { toolkit.lockAWT(); try { return + * Component.this.isVisible(); } finally { toolkit.unlockAWT(); } } public + * void removeFocusListener(FocusListener l) { + * Component.this.removeFocusListener(l); } + * @Override public void removePropertyChangeListener(PropertyChangeListener + * listener) { toolkit.lockAWT(); try { + * super.removePropertyChangeListener(listener); listenersCount--; if + * (listenersCount > 0) { return; } // if there are no more listeners, + * remove handlers: + * Component.this.removeFocusListener(accessibleAWTFocusHandler); + * Component.this.removeComponentListener(accessibleAWTComponentHandler); + * accessibleAWTComponentHandler = null; accessibleAWTFocusHandler = null; } + * finally { toolkit.unlockAWT(); } } public void requestFocus() { + * toolkit.lockAWT(); try { Component.this.requestFocus(); } finally { + * toolkit.unlockAWT(); } } public void setBackground(Color color) { + * toolkit.lockAWT(); try { Component.this.setBackground(color); } finally { + * toolkit.unlockAWT(); } } public void setBounds(Rectangle r) { + * toolkit.lockAWT(); try { Component.this.setBounds(r); } finally { + * toolkit.unlockAWT(); } } public void setCursor(Cursor cursor) { + * toolkit.lockAWT(); try { Component.this.setCursor(cursor); } finally { + * toolkit.unlockAWT(); } } public void setEnabled(boolean enabled) { + * toolkit.lockAWT(); try { Component.this.setEnabled(enabled); } finally { + * toolkit.unlockAWT(); } } public void setFont(Font f) { toolkit.lockAWT(); + * try { Component.this.setFont(f); } finally { toolkit.unlockAWT(); } } + * public void setForeground(Color color) { toolkit.lockAWT(); try { + * Component.this.setForeground(color); } finally { toolkit.unlockAWT(); } } + * public void setLocation(Point p) { toolkit.lockAWT(); try { + * Component.this.setLocation(p); } finally { toolkit.unlockAWT(); } } + * public void setSize(Dimension size) { toolkit.lockAWT(); try { + * Component.this.setSize(size); } finally { toolkit.unlockAWT(); } } public + * void setVisible(boolean visible) { toolkit.lockAWT(); try { + * Component.this.setVisible(visible); } finally { toolkit.unlockAWT(); } } + * @Override public Accessible getAccessibleParent() { toolkit.lockAWT(); + * try { Accessible aParent = super.getAccessibleParent(); if (aParent != + * null) { return aParent; } Container parent = getParent(); return (parent + * instanceof Accessible ? (Accessible) parent : null); } finally { + * toolkit.unlockAWT(); } } + * @Override public Accessible getAccessibleChild(int i) { + * toolkit.lockAWT(); try { return null; } finally { toolkit.unlockAWT(); } + * } + * @Override public int getAccessibleChildrenCount() { toolkit.lockAWT(); + * try { return 0; } finally { toolkit.unlockAWT(); } } + * @Override public AccessibleComponent getAccessibleComponent() { return + * this; } + * @Override public String getAccessibleDescription() { return + * super.getAccessibleDescription(); // why override? } + * @Override public int getAccessibleIndexInParent() { toolkit.lockAWT(); + * try { if (getAccessibleParent() == null) { return -1; } int count = 0; + * Container parent = getParent(); for (int i = 0; i < + * parent.getComponentCount(); i++) { Component aComp = + * parent.getComponent(i); if (aComp instanceof Accessible) { if (aComp == + * Component.this) { return count; } ++count; } } return -1; } finally { + * toolkit.unlockAWT(); } } + * @Override public AccessibleRole getAccessibleRole() { toolkit.lockAWT(); + * try { return AccessibleRole.AWT_COMPONENT; } finally { + * toolkit.unlockAWT(); } } + * @Override public AccessibleStateSet getAccessibleStateSet() { + * toolkit.lockAWT(); try { AccessibleStateSet set = new + * AccessibleStateSet(); if (isEnabled()) { + * set.add(AccessibleState.ENABLED); } if (isFocusable()) { + * set.add(AccessibleState.FOCUSABLE); } if (hasFocus()) { + * set.add(AccessibleState.FOCUSED); } if (isOpaque()) { + * set.add(AccessibleState.OPAQUE); } if (isShowing()) { + * set.add(AccessibleState.SHOWING); } if (isVisible()) { + * set.add(AccessibleState.VISIBLE); } return set; } finally { + * toolkit.unlockAWT(); } } + * @Override public Locale getLocale() throws IllegalComponentStateException + * { toolkit.lockAWT(); try { return Component.this.getLocale(); } finally { + * toolkit.unlockAWT(); } } } + */ + /** + * The BltBufferStrategy class provides opportunity of blitting offscreen + * surfaces to a component. For more information on blitting, see Bit blit. + * + * @since Android 1.0 */ protected class BltBufferStrategy extends BufferStrategy { - - /** The back buffers. */ + + /** + * The back buffers. + */ protected VolatileImage[] backBuffers; - /** The caps. */ + /** + * The caps. + */ protected BufferCapabilities caps; - /** The width. */ + /** + * The width. + */ protected int width; - /** The height. */ + /** + * The height. + */ protected int height; - /** The validated contents. */ + /** + * The validated contents. + */ protected boolean validatedContents; /** * Instantiates a new BltBufferStrategy buffer strategy. * - * @param numBuffers the number of buffers. - * @param caps the BufferCapabilities. - * - * @throws NotImplementedException the not implemented exception. + * @param numBuffers + * the number of buffers. + * @param caps + * the BufferCapabilities. + * @throws NotImplementedException + * the not implemented exception. */ - protected BltBufferStrategy(int numBuffers, BufferCapabilities caps) throws org.apache.harmony.luni.util.NotImplementedException { + protected BltBufferStrategy(int numBuffers, BufferCapabilities caps) + throws org.apache.harmony.luni.util.NotImplementedException { if (true) { throw new RuntimeException("Method is not implemented"); //$NON-NLS-1$ } } /** - * Returns true if the drawing buffer has been lost since the last call - * to getDrawGraphics. + * Returns true if the drawing buffer has been lost since the last call + * to getDrawGraphics. * - * @return true if the drawing buffer has been lost since the last call - * to getDrawGraphics, false otherwise. - * + * @return true if the drawing buffer has been lost since the last call + * to getDrawGraphics, false otherwise. * @see java.awt.image.BufferStrategy#contentsLost() */ @Override @@ -634,9 +360,8 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali * state and reinitialized to the default background color. * * @return true if the drawing buffer has been restored from a lost - * state and reinitialized to the default background color, - * false otherwise. - * + * state and reinitialized to the default background color, + * false otherwise. * @see java.awt.image.BufferStrategy#contentsRestored() */ @Override @@ -650,7 +375,8 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali /** * Creates the back buffers. * - * @param numBuffers the number of buffers. + * @param numBuffers + * the number of buffers. */ protected void createBackBuffers(int numBuffers) { if (true) { @@ -662,19 +388,17 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali * Returns the BufferCapabilities of the buffer strategy. * * @return the BufferCapabilities. - * * @see java.awt.image.BufferStrategy#getCapabilities() */ @Override public BufferCapabilities getCapabilities() { - return (BufferCapabilities) caps.clone(); + return (BufferCapabilities)caps.clone(); } /** * Gets Graphics of current buffer strategy. * * @return the Graphics of current buffer strategy. - * * @see java.awt.image.BufferStrategy#getDrawGraphics() */ @Override @@ -708,56 +432,68 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali } /** - * The FlipBufferStrategy class is for flipping buffers on a component. + * The FlipBufferStrategy class is for flipping buffers on a component. + * + * @since Android 1.0 */ protected class FlipBufferStrategy extends BufferStrategy { - - /** The Buffer Capabilities. */ + + /** + * The Buffer Capabilities. + */ protected BufferCapabilities caps; - /** The drawing buffer. */ + /** + * The drawing buffer. + */ protected Image drawBuffer; - /** The drawing VolatileImage buffer. */ + /** + * The drawing VolatileImage buffer. + */ protected VolatileImage drawVBuffer; - /** The number of buffers. */ + /** + * The number of buffers. + */ protected int numBuffers; - /** The validated contents indicates if the drawing buffer is restored from - * lost state. */ + /** + * The validated contents indicates if the drawing buffer is restored + * from lost state. + */ protected boolean validatedContents; /** * Instantiates a new flip buffer strategy. * - * @param numBuffers the number of buffers. - * @param caps the BufferCapabilities. - * - * @throws AWTException if the capabilities supplied could not - * be supported or met. + * @param numBuffers + * the number of buffers. + * @param caps + * the BufferCapabilities. + * @throws AWTException + * if the capabilities supplied could not be supported or + * met. */ - protected FlipBufferStrategy(int numBuffers, BufferCapabilities caps) - throws AWTException { - //???AWT + protected FlipBufferStrategy(int numBuffers, BufferCapabilities caps) throws AWTException { + // ???AWT /* - if (!(Component.this instanceof Window) && !(Component.this instanceof Canvas)) { - // awt.14B=Only Canvas or Window is allowed - throw new ClassCastException(Messages.getString("awt.14B")); //$NON-NLS-1$ - } - */ + * if (!(Component.this instanceof Window) && !(Component.this + * instanceof Canvas)) { // awt.14B=Only Canvas or Window is allowed + * throw new ClassCastException(Messages.getString("awt.14B")); + * //$NON-NLS-1$ } + */ // TODO: throw new AWTException("Capabilities are not supported"); this.numBuffers = numBuffers; - this.caps = (BufferCapabilities) caps.clone(); + this.caps = (BufferCapabilities)caps.clone(); } /** - * Returns true if the drawing buffer has been lost since the last call - * to getDrawGraphics. - * - * @return true if the drawing buffer has been lost since the last call - * to getDrawGraphics, false otherwise. + * Returns true if the drawing buffer has been lost since the last call + * to getDrawGraphics. * + * @return true if the drawing buffer has been lost since the last call + * to getDrawGraphics, false otherwise. * @see java.awt.image.BufferStrategy#contentsLost() */ @Override @@ -773,9 +509,8 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali * state and reinitialized to the default background color. * * @return true if the drawing buffer has been restored from a lost - * state and reinitialized to the default background color, - * false otherwise. - * + * state and reinitialized to the default background color, + * false otherwise. * @see java.awt.image.BufferStrategy#contentsRestored() */ @Override @@ -789,14 +524,14 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali /** * Creates flipping buffers with the specified buffer capabilities. * - * @param numBuffers the number of buffers. - * @param caps the BufferCapabilities. - * - * @throws AWTException if the capabilities could not be - * supported or met. + * @param numBuffers + * the number of buffers. + * @param caps + * the BufferCapabilities. + * @throws AWTException + * if the capabilities could not be supported or met. */ - protected void createBuffers(int numBuffers, BufferCapabilities caps) - throws AWTException { + protected void createBuffers(int numBuffers, BufferCapabilities caps) throws AWTException { if (numBuffers < 2) { // awt.14C=Number of buffers must be greater than one throw new IllegalArgumentException(Messages.getString("awt.14C")); //$NON-NLS-1$ @@ -827,7 +562,8 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali /** * Flips the contents of the back buffer to the front buffer. * - * @param flipAction the flip action. + * @param flipAction + * the flip action. */ protected void flip(BufferCapabilities.FlipContents flipAction) { if (true) { @@ -851,19 +587,17 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali * Returns the BufferCapabilities of the buffer strategy. * * @return the BufferCapabilities. - * * @see java.awt.image.BufferStrategy#getCapabilities() */ @Override public BufferCapabilities getCapabilities() { - return (BufferCapabilities) caps.clone(); + return (BufferCapabilities)caps.clone(); } /** * Gets Graphics of current buffer strategy. * * @return the Graphics of current buffer strategy. - * * @see java.awt.image.BufferStrategy#getDrawGraphics() */ @Override @@ -900,14 +634,16 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali * The internal component's state utilized by the visual theme. */ class ComponentState implements State { - - /** The default minimum size. */ + + /** + * The default minimum size. + */ private Dimension defaultMinimumSize = new Dimension(); /** * Checks if the component is enabled. * - * @return true, if the component is enabled + * @return true, if the component is enabled. */ public boolean isEnabled() { return enabled; @@ -916,7 +652,7 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali /** * Checks if the component is visible. * - * @return true, if the component is visible + * @return true, if the component is visible. */ public boolean isVisible() { return visible; @@ -925,17 +661,17 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali /** * Checks if is focused. * - * @return true, if is focused + * @return true, if is focused. */ public boolean isFocused() { - //???AWT: return isFocusOwner(); + // ???AWT: return isFocusOwner(); return false; } /** * Gets the font. * - * @return the font + * @return the font. */ public Font getFont() { return Component.this.getFont(); @@ -944,7 +680,7 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali /** * Checks if the font has been set. * - * @return true, if the font has been set + * @return true, if the font has been set. */ public boolean isFontSet() { return font != null; @@ -953,7 +689,7 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali /** * Gets the background color. * - * @return the background color + * @return the background color. */ public Color getBackground() { Color c = Component.this.getBackground(); @@ -963,7 +699,7 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali /** * Checks if the background is set. * - * @return true, if the background is set + * @return true, if the background is set. */ public boolean isBackgroundSet() { return backColor != null; @@ -972,7 +708,7 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali /** * Gets the text color. * - * @return the text color + * @return the text color. */ public Color getTextColor() { Color c = getForeground(); @@ -982,7 +718,7 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali /** * Checks if the text color is set. * - * @return true, if the text color is set + * @return true, if the text color is set. */ public boolean isTextColorSet() { return foreColor != null; @@ -991,7 +727,7 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali /** * Gets the font metrics. * - * @return the font metrics + * @return the font metrics. */ @SuppressWarnings("deprecation") public FontMetrics getFontMetrics() { @@ -1001,7 +737,7 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali /** * Gets the bounding rectangle. * - * @return the bounding rectangle + * @return the bounding rectangle. */ public Rectangle getBounds() { return new Rectangle(x, y, w, h); @@ -1010,7 +746,7 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali /** * Gets the size of the bounding rectangle. * - * @return the size of the bounding rectangle + * @return the size of the bounding rectangle. */ public Dimension getSize() { return new Dimension(w, h); @@ -1019,7 +755,7 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali /** * Gets the window id. * - * @return the window id + * @return the window id. */ public long getWindowId() { NativeWindow win = getNativeWindow(); @@ -1029,7 +765,7 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali /** * Gets the default minimum size. * - * @return the default minimum size + * @return the default minimum size. */ public Dimension getDefaultMinimumSize() { if (defaultMinimumSize == null) { @@ -1041,7 +777,8 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali /** * Sets the default minimum size. * - * @param size the new default minimum size + * @param size + * the new default minimum size. */ public void setDefaultMinimumSize(Dimension size) { defaultMinimumSize = size; @@ -1062,179 +799,283 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali } } - //???AWT: private transient AccessibleContext accessibleContext; + // ???AWT: private transient AccessibleContext accessibleContext; - /** The behaviour. */ + /** + * The behaviour. + */ final transient ComponentBehavior behaviour; - //???AWT: Container parent; + // ???AWT: Container parent; - /** The name. */ + /** + * The name. + */ private String name; - /** The auto name. */ + /** + * The auto name. + */ private boolean autoName = true; - /** The font. */ + /** + * The font. + */ private Font font; - /** The back color. */ + /** + * The back color. + */ private Color backColor; - /** The fore color. */ + /** + * The fore color. + */ private Color foreColor; - /** The deprecated event handler. */ + /** + * The deprecated event handler. + */ boolean deprecatedEventHandler = true; - /** The enabled events. */ + /** + * The enabled events. + */ private long enabledEvents; - /** The enabled awt events. */ + /** + * The enabled AWT events. + */ private long enabledAWTEvents; - /** The component listeners. */ + /** + * The component listeners. + */ private final AWTListenerList componentListeners = new AWTListenerList( this); - /** The focus listeners. */ + /** + * The focus listeners. + */ private final AWTListenerList focusListeners = new AWTListenerList( this); - /** The hierarchy listeners. */ + /** + * The hierarchy listeners. + */ private final AWTListenerList hierarchyListeners = new AWTListenerList( this); - /** The hierarchy bounds listeners. */ + /** + * The hierarchy bounds listeners. + */ private final AWTListenerList hierarchyBoundsListeners = new AWTListenerList( this); - /** The key listeners. */ - private final AWTListenerList keyListeners = new AWTListenerList( - this); + /** + * The key listeners. + */ + private final AWTListenerList keyListeners = new AWTListenerList(this); - /** The mouse listeners. */ + /** + * The mouse listeners. + */ private final AWTListenerList mouseListeners = new AWTListenerList( this); - /** The mouse motion listeners. */ + /** + * The mouse motion listeners. + */ private final AWTListenerList mouseMotionListeners = new AWTListenerList( this); - /** The mouse wheel listeners. */ + /** + * The mouse wheel listeners. + */ private final AWTListenerList mouseWheelListeners = new AWTListenerList( this); - /** The input method listeners. */ + /** + * The input method listeners. + */ private final AWTListenerList inputMethodListeners = new AWTListenerList( this); - /** The x. */ + /** + * The x. + */ int x; - /** The y. */ + /** + * The y. + */ int y; - /** The w. */ + /** + * The w. + */ int w; - /** The h. */ + /** + * The h. + */ int h; - /** The maximum size. */ + /** + * The maximum size. + */ private Dimension maximumSize; - /** The minimum size. */ + /** + * The minimum size. + */ private Dimension minimumSize; - /** The preferred size. */ + /** + * The preferred size. + */ private Dimension preferredSize; - /** The bounds mask param. */ + /** + * The bounds mask param. + */ private int boundsMaskParam; - /** The ignore repaint. */ + /** + * The ignore repaint. + */ private boolean ignoreRepaint; - /** The enabled. */ + /** + * The enabled. + */ private boolean enabled = true; - /** The input methods enabled. */ + /** + * The input methods enabled. + */ private boolean inputMethodsEnabled = true; - /** The dispatch to im. */ + /** + * The dispatch to im. + */ transient boolean dispatchToIM = true; - /** The focusable. */ + /** + * The focusable. + */ private boolean focusable = true; // By default, all Components return // true from isFocusable() method - /** The visible. */ + /** + * The visible. + */ boolean visible = true; - /** The called set focusable. */ + /** + * The called set focusable. + */ private boolean calledSetFocusable; - /** The overriden is focusable. */ + /** + * The overridden is focusable. + */ private boolean overridenIsFocusable = true; - /** The focus traversal keys enabled. */ + /** + * The focus traversal keys enabled. + */ private boolean focusTraversalKeysEnabled = true; - /** Possible keys are: FORWARD_TRAVERSAL_KEYS, BACKWARD_TRAVERSAL_KEYS, UP_CYCLE_TRAVERSAL_KEYS. */ + /** + * Possible keys are: FORWARD_TRAVERSAL_KEYS, BACKWARD_TRAVERSAL_KEYS, + * UP_CYCLE_TRAVERSAL_KEYS. + */ private final Map> traversalKeys = new HashMap>(); - /** The traversal i ds. */ + /** + * The traversal i ds. + */ int[] traversalIDs; - /** The locale. */ + /** + * The locale. + */ private Locale locale; - /** The orientation. */ + /** + * The orientation. + */ private ComponentOrientation orientation; - /** The property change support. */ + /** + * The property change support. + */ private PropertyChangeSupport propertyChangeSupport; - //???AWT: private ArrayList popups; + // ???AWT: private ArrayList popups; - /** The coalescer. */ + /** + * The coalescer. + */ private boolean coalescer; - /** The events table. */ + /** + * The events table. + */ private Hashtable> eventsTable; - /** Cashed reference used during EventQueue.postEvent() */ + /** + * Cashed reference used during EventQueue.postEvent() + */ private LinkedList eventsList; - /** The hierarchy changing counter. */ + /** + * The hierarchy changing counter. + */ private int hierarchyChangingCounter; - /** The was showing. */ + /** + * The was showing. + */ private boolean wasShowing; - /** The was displayable. */ + /** + * The was displayable. + */ private boolean wasDisplayable; - /** The cursor. */ + /** + * The cursor. + */ Cursor cursor; - //???AWT: DropTarget dropTarget; + // ???AWT: DropTarget dropTarget; - /** The mouse exited expected. */ + /** + * The mouse exited expected. + */ private boolean mouseExitedExpected; - /** The repaint region. */ + /** + * The repaint region. + */ transient MultiRectArea repaintRegion; - //???AWT: transient RedrawManager redrawManager; - /** The redraw manager. */ + // ???AWT: transient RedrawManager redrawManager; + /** + * The redraw manager. + */ transient Object redrawManager; - /** The valid. */ + /** + * The valid. + */ private boolean valid; - /** The updated images. */ + /** + * The updated images. + */ private HashMap updatedImages; /** @@ -1244,7 +1085,9 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali private class ComponentLock { } - /** The component lock. */ + /** + * The component lock. + */ private final transient Object componentLock = new ComponentLock(); static { PrivilegedAction action = new PrivilegedAction() { @@ -1276,17 +1119,16 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali try { orientation = ComponentOrientation.UNKNOWN; redrawManager = null; - //???AWT + // ???AWT /* - traversalIDs = this instanceof Container ? KeyboardFocusManager.contTraversalIDs - : KeyboardFocusManager.compTraversalIDs; - for (int element : traversalIDs) { - traversalKeys.put(new Integer(element), null); - } - behaviour = createBehavior(); - */ + * traversalIDs = this instanceof Container ? + * KeyboardFocusManager.contTraversalIDs : + * KeyboardFocusManager.compTraversalIDs; for (int element : + * traversalIDs) { traversalKeys.put(new Integer(element), null); } + * behaviour = createBehavior(); + */ behaviour = null; - + deriveCoalescerFlag(); } finally { toolkit.unlockAWT(); @@ -1307,8 +1149,8 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali for (Class c = thisClass; c != Component.class; c = c.getSuperclass()) { try { coalesceMethod = c.getDeclaredMethod("coalesceEvents", new Class[] { //$NON-NLS-1$ - Class.forName("java.awt.AWTEvent"), //$NON-NLS-1$ - Class.forName("java.awt.AWTEvent") }); //$NON-NLS-1$ + Class.forName("java.awt.AWTEvent"), //$NON-NLS-1$ + Class.forName("java.awt.AWTEvent")}); //$NON-NLS-1$ } catch (Exception e) { } if (coalesceMethod != null) { @@ -1332,7 +1174,8 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali /** * Sets the name of the Component. * - * @param name the new name of the Component. + * @param name + * the new name of the Component. */ public void setName(String name) { String oldName; @@ -1367,15 +1210,15 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali /** * Auto name. * - * @return the string + * @return the string. */ String autoName() { String name = getClass().getName(); if (name.indexOf("$") != -1) { //$NON-NLS-1$ return null; } - //???AWT - //int number = toolkit.autoNumber.nextComponent++; + // ???AWT + // int number = toolkit.autoNumber.nextComponent++; int number = 0; name = name.substring(name.lastIndexOf(".") + 1) + Integer.toString(number); //$NON-NLS-1$ return name; @@ -1390,10 +1233,8 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali public String toString() { /* * The format is based on 1.5 release behavior which can be revealed by - * the following code: - * - * Component c = new Component(){}; c.setVisible(false); - * System.out.println(c); + * the following code: Component c = new Component(){}; + * c.setVisible(false); System.out.println(c); */ toolkit.lockAWT(); try { @@ -1403,32 +1244,21 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali } } - //???AWT + // ???AWT /* - public void add(PopupMenu popup) { - toolkit.lockAWT(); - try { - if (popup.getParent() == this) { - return; - } - if (popups == null) { - popups = new ArrayList(); - } - popup.setParent(this); - popups.add(popup); - } finally { - toolkit.unlockAWT(); - } - } - */ + * public void add(PopupMenu popup) { toolkit.lockAWT(); try { if + * (popup.getParent() == this) { return; } if (popups == null) { popups = + * new ArrayList(); } popup.setParent(this); popups.add(popup); } + * finally { toolkit.unlockAWT(); } } + */ /** * Returns true, if the component contains the specified Point. * - * @param p the Point. - * - * @return true, if the component contains the specified Point, - * false otherwise. + * @param p + * the Point. + * @return true, if the component contains the specified Point, false + * otherwise. */ public boolean contains(Point p) { toolkit.lockAWT(); @@ -1440,14 +1270,15 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali } /** - * Returns true, if the component contains the point with - * the specified coordinates. + * Returns true, if the component contains the point with the specified + * coordinates. * - * @param x the x coordinate. - * @param y the y coordinate. - * - * @return true, if the component contains the point with - * the specified coordinates, false otherwise. + * @param x + * the x coordinate. + * @param y + * the y coordinate. + * @return true, if the component contains the point with the specified + * coordinates, false otherwise. */ public boolean contains(int x, int y) { toolkit.lockAWT(); @@ -1462,7 +1293,6 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali * Deprecated: replaced by replaced by getSize() method. * * @return the dimension. - * * @deprecated Replaced by getSize() method. */ @Deprecated @@ -1474,90 +1304,63 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali toolkit.unlockAWT(); } } - - //???AWT + + // ???AWT /* - public Container getParent() { - toolkit.lockAWT(); - try { - return parent; - } finally { - toolkit.unlockAWT(); - } - } - */ - + * public Container getParent() { toolkit.lockAWT(); try { return parent; } + * finally { toolkit.unlockAWT(); } } + */ + /** * List. * - * @param out the out - * @param indent the indent - * + * @param out + * the out. + * @param indent + * the indent * @return the nearest heavyweight ancestor in hierarchy or - * null if not found + * null if not found. */ - //???AWT + // ???AWT /* - Component getHWAncestor() { - return (parent != null ? parent.getHWSurface() : null); - } - */ - + * Component getHWAncestor() { return (parent != null ? + * parent.getHWSurface() : null); } + */ + /** * @return heavyweight component that is equal to or is a nearest * heavyweight container of the current component, or - * null if not found + * null if not found. */ - //???AWT + // ???AWT /* - Component getHWSurface() { - Component parent; - for (parent = this; (parent != null) && (parent.isLightweight()); parent = parent - .getParent()) { - ; - } - return parent; - } + * Component getHWSurface() { Component parent; for (parent = this; (parent + * != null) && (parent.isLightweight()); parent = parent .getParent()) { ; } + * return parent; } Window getWindowAncestor() { Component par; for (par = + * this; par != null && !(par instanceof Window); par = par.getParent()) { ; + * } return (Window) par; } + */ - Window getWindowAncestor() { - Component par; - for (par = this; par != null && !(par instanceof Window); par = par.getParent()) { - ; - } - return (Window) par; - } - */ - - /** To be called by container */ - //???AWT + /** + * To be called by container + */ + // ???AWT /* - void setParent(Container parent) { - this.parent = parent; - setRedrawManager(); - } - - void setRedrawManager() { - redrawManager = getRedrawManager(); - } - - public void remove(MenuComponent menu) { - toolkit.lockAWT(); - try { - if (menu.getParent() == this) { - menu.setParent(null); - popups.remove(menu); - } - } finally { - toolkit.unlockAWT(); - } - } - */ + * void setParent(Container parent) { this.parent = parent; + * setRedrawManager(); } void setRedrawManager() { redrawManager = + * getRedrawManager(); } public void remove(MenuComponent menu) { + * toolkit.lockAWT(); try { if (menu.getParent() == this) { + * menu.setParent(null); popups.remove(menu); } } finally { + * toolkit.unlockAWT(); } } + */ /** - * Prints a list of this component with the specified number of - * leading whitespace characters to the specified PrintStream. + * Prints a list of this component with the specified number of leading + * whitespace characters to the specified PrintStream. * - * @param out the output PrintStream object. - * @param indent how many leading whitespace characters to prepend + * @param out + * the output PrintStream object. + * @param indent + * how many leading whitespace characters to prepend. */ public void list(PrintStream out, int indent) { toolkit.lockAWT(); @@ -1571,7 +1374,8 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali /** * Prints a list of this component to the specified PrintWriter. * - * @param out the output PrintWriter object. + * @param out + * the output PrintWriter object. */ public void list(PrintWriter out) { toolkit.lockAWT(); @@ -1583,11 +1387,13 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali } /** - * Prints a list of this component with the specified number of - * leading whitespace characters to the specified PrintWriter. + * Prints a list of this component with the specified number of leading + * whitespace characters to the specified PrintWriter. * - * @param out the output PrintWriter object. - * @param indent how many leading whitespace characters to prepend + * @param out + * the output PrintWriter object. + * @param indent + * how many leading whitespace characters to prepend. */ public void list(PrintWriter out, int indent) { toolkit.lockAWT(); @@ -1599,13 +1405,12 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali } /** - * Gets a string composed of the desired number of - * whitespace characters. + * Gets a string composed of the desired number of whitespace characters. * - * @param indent the length of the String to return - * - * @return the string composed of the desired number of - * whitespace characters + * @param indent + * the length of the String to return. + * @return the string composed of the desired number of whitespace + * characters. */ String getIndentStr(int indent) { char[] ind = new char[indent]; @@ -1616,9 +1421,10 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali } /** - * Prints a list of this component to the specified PrintStream + * Prints a list of this component to the specified PrintStream. * - * @param out the output PrintStream object. + * @param out + * the output PrintStream object. */ public void list(PrintStream out) { toolkit.lockAWT(); @@ -1631,8 +1437,7 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali } /** - * Prints a list of this component to the standard system - * output stream. + * Prints a list of this component to the standard system output stream. */ public void list() { toolkit.lockAWT(); @@ -1644,9 +1449,10 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali } /** - * Prints this component. + * Prints this component. * - * @param g the Graphics to be used for painting. + * @param g + * the Graphics to be used for painting. */ public void print(Graphics g) { toolkit.lockAWT(); @@ -1660,7 +1466,8 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali /** * Prints the component and all of its subcomponents. * - * @param g the Graphics to be used for painting. + * @param g + * the Graphics to be used for painting. */ public void printAll(Graphics g) { toolkit.lockAWT(); @@ -1672,11 +1479,12 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali } /** - * Sets the size of the Component specified by width and height - * parameters. + * Sets the size of the Component specified by width and height parameters. * - * @param width the width of the Component. - * @param height the height of the Component. + * @param width + * the width of the Component. + * @param height + * the height of the Component. */ public void setSize(int width, int height) { toolkit.lockAWT(); @@ -1690,7 +1498,8 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali /** * Sets the size of the Component specified by Dimension object. * - * @param d the new size of the Component. + * @param d + * the new size of the Component. */ public void setSize(Dimension d) { toolkit.lockAWT(); @@ -1704,9 +1513,10 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali /** * Deprecated: replaced by setSize(int, int) method. * - * @param width the width. - * @param height the height. - * + * @param width + * the width. + * @param height + * the height. * @deprecated Replaced by setSize(int, int) method. */ @Deprecated @@ -1723,8 +1533,8 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali /** * Deprecated: replaced by setSize(int, int) method. * - * @param size the size. - * + * @param size + * the size. * @deprecated Replaced by setSize(int, int) method. */ @Deprecated @@ -1740,8 +1550,7 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali /** * Checks whether or not this component is completely opaque. * - * @return true, if this component is completely opaque, - * false by default. + * @return true, if this component is completely opaque, false by default. */ public boolean isOpaque() { toolkit.lockAWT(); @@ -1765,7 +1574,7 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali } finally { toolkit.unlockAWT(); } - //???AWT: fireAccessibleStateChange(AccessibleState.ENABLED, false); + // ???AWT: fireAccessibleStateChange(AccessibleState.ENABLED, false); } /** @@ -1781,15 +1590,15 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali } finally { toolkit.unlockAWT(); } - //???AWT: fireAccessibleStateChange(AccessibleState.ENABLED, true); + // ???AWT: fireAccessibleStateChange(AccessibleState.ENABLED, true); } /** * Enables or disable this component. * - * @param b the boolean parameter. - * - * @deprecated Replaced by setEnabled(boolean) method. + * @param b + * the boolean parameter. + * @deprecated Replaced by setEnabled(boolean) method. */ @Deprecated public void enable(boolean b) { @@ -1809,9 +1618,9 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali * Stores the location of this component to the specified Point object; * returns the point of the component's top-left corner. * - * @param rv the Point object where the component's top-left corner - * position will be stored. - * + * @param rv + * the Point object where the component's top-left corner + * position will be stored. * @return the Point which specifies the component's top-left corner. */ public Point getLocation(Point rv) { @@ -1828,8 +1637,8 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali } /** - * Gets the location of this component on the form; - * returns the point of the component's top-left corner. + * Gets the location of this component on the form; returns the point of the + * component's top-left corner. * * @return the Point which specifies the component's top-left corner. */ @@ -1857,12 +1666,11 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali } /** - * Stores the size of this Component to the specified Dimension - * object. - * - * @param rv the Dimension object where the size of the Component - * will be stored. + * Stores the size of this Component to the specified Dimension object. * + * @param rv + * the Dimension object where the size of the Component will be + * stored. * @return the Dimension of this Component. */ public Dimension getSize(Dimension rv) { @@ -1879,9 +1687,9 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali } /** - * Checks whether or not this Component is valid. A component is valid - * if it is correctly sized and positioned within its parent container - * and all its children are also valid. + * Checks whether or not this Component is valid. A component is valid if it + * is correctly sized and positioned within its parent container and all its + * children are also valid. * * @return true, if the Component is valid, false otherwise. */ @@ -1898,7 +1706,6 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali * Deprecated: replaced by getComponentAt(int, int) method. * * @return the Point. - * * @deprecated Replaced by getComponentAt(int, int) method. */ @Deprecated @@ -1912,7 +1719,7 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali } /** - * Connects this Component to a native screen resource and makes it + * Connects this Component to a native screen resource and makes it * displayable. This method not be called directly by user applications. */ public void addNotify() { @@ -1920,11 +1727,11 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali try { prepare4HierarchyChange(); behaviour.addNotify(); - //???AWT -// finishHierarchyChange(this, parent, 0); -// if (dropTarget != null) { -// dropTarget.addNotify(peer); -// } + // ???AWT + // finishHierarchyChange(this, parent, 0); + // if (dropTarget != null) { + // dropTarget.addNotify(peer); + // } } finally { toolkit.unlockAWT(); } @@ -1933,45 +1740,32 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali /** * Map to display. * - * @param b the b + * @param b + * the b. */ void mapToDisplay(boolean b) { - //???AWT + // ???AWT /* - if (b && !isDisplayable()) { - if ((this instanceof Window) || ((parent != null) && parent.isDisplayable())) { - addNotify(); - } - } else if (!b && isDisplayable()) { - removeNotify(); - } - */ + * if (b && !isDisplayable()) { if ((this instanceof Window) || ((parent + * != null) && parent.isDisplayable())) { addNotify(); } } else if (!b + * && isDisplayable()) { removeNotify(); } + */ } /** * Gets the toolkit. * - * @return accessible context specific for particular component + * @return accessible context specific for particular component. */ - //???AWT + // ???AWT /* - AccessibleContext createAccessibleContext() { - return null; - } + * AccessibleContext createAccessibleContext() { return null; } public + * AccessibleContext getAccessibleContext() { toolkit.lockAWT(); try { if + * (accessibleContext == null) { accessibleContext = + * createAccessibleContext(); } return accessibleContext; } finally { + * toolkit.unlockAWT(); } } + */ - public AccessibleContext getAccessibleContext() { - toolkit.lockAWT(); - try { - if (accessibleContext == null) { - accessibleContext = createAccessibleContext(); - } - return accessibleContext; - } finally { - toolkit.unlockAWT(); - } - } - */ - /** * Gets Toolkit for the current Component. * @@ -1982,8 +1776,8 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali } /** - * Gets this component's locking object for AWT component tree - * and layout operations. + * Gets this component's locking object for AWT component tree and layout + * operations. * * @return the tree locking object. */ @@ -1992,12 +1786,14 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali } /** - * @param evt the Event. - * @param what the event's key. + * Handles the event. Use ActionListener instead of this. * + * @param evt + * the Event. + * @param what + * the event's key. * @return true, if successful. - * - * @deprecated Use ActionListener class for registering event listener. + * @deprecated Use ActionListener class for registering event listener. */ @Deprecated public boolean action(Event evt, Object what) { @@ -2006,11 +1802,10 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali return false; } - /** * Gets the property change support. * - * @return the property change support + * @return the property change support. */ private PropertyChangeSupport getPropertyChangeSupport() { synchronized (componentLock) { @@ -2020,36 +1815,29 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali return propertyChangeSupport; } } - - //???AWT - /* - public void addPropertyChangeListener(PropertyChangeListener listener) { - getPropertyChangeSupport().addPropertyChangeListener(listener); - } - - public void addPropertyChangeListener(String propertyName, PropertyChangeListener listener) { - getPropertyChangeSupport().addPropertyChangeListener(propertyName, listener); - } - public void applyComponentOrientation(ComponentOrientation orientation) { - toolkit.lockAWT(); - try { - setComponentOrientation(orientation); - } finally { - toolkit.unlockAWT(); - } - } - */ + // ???AWT + /* + * public void addPropertyChangeListener(PropertyChangeListener listener) { + * getPropertyChangeSupport().addPropertyChangeListener(listener); } public + * void addPropertyChangeListener(String propertyName, + * PropertyChangeListener listener) { + * getPropertyChangeSupport().addPropertyChangeListener(propertyName, + * listener); } public void applyComponentOrientation(ComponentOrientation + * orientation) { toolkit.lockAWT(); try { + * setComponentOrientation(orientation); } finally { toolkit.unlockAWT(); } + * } + */ /** - * Returns true if the set of focus traversal keys for the given focus - * traversal operation has been explicitly defined for this Component. - * - * @param id the ID of traversal key. + * Returns true if the set of focus traversal keys for the given focus + * traversal operation has been explicitly defined for this Component. * - * @return true, if the set of focus traversal keys for the given focus - * traversal operation has been explicitly defined for this Component, - * false otherwise. + * @param id + * the ID of traversal key. + * @return true, if the set of focus traversal keys for the given focus. + * traversal operation has been explicitly defined for this + * Component, false otherwise. */ public boolean areFocusTraversalKeysSet(int id) { toolkit.lockAWT(); @@ -2069,7 +1857,6 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali * Gets the bounds of the Component. * * @return the rectangle bounds of the Component. - * * @deprecated Use getBounds() methood. */ @Deprecated @@ -2083,16 +1870,20 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali } /** - * Returns the construction status of a specified image - * with the specified width and height that is being created. - * - * - * @param image the image to be checked. - * @param width the width of scaled image which status is being checked, or -1. - * @param height the height of scaled image which status is being checked, or -1. - * @param observer the ImageObserver object to be notified while - * the image is being prepared. + * Returns the construction status of a specified image with the specified + * width and height that is being created. * + * @param image + * the image to be checked. + * @param width + * the width of scaled image which status is being checked, or + * -1. + * @param height + * the height of scaled image which status is being checked, or + * -1. + * @param observer + * the ImageObserver object to be notified while the image is + * being prepared. * @return the ImageObserver flags of the current state of the image data. */ public int checkImage(Image image, int width, int height, ImageObserver observer) { @@ -2105,13 +1896,14 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali } /** - * Returns the construction status of a specified image that is being created. - * - * - * @param image the image to be checked. - * @param observer the ImageObserver object to be notified while - * the image is being prepared. + * Returns the construction status of a specified image that is being + * created. * + * @param image + * the image to be checked. + * @param observer + * the ImageObserver object to be notified while the image is + * being prepared. * @return the ImageObserver flags of the current state of the image data. */ public int checkImage(Image image, ImageObserver observer) { @@ -2126,10 +1918,11 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali /** * Coalesces the existed event with new event. * - * @param existingEvent the existing event in the EventQueue. - * @param newEvent the new event to be posted to the EventQueue. - * - * @return the coalesced AWTEvent, or null if there is no coalescing done. + * @param existingEvent + * the existing event in the EventQueue. + * @param newEvent + * the new event to be posted to the EventQueue. + * @return the coalesced AWTEvent, or null if there is no coalescing done. */ protected AWTEvent coalesceEvents(AWTEvent existingEvent, AWTEvent newEvent) { toolkit.lockAWT(); @@ -2147,7 +1940,7 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali /** * Checks if this Component is a coalescer. * - * @return true, if is coalescer + * @return true, if is coalescer. */ boolean isCoalescer() { return coalescer; @@ -2156,9 +1949,9 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali /** * Gets the relative event. * - * @param id the id - * - * @return the relative event + * @param id + * the id. + * @return the relative event. */ AWTEvent getRelativeEvent(int id) { Integer idWrapper = new Integer(id); @@ -2177,7 +1970,8 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali /** * Adds the new event. * - * @param event the event + * @param event + * the event. */ void addNewEvent(AWTEvent event) { eventsList.addLast(event); @@ -2193,7 +1987,8 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali /** * Removes the next event. * - * @param id the id + * @param id + * the id. */ void removeNextEvent(int id) { eventsTable.get(new Integer(id)).removeFirst(); @@ -2202,8 +1997,8 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali /** * Creates the image with the specified ImageProducer. * - * @param producer the ImageProducer to be used for image creation. - * + * @param producer + * the ImageProducer to be used for image creation. * @return the image with the specified ImageProducer. */ public Image createImage(ImageProducer producer) { @@ -2218,11 +2013,13 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali /** * Creates an off-screen drawable image to be used for double buffering. * - * @param width the width of the image. - * @param height the height of the image. - * - * @return the off-screen drawable image or null if the component is not - * displayable or GraphicsEnvironment.isHeadless() method returns true. + * @param width + * the width of the image. + * @param height + * the height of the image. + * @return the off-screen drawable image or null if the component is not + * displayable or GraphicsEnvironment.isHeadless() method returns + * true. */ public Image createImage(int width, int height) { toolkit.lockAWT(); @@ -2245,17 +2042,19 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali } /** - * Creates an off-screen drawable image with the specified width, - * height and ImageCapabilities. - * - * @param width the width - * @param height the height - * @param caps the ImageCapabilities. + * Creates an off-screen drawable image with the specified width, height and + * ImageCapabilities. * - * @return the volatile image - * - * @throws AWTException if an image with the specified capabilities - * cannot be created. + * @param width + * the width. + * @param height + * the height. + * @param caps + * the ImageCapabilities. + * @return the volatile image. + * @throws AWTException + * if an image with the specified capabilities cannot be + * created. */ public VolatileImage createVolatileImage(int width, int height, ImageCapabilities caps) throws AWTException { @@ -2277,16 +2076,17 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali } /** - * Creates a volatile off-screen drawable image which is used - * for double buffering. - * - * @param width the width of image. - * @param height the height of image. + * Creates a volatile off-screen drawable image which is used for double + * buffering. * - * @return the volatile image a volatile off-screen drawable image - * which is used for double buffering or null if the component - * is not displayable, or GraphicsEnvironment.isHeadless() method - * returns true. + * @param width + * the width of image. + * @param height + * the height of image. + * @return the volatile image a volatile off-screen drawable image which is + * used for double buffering or null if the component is not + * displayable, or GraphicsEnvironment.isHeadless() method returns + * true. */ public VolatileImage createVolatileImage(int width, int height) { toolkit.lockAWT(); @@ -2311,9 +2111,12 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali * with the component's background color to prepare it for double-buffered * painting. * - * @param image the image - * @param width the width - * @param height the height + * @param image + * the image. + * @param width + * the width. + * @param height + * the height. */ private void fillImageBackground(Image image, int width, int height) { Graphics gr = image.getGraphics(); @@ -2325,8 +2128,8 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali /** * Delivers event. * - * @param evt the event. - * + * @param evt + * the event. * @deprecated Replaced by dispatchEvent(AWTEvent e) method. */ @Deprecated @@ -2335,7 +2138,7 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali } /** - * Prompts the layout manager to lay out this component. + * Prompts the layout manager to lay out this component. */ public void doLayout() { toolkit.lockAWT(); @@ -2350,9 +2153,12 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali /** * Fire property change impl. * - * @param propertyName the property name - * @param oldValue the old value - * @param newValue the new value + * @param propertyName + * the property name. + * @param oldValue + * the old value. + * @param newValue + * the new value. */ private void firePropertyChangeImpl(String propertyName, Object oldValue, Object newValue) { PropertyChangeSupport pcs; @@ -2368,32 +2174,40 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali /** * Reports a bound property changes for int properties. * - * @param propertyName the property name. - * @param oldValue the old property's value. - * @param newValue the new property's value. + * @param propertyName + * the property name. + * @param oldValue + * the old property's value. + * @param newValue + * the new property's value. */ protected void firePropertyChange(String propertyName, int oldValue, int newValue) { firePropertyChangeImpl(propertyName, new Integer(oldValue), new Integer(newValue)); } /** - * Report a bound property change for a boolean-valued property. - * - * @param propertyName the property name. - * @param oldValue the property's old value. - * @param newValue the property's new value. + * Report a bound property change for a boolean-valued property. + * + * @param propertyName + * the property name. + * @param oldValue + * the property's old value. + * @param newValue + * the property's new value. */ protected void firePropertyChange(String propertyName, boolean oldValue, boolean newValue) { - firePropertyChangeImpl(propertyName, Boolean.valueOf(oldValue), Boolean - .valueOf(newValue)); + firePropertyChangeImpl(propertyName, Boolean.valueOf(oldValue), Boolean.valueOf(newValue)); } /** - * Reports a bound property change for an Object-valued property. + * Reports a bound property change for an Object-valued property. * - * @param propertyName the property name. - * @param oldValue the property's old value - * @param newValue the property's new value + * @param propertyName + * the property name. + * @param oldValue + * the property's old value. + * @param newValue + * the property's new value. */ protected void firePropertyChange(final String propertyName, final Object oldValue, final Object newValue) { @@ -2401,75 +2215,93 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali } /** - * Report a bound property change for a byte-valued property. + * Report a bound property change for a byte-valued property. * - * @param propertyName the property name. - * @param oldValue the property's old value. - * @param newValue the property's new value. + * @param propertyName + * the property name. + * @param oldValue + * the property's old value. + * @param newValue + * the property's new value. */ public void firePropertyChange(String propertyName, byte oldValue, byte newValue) { firePropertyChangeImpl(propertyName, new Byte(oldValue), new Byte(newValue)); } /** - * Report a bound property change for a char-valued property. + * Report a bound property change for a char-valued property. * - * @param propertyName the property name. - * @param oldValue the old property's value. - * @param newValue the new property's value. + * @param propertyName + * the property name. + * @param oldValue + * the old property's value. + * @param newValue + * the new property's value. */ public void firePropertyChange(String propertyName, char oldValue, char newValue) { firePropertyChangeImpl(propertyName, new Character(oldValue), new Character(newValue)); } /** - * Report a bound property change for a short-valued property. + * Report a bound property change for a short-valued property. * - * @param propertyName the property name. - * @param oldValue the old property's value. - * @param newValue the new property's value. + * @param propertyName + * the property name. + * @param oldValue + * the old property's value. + * @param newValue + * the new property's value. */ public void firePropertyChange(String propertyName, short oldValue, short newValue) { firePropertyChangeImpl(propertyName, new Short(oldValue), new Short(newValue)); } /** - * Report a bound property change for a long-valued property. + * Report a bound property change for a long-valued property. * - * @param propertyName the property name. - * @param oldValue the old property's value. - * @param newValue the new property's value. + * @param propertyName + * the property name. + * @param oldValue + * the old property's value. + * @param newValue + * the new property's value. */ public void firePropertyChange(String propertyName, long oldValue, long newValue) { firePropertyChangeImpl(propertyName, new Long(oldValue), new Long(newValue)); } /** - * Report a bound property change for a float-valued property. + * Report a bound property change for a float-valued property. * - * @param propertyName the property name. - * @param oldValue the old property's value. - * @param newValue the new property's value. + * @param propertyName + * the property name. + * @param oldValue + * the old property's value. + * @param newValue + * the new property's value. */ public void firePropertyChange(String propertyName, float oldValue, float newValue) { firePropertyChangeImpl(propertyName, new Float(oldValue), new Float(newValue)); } /** - * Report a bound property change for a double-valued property. + * Report a bound property change for a double-valued property. * - * @param propertyName the property name. - * @param oldValue the old property's value. - * @param newValue the new property's value. + * @param propertyName + * the property name. + * @param oldValue + * the old property's value. + * @param newValue + * the new property's value. */ public void firePropertyChange(String propertyName, double oldValue, double newValue) { firePropertyChangeImpl(propertyName, new Double(oldValue), new Double(newValue)); } /** - * Gets the alignment along the x axis. + * Gets the alignment along the x axis. * - * @return the alignment along the x axis. + * @return the alignment along the x axis. */ public float getAlignmentX() { toolkit.lockAWT(); @@ -2481,7 +2313,7 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali } /** - * Gets the alignment along the y axis. + * Gets the alignment along the y axis. * * @return the alignment along y axis. */ @@ -2502,12 +2334,11 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali public Color getBackground() { toolkit.lockAWT(); try { - //???AWT + // ???AWT /* - if ((backColor == null) && (parent != null)) { - return parent.getBackground(); - } - */ + * if ((backColor == null) && (parent != null)) { return + * parent.getBackground(); } + */ return backColor; } finally { toolkit.unlockAWT(); @@ -2529,11 +2360,12 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali } /** - * Writes the data of the bounding rectangle to the specified - * Rectangle object. - * - * @param rv the Rectangle object where the bounding rectangle's data is stored. + * Writes the data of the bounding rectangle to the specified Rectangle + * object. * + * @param rv + * the Rectangle object where the bounding rectangle's data is + * stored. * @return the bounding rectangle. */ public Rectangle getBounds(Rectangle rv) { @@ -2566,8 +2398,8 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali /** * Gets the Component which contains the specified Point. * - * @param p the Point. - * + * @param p + * the Point. * @return the Component which contains the specified Point. */ public Component getComponentAt(Point p) { @@ -2580,14 +2412,15 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali } /** - * Gets the Component which contains the point with the - * specified coordinates. - * - * @param x the x coordinate of the point. - * @param y the y coordinate of the point. + * Gets the Component which contains the point with the specified + * coordinates. * - * @return the Component which contains the point with the - * specified coordinates. + * @param x + * the x coordinate of the point. + * @param y + * the y coordinate of the point. + * @return the Component which contains the point with the specified + * coordinates. */ public Component getComponentAt(int x, int y) { toolkit.lockAWT(); @@ -2622,11 +2455,10 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali try { if (cursor != null) { return cursor; - //???AWT - /* - } else if (parent != null) { - return parent.getCursor(); - */ + // ???AWT + /* + * } else if (parent != null) { return parent.getCursor(); + */ } return Cursor.getDefaultCursor(); } finally { @@ -2634,57 +2466,29 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali } } - //???AWT + // ???AWT /* - public DropTarget getDropTarget() { - toolkit.lockAWT(); - try { - return dropTarget; - } finally { - toolkit.unlockAWT(); - } - } - - public Container getFocusCycleRootAncestor() { - toolkit.lockAWT(); - try { - for (Container c = parent; c != null; c = c.getParent()) { - if (c.isFocusCycleRoot()) { - return c; - } - } - return null; - } finally { - toolkit.unlockAWT(); - } - } - - @SuppressWarnings("unchecked") - public Set getFocusTraversalKeys(int id) { - toolkit.lockAWT(); - try { - Integer kId = new Integer(id); - KeyboardFocusManager.checkTraversalKeysID(traversalKeys, kId); - Set keys = traversalKeys.get(kId); - if (keys == null && parent != null) { - keys = parent.getFocusTraversalKeys(id); - } - if (keys == null) { - keys = KeyboardFocusManager.getCurrentKeyboardFocusManager() - .getDefaultFocusTraversalKeys(id); - } - return (Set) keys; - } finally { - toolkit.unlockAWT(); - } - } - */ - + * public DropTarget getDropTarget() { toolkit.lockAWT(); try { return + * dropTarget; } finally { toolkit.unlockAWT(); } } public Container + * getFocusCycleRootAncestor() { toolkit.lockAWT(); try { for (Container c = + * parent; c != null; c = c.getParent()) { if (c.isFocusCycleRoot()) { + * return c; } } return null; } finally { toolkit.unlockAWT(); } } + * @SuppressWarnings("unchecked") public Set + * getFocusTraversalKeys(int id) { toolkit.lockAWT(); try { Integer kId = + * new Integer(id); KeyboardFocusManager.checkTraversalKeysID(traversalKeys, + * kId); Set keys = traversalKeys.get(kId); if (keys + * == null && parent != null) { keys = parent.getFocusTraversalKeys(id); } + * if (keys == null) { keys = + * KeyboardFocusManager.getCurrentKeyboardFocusManager() + * .getDefaultFocusTraversalKeys(id); } return (Set) keys; } + * finally { toolkit.unlockAWT(); } } + */ + /** * Checks if the the focus traversal keys are enabled for this component. * - * @return true, if the the focus traversal keys are enabled for - * this component, false otherwise. + * @return true, if the the focus traversal keys are enabled for this + * component, false otherwise. */ public boolean getFocusTraversalKeysEnabled() { toolkit.lockAWT(); @@ -2698,8 +2502,8 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali /** * Gets the font metrics of the specified Font. * - * @param f the Font. - * + * @param f + * the Font. * @return the FontMetrics of the specified Font. */ @SuppressWarnings("deprecation") @@ -2715,12 +2519,11 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali public Color getForeground() { toolkit.lockAWT(); try { - //???AWT + // ???AWT /* - if (foreColor == null && parent != null) { - return parent.getForeground(); - } - */ + * if (foreColor == null && parent != null) { return + * parent.getForeground(); } + */ return foreColor; } finally { toolkit.unlockAWT(); @@ -2728,11 +2531,11 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali } /** - * Gets the Graphics of the Component or null if this Component - * is not displayable. + * Gets the Graphics of the Component or null if this Component is not + * displayable. * - * @return the Graphics of the Component or null if this Component - * is not displayable. + * @return the Graphics of the Component or null if this Component is not + * displayable. */ public Graphics getGraphics() { toolkit.lockAWT(); @@ -2749,26 +2552,18 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali } } - /** * Gets the GraphicsConfiguration associated with this Component. * * @return the GraphicsConfiguration associated with this Component. */ public GraphicsConfiguration getGraphicsConfiguration() { - //???AWT + // ???AWT /* - toolkit.lockAWT(); - try { - Window win = getWindowAncestor(); - if (win == null) { - return null; - } - return win.getGraphicsConfiguration(); - } finally { - toolkit.unlockAWT(); - } - */ + * toolkit.lockAWT(); try { Window win = getWindowAncestor(); if (win == + * null) { return null; } return win.getGraphicsConfiguration(); } + * finally { toolkit.unlockAWT(); } + */ return null; } @@ -2787,11 +2582,11 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali } /** - * Returns true if paint messages received from the operating system - * should be ignored. + * Returns true if paint messages received from the operating system should + * be ignored. * - * @return true if paint messages received from the operating system - * should be ignored, false otherwise. + * @return true if paint messages received from the operating system should + * be ignored, false otherwise. */ public boolean getIgnoreRepaint() { toolkit.lockAWT(); @@ -2803,23 +2598,20 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali } /** - * Gets the input context of this component for handling - * the communication with input methods when text is entered - * in this component. + * Gets the input context of this component for handling the communication + * with input methods when text is entered in this component. * - * @return the InputContext used by this Component or - * null if no context is specifined. + * @return the InputContext used by this Component or null if no context is + * specifined. */ public InputContext getInputContext() { toolkit.lockAWT(); try { - //???AWT + // ???AWT /* - Container parent = getParent(); - if (parent != null) { - return parent.getInputContext(); - } - */ + * Container parent = getParent(); if (parent != null) { return + * parent.getInputContext(); } + */ return null; } finally { toolkit.unlockAWT(); @@ -2827,11 +2619,11 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali } /** - * Gets the input method request handler which supports requests - * from input methods for this component, or null for default. + * Gets the input method request handler which supports requests from input + * methods for this component, or null for default. * - * @return the input method request handler which supports requests - * from input methods for this component, or null for default. + * @return the input method request handler which supports requests from + * input methods for this component, or null for default. */ public InputMethodRequests getInputMethodRequests() { return null; @@ -2845,19 +2637,14 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali public Locale getLocale() { toolkit.lockAWT(); try { - //???AWT + // ???AWT /* - if (locale == null) { - if (parent == null) { - if (this instanceof Window) { - return Locale.getDefault(); - } - // awt.150=no parent - throw new IllegalComponentStateException(Messages.getString("awt.150")); //$NON-NLS-1$ - } - return getParent().getLocale(); - } - */ + * if (locale == null) { if (parent == null) { if (this instanceof + * Window) { return Locale.getDefault(); } // awt.150=no parent + * throw new + * IllegalComponentStateException(Messages.getString("awt.150")); + * //$NON-NLS-1$ } return getParent().getLocale(); } + */ return locale; } finally { toolkit.unlockAWT(); @@ -2865,35 +2652,30 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali } /** - * Gets the location of this component in the form of a point - * specifying the component's top-left corner in the - * screen's coordinate space. + * Gets the location of this component in the form of a point specifying the + * component's top-left corner in the screen's coordinate space. * - * @return the Point giving the component's location in the - * screen's coordinate space. - * - * @throws IllegalComponentStateException if the component is - * not shown on the screen. + * @return the Point giving the component's location in the screen's + * coordinate space. + * @throws IllegalComponentStateException + * if the component is not shown on the screen. */ public Point getLocationOnScreen() throws IllegalComponentStateException { toolkit.lockAWT(); try { Point p = new Point(); if (isShowing()) { - //???AWT + // ???AWT /* - Component comp; - for (comp = this; comp != null && !(comp instanceof Window); comp = comp - .getParent()) { - p.translate(comp.getX(), comp.getY()); - } - if (comp instanceof Window) { - p.translate(comp.getX(), comp.getY()); - } - */ + * Component comp; for (comp = this; comp != null && !(comp + * instanceof Window); comp = comp .getParent()) { + * p.translate(comp.getX(), comp.getY()); } if (comp instanceof + * Window) { p.translate(comp.getX(), comp.getY()); } + */ return p; } - // awt.151=component must be showing on the screen to determine its location + // awt.151=component must be showing on the screen to determine its + // location throw new IllegalComponentStateException(Messages.getString("awt.151")); //$NON-NLS-1$ } finally { toolkit.unlockAWT(); @@ -2901,11 +2683,10 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali } /** - * Gets the peer. This method should not be called directly by - * user applications. + * Gets the peer. This method should not be called directly by user + * applications. * * @return the ComponentPeer. - * * @deprecated Replaced by isDisplayable(). */ @Deprecated @@ -2922,24 +2703,24 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali } /** - * Gets an array of the property change listeners registered to - * this Component. + * Gets an array of the property change listeners registered to this + * Component. * - * @return an array of the PropertyChangeListeners registered to - * this Component. + * @return an array of the PropertyChangeListeners registered to this + * Component. */ public PropertyChangeListener[] getPropertyChangeListeners() { return getPropertyChangeSupport().getPropertyChangeListeners(); } /** - * Gets an array of PropertyChangeListener objects registered - * to this Component for the specified property. + * Gets an array of PropertyChangeListener objects registered to this + * Component for the specified property. * - * @param propertyName the property name. - * - * @return an array of PropertyChangeListener objects registered - * to this Component for the specified property. + * @param propertyName + * the property name. + * @return an array of PropertyChangeListener objects registered to this + * Component for the specified property. */ public PropertyChangeListener[] getPropertyChangeListeners(String propertyName) { return getPropertyChangeSupport().getPropertyChangeListeners(propertyName); @@ -2990,11 +2771,11 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali /** * Got the focus. * - * @param evt the Event. - * @param what the Object. - * + * @param evt + * the Event. + * @param what + * the Object. * @return true, if successful. - * * @deprecated Replaced by processFocusEvent(FocusEvent) method. */ @Deprecated @@ -3007,10 +2788,9 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali /** * Handles event. * - * @param evt the Event. - * + * @param evt + * the Event. * @return true, if successful. - * * @deprecated Replaced by processEvent(AWTEvent) method. */ @Deprecated @@ -3052,7 +2832,7 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali public boolean hasFocus() { toolkit.lockAWT(); try { - //???AWT: return isFocusOwner(); + // ???AWT: return isFocusOwner(); return false; } finally { toolkit.unlockAWT(); @@ -3076,24 +2856,24 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali moveFocusOnHide(); behaviour.setVisible(false); postEvent(new ComponentEvent(this, ComponentEvent.COMPONENT_HIDDEN)); - //???AWT: finishHierarchyChange(this, parent, 0); + // ???AWT: finishHierarchyChange(this, parent, 0); notifyInputMethod(null); - //???AWT: invalidateRealParent(); + // ???AWT: invalidateRealParent(); } finally { toolkit.unlockAWT(); } } /** - * Checks whether or not the point with the specified coordinates - * belongs to the Commponent. - * - * @param x the x coordinate of the Point. - * @param y the y coordinate of the Point. - * - * @return true, if the point with the specified coordinates - * belongs to the Commponent, false otherwise. + * Checks whether or not the point with the specified coordinates belongs to + * the Commponent. * + * @param x + * the x coordinate of the Point. + * @param y + * the y coordinate of the Point. + * @return true, if the point with the specified coordinates belongs to the + * Commponent, false otherwise. * @deprecated Replaced by contains(int, int) method. */ @Deprecated @@ -3107,15 +2887,15 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali } /** - * Invalidates the component, this component and all parents - * above it are marked as needing to be laid out. + * Invalidates the component, this component and all parents above it are + * marked as needing to be laid out. */ public void invalidate() { toolkit.lockAWT(); try { valid = false; resetDefaultSize(); - //???AWT: invalidateRealParent(); + // ???AWT: invalidateRealParent(); } finally { toolkit.unlockAWT(); } @@ -3124,8 +2904,8 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali /** * Checks whether or not the background color is set to this Component. * - * @return true, if the background color is set to this Component, - * false otherwise. + * @return true, if the background color is set to this Component, false + * otherwise. */ public boolean isBackgroundSet() { toolkit.lockAWT(); @@ -3139,8 +2919,7 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali /** * Checks whether or not a cursor is set for the Component. * - * @return true, if a cursor is set for the Component, - * false otherwise. + * @return true, if a cursor is set for the Component, false otherwise. */ public boolean isCursorSet() { toolkit.lockAWT(); @@ -3166,11 +2945,11 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali } /** - * Checks whether or not this component is painted to an buffer - * which is copied to the screen later. + * Checks whether or not this component is painted to an buffer which is + * copied to the screen later. * - * @return true, if this component is painted to an buffer - * which is copied to the screen later, false otherwise. + * @return true, if this component is painted to an buffer which is copied + * to the screen later, false otherwise. */ public boolean isDoubleBuffered() { toolkit.lockAWT(); @@ -3200,7 +2979,7 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali * "Recursive" isEnabled(). * * @return true if not only component itself is enabled but its heavyweight - * parent is also "indirectly" enabled + * parent is also "indirectly" enabled. */ boolean isIndirectlyEnabled() { Component comp = this; @@ -3208,7 +2987,7 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali if (!comp.isLightweight() && !comp.isEnabled()) { return false; } - //???AWT: comp = comp.getRealParent(); + // ???AWT: comp = comp.getRealParent(); } return true; } @@ -3216,7 +2995,7 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali /** * Checks if the component is key enabled. * - * @return true, if the component is enabled and indirectly enabled + * @return true, if the component is enabled and indirectly enabled. */ boolean isKeyEnabled() { if (!isEnabled()) { @@ -3229,39 +3008,24 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali * Gets only parent of a child component, but not owner of a window. * * @return parent of child component, null if component is a top-level - * (Window instance) + * (Window instance). */ - //???AWT + // ???AWT /* - Container getRealParent() { - return (!(this instanceof Window) ? getParent() : null); - } - - public boolean isFocusCycleRoot(Container container) { - toolkit.lockAWT(); - try { - return getFocusCycleRootAncestor() == container; - } finally { - toolkit.unlockAWT(); - } - } + * Container getRealParent() { return (!(this instanceof Window) ? + * getParent() : null); } public boolean isFocusCycleRoot(Container + * container) { toolkit.lockAWT(); try { return getFocusCycleRootAncestor() + * == container; } finally { toolkit.unlockAWT(); } } public boolean + * isFocusOwner() { toolkit.lockAWT(); try { return + * KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner() == + * this; } finally { toolkit.unlockAWT(); } } + */ - public boolean isFocusOwner() { - toolkit.lockAWT(); - try { - return KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner() == this; - } finally { - toolkit.unlockAWT(); - } - } - */ - /** * Checks whether or not this Component can be focusable. * * @return true, if this Component can be focusable, false otherwise. - * - * @deprecated Replaced by isFocusable(). + * @deprecated Replaced by isFocusable(). */ @Deprecated public boolean isFocusTraversable() { @@ -3306,8 +3070,8 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali /** * Checks if foreground color is set for the Component or not. * - * @return true, if is foreground color is set for the Component, - * false otherwise. + * @return true, if is foreground color is set for the Component, false + * otherwise. */ public boolean isForegroundSet() { toolkit.lockAWT(); @@ -3321,8 +3085,8 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali /** * Returns true if this component has a lightweight peer. * - * @return true, if this component has a lightweight peer, - * false if it has a native peer or no peer. + * @return true, if this component has a lightweight peer, false if it has a + * native peer or no peer. */ public boolean isLightweight() { toolkit.lockAWT(); @@ -3333,22 +3097,18 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali } } - /** * Checks whether or not this Component is shown. * * @return true, if this Component is shown, false otherwise. */ public boolean isShowing() { - //???AWT + // ???AWT /* - toolkit.lockAWT(); - try { - return (isVisible() && isDisplayable() && (parent != null) && parent.isShowing()); - } finally { - toolkit.unlockAWT(); - } - */ + * toolkit.lockAWT(); try { return (isVisible() && isDisplayable() && + * (parent != null) && parent.isShowing()); } finally { + * toolkit.unlockAWT(); } + */ return false; } @@ -3369,11 +3129,11 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali /** * Deprecated: replaced by processKeyEvent(KeyEvent) method. * - * @param evt the Event. - * @param key the key code. - * + * @param evt + * the Event. + * @param key + * the key code. * @return true, if successful. - * * @deprecated Replaced by replaced by processKeyEvent(KeyEvent) method. */ @Deprecated @@ -3386,11 +3146,11 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali /** * Deprecated: replaced by processKeyEvent(KeyEvent) method. * - * @param evt the Event. - * @param key the key code. - * + * @param evt + * the Event. + * @param key + * the key code. * @return true, if successful. - * * @deprecated Replaced by processKeyEvent(KeyEvent) method. */ @Deprecated @@ -3418,11 +3178,11 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali /** * Deprecated: replaced by getComponentAt(int, int) method. * - * @param x the x coordinate. - * @param y the y coordinate. - * + * @param x + * the x coordinate. + * @param y + * the y coordinate. * @return The component. - * * @deprecated Replaced by getComponentAt(int, int) method. */ @Deprecated @@ -3439,13 +3199,13 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali } /** - * Deprecated: replaced by processFocusEvent(FocusEvent). - * - * @param evt the Event. - * @param what the Object. + * Deprecated: replaced by processFocusEvent(FocusEvent). * + * @param evt + * the Event. + * @param what + * the Object. * @return true, if successful. - * * @deprecated Replaced by processFocusEvent(FocusEvent). */ @Deprecated @@ -3458,12 +3218,13 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali /** * Deprecated: replaced by processMouseEvent(MouseEvent) method. * - * @param evt the MouseEvent. - * @param x the x coordinate. - * @param y the y coordinate. - * + * @param evt + * the MouseEvent. + * @param x + * the x coordinate. + * @param y + * the y coordinate. * @return true, if successful. - * * @deprecated Replaced by processMouseEvent(MouseEvent) method. */ @Deprecated @@ -3476,12 +3237,13 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali /** * Deprecated: replaced by getMinimumSize() method. * - * @param evt the Event. - * @param x the x coordinate. - * @param y the y coordinate. - * + * @param evt + * the Event. + * @param x + * the x coordinate. + * @param y + * the y coordinate. * @return true, if successful. - * * @deprecated Replaced by getMinimumSize() method. */ @Deprecated @@ -3494,12 +3256,13 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali /** * Replaced by processMouseEvent(MouseEvent) method. * - * @param evt the Event. - * @param x the x coordinate. - * @param y the y coordinate. - * + * @param evt + * the Event. + * @param x + * the x coordinate. + * @param y + * the y coordinate. * @return true, if successful. - * * @deprecated replaced by processMouseEvent(MouseEvent) method. */ @Deprecated @@ -3512,12 +3275,13 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali /** * Replaced by processMouseEvent(MouseEvent) method. * - * @param evt the Event. - * @param x the x coordinate. - * @param y the y coordinate. - * + * @param evt + * the Event. + * @param x + * the x coordinate. + * @param y + * the y coordinate. * @return true, if successful. - * * @deprecated Replaced by processMouseEvent(MouseEvent) method. */ @Deprecated @@ -3530,12 +3294,13 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali /** * Replaced by processMouseEvent(MouseEvent) method. * - * @param evt the Event. - * @param x the x coordinate. - * @param y the y coordinate. - * + * @param evt + * the Event. + * @param x + * the x coordinate. + * @param y + * the y coordinate. * @deprecated Replaced by processMouseEvent(MouseEvent) method. - * * @return true, if successful. */ @Deprecated @@ -3548,12 +3313,13 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali /** * Replaced by processMouseEvent(MouseEvent) method. * - * @param evt the Event. - * @param x the x coordinate. - * @param y the y coordinate. - * + * @param evt + * the Event. + * @param x + * the x coordinate. + * @param y + * the y coordinate. * @return true, if successful. - * * @deprecated Replaced by processMouseEvent(MouseEvent) method. */ @Deprecated @@ -3566,9 +3332,10 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali /** * Deprecated: replaced by setLocation(int, int) method. * - * @param x the x coordinates. - * @param y the y coordinates. - * + * @param x + * the x coordinates. + * @param y + * the y coordinates. * @deprecated Replaced by setLocation(int, int) method. */ @Deprecated @@ -3582,18 +3349,12 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali } } - //???AWT + // ???AWT /* - @Deprecated - public void nextFocus() { - toolkit.lockAWT(); - try { - transferFocus(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS); - } finally { - toolkit.unlockAWT(); - } - } - */ + * @Deprecated public void nextFocus() { toolkit.lockAWT(); try { + * transferFocus(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS); } finally { + * toolkit.unlockAWT(); } } + */ /** * Returns a string representation of the component's state. @@ -3603,10 +3364,8 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali protected String paramString() { /* * The format is based on 1.5 release behavior which can be revealed by - * the following code: - * - * Component c = new Component(){}; c.setVisible(false); - * System.out.println(c); + * the following code: Component c = new Component(){}; + * c.setVisible(false); System.out.println(c); */ toolkit.lockAWT(); try { @@ -3624,35 +3383,27 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali if (handled) { return true; } - //???AWT + // ???AWT /* - - // propagate non-handled events up to parent - Component par = parent; - // try to call postEvent only on components which - // override any of deprecated method handlers - // while (par != null && !par.deprecatedEventHandler) { - // par = par.parent; - // } - // translate event coordinates before posting it to parent - if (par != null) { - evt.translate(x, y); - par.postEvent(evt); - } - - */ + * // propagate non-handled events up to parent Component par = parent; + * // try to call postEvent only on components which // override any of + * deprecated method handlers // while (par != null && + * !par.deprecatedEventHandler) { // par = par.parent; // } // translate + * event coordinates before posting it to parent if (par != null) { + * evt.translate(x, y); par.postEvent(evt); } + */ return false; } /** - * Prepares an image for rendering on the Component. - * - * @param image the Image to be prepared. - * @param observer the ImageObserver object to be notified as soon as - * the image is prepared. + * Prepares an image for rendering on the Component. * - * @return true if the image has been fully prepared, - * false otherwise. + * @param image + * the Image to be prepared. + * @param observer + * the ImageObserver object to be notified as soon as the image + * is prepared. + * @return true if the image has been fully prepared, false otherwise. */ public boolean prepareImage(Image image, ImageObserver observer) { toolkit.lockAWT(); @@ -3664,17 +3415,19 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali } /** - * Prepares an image for rendering on the Component with the - * specified width, height, and ImageObserver. + * Prepares an image for rendering on the Component with the specified + * width, height, and ImageObserver. * - * @param image the Image to be prepared. - * @param width the width of scaled image. - * @param height the height of scaled height. - * @param observer the ImageObserver object to be notified as soon as - * the image is prepared. - * - * @return true if the image is been fully prepared, - * false otherwise. + * @param image + * the Image to be prepared. + * @param width + * the width of scaled image. + * @param height + * the height of scaled height. + * @param observer + * the ImageObserver object to be notified as soon as the image + * is prepared. + * @return true if the image is been fully prepared, false otherwise. */ public boolean prepareImage(Image image, int width, int height, ImageObserver observer) { toolkit.lockAWT(); @@ -3691,16 +3444,14 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali public void removeNotify() { toolkit.lockAWT(); try { - //???AWT + // ???AWT /* - if (dropTarget != null) { - dropTarget.removeNotify(peer); - } - */ + * if (dropTarget != null) { dropTarget.removeNotify(peer); } + */ prepare4HierarchyChange(); - ///???AWT: moveFocus(); + // /???AWT: moveFocus(); behaviour.removeNotify(); - //???AWT: finishHierarchyChange(this, parent, 0); + // ???AWT: finishHierarchyChange(this, parent, 0); removeNotifyInputContext(); } finally { toolkit.unlockAWT(); @@ -3708,7 +3459,7 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali } /** - * Calls InputContext.removeNotify + * Calls InputContext.removeNotify. */ private void removeNotifyInputContext() { if (!inputMethodsEnabled) { @@ -3716,7 +3467,7 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali } InputContext ic = getInputContext(); if (ic != null) { - //???AWT: ic.removeNotify(this); + // ???AWT: ic.removeNotify(this); } } @@ -3726,46 +3477,25 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali * setFocusable(false) is called, and therefore automatic forward focus * traversal is necessary */ - //???AWT + // ???AWT /* - void moveFocus() { - // don't use transferFocus(), but query focus traversal policy directly - // and if it returns null, transfer focus up cycle - // and find next focusable component there - KeyboardFocusManager kfm = KeyboardFocusManager.getCurrentKeyboardFocusManager(); - Container root = kfm.getCurrentFocusCycleRoot(); - Component nextComp = this; - boolean success = !isFocusOwner(); - while (!success) { - if (root != nextComp.getFocusCycleRootAncestor()) { - // component was probably removed from container - // so focus will be lost in some time - return; - } - nextComp = root.getFocusTraversalPolicy().getComponentAfter(root, nextComp); - if (nextComp == this) { - nextComp = null; // avoid looping - } - if (nextComp != null) { - success = nextComp.requestFocusInWindow(); - } else { - nextComp = root; - root = root.getFocusCycleRootAncestor(); - // if no acceptable component is found at all - clear global - // focus owner - if (root == null) { - if (nextComp instanceof Window) { - Window wnd = (Window) nextComp; - wnd.setFocusOwner(null); - wnd.setRequestedFocus(null); - } - kfm.clearGlobalFocusOwner(); - return; - } - } - } - } - */ + * void moveFocus() { // don't use transferFocus(), but query focus + * traversal policy directly // and if it returns null, transfer focus up + * cycle // and find next focusable component there KeyboardFocusManager kfm + * = KeyboardFocusManager.getCurrentKeyboardFocusManager(); Container root = + * kfm.getCurrentFocusCycleRoot(); Component nextComp = this; boolean + * success = !isFocusOwner(); while (!success) { if (root != + * nextComp.getFocusCycleRootAncestor()) { // component was probably removed + * from container // so focus will be lost in some time return; } nextComp = + * root.getFocusTraversalPolicy().getComponentAfter(root, nextComp); if + * (nextComp == this) { nextComp = null; // avoid looping } if (nextComp != + * null) { success = nextComp.requestFocusInWindow(); } else { nextComp = + * root; root = root.getFocusCycleRootAncestor(); // if no acceptable + * component is found at all - clear global // focus owner if (root == null) + * { if (nextComp instanceof Window) { Window wnd = (Window) nextComp; + * wnd.setFocusOwner(null); wnd.setRequestedFocus(null); } + * kfm.clearGlobalFocusOwner(); return; } } } } + */ /** * For Container there's a difference between moving focus when being made @@ -3774,80 +3504,73 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali * setVisible() is not called. */ void moveFocusOnHide() { - //???AWT: moveFocus(); + // ???AWT: moveFocus(); } /** * Removes the property change listener registered for this component. * - * @param listener the PropertyChangeListener. + * @param listener + * the PropertyChangeListener. */ public void removePropertyChangeListener(PropertyChangeListener listener) { getPropertyChangeSupport().removePropertyChangeListener(listener); } /** - * Removes the property change listener registered fot this component - * for the specified propertyy. + * Removes the property change listener registered fot this component for + * the specified propertyy. * - * @param propertyName the property name. - * @param listener the PropertyChangeListener. + * @param propertyName + * the property name. + * @param listener + * the PropertyChangeListener. */ - public void removePropertyChangeListener(String propertyName, - PropertyChangeListener listener) { + public void removePropertyChangeListener(String propertyName, PropertyChangeListener listener) { getPropertyChangeSupport().removePropertyChangeListener(propertyName, listener); } - /** - * Repaints the specified rectangle of this component within - * tm milliseconds. + * Repaints the specified rectangle of this component within tm + * milliseconds. * - * @param tm the time in milliseconds before updating. - * @param x the x coordinate of Rectangle. - * @param y the y coordinate of Rectangle. - * @param width the width of Rectangle. - * @param height the height of Rectangle. + * @param tm + * the time in milliseconds before updating. + * @param x + * the x coordinate of Rectangle. + * @param y + * the y coordinate of Rectangle. + * @param width + * the width of Rectangle. + * @param height + * the height of Rectangle. */ public void repaint(long tm, int x, int y, int width, int height) { - //???AWT + // ???AWT /* - toolkit.lockAWT(); - try { - if (width <= 0 || height <= 0 || (redrawManager == null) || !isShowing()) { - return; - } - if (behaviour instanceof LWBehavior) { - if (parent == null || !parent.visible || !parent.behaviour.isDisplayable()) { - return; - } - if (repaintRegion == null) { - repaintRegion = new MultiRectArea(new Rectangle(x, y, width, height)); - } - repaintRegion.intersect(new Rectangle(0, 0, this.w, this.h)); - repaintRegion.translate(this.x, this.y); - parent.repaintRegion = repaintRegion; - repaintRegion = null; - parent.repaint(tm, x + this.x, y + this.y, width, height); - } else { - if (repaintRegion != null) { - redrawManager.addUpdateRegion(this, repaintRegion); - repaintRegion = null; - } else { - redrawManager.addUpdateRegion(this, new Rectangle(x, y, width, height)); - } - toolkit.getSystemEventQueueCore().notifyEventMonitor(toolkit); - } - } finally { - toolkit.unlockAWT(); - } - */ + * toolkit.lockAWT(); try { if (width <= 0 || height <= 0 || + * (redrawManager == null) || !isShowing()) { return; } if (behaviour + * instanceof LWBehavior) { if (parent == null || !parent.visible || + * !parent.behaviour.isDisplayable()) { return; } if (repaintRegion == + * null) { repaintRegion = new MultiRectArea(new Rectangle(x, y, width, + * height)); } repaintRegion.intersect(new Rectangle(0, 0, this.w, + * this.h)); repaintRegion.translate(this.x, this.y); + * parent.repaintRegion = repaintRegion; repaintRegion = null; + * parent.repaint(tm, x + this.x, y + this.y, width, height); } else { + * if (repaintRegion != null) { redrawManager.addUpdateRegion(this, + * repaintRegion); repaintRegion = null; } else { + * redrawManager.addUpdateRegion(this, new Rectangle(x, y, width, + * height)); } + * toolkit.getSystemEventQueueCore().notifyEventMonitor(toolkit); } } + * finally { toolkit.unlockAWT(); } + */ } /** * Post event. * - * @param e the e + * @param e + * the e. */ void postEvent(AWTEvent e) { getToolkit().getSystemEventQueueImpl().postEvent(e); @@ -3856,10 +3579,14 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali /** * Repaints the specified Rectangle of this Component. * - * @param x the x coordinate of Rectangle. - * @param y the y coordinate of Rectangle. - * @param width the width of Rectangle. - * @param height the height of Rectangle. + * @param x + * the x coordinate of Rectangle. + * @param y + * the y coordinate of Rectangle. + * @param width + * the width of Rectangle. + * @param height + * the height of Rectangle. */ public void repaint(int x, int y, int width, int height) { toolkit.lockAWT(); @@ -3887,7 +3614,8 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali /** * Repaints the component within tm milliseconds. * - * @param tm the time in milliseconds before updating. + * @param tm + * the time in milliseconds before updating. */ public void repaint(long tm) { toolkit.lockAWT(); @@ -3899,29 +3627,28 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali } /** - * Requests that this Component get the input focus temporarily. - * This component must be displayable, visible, and focusable. + * Requests that this Component get the input focus temporarily. This + * component must be displayable, visible, and focusable. * - * @param temporary this parameter is true if the focus change - * is temporary, when the window loses the focus. - * - * @return true if the focus change request is succeeded, - * false otherwise. + * @param temporary + * this parameter is true if the focus change is temporary, when + * the window loses the focus. + * @return true if the focus change request is succeeded, false otherwise. */ protected boolean requestFocus(boolean temporary) { toolkit.lockAWT(); try { - //???AWT: return requestFocusImpl(temporary, true, false); + // ???AWT: return requestFocusImpl(temporary, true, false); } finally { toolkit.unlockAWT(); } - //???AWT + // ???AWT return false; } /** - * Requests that this Component get the input focus. - * This component must be displayable, visible, and focusable. + * Requests that this Component get the input focus. This component must be + * displayable, visible, and focusable. */ public void requestFocus() { toolkit.lockAWT(); @@ -3932,55 +3659,35 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali } } - //???AWT + // ???AWT /* - protected boolean requestFocusInWindow(boolean temporary) { - toolkit.lockAWT(); - try { - Window wnd = getWindowAncestor(); - if ((wnd == null) || !wnd.isFocused()) { - return false; - } - return requestFocusImpl(temporary, false, false); - } finally { - toolkit.unlockAWT(); - } - } - - boolean requestFocusImpl(boolean temporary, boolean crossWindow, boolean rejectionRecovery) { - if (!rejectionRecovery && isFocusOwner()) { - return true; - } - Window wnd = getWindowAncestor(); - Container par = getRealParent(); - if ((par != null) && par.isRemoved) { - return false; - } - if (!isShowing() || !isFocusable() || !wnd.isFocusableWindow()) { - return false; - } - return KeyboardFocusManager.getCurrentKeyboardFocusManager().requestFocus(this, - temporary, crossWindow, true); - } - - public boolean requestFocusInWindow() { - toolkit.lockAWT(); - try { - return requestFocusInWindow(false); - } finally { - toolkit.unlockAWT(); - } - } - */ + * protected boolean requestFocusInWindow(boolean temporary) { + * toolkit.lockAWT(); try { Window wnd = getWindowAncestor(); if ((wnd == + * null) || !wnd.isFocused()) { return false; } return + * requestFocusImpl(temporary, false, false); } finally { + * toolkit.unlockAWT(); } } boolean requestFocusImpl(boolean temporary, + * boolean crossWindow, boolean rejectionRecovery) { if (!rejectionRecovery + * && isFocusOwner()) { return true; } Window wnd = getWindowAncestor(); + * Container par = getRealParent(); if ((par != null) && par.isRemoved) { + * return false; } if (!isShowing() || !isFocusable() || + * !wnd.isFocusableWindow()) { return false; } return + * KeyboardFocusManager.getCurrentKeyboardFocusManager().requestFocus(this, + * temporary, crossWindow, true); } public boolean requestFocusInWindow() { + * toolkit.lockAWT(); try { return requestFocusInWindow(false); } finally { + * toolkit.unlockAWT(); } } + */ /** * Deprecated: replaced by setBounds(int, int, int, int) method. * - * @param x the x coordinate. - * @param y the y coordinate. - * @param w the width. - * @param h the height. - * + * @param x + * the x coordinate. + * @param y + * the y coordinate. + * @param w + * the width. + * @param h + * the height. * @deprecated Replaced by setBounds(int, int, int, int) method. */ @Deprecated @@ -3995,13 +3702,17 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali } /** - * Sets rectangle for this Component to be the rectangle with the specified + * Sets rectangle for this Component to be the rectangle with the specified * x,y coordinates of the top-left corner and the width and height. * - * @param x the x coordinate of the rectangle's top-left corner. - * @param y the y coordinate of the rectangle's top-left corner. - * @param w the width of rectangle. - * @param h the height of rectangle. + * @param x + * the x coordinate of the rectangle's top-left corner. + * @param y + * the y coordinate of the rectangle's top-left corner. + * @param w + * the width of rectangle. + * @param h + * the height of rectangle. */ public void setBounds(int x, int y, int w, int h) { toolkit.lockAWT(); @@ -4013,16 +3724,22 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali } /** - * Sets rectangle for this Component to be the rectangle with the specified - * x,y coordinates of the top-left corner and the width and height - * and posts the appropriate events. + * Sets rectangle for this Component to be the rectangle with the specified + * x,y coordinates of the top-left corner and the width and height and posts + * the appropriate events. * - * @param x the x coordinate of the rectangle's top-left corner. - * @param y the y coordinate of the rectangle's top-left corner. - * @param w the width of rectangle. - * @param h the height of rectangle. - * @param bMask the bitmask of bounds options - * @param updateBehavior the whether to update the behavoir's bounds as well + * @param x + * the x coordinate of the rectangle's top-left corner. + * @param y + * the y coordinate of the rectangle's top-left corner. + * @param w + * the width of rectangle. + * @param h + * the height of rectangle. + * @param bMask + * the bitmask of bounds options. + * @param updateBehavior + * the whether to update the behavoir's bounds as well. */ void setBounds(int x, int y, int w, int h, int bMask, boolean updateBehavior) { int oldX = this.x; @@ -4032,7 +3749,7 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali setBoundsFields(x, y, w, h, bMask); // Moved if ((oldX != this.x) || (oldY != this.y)) { - //???AWT: invalidateRealParent(); + // ???AWT: invalidateRealParent(); postEvent(new ComponentEvent(this, ComponentEvent.COMPONENT_MOVED)); spreadHierarchyBoundsEvents(this, HierarchyEvent.ANCESTOR_MOVED); } @@ -4051,7 +3768,8 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali /** * Calls InputContextImpl.notifyClientWindowChanged. * - * @param bounds the bounds + * @param bounds + * the bounds. */ void notifyInputMethod(Rectangle bounds) { // only Window actually notifies IM of bounds change @@ -4060,11 +3778,16 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali /** * Sets the bounds fields. * - * @param x the x - * @param y the y - * @param w the w - * @param h the h - * @param bMask the b mask + * @param x + * the x. + * @param y + * the y. + * @param w + * the w. + * @param h + * the h. + * @param bMask + * the b mask. */ private void setBoundsFields(int x, int y, int w, int h, int bMask) { if ((bMask & NativeWindow.BOUNDS_NOSIZE) == 0) { @@ -4080,7 +3803,7 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali /** * Gets the native insets. * - * @return the native insets + * @return the native insets. */ Insets getNativeInsets() { return new Insets(0, 0, 0, 0); @@ -4089,7 +3812,7 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali /** * Gets the insets. * - * @return the insets + * @return the insets. */ Insets getInsets() { return new Insets(0, 0, 0, 0); @@ -4098,7 +3821,7 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali /** * Checks if is mouse exited expected. * - * @return true, if is mouse exited expected + * @return true, if is mouse exited expected. */ boolean isMouseExitedExpected() { return mouseExitedExpected; @@ -4107,7 +3830,8 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali /** * Sets the mouse exited expected. * - * @param expected the new mouse exited expected + * @param expected + * the new mouse exited expected. */ void setMouseExitedExpected(boolean expected) { mouseExitedExpected = expected; @@ -4116,7 +3840,8 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali /** * Sets the new bounding rectangle for this Component. * - * @param r the new bounding rectangle. + * @param r + * the new bounding rectangle. */ public void setBounds(Rectangle r) { toolkit.lockAWT(); @@ -4128,10 +3853,11 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali } /** - * Sets the component orientation which affects the component's - * elements and text within this component. + * Sets the component orientation which affects the component's elements and + * text within this component. * - * @param o the ComponentOrientation object. + * @param o + * the ComponentOrientation object. */ public void setComponentOrientation(ComponentOrientation o) { ComponentOrientation oldOrientation; @@ -4149,7 +3875,8 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali /** * Sets the specified cursor for this Component. * - * @param cursor the new Cursor. + * @param cursor + * the new Cursor. */ public void setCursor(Cursor cursor) { toolkit.lockAWT(); @@ -4168,26 +3895,20 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali if (isDisplayable() && isShowing()) { Rectangle absRect = new Rectangle(getLocationOnScreen(), getSize()); Point absPointerPos = toolkit.dispatcher.mouseDispatcher.getPointerPos(); - //???AWT + // ???AWT /* - if (absRect.contains(absPointerPos)) { - // set Cursor only on top-level Windows(on X11) - Window topLevelWnd = getWindowAncestor(); - if (topLevelWnd != null) { - Point pointerPos = MouseDispatcher.convertPoint(null, absPointerPos, - topLevelWnd); - Component compUnderCursor = topLevelWnd.findComponentAt(pointerPos); - // if (compUnderCursor == this || - // compUnderCursor.getCursorAncestor() == this) { - NativeWindow wnd = topLevelWnd.getNativeWindow(); - if (compUnderCursor != null && wnd != null) { - compUnderCursor.getRealCursor().getNativeCursor() - .setCursor(wnd.getId()); - } - // } - } - } - */ + * if (absRect.contains(absPointerPos)) { // set Cursor only on + * top-level Windows(on X11) Window topLevelWnd = + * getWindowAncestor(); if (topLevelWnd != null) { Point pointerPos + * = MouseDispatcher.convertPoint(null, absPointerPos, topLevelWnd); + * Component compUnderCursor = + * topLevelWnd.findComponentAt(pointerPos); // if (compUnderCursor + * == this || // compUnderCursor.getCursorAncestor() == this) { + * NativeWindow wnd = topLevelWnd.getNativeWindow(); if + * (compUnderCursor != null && wnd != null) { + * compUnderCursor.getRealCursor().getNativeCursor() + * .setCursor(wnd.getId()); } // } } } + */ } } @@ -4195,68 +3916,44 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali * Gets the ancestor Cursor if Component is disabled (directly or via an * ancestor) even if Cursor is explicitly set. * - * @param value the value - * - * @return actual Cursor to be displayed + * @param value + * the value. + * @return the actual Cursor to be displayed. */ - //???AWT + // ???AWT /* - Cursor getRealCursor() { - Component cursorAncestor = getCursorAncestor(); - return cursorAncestor != null ? cursorAncestor.getCursor() : Cursor.getDefaultCursor(); - } - */ + * Cursor getRealCursor() { Component cursorAncestor = getCursorAncestor(); + * return cursorAncestor != null ? cursorAncestor.getCursor() : + * Cursor.getDefaultCursor(); } + */ /** * Gets the ancestor(or component itself) whose cursor is set when pointer * is inside component * - * @return actual Cursor to be displayed + * @return the actual Cursor to be displayed. */ - //???AWT + // ???AWT /* - Component getCursorAncestor() { - Component comp; - for (comp = this; comp != null; comp = comp.getParent()) { - if (comp instanceof Window || comp.isCursorSet() && comp.isKeyEnabled()) { - return comp; - } - } - return null; - } + * Component getCursorAncestor() { Component comp; for (comp = this; comp != + * null; comp = comp.getParent()) { if (comp instanceof Window || + * comp.isCursorSet() && comp.isKeyEnabled()) { return comp; } } return + * null; } public void setDropTarget(DropTarget dt) { toolkit.lockAWT(); try + * { if (dropTarget == dt) { return; } DropTarget oldDropTarget = + * dropTarget; dropTarget = dt; if (oldDropTarget != null) { if + * (behaviour.isDisplayable()) { oldDropTarget.removeNotify(peer); } + * oldDropTarget.setComponent(null); } if (dt != null) { + * dt.setComponent(this); if (behaviour.isDisplayable()) { + * dt.addNotify(peer); } } } finally { toolkit.unlockAWT(); } } + */ - public void setDropTarget(DropTarget dt) { - toolkit.lockAWT(); - try { - if (dropTarget == dt) { - return; - } - DropTarget oldDropTarget = dropTarget; - dropTarget = dt; - if (oldDropTarget != null) { - if (behaviour.isDisplayable()) { - oldDropTarget.removeNotify(peer); - } - oldDropTarget.setComponent(null); - } - if (dt != null) { - dt.setComponent(this); - if (behaviour.isDisplayable()) { - dt.addNotify(peer); - } - } - } finally { - toolkit.unlockAWT(); - } - } - */ - /** - * Sets this component to the "enabled" or "disabled" state depending - * on the specified boolean parameter. + * Sets this component to the "enabled" or "disabled" state depending on the + * specified boolean parameter. * - * @param value true if this component should be enabled; false - * if this component should be disabled. + * @param value + * true if this component should be enabled; false if this + * component should be disabled. */ public void setEnabled(boolean value) { toolkit.lockAWT(); @@ -4270,7 +3967,8 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali /** * Sets the enabled impl. * - * @param value the new enabled impl + * @param value + * the new enabled impl. */ void setEnabledImpl(boolean value) { if (enabled != value) { @@ -4283,77 +3981,49 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali } } - //???AWT + // ???AWT /* - private void fireAccessibleStateChange(AccessibleState state, boolean value) { - if (behaviour.isLightweight()) { - return; - } - AccessibleContext ac = getAccessibleContext(); - if (ac != null) { - AccessibleState oldValue = null; - AccessibleState newValue = null; - if (value) { - newValue = state; - } else { - oldValue = state; - } - ac.firePropertyChange(AccessibleContext.ACCESSIBLE_STATE_PROPERTY, oldValue, - newValue); - } - } - */ + * private void fireAccessibleStateChange(AccessibleState state, boolean + * value) { if (behaviour.isLightweight()) { return; } AccessibleContext ac + * = getAccessibleContext(); if (ac != null) { AccessibleState oldValue = + * null; AccessibleState newValue = null; if (value) { newValue = state; } + * else { oldValue = state; } + * ac.firePropertyChange(AccessibleContext.ACCESSIBLE_STATE_PROPERTY, + * oldValue, newValue); } } + */ - //???AWT + // ???AWT /* - public void setFocusTraversalKeys(int id, Set keystrokes) { - Set oldTraversalKeys; - String propName = "FocusTraversalKeys"; //$NON-NLS-1$ - toolkit.lockAWT(); - try { - Integer kId = new Integer(id); - KeyboardFocusManager.checkTraversalKeysID(traversalKeys, kId); - Map> keys = new HashMap>(); - for (int kid : traversalIDs) { - Integer key = new Integer(kid); - keys.put(key, getFocusTraversalKeys(kid)); - } - KeyboardFocusManager.checkKeyStrokes(traversalIDs, keys, kId, keystrokes); - oldTraversalKeys = traversalKeys.get(new Integer(id)); - // put a copy of keystrokes object into map: - Set newKeys = keystrokes; - if (keystrokes != null) { - newKeys = new HashSet(keystrokes); - } - traversalKeys.put(kId, newKeys); - String direction = ""; //$NON-NLS-1$ - switch (id) { - case KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS: - direction = "forward"; //$NON-NLS-1$ - break; - case KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS: - direction = "backward"; //$NON-NLS-1$ - break; - case KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS: - direction = "upCycle"; //$NON-NLS-1$ - break; - case KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS: - direction = "downCycle"; //$NON-NLS-1$ - break; - } - propName = direction + propName; - } finally { - toolkit.unlockAWT(); - } - firePropertyChange(propName, oldTraversalKeys, keystrokes); - } - */ + * public void setFocusTraversalKeys(int id, Set + * keystrokes) { Set oldTraversalKeys; String + * propName = "FocusTraversalKeys"; //$NON-NLS-1$ toolkit.lockAWT(); try { + * Integer kId = new Integer(id); + * KeyboardFocusManager.checkTraversalKeysID(traversalKeys, kId); + * Map> keys = new HashMap>(); for (int kid : traversalIDs) { Integer + * key = new Integer(kid); keys.put(key, getFocusTraversalKeys(kid)); } + * KeyboardFocusManager.checkKeyStrokes(traversalIDs, keys, kId, + * keystrokes); oldTraversalKeys = traversalKeys.get(new Integer(id)); // + * put a copy of keystrokes object into map: Set + * newKeys = keystrokes; if (keystrokes != null) { newKeys = new + * HashSet(keystrokes); } traversalKeys.put(kId, newKeys); + * String direction = ""; //$NON-NLS-1$ switch (id) { case + * KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS: direction = "forward"; + * //$NON-NLS-1$ break; case KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS: + * direction = "backward"; //$NON-NLS-1$ break; case + * KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS: direction = "upCycle"; + * //$NON-NLS-1$ break; case KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS: + * direction = "downCycle"; //$NON-NLS-1$ break; } propName = direction + + * propName; } finally { toolkit.unlockAWT(); } firePropertyChange(propName, + * oldTraversalKeys, keystrokes); } + */ /** * Sets the focus traversal keys state for this component. * - * @param value true if the focus traversal keys state is enabled, - * false if the focus traversal keys state is disabled. + * @param value + * true if the focus traversal keys state is enabled, false if + * the focus traversal keys state is disabled. */ public void setFocusTraversalKeysEnabled(boolean value) { boolean oldFocusTraversalKeysEnabled; @@ -4368,38 +4038,23 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali focusTraversalKeysEnabled); } - //???AWT + // ???AWT /* - public void setFocusable(boolean focusable) { - boolean oldFocusable; - toolkit.lockAWT(); - try { - calledSetFocusable = true; - oldFocusable = this.focusable; - this.focusable = focusable; - if (!focusable) { - moveFocus(); - } - } finally { - toolkit.unlockAWT(); - } - firePropertyChange("focusable", oldFocusable, focusable); //$NON-NLS-1$ - } - - public Font getFont() { - toolkit.lockAWT(); - try { - return (font == null) && (parent != null) ? parent.getFont() : font; - } finally { - toolkit.unlockAWT(); - } - } - */ + * public void setFocusable(boolean focusable) { boolean oldFocusable; + * toolkit.lockAWT(); try { calledSetFocusable = true; oldFocusable = + * this.focusable; this.focusable = focusable; if (!focusable) { + * moveFocus(); } } finally { toolkit.unlockAWT(); } + * firePropertyChange("focusable", oldFocusable, focusable); //$NON-NLS-1$ } + * public Font getFont() { toolkit.lockAWT(); try { return (font == null) && + * (parent != null) ? parent.getFont() : font; } finally { + * toolkit.unlockAWT(); } } + */ /** * Sets the font for this Component. * - * @param f the new font of the Component. + * @param f + * the new font of the Component. */ public void setFont(Font f) { Font oldFont; @@ -4416,7 +4071,8 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali /** * Sets the font impl. * - * @param f the new font impl + * @param f + * the new font impl. */ void setFontImpl(Font f) { font = f; @@ -4426,12 +4082,11 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali } } - /** * Invalidate the component if it inherits the font from the parent. This * method is overridden in Container. * - * @return true if the component was invalidated, false otherwise + * @return true if the component was invalidated, false otherwise. */ boolean propagateFont() { if (font == null) { @@ -4444,7 +4099,8 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali /** * Sets the foreground color for this Component. * - * @param c the new foreground color. + * @param c + * the new foreground color. */ public void setForeground(Color c) { Color oldFgColor; @@ -4462,7 +4118,8 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali /** * Sets the background color for the Component. * - * @param c the new background color for this component. + * @param c + * the new background color for this component. */ public void setBackground(Color c) { Color oldBkColor; @@ -4478,11 +4135,12 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali } /** - * Sets the flag for whether paint messages received from the operating - * system should be ignored or not. + * Sets the flag for whether paint messages received from the operating + * system should be ignored or not. * - * @param value true if paint messages received from the operating - * system should be ignored, false otherwise. + * @param value + * true if paint messages received from the operating system + * should be ignored, false otherwise. */ public void setIgnoreRepaint(boolean value) { toolkit.lockAWT(); @@ -4496,7 +4154,8 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali /** * Sets the locale of the component. * - * @param locale the new Locale. + * @param locale + * the new Locale. */ public void setLocale(Locale locale) { Locale oldLocale; @@ -4513,7 +4172,8 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali /** * Sets the location of the Component to the specified point. * - * @param p the new location of the Component + * @param p + * the new location of the Component. */ public void setLocation(Point p) { toolkit.lockAWT(); @@ -4525,10 +4185,12 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali } /** - * Sets the location of the Component to the specified x, y coordinates. + * Sets the location of the Component to the specified x, y coordinates. * - * @param x the x coordinate. - * @param y the y coordinate. + * @param x + * the x coordinate. + * @param y + * the y coordinate. */ public void setLocation(int x, int y) { toolkit.lockAWT(); @@ -4542,8 +4204,9 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali /** * Sets the visibility state of the component. * - * @param b true if the component is visible, false if the component - * is not shown. + * @param b + * true if the component is visible, false if the component is + * not shown. */ public void setVisible(boolean b) { // show() & hide() are not deprecated for Window, @@ -4569,9 +4232,9 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali visible = true; behaviour.setVisible(true); postEvent(new ComponentEvent(this, ComponentEvent.COMPONENT_SHOWN)); - //???AWT: finishHierarchyChange(this, parent, 0); + // ???AWT: finishHierarchyChange(this, parent, 0); notifyInputMethod(new Rectangle(x, y, w, h)); - //???AWT: invalidateRealParent(); + // ???AWT: invalidateRealParent(); } finally { toolkit.unlockAWT(); } @@ -4580,8 +4243,8 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali /** * Deprecated: replaced by setVisible(boolean) method. * - * @param b the visibility's state. - * + * @param b + * the visibility's state. * @deprecated Replaced by setVisible(boolean) method. */ @Deprecated @@ -4593,97 +4256,40 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali } } - //???AWT + // ???AWT /* - void transferFocus(int dir) { - Container root = null; - if (this instanceof Container) { - Container cont = (Container) this; - if (cont.isFocusCycleRoot()) { - root = cont.getFocusTraversalRoot(); - } - } - if (root == null) { - root = getFocusCycleRootAncestor(); - } - // transfer focus up cycle if root is unreachable - Component comp = this; - while ((root != null) - && !(root.isFocusCycleRoot() && root.isShowing() && root.isEnabled() && root - .isFocusable())) { - comp = root; - root = root.getFocusCycleRootAncestor(); - } - if (root == null) { - return; - } - FocusTraversalPolicy policy = root.getFocusTraversalPolicy(); - Component nextComp = null; - switch (dir) { - case KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS: - nextComp = policy.getComponentAfter(root, comp); - break; - case KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS: - nextComp = policy.getComponentBefore(root, comp); - break; - } - if (nextComp != null) { - nextComp.requestFocus(false); - } - } - - public void transferFocus() { - toolkit.lockAWT(); - try { - nextFocus(); - } finally { - toolkit.unlockAWT(); - } - } - - public void transferFocusBackward() { - toolkit.lockAWT(); - try { - transferFocus(KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS); - } finally { - toolkit.unlockAWT(); - } - } - - public void transferFocusUpCycle() { - toolkit.lockAWT(); - try { - KeyboardFocusManager kfm = KeyboardFocusManager.getCurrentKeyboardFocusManager(); - Container root = kfm.getCurrentFocusCycleRoot(); - - if(root == null) { - return; - } - - boolean success = false; - Component nextComp = null; - Container newRoot = root; - do { - nextComp = newRoot instanceof Window ? newRoot.getFocusTraversalPolicy() - .getDefaultComponent(newRoot) : newRoot; - newRoot = newRoot.getFocusCycleRootAncestor(); - if (nextComp == null) { - break; - } - success = nextComp.requestFocusInWindow(); - if (newRoot == null) { - break; - } - kfm.setGlobalCurrentFocusCycleRoot(newRoot); - } while (!success); - if (!success && root != newRoot) { - kfm.setGlobalCurrentFocusCycleRoot(root); - } - } finally { - toolkit.unlockAWT(); - } - } - */ + * void transferFocus(int dir) { Container root = null; if (this instanceof + * Container) { Container cont = (Container) this; if + * (cont.isFocusCycleRoot()) { root = cont.getFocusTraversalRoot(); } } if + * (root == null) { root = getFocusCycleRootAncestor(); } // transfer focus + * up cycle if root is unreachable Component comp = this; while ((root != + * null) && !(root.isFocusCycleRoot() && root.isShowing() && + * root.isEnabled() && root .isFocusable())) { comp = root; root = + * root.getFocusCycleRootAncestor(); } if (root == null) { return; } + * FocusTraversalPolicy policy = root.getFocusTraversalPolicy(); Component + * nextComp = null; switch (dir) { case + * KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS: nextComp = + * policy.getComponentAfter(root, comp); break; case + * KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS: nextComp = + * policy.getComponentBefore(root, comp); break; } if (nextComp != null) { + * nextComp.requestFocus(false); } } public void transferFocus() { + * toolkit.lockAWT(); try { nextFocus(); } finally { toolkit.unlockAWT(); } + * } public void transferFocusBackward() { toolkit.lockAWT(); try { + * transferFocus(KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS); } finally { + * toolkit.unlockAWT(); } } public void transferFocusUpCycle() { + * toolkit.lockAWT(); try { KeyboardFocusManager kfm = + * KeyboardFocusManager.getCurrentKeyboardFocusManager(); Container root = + * kfm.getCurrentFocusCycleRoot(); if(root == null) { return; } boolean + * success = false; Component nextComp = null; Container newRoot = root; do + * { nextComp = newRoot instanceof Window ? + * newRoot.getFocusTraversalPolicy() .getDefaultComponent(newRoot) : + * newRoot; newRoot = newRoot.getFocusCycleRootAncestor(); if (nextComp == + * null) { break; } success = nextComp.requestFocusInWindow(); if (newRoot + * == null) { break; } kfm.setGlobalCurrentFocusCycleRoot(newRoot); } while + * (!success); if (!success && root != newRoot) { + * kfm.setGlobalCurrentFocusCycleRoot(root); } } finally { + * toolkit.unlockAWT(); } } + */ /** * Validates that this component has a valid layout. @@ -4710,7 +4316,7 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali /** * Gets the native window. * - * @return the native window + * @return the native window. */ NativeWindow getNativeWindow() { return behaviour.getNativeWindow(); @@ -4719,8 +4325,8 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali /** * Checks whether or not a maximum size is set for the Component. * - * @return true, if the maximum size is set for the Component, - * false otherwise. + * @return true, if the maximum size is set for the Component, false + * otherwise. */ public boolean isMaximumSizeSet() { toolkit.lockAWT(); @@ -4734,8 +4340,8 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali /** * Checks whether or not the minimum size is set for the component. * - * @return true, if the minimum size is set for the component, - * false otherwise. + * @return true, if the minimum size is set for the component, false + * otherwise. */ public boolean isMinimumSizeSet() { toolkit.lockAWT(); @@ -4749,8 +4355,8 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali /** * Checks whether or not the preferred size is set for the Component. * - * @return true, if the preferred size is set for the Component, - * false otherwise. + * @return true, if the preferred size is set for the Component, false + * otherwise. */ public boolean isPreferredSizeSet() { toolkit.lockAWT(); @@ -4769,8 +4375,8 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali public Dimension getMaximumSize() { toolkit.lockAWT(); try { - return isMaximumSizeSet() ? new Dimension(maximumSize) : new Dimension( - Short.MAX_VALUE, Short.MAX_VALUE); + return isMaximumSizeSet() ? new Dimension(maximumSize) : new Dimension(Short.MAX_VALUE, + Short.MAX_VALUE); } finally { toolkit.unlockAWT(); } @@ -4794,7 +4400,6 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali * Deprecated: replaced by getMinimumSize() method. * * @return the Dimension. - * * @deprecated Replaced by getMinimumSize() method. */ @Deprecated @@ -4808,7 +4413,7 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali if (defSize != null) { return (Dimension)defSize.clone(); } - return isDisplayable()? new Dimension(1, 1) : new Dimension(w, h); + return isDisplayable() ? new Dimension(1, 1) : new Dimension(w, h); } finally { toolkit.unlockAWT(); } @@ -4832,7 +4437,6 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali * Deprecated: replaced by getPreferredSize() method. * * @return the Dimension. - * * @deprecated Replaced by getPreferredSize() method. */ @Deprecated @@ -4855,7 +4459,8 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali /** * Sets the maximum size of the Component. * - * @param maximumSize the new maximum size of the Component. + * @param maximumSize + * the new maximum size of the Component. */ public void setMaximumSize(Dimension maximumSize) { Dimension oldMaximumSize; @@ -4882,7 +4487,7 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali firePropertyChange("maximumSize", oldMaximumSize, this.maximumSize); //$NON-NLS-1$ toolkit.lockAWT(); try { - //???AWT: invalidateRealParent(); + // ???AWT: invalidateRealParent(); } finally { toolkit.unlockAWT(); } @@ -4891,7 +4496,8 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali /** * Sets the minimum size of the Component. * - * @param minimumSize the new minimum size of the Component. + * @param minimumSize + * the new minimum size of the Component. */ public void setMinimumSize(Dimension minimumSize) { Dimension oldMinimumSize; @@ -4918,7 +4524,7 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali firePropertyChange("minimumSize", oldMinimumSize, this.minimumSize); //$NON-NLS-1$ toolkit.lockAWT(); try { - //???AWT: invalidateRealParent(); + // ???AWT: invalidateRealParent(); } finally { toolkit.unlockAWT(); } @@ -4927,7 +4533,8 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali /** * Sets the preferred size of the Component. * - * @param preferredSize the new preferred size of the Component. + * @param preferredSize + * the new preferred size of the Component. */ public void setPreferredSize(Dimension preferredSize) { Dimension oldPreferredSize; @@ -4954,47 +4561,38 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali firePropertyChange("preferredSize", oldPreferredSize, this.preferredSize); //$NON-NLS-1$ toolkit.lockAWT(); try { - //???AWT: invalidateRealParent(); + // ???AWT: invalidateRealParent(); } finally { toolkit.unlockAWT(); } } - //???AWT + // ???AWT /* - RedrawManager getRedrawManager() { - if (parent == null) { - return null; - } - return parent.getRedrawManager(); - } - */ + * RedrawManager getRedrawManager() { if (parent == null) { return null; } + * return parent.getRedrawManager(); } + */ /** * Checks if is focusability explicitly set. * - * @return true if component has a focusable peer + * @return true if component has a focusable peer. */ - //???AWT + // ???AWT /* - boolean isPeerFocusable() { - // The recommendations for Windows and Unix are that - // Canvases, Labels, Panels, Scrollbars, ScrollPanes, Windows, - // and lightweight Components have non-focusable peers, - // and all other Components have focusable peers. - if (this instanceof Canvas || this instanceof Label || this instanceof Panel - || this instanceof Scrollbar || this instanceof ScrollPane - || this instanceof Window || isLightweight()) { - return false; - } - return true; - } - */ + * boolean isPeerFocusable() { // The recommendations for Windows and Unix + * are that // Canvases, Labels, Panels, Scrollbars, ScrollPanes, Windows, + * // and lightweight Components have non-focusable peers, // and all other + * Components have focusable peers. if (this instanceof Canvas || this + * instanceof Label || this instanceof Panel || this instanceof Scrollbar || + * this instanceof ScrollPane || this instanceof Window || isLightweight()) + * { return false; } return true; } + */ /** * @return true if focusability was explicitly set via a call to * setFocusable() or via overriding isFocusable() or - * isFocusTraversable() + * isFocusTraversable(). */ boolean isFocusabilityExplicitlySet() { return calledSetFocusable || overridenIsFocusable; @@ -5003,7 +4601,8 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali /** * Paints the component and all of its subcomponents. * - * @param g the Graphics to be used for painting. + * @param g + * the Graphics to be used for painting. */ public void paintAll(Graphics g) { toolkit.lockAWT(); @@ -5017,7 +4616,8 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali /** * Updates this Component. * - * @param g the Graphics to be used for updating. + * @param g + * the Graphics to be used for updating. */ public void update(Graphics g) { toolkit.lockAWT(); @@ -5036,7 +4636,8 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali /** * Paints this component. * - * @param g the Graphics to be used for painting. + * @param g + * the Graphics to be used for painting. */ public void paint(Graphics g) { toolkit.lockAWT(); @@ -5050,7 +4651,8 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali /** * Prepares the component to be painted. * - * @param g the Graphics to be used for painting. + * @param g + * the Graphics to be used for painting. */ void prepaint(Graphics g) { // Just to nothing. For overriding. @@ -5059,7 +4661,7 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali /** * Checks if is prepainter. * - * @return true, if is prepainter + * @return true, if is prepainter. */ boolean isPrepainter() { return false; @@ -5083,41 +4685,29 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali // To be inherited by Container } - //???AWT + // ???AWT /* - void finishHierarchyChange(Component changed, Container changedParent, int ancestorFlags) { - if (--hierarchyChangingCounter == 0) { - int changeFlags = ancestorFlags; - if (wasShowing != isShowing()) { - changeFlags |= HierarchyEvent.SHOWING_CHANGED; - } - if (wasDisplayable != isDisplayable()) { - changeFlags |= HierarchyEvent.DISPLAYABILITY_CHANGED; - } - if (changeFlags > 0) { - postEvent(new HierarchyEvent(this, HierarchyEvent.HIERARCHY_CHANGED, changed, - changedParent, changeFlags)); - } - finishChildrenHierarchyChange(changed, changedParent, ancestorFlags); - } - } - - - void finishChildrenHierarchyChange(Component changed, Container changedParent, - int ancestorFlags) { - // To be inherited by Container - } + * void finishHierarchyChange(Component changed, Container changedParent, + * int ancestorFlags) { if (--hierarchyChangingCounter == 0) { int + * changeFlags = ancestorFlags; if (wasShowing != isShowing()) { changeFlags + * |= HierarchyEvent.SHOWING_CHANGED; } if (wasDisplayable != + * isDisplayable()) { changeFlags |= HierarchyEvent.DISPLAYABILITY_CHANGED; + * } if (changeFlags > 0) { postEvent(new HierarchyEvent(this, + * HierarchyEvent.HIERARCHY_CHANGED, changed, changedParent, changeFlags)); + * } finishChildrenHierarchyChange(changed, changedParent, ancestorFlags); } + * } void finishChildrenHierarchyChange(Component changed, Container + * changedParent, int ancestorFlags) { // To be inherited by Container } + * void postHierarchyBoundsEvents(Component changed, int id) { postEvent(new + * HierarchyEvent(this, id, changed, null, 0)); } + */ - void postHierarchyBoundsEvents(Component changed, int id) { - postEvent(new HierarchyEvent(this, id, changed, null, 0)); - } - */ - /** * Spread hierarchy bounds events. * - * @param changed the changed - * @param id the id + * @param changed + * the changed. + * @param id + * the id. */ void spreadHierarchyBoundsEvents(Component changed, int id) { // To be inherited by Container @@ -5126,59 +4716,40 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali /** * Dispatches an event to this component. * - * @param e the Event. + * @param e + * the Event. */ public final void dispatchEvent(AWTEvent e) { - //???AWT + // ???AWT /* - if (e.isConsumed()) { - return; - } - if (e instanceof PaintEvent) { - toolkit.dispatchAWTEvent(e); - processPaintEvent((PaintEvent) e); - return; - } - KeyboardFocusManager kfm = KeyboardFocusManager.getCurrentKeyboardFocusManager(); - if (!e.dispatchedByKFM && kfm.dispatchEvent(e)) { - return; - } - if (e instanceof KeyEvent) { - KeyEvent ke = (KeyEvent) e; - // consumes KeyEvent which represents a focus traversal key - if (getFocusTraversalKeysEnabled()) { - kfm.processKeyEvent(this, ke); - if (ke.isConsumed()) { - return; - } - } - } - if (inputMethodsEnabled && dispatchToIM && e.isPosted && dispatchEventToIM(e)) { - return; - } - if (e.getID() == WindowEvent.WINDOW_ICONIFIED) { - notifyInputMethod(null); - } - AWTEvent.EventDescriptor descriptor = toolkit.eventTypeLookup.getEventDescriptor(e); - toolkit.dispatchAWTEvent(e); - if (descriptor != null) { - if (isEventEnabled(descriptor.eventMask) - || (getListeners(descriptor.listenerType).length > 0)) { - processEvent(e); - } - // input events can be consumed by user listeners: - if (!e.isConsumed() && ((enabledAWTEvents & descriptor.eventMask) != 0)) { - postprocessEvent(e, descriptor.eventMask); - } - } - postDeprecatedEvent(e); - */ + * if (e.isConsumed()) { return; } if (e instanceof PaintEvent) { + * toolkit.dispatchAWTEvent(e); processPaintEvent((PaintEvent) e); + * return; } KeyboardFocusManager kfm = + * KeyboardFocusManager.getCurrentKeyboardFocusManager(); if + * (!e.dispatchedByKFM && kfm.dispatchEvent(e)) { return; } if (e + * instanceof KeyEvent) { KeyEvent ke = (KeyEvent) e; // consumes + * KeyEvent which represents a focus traversal key if + * (getFocusTraversalKeysEnabled()) { kfm.processKeyEvent(this, ke); if + * (ke.isConsumed()) { return; } } } if (inputMethodsEnabled && + * dispatchToIM && e.isPosted && dispatchEventToIM(e)) { return; } if + * (e.getID() == WindowEvent.WINDOW_ICONIFIED) { + * notifyInputMethod(null); } AWTEvent.EventDescriptor descriptor = + * toolkit.eventTypeLookup.getEventDescriptor(e); + * toolkit.dispatchAWTEvent(e); if (descriptor != null) { if + * (isEventEnabled(descriptor.eventMask) || + * (getListeners(descriptor.listenerType).length > 0)) { + * processEvent(e); } // input events can be consumed by user listeners: + * if (!e.isConsumed() && ((enabledAWTEvents & descriptor.eventMask) != + * 0)) { postprocessEvent(e, descriptor.eventMask); } } + * postDeprecatedEvent(e); + */ } /** * Post deprecated event. * - * @param e the e + * @param e + * the e. */ private void postDeprecatedEvent(AWTEvent e) { if (deprecatedEventHandler) { @@ -5192,27 +4763,29 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali /** * Postprocess event. * - * @param e the e - * @param eventMask the event mask + * @param e + * the e. + * @param eventMask + * the event mask. */ void postprocessEvent(AWTEvent e, long eventMask) { toolkit.lockAWT(); try { // call system listeners under AWT lock if (eventMask == AWTEvent.FOCUS_EVENT_MASK) { - preprocessFocusEvent((FocusEvent) e); + preprocessFocusEvent((FocusEvent)e); } else if (eventMask == AWTEvent.KEY_EVENT_MASK) { - preprocessKeyEvent((KeyEvent) e); + preprocessKeyEvent((KeyEvent)e); } else if (eventMask == AWTEvent.MOUSE_EVENT_MASK) { - preprocessMouseEvent((MouseEvent) e); + preprocessMouseEvent((MouseEvent)e); } else if (eventMask == AWTEvent.MOUSE_MOTION_EVENT_MASK) { - preprocessMouseMotionEvent((MouseEvent) e); + preprocessMouseMotionEvent((MouseEvent)e); } else if (eventMask == AWTEvent.COMPONENT_EVENT_MASK) { - preprocessComponentEvent((ComponentEvent) e); + preprocessComponentEvent((ComponentEvent)e); } else if (eventMask == AWTEvent.MOUSE_WHEEL_EVENT_MASK) { - preprocessMouseWheelEvent((MouseWheelEvent) e); + preprocessMouseWheelEvent((MouseWheelEvent)e); } else if (eventMask == AWTEvent.INPUT_METHOD_EVENT_MASK) { - preprocessInputMethodEvent((InputMethodEvent) e); + preprocessInputMethodEvent((InputMethodEvent)e); } } finally { toolkit.unlockAWT(); @@ -5222,7 +4795,8 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali /** * Preprocess input method event. * - * @param e the e + * @param e + * the e. */ private void preprocessInputMethodEvent(InputMethodEvent e) { processInputMethodEventImpl(e, inputMethodListeners.getSystemListeners()); @@ -5231,7 +4805,8 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali /** * Preprocess mouse wheel event. * - * @param e the e + * @param e + * the e. */ private void preprocessMouseWheelEvent(MouseWheelEvent e) { processMouseWheelEventImpl(e, mouseWheelListeners.getSystemListeners()); @@ -5240,8 +4815,10 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali /** * Process mouse wheel event impl. * - * @param e the e - * @param c the c + * @param e + * the e. + * @param c + * the c. */ private void processMouseWheelEventImpl(MouseWheelEvent e, Collection c) { for (MouseWheelListener listener : c) { @@ -5256,7 +4833,8 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali /** * Preprocess component event. * - * @param e the e + * @param e + * the e. */ private void preprocessComponentEvent(ComponentEvent e) { processComponentEventImpl(e, componentListeners.getSystemListeners()); @@ -5265,7 +4843,8 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali /** * Preprocess mouse motion event. * - * @param e the e + * @param e + * the e. */ void preprocessMouseMotionEvent(MouseEvent e) { processMouseMotionEventImpl(e, mouseMotionListeners.getSystemListeners()); @@ -5274,7 +4853,8 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali /** * Preprocess mouse event. * - * @param e the e + * @param e + * the e */ void preprocessMouseEvent(MouseEvent e) { processMouseEventImpl(e, mouseListeners.getSystemListeners()); @@ -5283,7 +4863,8 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali /** * Preprocess key event. * - * @param e the e + * @param e + * the e. */ void preprocessKeyEvent(KeyEvent e) { processKeyEventImpl(e, keyListeners.getSystemListeners()); @@ -5292,79 +4873,82 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali /** * Preprocess focus event. * - * @param e the e + * @param e + * the e. */ void preprocessFocusEvent(FocusEvent e) { processFocusEventImpl(e, focusListeners.getSystemListeners()); } /** - * Processes AWTEvent occurred on this component. + * Processes AWTEvent occurred on this component. * - * @param e the AWTEvent. + * @param e + * the AWTEvent. */ protected void processEvent(AWTEvent e) { long eventMask = toolkit.eventTypeLookup.getEventMask(e); if (eventMask == AWTEvent.COMPONENT_EVENT_MASK) { - processComponentEvent((ComponentEvent) e); + processComponentEvent((ComponentEvent)e); } else if (eventMask == AWTEvent.FOCUS_EVENT_MASK) { - processFocusEvent((FocusEvent) e); + processFocusEvent((FocusEvent)e); } else if (eventMask == AWTEvent.KEY_EVENT_MASK) { - processKeyEvent((KeyEvent) e); + processKeyEvent((KeyEvent)e); } else if (eventMask == AWTEvent.MOUSE_EVENT_MASK) { - processMouseEvent((MouseEvent) e); + processMouseEvent((MouseEvent)e); } else if (eventMask == AWTEvent.MOUSE_WHEEL_EVENT_MASK) { - processMouseWheelEvent((MouseWheelEvent) e); + processMouseWheelEvent((MouseWheelEvent)e); } else if (eventMask == AWTEvent.MOUSE_MOTION_EVENT_MASK) { - processMouseMotionEvent((MouseEvent) e); + processMouseMotionEvent((MouseEvent)e); } else if (eventMask == AWTEvent.HIERARCHY_EVENT_MASK) { - processHierarchyEvent((HierarchyEvent) e); + processHierarchyEvent((HierarchyEvent)e); } else if (eventMask == AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK) { - processHierarchyBoundsEvent((HierarchyEvent) e); + processHierarchyBoundsEvent((HierarchyEvent)e); } else if (eventMask == AWTEvent.INPUT_METHOD_EVENT_MASK) { - processInputMethodEvent((InputMethodEvent) e); + processInputMethodEvent((InputMethodEvent)e); } } /** - * Gets an array of all listener's objects based on the specified - * listener type and registered to this Component. - * - * @param listenerType the listener type. + * Gets an array of all listener's objects based on the specified listener + * type and registered to this Component. * + * @param listenerType + * the listener type. * @return an array of all listener's objects based on the specified - * listener type and registered to this Component. + * listener type and registered to this Component. */ @SuppressWarnings("unchecked") public T[] getListeners(Class listenerType) { if (ComponentListener.class.isAssignableFrom(listenerType)) { - return (T[]) getComponentListeners(); + return (T[])getComponentListeners(); } else if (FocusListener.class.isAssignableFrom(listenerType)) { - return (T[]) getFocusListeners(); + return (T[])getFocusListeners(); } else if (HierarchyBoundsListener.class.isAssignableFrom(listenerType)) { - return (T[]) getHierarchyBoundsListeners(); + return (T[])getHierarchyBoundsListeners(); } else if (HierarchyListener.class.isAssignableFrom(listenerType)) { - return (T[]) getHierarchyListeners(); + return (T[])getHierarchyListeners(); } else if (InputMethodListener.class.isAssignableFrom(listenerType)) { - return (T[]) getInputMethodListeners(); + return (T[])getInputMethodListeners(); } else if (KeyListener.class.isAssignableFrom(listenerType)) { - return (T[]) getKeyListeners(); + return (T[])getKeyListeners(); } else if (MouseWheelListener.class.isAssignableFrom(listenerType)) { - return (T[]) getMouseWheelListeners(); + return (T[])getMouseWheelListeners(); } else if (MouseMotionListener.class.isAssignableFrom(listenerType)) { - return (T[]) getMouseMotionListeners(); + return (T[])getMouseMotionListeners(); } else if (MouseListener.class.isAssignableFrom(listenerType)) { - return (T[]) getMouseListeners(); + return (T[])getMouseListeners(); } else if (PropertyChangeListener.class.isAssignableFrom(listenerType)) { - return (T[]) getPropertyChangeListeners(); + return (T[])getPropertyChangeListeners(); } - return (T[]) Array.newInstance(listenerType, 0); + return (T[])Array.newInstance(listenerType, 0); } /** * Process paint event. * - * @param event the event + * @param event + * the event. */ private void processPaintEvent(PaintEvent event) { if (redrawManager == null) { @@ -5392,13 +4976,15 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali /** * Inits the graphics. * - * @param g the g - * @param e the e + * @param g + * the g. + * @param e + * the e. */ void initGraphics(Graphics g, PaintEvent e) { Rectangle clip = e.getUpdateRect(); if (clip instanceof ClipRegion) { - g.setClip(((ClipRegion) clip).getClip()); + g.setClip(((ClipRegion)clip).getClip()); } else { g.setClip(clip); } @@ -5413,11 +4999,11 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali } /** - * Enables the events with the specified event mask to be delivered to - * this component. + * Enables the events with the specified event mask to be delivered to this + * component. * - * @param eventsToEnable the events mask which specifies the types - * of events to enable. + * @param eventsToEnable + * the events mask which specifies the types of events to enable. */ protected final void enableEvents(long eventsToEnable) { toolkit.lockAWT(); @@ -5432,17 +5018,19 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali /** * Enable awt events. * - * @param eventsToEnable the events to enable + * @param eventsToEnable + * the events to enable. */ private void enableAWTEvents(long eventsToEnable) { enabledAWTEvents |= eventsToEnable; } /** - * Disables the events with types specified by the specified event mask - * from being delivered to this component. + * Disables the events with types specified by the specified event mask from + * being delivered to this component. * - * @param eventsToDisable the event mask specifying the event types. + * @param eventsToDisable + * the event mask specifying the event types. */ protected final void disableEvents(long eventsToDisable) { toolkit.lockAWT(); @@ -5459,9 +5047,9 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali /** * Checks if is mouse event enabled. * - * @param eventMask the event mask - * - * @return true, if is mouse event enabled + * @param eventMask + * the event mask. + * @return true, if is mouse event enabled. */ boolean isMouseEventEnabled(long eventMask) { return (isEventEnabled(eventMask) || (enabledAWTEvents & eventMask) != 0); @@ -5470,18 +5058,19 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali /** * Checks if is event enabled. * - * @param eventMask the event mask - * - * @return true, if is event enabled + * @param eventMask + * the event mask. + * @return true, if is event enabled. */ boolean isEventEnabled(long eventMask) { return ((enabledEvents & eventMask) != 0); } /** - * Enables or disables input method support for this component. + * Enables or disables input method support for this component. * - * @param enable true to enable input method support, false to disable it. + * @param enable + * true to enable input method support, false to disable it. */ public void enableInputMethods(boolean enable) { toolkit.lockAWT(); @@ -5496,11 +5085,10 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali } /** - * Gets an array of all component's listeners registered for this - * component. + * Gets an array of all component's listeners registered for this component. * * @return an array of all component's listeners registered for this - * component. + * component. */ public ComponentListener[] getComponentListeners() { return componentListeners.getUserListeners(new ComponentListener[0]); @@ -5510,7 +5098,8 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali * Adds the specified component listener to the Component for receiving * component's event. * - * @param l the ComponentListener. + * @param l + * the ComponentListener. */ public void addComponentListener(ComponentListener l) { componentListeners.addUserListener(l); @@ -5519,17 +5108,19 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali /** * Removes the component listener registered for this Component. * - * @param l the ComponentListener. + * @param l + * the ComponentListener. */ public void removeComponentListener(ComponentListener l) { componentListeners.removeUserListener(l); } /** - * Processes a component event that has occurred on this component - * by dispatching them to any registered ComponentListener objects. + * Processes a component event that has occurred on this component by + * dispatching them to any registered ComponentListener objects. * - * @param e the ComponentEvent. + * @param e + * the ComponentEvent. */ protected void processComponentEvent(ComponentEvent e) { processComponentEventImpl(e, componentListeners.getUserListeners()); @@ -5538,8 +5129,10 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali /** * Process component event impl. * - * @param e the e - * @param c the c + * @param e + * the e. + * @param c + * the c. */ private void processComponentEventImpl(ComponentEvent e, Collection c) { for (ComponentListener listener : c) { @@ -5570,10 +5163,11 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali } /** - * Adds the specified focus listener to the Component for receiving - * focus events. + * Adds the specified focus listener to the Component for receiving focus + * events. * - * @param l the FocusListener. + * @param l + * the FocusListener. */ public void addFocusListener(FocusListener l) { focusListeners.addUserListener(l); @@ -5582,7 +5176,8 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali /** * Adds the awt focus listener. * - * @param l the l + * @param l + * the l. */ void addAWTFocusListener(FocusListener l) { enableAWTEvents(AWTEvent.FOCUS_EVENT_MASK); @@ -5592,17 +5187,19 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali /** * Removes the focus listener registered for this Component. * - * @param l the FocusListener. + * @param l + * the FocusListener. */ public void removeFocusListener(FocusListener l) { focusListeners.removeUserListener(l); } /** - * Processes a FocusEvent that has occurred on this component - * by dispatching it to the registered listeners. - * - * @param e the FocusEvent. + * Processes a FocusEvent that has occurred on this component by dispatching + * it to the registered listeners. + * + * @param e + * the FocusEvent. */ protected void processFocusEvent(FocusEvent e) { processFocusEventImpl(e, focusListeners.getUserListeners()); @@ -5611,8 +5208,10 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali /** * Process focus event impl. * - * @param e the e - * @param c the c + * @param e + * the e. + * @param c + * the c. */ private void processFocusEventImpl(FocusEvent e, Collection c) { for (FocusListener listener : c) { @@ -5628,11 +5227,9 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali } /** - * Gets an array of registered HierarchyListeners for - * this Component. + * Gets an array of registered HierarchyListeners for this Component. * - * @return an array of registered HierarchyListeners for - * this Component. + * @return an array of registered HierarchyListeners for this Component. */ public HierarchyListener[] getHierarchyListeners() { return hierarchyListeners.getUserListeners(new HierarchyListener[0]); @@ -5641,7 +5238,8 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali /** * Adds the specified hierarchy listener. * - * @param l the HierarchyListener. + * @param l + * the HierarchyListener. */ public void addHierarchyListener(HierarchyListener l) { hierarchyListeners.addUserListener(l); @@ -5650,17 +5248,19 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali /** * Removes the hierarchy listener registered for this component. * - * @param l the HierarchyListener. + * @param l + * the HierarchyListener. */ public void removeHierarchyListener(HierarchyListener l) { hierarchyListeners.removeUserListener(l); } /** - * Processes a hierarchy event that has occurred on this component - * by dispatching it to the registered listeners. + * Processes a hierarchy event that has occurred on this component by + * dispatching it to the registered listeners. * - * @param e the HierarchyEvent. + * @param e + * the HierarchyEvent. */ protected void processHierarchyEvent(HierarchyEvent e) { for (HierarchyListener listener : hierarchyListeners.getUserListeners()) { @@ -5673,8 +5273,8 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali } /** - * Gets an array of HierarchyBoundsListener objects registered - * to this Component. + * Gets an array of HierarchyBoundsListener objects registered to this + * Component. * * @return an array of HierarchyBoundsListener objects. */ @@ -5685,7 +5285,8 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali /** * Adds the specified hierarchy bounds listener. * - * @param l the HierarchyBoundsListener. + * @param l + * the HierarchyBoundsListener. */ public void addHierarchyBoundsListener(HierarchyBoundsListener l) { hierarchyBoundsListeners.addUserListener(l); @@ -5694,17 +5295,19 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali /** * Removes the hierarchy bounds listener registered for this Component. * - * @param l the HierarchyBoundsListener. + * @param l + * the HierarchyBoundsListener. */ public void removeHierarchyBoundsListener(HierarchyBoundsListener l) { hierarchyBoundsListeners.removeUserListener(l); } /** - * Processes a hierarchy bounds event that has occurred on this component - * by dispatching it to the registered listeners. - * - * @param e the HierarchyBoundsEvent. + * Processes a hierarchy bounds event that has occurred on this component by + * dispatching it to the registered listeners. + * + * @param e + * the HierarchyBoundsEvent. */ protected void processHierarchyBoundsEvent(HierarchyEvent e) { for (HierarchyBoundsListener listener : hierarchyBoundsListeners.getUserListeners()) { @@ -5731,7 +5334,8 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali /** * Adds the specified key listener. * - * @param l the KeyListener. + * @param l + * the KeyListener. */ public void addKeyListener(KeyListener l) { keyListeners.addUserListener(l); @@ -5740,7 +5344,8 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali /** * Adds the awt key listener. * - * @param l the l + * @param l + * the l. */ void addAWTKeyListener(KeyListener l) { enableAWTEvents(AWTEvent.KEY_EVENT_MASK); @@ -5750,17 +5355,19 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali /** * Removes the key listener registered for this Component. * - * @param l the KeyListener. + * @param l + * the KeyListener. */ public void removeKeyListener(KeyListener l) { keyListeners.removeUserListener(l); } /** - * Processes a key event that has occurred on this component - * by dispatching it to the registered listeners. + * Processes a key event that has occurred on this component by dispatching + * it to the registered listeners. * - * @param e the KeyEvent. + * @param e + * the KeyEvent. */ protected void processKeyEvent(KeyEvent e) { processKeyEventImpl(e, keyListeners.getUserListeners()); @@ -5769,8 +5376,10 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali /** * Process key event impl. * - * @param e the e - * @param c the c + * @param e + * the e. + * @param c + * the c. */ private void processKeyEventImpl(KeyEvent e, Collection c) { for (KeyListener listener : c) { @@ -5800,7 +5409,8 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali /** * Adds the specified mouse listener. * - * @param l the MouseListener. + * @param l + * the MouseListener. */ public void addMouseListener(MouseListener l) { mouseListeners.addUserListener(l); @@ -5809,7 +5419,8 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali /** * Adds the awt mouse listener. * - * @param l the l + * @param l + * the l. */ void addAWTMouseListener(MouseListener l) { enableAWTEvents(AWTEvent.MOUSE_EVENT_MASK); @@ -5819,7 +5430,8 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali /** * Adds the awt mouse motion listener. * - * @param l the l + * @param l + * the l. */ void addAWTMouseMotionListener(MouseMotionListener l) { enableAWTEvents(AWTEvent.MOUSE_MOTION_EVENT_MASK); @@ -5829,7 +5441,8 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali /** * Adds the awt component listener. * - * @param l the l + * @param l + * the l. */ void addAWTComponentListener(ComponentListener l) { enableAWTEvents(AWTEvent.COMPONENT_EVENT_MASK); @@ -5839,7 +5452,8 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali /** * Adds the awt input method listener. * - * @param l the l + * @param l + * the l. */ void addAWTInputMethodListener(InputMethodListener l) { enableAWTEvents(AWTEvent.INPUT_METHOD_EVENT_MASK); @@ -5849,7 +5463,8 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali /** * Adds the awt mouse wheel listener. * - * @param l the l + * @param l + * the l. */ void addAWTMouseWheelListener(MouseWheelListener l) { enableAWTEvents(AWTEvent.MOUSE_WHEEL_EVENT_MASK); @@ -5859,17 +5474,19 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali /** * Removes the mouse listener registered for this Component. * - * @param l the MouseListener. + * @param l + * the MouseListener. */ public void removeMouseListener(MouseListener l) { mouseListeners.removeUserListener(l); } /** - * Processes a mouse event that has occurred on this component - * by dispatching it to the registered listeners. + * Processes a mouse event that has occurred on this component by + * dispatching it to the registered listeners. * - * @param e the MouseEvent. + * @param e + * the MouseEvent. */ protected void processMouseEvent(MouseEvent e) { processMouseEventImpl(e, mouseListeners.getUserListeners()); @@ -5878,8 +5495,10 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali /** * Process mouse event impl. * - * @param e the e - * @param c the c + * @param e + * the e. + * @param c + * the c. */ private void processMouseEventImpl(MouseEvent e, Collection c) { for (MouseListener listener : c) { @@ -5906,8 +5525,10 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali /** * Process mouse motion event impl. * - * @param e the e - * @param c the c + * @param e + * the e. + * @param c + * the c. */ private void processMouseMotionEventImpl(MouseEvent e, Collection c) { for (MouseMotionListener listener : c) { @@ -5923,11 +5544,9 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali } /** - * Gets an array of the mouse motion listeners registered to - * the Component. + * Gets an array of the mouse motion listeners registered to the Component. * - * @return an array of the MouseMotionListeners registered to - * the Component. + * @return an array of the MouseMotionListeners registered to the Component. */ public MouseMotionListener[] getMouseMotionListeners() { return mouseMotionListeners.getUserListeners(new MouseMotionListener[0]); @@ -5936,7 +5555,8 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali /** * Adds the specified mouse motion listener. * - * @param l the MouseMotionListener. + * @param l + * the MouseMotionListener. */ public void addMouseMotionListener(MouseMotionListener l) { mouseMotionListeners.addUserListener(l); @@ -5945,28 +5565,28 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali /** * Removes the mouse motion listener registered for this component. * - * @param l the MouseMotionListener. + * @param l + * the MouseMotionListener. */ public void removeMouseMotionListener(MouseMotionListener l) { mouseMotionListeners.removeUserListener(l); } /** - * Processes a mouse motion event that has occurred on this component - * by dispatching it to the registered listeners. + * Processes a mouse motion event that has occurred on this component by + * dispatching it to the registered listeners. * - * @param e the MouseEvent. + * @param e + * the MouseEvent. */ protected void processMouseMotionEvent(MouseEvent e) { processMouseMotionEventImpl(e, mouseMotionListeners.getUserListeners()); } /** - * Gets an array of the mouse wheel listeners registered to - * the Component. + * Gets an array of the mouse wheel listeners registered to the Component. * - * @return an array of the MouseWheelListeners registered to - * the Component. + * @return an array of the MouseWheelListeners registered to the Component. */ public MouseWheelListener[] getMouseWheelListeners() { return mouseWheelListeners.getUserListeners(new MouseWheelListener[0]); @@ -5975,7 +5595,8 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali /** * Adds the specified mouse wheel listener. * - * @param l the MouseWheelListener. + * @param l + * the MouseWheelListener. */ public void addMouseWheelListener(MouseWheelListener l) { mouseWheelListeners.addUserListener(l); @@ -5984,28 +5605,30 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali /** * Removes the mouse wheel listener registered for this component. * - * @param l the MouseWheelListener. + * @param l + * the MouseWheelListener. */ public void removeMouseWheelListener(MouseWheelListener l) { mouseWheelListeners.removeUserListener(l); } /** - * Processes a mouse wheel event that has occurred on this component - * by dispatching it to the registered listeners. + * Processes a mouse wheel event that has occurred on this component by + * dispatching it to the registered listeners. * - * @param e the MouseWheelEvent. + * @param e + * the MouseWheelEvent. */ protected void processMouseWheelEvent(MouseWheelEvent e) { processMouseWheelEventImpl(e, mouseWheelListeners.getUserListeners()); } /** - * Gets an array of the InputMethodListener listeners - * registered to the Component. + * Gets an array of the InputMethodListener listeners registered to the + * Component. * - * @return an array of the InputMethodListener listeners - * registered to the Component. + * @return an array of the InputMethodListener listeners registered to the + * Component. */ public InputMethodListener[] getInputMethodListeners() { return inputMethodListeners.getUserListeners(new InputMethodListener[0]); @@ -6014,7 +5637,8 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali /** * Adds the specified input method listener. * - * @param l the InputMethodListener. + * @param l + * the InputMethodListener. */ public void addInputMethodListener(InputMethodListener l) { inputMethodListeners.addUserListener(l); @@ -6023,17 +5647,19 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali /** * Removes the input method listener registered for this component. * - * @param l the InputMethodListener. + * @param l + * the InputMethodListener. */ public void removeInputMethodListener(InputMethodListener l) { inputMethodListeners.removeUserListener(l); } /** - * Processes an input method event that has occurred on this component - * by dispatching it to the registered listeners. + * Processes an input method event that has occurred on this component by + * dispatching it to the registered listeners. * - * @param e the InputMethodEvent. + * @param e + * the InputMethodEvent. */ protected void processInputMethodEvent(InputMethodEvent e) { processInputMethodEventImpl(e, inputMethodListeners.getUserListeners()); @@ -6042,11 +5668,12 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali /** * Process input method event impl. * - * @param e the e - * @param c the c + * @param e + * the e. + * @param c + * the c. */ - private void processInputMethodEventImpl(InputMethodEvent e, - Collection c) { + private void processInputMethodEventImpl(InputMethodEvent e, Collection c) { for (InputMethodListener listener : c) { switch (e.getID()) { case InputMethodEvent.CARET_POSITION_CHANGED: @@ -6059,31 +5686,28 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali } } - //???AWT + // ???AWT /* - public Point getMousePosition() throws HeadlessException { - Point absPointerPos = MouseInfo.getPointerInfo().getLocation(); - Window winUnderPtr = toolkit.dispatcher.mouseDispatcher.findWindowAt(absPointerPos); - Point pointerPos = MouseDispatcher.convertPoint(null, absPointerPos, winUnderPtr); - boolean isUnderPointer = false; - if (winUnderPtr == null) { - return null; - } - isUnderPointer = winUnderPtr.isComponentAt(this, pointerPos); - if (isUnderPointer) { - return MouseDispatcher.convertPoint(null, absPointerPos, this); - } - return null; - } - */ + * public Point getMousePosition() throws HeadlessException { Point + * absPointerPos = MouseInfo.getPointerInfo().getLocation(); Window + * winUnderPtr = + * toolkit.dispatcher.mouseDispatcher.findWindowAt(absPointerPos); Point + * pointerPos = MouseDispatcher.convertPoint(null, absPointerPos, + * winUnderPtr); boolean isUnderPointer = false; if (winUnderPtr == null) { + * return null; } isUnderPointer = winUnderPtr.isComponentAt(this, + * pointerPos); if (isUnderPointer) { return + * MouseDispatcher.convertPoint(null, absPointerPos, this); } return null; } + */ /** * Set native caret at the given position
* Note: this method takes AWT lock inside because it walks through the * component hierarchy. * - * @param x the x - * @param y the y + * @param x + * the x. + * @param y + * the y. */ void setCaretPos(final int x, final int y) { Runnable r = new Runnable() { @@ -6106,35 +5730,34 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali /** * This method should be called only at event dispatch thread. * - * @param x the x - * @param y the y + * @param x + * the x. + * @param y + * the y. */ void setCaretPosImpl(int x, int y) { Component c = this; while ((c != null) && c.behaviour.isLightweight()) { x += c.x; y += c.y; - //???AWT: c = c.getParent(); + // ???AWT: c = c.getParent(); } if (c == null) { return; } - //???AWT + // ???AWT /* - if (c instanceof Window) { - Insets insets = c.getNativeInsets(); - x -= insets.left; - y -= insets.top; - } - toolkit.getWindowFactory().setCaretPosition(x, y); - */ + * if (c instanceof Window) { Insets insets = c.getNativeInsets(); x -= + * insets.left; y -= insets.top; } + * toolkit.getWindowFactory().setCaretPosition(x, y); + */ } // to be overridden in standard components such as Button and List /** * Gets the default minimum size. * - * @return the default minimum size + * @return the default minimum size. */ Dimension getDefaultMinimumSize() { return null; @@ -6144,7 +5767,7 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali /** * Gets the default preferred size. * - * @return the default preferred size + * @return the default preferred size. */ Dimension getDefaultPreferredSize() { return null; @@ -6157,30 +5780,28 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali void resetDefaultSize() { } - //???AWT + // ???AWT /* - ComponentBehavior createBehavior() { - return new LWBehavior(this); - } - */ + * ComponentBehavior createBehavior() { return new LWBehavior(this); } + */ /** * Gets the default background. * - * @return the default background + * @return the default background. */ Color getDefaultBackground() { - //???AWT: return getWindowAncestor().getDefaultBackground(); + // ???AWT: return getWindowAncestor().getDefaultBackground(); return getBackground(); } /** * Gets the default foreground. * - * @return the default foreground + * @return the default foreground. */ Color getDefaultForeground() { - //???AWT return getWindowAncestor().getDefaultForeground(); + // ???AWT return getWindowAncestor().getDefaultForeground(); return getForeground(); } @@ -6188,7 +5809,8 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali * Called when native resource for this component is created (for * heavyweights only). * - * @param win the win + * @param win + * the win. */ void nativeWindowCreated(NativeWindow win) { // to be overridden @@ -6198,48 +5820,37 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali * Determine the component's area hidden behind the windows that have higher * Z-order, including windows of other applications. * - * @param image the image - * @param destLocation the dest location - * @param destSize the dest size - * @param source the source - * - * @return the calculated region, or null if it cannot be determined - */ - //???AWT + * @param image + * the image. + * @param destLocation + * the dest location. + * @param destSize + * the dest size. + * @param source + * the source. + * @return the calculated region, or null if it cannot be determined. + */ + // ???AWT /* - MultiRectArea getObscuredRegion(Rectangle part) { - if (!visible || parent == null || !parent.visible) { - return null; - } - Rectangle r = new Rectangle(0, 0, w, h); - if (part != null) { - r = r.intersection(part); - } - if (r.isEmpty()) { - return null; - } - r.translate(x, y); - MultiRectArea ret = parent.getObscuredRegion(r); - if (ret != null) { - parent.addObscuredRegions(ret, this); - ret.translate(-x, -y); - ret.intersect(new Rectangle(0, 0, w, h)); - } - return ret; - } - */ + * MultiRectArea getObscuredRegion(Rectangle part) { if (!visible || parent + * == null || !parent.visible) { return null; } Rectangle r = new + * Rectangle(0, 0, w, h); if (part != null) { r = r.intersection(part); } if + * (r.isEmpty()) { return null; } r.translate(x, y); MultiRectArea ret = + * parent.getObscuredRegion(r); if (ret != null) { + * parent.addObscuredRegions(ret, this); ret.translate(-x, -y); + * ret.intersect(new Rectangle(0, 0, w, h)); } return ret; } + */ - //???AWT + // ???AWT /* - private void readObject(ObjectInputStream stream) throws IOException, - ClassNotFoundException { - stream.defaultReadObject(); - FieldsAccessor accessor = new FieldsAccessor(Component.class, this); - accessor.set("toolkit", Toolkit.getDefaultToolkit()); //$NON-NLS-1$ - accessor.set("behaviour", createBehavior()); //$NON-NLS-1$ - accessor.set("componentLock", new Object()); // $NON-LOCK-1$ //$NON-NLS-1$ - } - */ + * private void readObject(ObjectInputStream stream) throws IOException, + * ClassNotFoundException { stream.defaultReadObject(); FieldsAccessor + * accessor = new FieldsAccessor(Component.class, this); + * accessor.set("toolkit", Toolkit.getDefaultToolkit()); //$NON-NLS-1$ + * accessor.set("behaviour", createBehavior()); //$NON-NLS-1$ + * accessor.set("componentLock", new Object()); // $NON-LOCK-1$ + * //$NON-NLS-1$ } + */ final void onDrawImage(Image image, Point destLocation, Dimension destSize, Rectangle source) { ImageParameters imageParams; @@ -6272,33 +5883,37 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali } } - //???AWT + // ???AWT /* - private void invalidateRealParent() { - Container realParent = getRealParent(); - if ((realParent != null) && realParent.isValid()) { - realParent.invalidate(); - } - } - */ + * private void invalidateRealParent() { Container realParent = + * getRealParent(); if ((realParent != null) && realParent.isValid()) { + * realParent.invalidate(); } } + */ /** * The Class ImageParameters. */ private class ImageParameters { - - /** The drawing params. */ + + /** + * The drawing params. + */ private final LinkedList drawingParams = new LinkedList(); - /** The size. */ + /** + * The size. + */ Dimension size = new Dimension(Component.this.w, Component.this.h); /** * Adds the drawing. * - * @param destLocation the dest location - * @param destSize the dest size - * @param source the source + * @param destLocation + * the dest location. + * @param destSize + * the dest size. + * @param source + * the source. */ void addDrawing(Point destLocation, Dimension destSize, Rectangle source) { drawingParams.add(new DrawingParameters(destLocation, destSize, source)); @@ -6307,7 +5922,7 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali /** * Drawing parameters iterator. * - * @return the iterator< drawing parameters> + * @return the iterator< drawing parameters>. */ Iterator drawingParametersIterator() { return drawingParams.iterator(); @@ -6317,22 +5932,31 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali * The Class DrawingParameters. */ class DrawingParameters { - - /** The dest location. */ + + /** + * The dest location. + */ Point destLocation; - /** The dest size. */ + /** + * The dest size. + */ Dimension destSize; - /** The source. */ + /** + * The source. + */ Rectangle source; /** * Instantiates a new drawing parameters. * - * @param destLocation the dest location - * @param destSize the dest size - * @param source the source + * @param destLocation + * the dest location. + * @param destSize + * the dest size. + * @param source + * the source. */ DrawingParameters(Point destLocation, Dimension destSize, Rectangle source) { this.destLocation = new Point(destLocation); @@ -6353,44 +5977,32 @@ public abstract class Component implements ImageObserver, MenuContainer, Seriali /** * TextComponent support. * - * @param e the e - * - * @return true, if dispatch event to im + * @param e + * the e. + * @return true, if dispatch event to im. */ - //???AWT + // ???AWT /* - private TextKit textKit = null; - - TextKit getTextKit() { - return textKit; - } - - void setTextKit(TextKit kit) { - textKit = kit; - } - */ + * private TextKit textKit = null; TextKit getTextKit() { return textKit; } + * void setTextKit(TextKit kit) { textKit = kit; } + */ /** - * TextField support + * TextField support. */ - //???AWT + // ???AWT /* - private TextFieldKit textFieldKit = null; - - TextFieldKit getTextFieldKit() { - return textFieldKit; - } - - void setTextFieldKit(TextFieldKit kit) { - textFieldKit = kit; - } - */ + * private TextFieldKit textFieldKit = null; TextFieldKit getTextFieldKit() + * { return textFieldKit; } void setTextFieldKit(TextFieldKit kit) { + * textFieldKit = kit; } + */ /** - * Dispatches input & focus events to input method - * context. - * @param e event to pass to InputContext.dispatchEvent() - * @return true if event was consumed by IM, false otherwise + * Dispatches input & focus events to input method context. + * + * @param e + * event to pass to InputContext.dispatchEvent(). + * @return true if event was consumed by IM, false otherwise. */ private boolean dispatchEventToIM(AWTEvent e) { InputContext ic = getInputContext(); diff --git a/awt/java/awt/ComponentBehavior.java b/awt/java/awt/ComponentBehavior.java index 89c9999a622e21b7ca39bd51837e2e5d5a8e596a..f4e8ffbf204527ff04befe5c2404c3904f7fd822 100644 --- a/awt/java/awt/ComponentBehavior.java +++ b/awt/java/awt/ComponentBehavior.java @@ -24,7 +24,7 @@ import org.apache.harmony.awt.wtk.NativeWindow; /** * The interface of the helper object that encapsulates the difference - * between lightweight and heavyweight components. + * between lightweight and heavyweight components. */ interface ComponentBehavior { diff --git a/awt/java/awt/ComponentOrientation.java b/awt/java/awt/ComponentOrientation.java index ddb118d592d41684d79615613b84d602d7ef6b3d..5acc11a341951e9303b2f605cc4ddbddc3edfd4b 100644 --- a/awt/java/awt/ComponentOrientation.java +++ b/awt/java/awt/ComponentOrientation.java @@ -18,44 +18,59 @@ * @author Michael Danilov, Dmitry A. Durnev * @version $Revision$ */ + package java.awt; import java.io.Serializable; import java.util.*; /** - * The ComponentOrientation class specifies the language-sensitive orientation - * of component's elements or text. It is used to reflect the differences in this - * ordering between different writting systems. The ComponentOrientation class - * indicates the orientation of the elements/text in the horizontal direction - * ("left to right" or "right to left") and in the vertical direction + * The ComponentOrientation class specifies the language-sensitive orientation + * of component's elements or text. It is used to reflect the differences in + * this ordering between different writing systems. The ComponentOrientation + * class indicates the orientation of the elements/text in the horizontal + * direction ("left to right" or "right to left") and in the vertical direction * ("top to bottom" or "bottom to top"). + * + * @since Android 1.0 */ public final class ComponentOrientation implements Serializable { - - /** The Constant serialVersionUID. */ + + /** + * The Constant serialVersionUID. + */ private static final long serialVersionUID = -4113291392143563828L; - /** + /** * The Constant LEFT_TO_RIGHT indicates that items run left to right. */ public static final ComponentOrientation LEFT_TO_RIGHT = new ComponentOrientation(true, true); - /** + /** * The Constant RIGHT_TO_LEFT indicates that items run right to left. */ public static final ComponentOrientation RIGHT_TO_LEFT = new ComponentOrientation(true, false); - /** The Constant UNKNOWN indicates that a component's orientation is not set. */ + /** + * The Constant UNKNOWN indicates that a component's orientation is not set. + */ public static final ComponentOrientation UNKNOWN = new ComponentOrientation(true, true); - /** The Constant rlLangs. */ - private static final Set rlLangs = new HashSet(); //RIGHT_TO_LEFT languages + /** + * The Constant rlLangs. + */ + private static final Set rlLangs = new HashSet(); // RIGHT_TO_LEFT - /** The horizontal. */ + // languages + + /** + * The horizontal. + */ private final boolean horizontal; - /** The left2right. */ + /** + * The left2right. + */ private final boolean left2right; static { @@ -68,10 +83,9 @@ public final class ComponentOrientation implements Serializable { /** * Gets the orientation for the given ResourceBundle's localization. * - * @param bdl the ResourceBundle. - * + * @param bdl + * the ResourceBundle. * @return the ComponentOrientation. - * * @deprecated Use getOrientation(java.util.Locale) method. */ @Deprecated @@ -79,12 +93,11 @@ public final class ComponentOrientation implements Serializable { Object obj = null; try { obj = bdl.getObject("Orientation"); //$NON-NLS-1$ - } - catch (MissingResourceException mre) { + } catch (MissingResourceException mre) { obj = null; } if (obj instanceof ComponentOrientation) { - return (ComponentOrientation) obj; + return (ComponentOrientation)obj; } Locale locale = bdl.getLocale(); if (locale == null) { @@ -96,8 +109,8 @@ public final class ComponentOrientation implements Serializable { /** * Gets the orientation for the specified locale. * - * @param locale the specified Locale. - * + * @param locale + * the specified Locale. * @return the ComponentOrientation. */ public static ComponentOrientation getOrientation(Locale locale) { @@ -108,8 +121,10 @@ public final class ComponentOrientation implements Serializable { /** * Instantiates a new component orientation. * - * @param hor whether the items should be arranged horizontally - * @param l2r whether this orientation specifies a left-to-right flow + * @param hor + * whether the items should be arranged horizontally. + * @param l2r + * whether this orientation specifies a left-to-right flow. */ private ComponentOrientation(boolean hor, boolean l2r) { horizontal = hor; @@ -117,11 +132,10 @@ public final class ComponentOrientation implements Serializable { } /** - * Returns true if the text of the of writing systems arranged - * horizontally. + * Returns true if the text of the of writing systems arranged horizontally. * - * @return true, if the text is written horizontally, false - * for a vertical arrangement. + * @return true, if the text is written horizontally, false for a vertical + * arrangement. */ public boolean isHorizontal() { return horizontal; @@ -130,8 +144,8 @@ public final class ComponentOrientation implements Serializable { /** * Returns true if the text is arranged from left to right. * - * @return true, for writing systems written from left to right; - * false for right-to-left. + * @return true, for writing systems written from left to right; false for + * right-to-left. */ public boolean isLeftToRight() { return left2right; diff --git a/awt/java/awt/Composite.java b/awt/java/awt/Composite.java index 8e5b90a676b1faa36a35c9d97e5ad05c3c84d821..d1730fef4a677e97fdad492520be636266ed61fd 100644 --- a/awt/java/awt/Composite.java +++ b/awt/java/awt/Composite.java @@ -18,30 +18,34 @@ * @author Igor V. Stolyarov * @version $Revision$ */ + package java.awt; import java.awt.image.ColorModel; /** - * The Composite interface allows the methods to compose a draw primitive - * on the graphics area. The classes implementing this interface provides - * the rules and a method to create the context for a particular operation. + * The Composite interface allows the methods to compose a draw primitive on the + * graphics area. The classes implementing this interface provides the rules and + * a method to create the context for a particular operation. + * + * @since Android 1.0 */ public interface Composite { /** - * Creates a CompositeContext which defines the encapsulated and - * optimized environment for a compositing operation. Several contexts - * can exist for a single Composite object. - * - * @param srcColorModel the source's ColorModel. - * @param dstColorModel the destination's ColorModel. - * @param hints the RenderingHints. + * Creates a CompositeContext which defines the encapsulated and optimized + * environment for a compositing operation. Several contexts can exist for a + * single Composite object. * + * @param srcColorModel + * the source's ColorModel. + * @param dstColorModel + * the destination's ColorModel. + * @param hints + * the RenderingHints. * @return the CompositeContext object. */ - public CompositeContext createContext(ColorModel srcColorModel, - ColorModel dstColorModel, RenderingHints hints); + public CompositeContext createContext(ColorModel srcColorModel, ColorModel dstColorModel, + RenderingHints hints); } - diff --git a/awt/java/awt/CompositeContext.java b/awt/java/awt/CompositeContext.java index c6760325b6ad61a076c1ea26bd0a149f651b916a..795640d429a4c717a57a63556a55fadf83e46b02 100644 --- a/awt/java/awt/CompositeContext.java +++ b/awt/java/awt/CompositeContext.java @@ -18,25 +18,31 @@ * @author Igor V. Stolyarov * @version $Revision$ */ + package java.awt; import java.awt.image.Raster; import java.awt.image.WritableRaster; /** - * The CompositeContext interface specifies the encapsulated and optimized - * environment for a compositing operation. + * The CompositeContext interface specifies the encapsulated and optimized + * environment for a compositing operation. + * + * @since Android 1.0 */ public interface CompositeContext { /** - * Composes the two source Raster objects and places the result in the - * destination WritableRaster. + * Composes the two source Raster objects and places the result in the + * destination WritableRaster. * - * @param src the source Raster. - * @param dstIn the destination Raster. - * @param dstOut the WritableRaster object where the result of - * composing operation is stored. + * @param src + * the source Raster. + * @param dstIn + * the destination Raster. + * @param dstOut + * the WritableRaster object where the result of composing + * operation is stored. */ public void compose(Raster src, Raster dstIn, WritableRaster dstOut); @@ -46,4 +52,3 @@ public interface CompositeContext { public void dispose(); } - diff --git a/awt/java/awt/Cursor.java b/awt/java/awt/Cursor.java index 625686c90ab5e57ac5a66e78af157f342d2754b8..0a0cc8498722bb205485ed89f2317712fe44715d 100644 --- a/awt/java/awt/Cursor.java +++ b/awt/java/awt/Cursor.java @@ -18,6 +18,7 @@ * @author Dmitry A. Durnev * @version $Revision$ */ + package java.awt; import java.io.File; @@ -35,61 +36,99 @@ import org.apache.harmony.awt.wtk.NativeCursor; /** * The Cursor class represents the bitmap of the mouse cursor. + * + * @since Android 1.0 */ public class Cursor implements Serializable { - - /** The Constant serialVersionUID. */ + + /** + * The Constant serialVersionUID. + */ private static final long serialVersionUID = 8028237497568985504L; - - /** The Constant DEFAULT_CURSOR indicates the default cursor type. */ + + /** + * The Constant DEFAULT_CURSOR indicates the default cursor type. + */ public static final int DEFAULT_CURSOR = 0; - /** The Constant CROSSHAIR_CURSOR cursor type. */ + /** + * The Constant CROSSHAIR_CURSOR cursor type. + */ public static final int CROSSHAIR_CURSOR = 1; - /** The Constant TEXT_CURSOR cursor type. */ + /** + * The Constant TEXT_CURSOR cursor type. + */ public static final int TEXT_CURSOR = 2; - /** The Constant WAIT_CURSOR cursor type. */ + /** + * The Constant WAIT_CURSOR cursor type. + */ public static final int WAIT_CURSOR = 3; - /** The Constant SW_RESIZE_CURSOR cursor type. */ + /** + * The Constant SW_RESIZE_CURSOR cursor type. + */ public static final int SW_RESIZE_CURSOR = 4; - /** The Constant SE_RESIZE_CURSOR cursor type. */ + /** + * The Constant SE_RESIZE_CURSOR cursor type. + */ public static final int SE_RESIZE_CURSOR = 5; - /** The Constant NW_RESIZE_CURSOR cursor type. */ + /** + * The Constant NW_RESIZE_CURSOR cursor type. + */ public static final int NW_RESIZE_CURSOR = 6; - /** The Constant NE_RESIZE_CURSOR cursor type. */ + /** + * The Constant NE_RESIZE_CURSOR cursor type. + */ public static final int NE_RESIZE_CURSOR = 7; - /** The Constant N_RESIZE_CURSOR cursor type. */ + /** + * The Constant N_RESIZE_CURSOR cursor type. + */ public static final int N_RESIZE_CURSOR = 8; - /** The Constant S_RESIZE_CURSOR cursor type. */ + /** + * The Constant S_RESIZE_CURSOR cursor type. + */ public static final int S_RESIZE_CURSOR = 9; - /** The Constant W_RESIZE_CURSOR cursor type. */ + /** + * The Constant W_RESIZE_CURSOR cursor type. + */ public static final int W_RESIZE_CURSOR = 10; - /** The Constant E_RESIZE_CURSOR cursor type. */ + /** + * The Constant E_RESIZE_CURSOR cursor type. + */ public static final int E_RESIZE_CURSOR = 11; - /** The Constant HAND_CURSOR cursor type. */ + /** + * The Constant HAND_CURSOR cursor type. + */ public static final int HAND_CURSOR = 12; - /** The Constant MOVE_CURSOR cursor type. */ + /** + * The Constant MOVE_CURSOR cursor type. + */ public static final int MOVE_CURSOR = 13; - /** A mapping from names to system custom cursors. */ + /** + * A mapping from names to system custom cursors. + */ static Map systemCustomCursors; - - /** The cursor props. */ + + /** + * The cursor props. + */ static Properties cursorProps; - /** The Constant predefinedNames. */ + /** + * The Constant predefinedNames. + */ static final String[] predefinedNames = { "Default", "Crosshair", "Text", "Wait", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ "Southwest Resize", "Southeast Resize", //$NON-NLS-1$ //$NON-NLS-2$ @@ -99,41 +138,52 @@ public class Cursor implements Serializable { }; - /** The predefined set of cursors. */ + /** + * The predefined set of cursors. + */ protected static Cursor[] predefined = { - new Cursor(DEFAULT_CURSOR), null, null, null, - null, null, null, null, - null, null, null, null, - null, null + new Cursor(DEFAULT_CURSOR), null, null, null, null, null, null, null, null, null, null, + null, null, null }; - /** The Constant CUSTOM_CURSOR is associated with all custom cursor types. + /** + * The Constant CUSTOM_CURSOR is associated with all custom cursor types. * (Those which are not predefined) */ public static final int CUSTOM_CURSOR = -1; - /** The name of the cursor. */ + /** + * The name of the cursor. + */ protected String name; - /** The type of the cursor, chosen from the list of cursor type constants. */ + /** + * The type of the cursor, chosen from the list of cursor type constants. + */ private final int type; - - /** The native cursor. */ + + /** + * The native cursor. + */ private transient NativeCursor nativeCursor; - - /** The exact point on the cursor image that indicates which point - * the cursor is selecting (pointing to). The coordinates are given - * with respect the origin of the Image (its upper left corner). + + /** + * The exact point on the cursor image that indicates which point the cursor + * is selecting (pointing to). The coordinates are given with respect the + * origin of the Image (its upper left corner). */ private Point hotSpot; - - /** The image to draw on the screen representing the cursor. */ + + /** + * The image to draw on the screen representing the cursor. + */ private Image image; /** * Instantiates a new cursor with the specified name. * - * @param name the name of cursor. + * @param name + * the name of cursor. */ protected Cursor(String name) { this(name, null, new Point()); @@ -142,7 +192,8 @@ public class Cursor implements Serializable { /** * Instantiates a new cursor of the specified type. * - * @param type the type of cursor. + * @param type + * the type of cursor. */ public Cursor(int type) { checkType(type); @@ -155,9 +206,12 @@ public class Cursor implements Serializable { /** * Instantiates a new cursor. * - * @param name the name - * @param img the img - * @param hotSpot the hot spot + * @param name + * the name. + * @param img + * the img. + * @param hotSpot + * the hot spot. */ Cursor(String name, Image img, Point hotSpot) { this.name = name; @@ -167,10 +221,11 @@ public class Cursor implements Serializable { } /** - * Finalize method overrided finalize method from Object class. + * Finalize method overrides the finalize method from Object class. * - * @throws Throwable if the native cursor is not null and throws - * a throwable when destroyed. + * @throws Throwable + * if the native cursor is not null and throws a Throwable when + * destroyed. */ @Override protected void finalize() throws Throwable { @@ -201,7 +256,7 @@ public class Cursor implements Serializable { /** * Gets the cursor type. * - * @return the cursor type + * @return the cursor type. */ public int getType() { return type; @@ -210,8 +265,8 @@ public class Cursor implements Serializable { /** * Gets the predefined cursor with the specified type. * - * @param type the type of cursor. - * + * @param type + * the type of cursor. * @return the predefined cursor with the specified type. */ public static Cursor getPredefinedCursor(int type) { @@ -236,33 +291,33 @@ public class Cursor implements Serializable { /** * Gets the specified system custom cursor. * - * @param name the name of the desired system cursor. - * + * @param name + * the name of the desired system cursor. * @return the specific system cursor with the specified name. - * - * @throws AWTException if the desired cursor has malformed data - * such as an incorrectly defined hot spot. - * @throws HeadlessException if the isHeadless method of the GraphicsEnvironment - * returns true. + * @throws AWTException + * if the desired cursor has malformed data such as an + * incorrectly defined hot spot. + * @throws HeadlessException + * if the isHeadless method of the GraphicsEnvironment returns + * true. */ - public static Cursor getSystemCustomCursor(String name) - throws AWTException, HeadlessException { + public static Cursor getSystemCustomCursor(String name) throws AWTException, HeadlessException { Toolkit.checkHeadless(); return getSystemCustomCursorFromMap(name); } /** - * Gets the specified system custom cursor from the map of system custom cursors. + * Gets the specified system custom cursor from the map of system custom + * cursors. * - * @param name the name of the desired cursor. - * - * @return the desired system custom cursor from the - * map of system custom cursors. - * - * @throws AWTException the AWT exception + * @param name + * the name of the desired cursor. + * @return the desired system custom cursor from the map of system custom + * cursors. + * @throws AWTException + * the AWT exception. */ - private static Cursor getSystemCustomCursorFromMap (String name) - throws AWTException { + private static Cursor getSystemCustomCursorFromMap(String name) throws AWTException { loadCursorProps(); if (systemCustomCursors == null) { systemCustomCursors = new HashMap(); @@ -284,8 +339,7 @@ public class Cursor implements Serializable { int x, y; try { x = new Integer(hotSpotStr.substring(0, idx)).intValue(); - y = new Integer(hotSpotStr.substring(idx + 1, - hotSpotStr.length())).intValue(); + y = new Integer(hotSpotStr.substring(idx + 1, hotSpotStr.length())).intValue(); } catch (NumberFormatException nfe) { throw new AWTException(exMsg); } @@ -299,7 +353,8 @@ public class Cursor implements Serializable { /** * Load cursor props. * - * @throws AWTException the AWT exception + * @throws AWTException + * the AWT exception. */ private static void loadCursorProps() throws AWTException { if (cursorProps != null) { @@ -308,18 +363,18 @@ public class Cursor implements Serializable { String sep = File.separator; String cursorsDir = "lib" + sep + "images" + sep + "cursors"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ String cursorsAbsDir = System.getProperty("java.home") + sep + //$NON-NLS-1$ - cursorsDir; + cursorsDir; String cursorPropsFileName = "cursors.properties"; //$NON-NLS-1$ - String cursorPropsFullFileName = (cursorsAbsDir + sep + - cursorPropsFileName); + String cursorPropsFullFileName = (cursorsAbsDir + sep + cursorPropsFileName); cursorProps = new Properties(); try { - cursorProps.load(new FileInputStream(new File( - cursorPropsFullFileName))); + cursorProps.load(new FileInputStream(new File(cursorPropsFullFileName))); } catch (FileNotFoundException e) { // awt.142=Exception: class {0} {1} occurred while loading: {2} throw new AWTException(Messages.getString("awt.142",//$NON-NLS-1$ - new Object[]{e.getClass(), e.getMessage(), cursorPropsFullFileName})); + new Object[] { + e.getClass(), e.getMessage(), cursorPropsFullFileName + })); } catch (IOException e) { throw new AWTException(e.getMessage()); } @@ -329,7 +384,8 @@ public class Cursor implements Serializable { /** * Check type. * - * @param type the type + * @param type + * the type. */ static void checkType(int type) { // can't use predefined array here because it may not have been @@ -344,7 +400,7 @@ public class Cursor implements Serializable { /** * Gets the native cursor. * - * @return the native cursor + * @return the native cursor. */ NativeCursor getNativeCursor() { if (nativeCursor != null) { @@ -354,8 +410,7 @@ public class Cursor implements Serializable { if (type != CUSTOM_CURSOR) { nativeCursor = toolkit.createNativeCursor(type); } else { - nativeCursor = toolkit.createCustomNativeCursor(image, hotSpot, - name); + nativeCursor = toolkit.createCustomNativeCursor(image, hotSpot, name); } return nativeCursor; } @@ -363,10 +418,10 @@ public class Cursor implements Serializable { /** * Sets the native cursor. * - * @param nativeCursor the new native cursor + * @param nativeCursor + * the new native cursor. */ void setNativeCursor(NativeCursor nativeCursor) { this.nativeCursor = nativeCursor; } } - diff --git a/awt/java/awt/Dimension.java b/awt/java/awt/Dimension.java index 8137846018d2dba5a1d05cb8563b691f172424f1..6777962e7a37a739e4d0c4bb0be0b7a15595d79e 100644 --- a/awt/java/awt/Dimension.java +++ b/awt/java/awt/Dimension.java @@ -18,6 +18,7 @@ * @author Denis M. Kishenko * @version $Revision$ */ + package java.awt; import java.awt.geom.Dimension2D; @@ -26,26 +27,36 @@ import java.io.Serializable; import org.apache.harmony.misc.HashCode; /** - * The Dimension represents the size (width and height) of a component. - * The width and height values can be negative, but in that case the - * behavior of some methods is unexpected. + * The Dimension represents the size (width and height) of a component. The + * width and height values can be negative, but in that case the behavior of + * some methods is unexpected. + * + * @since Android 1.0 */ public class Dimension extends Dimension2D implements Serializable { - /** The Constant serialVersionUID. */ + /** + * The Constant serialVersionUID. + */ private static final long serialVersionUID = 4723952579491349524L; - /** The width dimension. */ + /** + * The width dimension. + */ public int width; - - /** The height dimension. */ + + /** + * The height dimension. + */ public int height; /** - * Instantiates a new Dimension with the same data as the specified Dimension. + * Instantiates a new Dimension with the same data as the specified + * Dimension. * - * @param d the Dimension to copy the data from when creating the - * new Dimension object. + * @param d + * the Dimension to copy the data from when creating the new + * Dimension object. */ public Dimension(Dimension d) { this(d.width, d.height); @@ -61,8 +72,10 @@ public class Dimension extends Dimension2D implements Serializable { /** * Instantiates a new Dimension with the specified width and height. * - * @param width the width of the new Dimension. - * @param height the height of the new Dimension. + * @param width + * the width of the new Dimension. + * @param height + * the height of the new Dimension. */ public Dimension(int width, int height) { setSize(width, height); @@ -84,10 +97,10 @@ public class Dimension extends Dimension2D implements Serializable { /** * Compares this Dimension object with the specified object. * - * @param obj the Object to be compared. - * - * @return true, if the specified Object is a Dimension with - * the same width and height data as this Dimension. + * @param obj + * the Object to be compared. + * @return true, if the specified Object is a Dimension with the same width + * and height data as this Dimension. */ @Override public boolean equals(Object obj) { @@ -108,16 +121,20 @@ public class Dimension extends Dimension2D implements Serializable { */ @Override public String toString() { - // The output format based on 1.5 release behaviour. It could be obtained in the following way + // The output format based on 1.5 release behaviour. It could be + // obtained in the following way // System.out.println(new Dimension().toString()) return getClass().getName() + "[width=" + width + ",height=" + height + "]"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ } /** - * Sets the size of this Dimension object with the specified width and height. + * Sets the size of this Dimension object with the specified width and + * height. * - * @param width the width of the Dimension. - * @param height the height of the Dimension. + * @param width + * the width of the Dimension. + * @param height + * the height of the Dimension. */ public void setSize(int width, int height) { this.width = width; @@ -125,22 +142,24 @@ public class Dimension extends Dimension2D implements Serializable { } /** - * Sets the size of this Dimension object by copying the - * data from the specified Dimension object. + * Sets the size of this Dimension object by copying the data from the + * specified Dimension object. * - * @param d the Dimension that gives the new size values. + * @param d + * the Dimension that gives the new size values. */ public void setSize(Dimension d) { setSize(d.width, d.height); } /** - * Sets the size of this Dimension object with the specified double width + * Sets the size of this Dimension object with the specified double width * and height. * - * @param width the width of the Dimension. - * @param height the height of the Dimension. - * + * @param width + * the width of the Dimension. + * @param height + * the height of the Dimension. * @see java.awt.geom.Dimension2D#setSize(double, double) */ @Override @@ -161,7 +180,6 @@ public class Dimension extends Dimension2D implements Serializable { * Gets the height of the Dimension. * * @return the height of the Dimension. - * * @see java.awt.geom.Dimension2D#getHeight() */ @Override @@ -173,7 +191,6 @@ public class Dimension extends Dimension2D implements Serializable { * Gets the width of the Dimension. * * @return the width of the Dimension. - * * @see java.awt.geom.Dimension2D#getWidth() */ @Override @@ -182,4 +199,3 @@ public class Dimension extends Dimension2D implements Serializable { } } - diff --git a/awt/java/awt/DisplayMode.java b/awt/java/awt/DisplayMode.java index 082c7b8aeaa580663272d5712602e79f55bd36d4..8021010198f4591804e9aedd684ce7aadf717272 100644 --- a/awt/java/awt/DisplayMode.java +++ b/awt/java/awt/DisplayMode.java @@ -18,41 +18,60 @@ * @author Alexey A. Petrenko * @version $Revision$ */ + package java.awt; /** - * The DisplayMode class containes the bit depth, height, width and - * refresh rate of a GraphicsDevice. + * The DisplayMode class contains the bit depth, height, width and refresh rate + * of a GraphicsDevice. + * + * @since Android 1.0 */ public final class DisplayMode { - - /** The width. */ + + /** + * The width. + */ private final int width; - /** The height. */ + /** + * The height. + */ private final int height; - /** The bit depth. */ + /** + * The bit depth. + */ private final int bitDepth; - /** The refresh rate. */ + /** + * The refresh rate. + */ private final int refreshRate; - /** The Constant Value BIT_DEPTH_MULTI indicates the bit depth */ + /** + * The Constant Value BIT_DEPTH_MULTI indicates the bit depth + */ public static final int BIT_DEPTH_MULTI = -1; - /** The Constant REFRESH_RATE_UNKNOWN indicates the refresh rate. */ + /** + * The Constant REFRESH_RATE_UNKNOWN indicates the refresh rate. + */ public static final int REFRESH_RATE_UNKNOWN = 0; - /** - * Creates a new DisplayMode object with the specified parameters. - * - * @param width the width of the display. - * @param height the height of the display. - * @param bitDepth the bit depth of the display. - * @param refreshRate the refresh rate of the display. - */ + /** + * Creates a new DisplayMode object with the specified parameters. + * + * @param width + * the width of the display. + * @param height + * the height of the display. + * @param bitDepth + * the bit depth of the display. + * @param refreshRate + * the refresh rate of the display. + */ public DisplayMode(int width, int height, int bitDepth, int refreshRate) { this.width = width; @@ -61,15 +80,14 @@ public final class DisplayMode { this.refreshRate = refreshRate; } - - /** - * Compares if this DisplayMode is equal to the specified object or not. - * - * @param dm the Object to be compared. - * - * @return true, if the specified object is a DisplayMode with the same - * data values as this DisplayMode, false otherwise. - */ + /** + * Compares if this DisplayMode is equal to the specified object or not. + * + * @param dm + * the Object to be compared. + * @return true, if the specified object is a DisplayMode with the same data + * values as this DisplayMode, false otherwise. + */ @Override public boolean equals(Object dm) { @@ -80,13 +98,13 @@ public final class DisplayMode { } /** - * Compares if this DisplayMode is equal to the specified DisplayMode object - * or not. - * - * @param dm the DisplayMode to be compared. - * - * @return true, if all of the data values of this DisplayMode are equal - * to the values of the specified DisplayMode object, false otherwise. + * Compares if this DisplayMode is equal to the specified DisplayMode object + * or not. + * + * @param dm + * the DisplayMode to be compared. + * @return true, if all of the data values of this DisplayMode are equal to + * the values of the specified DisplayMode object, false otherwise. */ public boolean equals(DisplayMode dm) { if (dm == null) { @@ -108,8 +126,8 @@ public final class DisplayMode { } /** - * Gets the bit depth of the DisplayMode, returns BIT_DEPTH_MULTI value - * if multiple bit depths are supported in this display mode. + * Gets the bit depth of the DisplayMode, returns BIT_DEPTH_MULTI value if + * multiple bit depths are supported in this display mode. * * @return the bit depth of the DisplayMode. */ diff --git a/awt/java/awt/Event.java b/awt/java/awt/Event.java index f074258db7f48cf251b8297f40fc8f0a6048f5ed..226a61fffed33c8fc4873f8d5b05feeb8294a18f 100644 --- a/awt/java/awt/Event.java +++ b/awt/java/awt/Event.java @@ -18,224 +18,293 @@ * @author Dmitry A. Durnev * @version $Revision$ */ + package java.awt; import java.io.Serializable; /** - * The Event Class is obsolete and has been replaced by AWTEvent class. + * The Event class is obsolete and has been replaced by AWTEvent class. * + * @since Android 1.0 */ public class Event implements Serializable { - - /** The Constant serialVersionUID. */ + + /** + * The Constant serialVersionUID. + */ private static final long serialVersionUID = 5488922509400504703L; - - /** - * The Constant SHIFT_MASK indicates that the Shift key is down when - * the event occurred. + + /** + * The Constant SHIFT_MASK indicates that the Shift key is down when the + * event occurred. */ public static final int SHIFT_MASK = 1; - /** - * The Constant CTRL_MASK indicates that the Control key is down when - * the event occurred. + /** + * The Constant CTRL_MASK indicates that the Control key is down when the + * event occurred. */ public static final int CTRL_MASK = 2; - /** The Constant META_MASK indicates that the Meta key is down when t - * he event occurred (or the right mouse button). */ + /** + * The Constant META_MASK indicates that the Meta key is down when t he + * event occurred (or the right mouse button). + */ public static final int META_MASK = 4; - /** - * The Constant ALT_MASK indicates that the Alt key is down when - * the event occurred (or the middle mouse button). + /** + * The Constant ALT_MASK indicates that the Alt key is down when the event + * occurred (or the middle mouse button). */ public static final int ALT_MASK = 8; - /** The Constant HOME indicates Home key. */ + /** + * The Constant HOME indicates Home key. + */ public static final int HOME = 1000; - /** The Constant END indicates End key. */ + /** + * The Constant END indicates End key. + */ public static final int END = 1001; - /** The Constant PGUP indicates Page Up key. */ + /** + * The Constant PGUP indicates Page Up key. + */ public static final int PGUP = 1002; - /** The Constant PGDN indicates Page Down key. */ + /** + * The Constant PGDN indicates Page Down key. + */ public static final int PGDN = 1003; - /** The Constant UP indicates Up key. */ + /** + * The Constant UP indicates Up key. + */ public static final int UP = 1004; - /** The Constant DOWN indicates Down key. */ + /** + * The Constant DOWN indicates Down key. + */ public static final int DOWN = 1005; - /** The Constant LEFT indicates Left key. */ + /** + * The Constant LEFT indicates Left key. + */ public static final int LEFT = 1006; - /** The Constant RIGHT indicates Right key. */ + /** + * The Constant RIGHT indicates Right key. + */ public static final int RIGHT = 1007; - /** The Constant F1 indicates F1 key. */ + /** + * The Constant F1 indicates F1 key. + */ public static final int F1 = 1008; - /** The Constant F2 indicates F2 key. */ + /** + * The Constant F2 indicates F2 key. + */ public static final int F2 = 1009; - /** The Constant F3 indicates F3 key. */ + /** + * The Constant F3 indicates F3 key. + */ public static final int F3 = 1010; - /** The Constant F4 indicates F4 key. */ + /** + * The Constant F4 indicates F4 key. + */ public static final int F4 = 1011; - /** The Constant F5 indicates F5 key. */ + /** + * The Constant F5 indicates F5 key. + */ public static final int F5 = 1012; - /** The Constant F6 indicates F6 key. */ + /** + * The Constant F6 indicates F6 key. + */ public static final int F6 = 1013; - /** The Constant F7 indicates F7 key. */ + /** + * The Constant F7 indicates F7 key. + */ public static final int F7 = 1014; - /** The Constant F8 indicates F8 key. */ + /** + * The Constant F8 indicates F8 key. + */ public static final int F8 = 1015; - /** The Constant F9 indicates F9 key. */ + /** + * The Constant F9 indicates F9 key. + */ public static final int F9 = 1016; - /** The Constant F10 indicates F10 key. */ + /** + * The Constant F10 indicates F10 key. + */ public static final int F10 = 1017; - /** The Constant F11 indicates F11 key. */ + /** + * The Constant F11 indicates F11 key. + */ public static final int F11 = 1018; - /** The Constant F12 indicates F12 key. */ + /** + * The Constant F12 indicates F12 key. + */ public static final int F12 = 1019; - /** The Constant PRINT_SCREEN indicates Print Screen key. */ + /** + * The Constant PRINT_SCREEN indicates Print Screen key. + */ public static final int PRINT_SCREEN = 1020; - /** The Constant SCROLL_LOCK indicates Scroll Lock key. */ + /** + * The Constant SCROLL_LOCK indicates Scroll Lock key. + */ public static final int SCROLL_LOCK = 1021; - /** The Constant CAPS_LOCK indicates Caps Lock key. */ + /** + * The Constant CAPS_LOCK indicates Caps Lock key. + */ public static final int CAPS_LOCK = 1022; - /** The Constant NUM_LOCK indicates Num Lock key. */ + /** + * The Constant NUM_LOCK indicates Num Lock key. + */ public static final int NUM_LOCK = 1023; - /** The Constant PAUSE indicates Pause key. */ + /** + * The Constant PAUSE indicates Pause key. + */ public static final int PAUSE = 1024; - /** The Constant INSERT indicates Insert key. */ + /** + * The Constant INSERT indicates Insert key. + */ public static final int INSERT = 1025; - /** The Constant ENTER indicates Enter key. */ + /** + * The Constant ENTER indicates Enter key. + */ public static final int ENTER = 10; - /** The Constant BACK_SPACE indicates Back Space key. */ + /** + * The Constant BACK_SPACE indicates Back Space key. + */ public static final int BACK_SPACE = 8; - /** The Constant TAB indicates TAb key. */ + /** + * The Constant TAB indicates TAb key. + */ public static final int TAB = 9; - /** The Constant ESCAPE indicates Escape key. */ + /** + * The Constant ESCAPE indicates Escape key. + */ public static final int ESCAPE = 27; - /** The Constant DELETE indicates Delete key. */ + /** + * The Constant DELETE indicates Delete key. + */ public static final int DELETE = 127; - /** - * The Constant WINDOW_DESTROY indicates an event when the user has asked the - * window manager to kill the window. + /** + * The Constant WINDOW_DESTROY indicates an event when the user has asked + * the window manager to kill the window. */ public static final int WINDOW_DESTROY = 201; - /** + /** * The Constant WINDOW_EXPOSE indicates an event when the user has asked the * window manager to expose the window. */ public static final int WINDOW_EXPOSE = 202; - /** - * The Constant WINDOW_ICONIFY indicates an event when the user has asked the - * window manager to inconify the window. + /** + * The Constant WINDOW_ICONIFY indicates an event when the user has asked + * the window manager to iconify the window. */ public static final int WINDOW_ICONIFY = 203; - /** - * The Constant WINDOW_DEICONIFY indicates an event when the user has asked the - * window manager to deinconify the window. + /** + * The Constant WINDOW_DEICONIFY indicates an event when the user has asked + * the window manager to deiconify the window. */ public static final int WINDOW_DEICONIFY = 204; - /** + /** * The Constant WINDOW_MOVED indicates an event when the user has asked the - * window manager to move the window. + * window manager to move the window. */ public static final int WINDOW_MOVED = 205; - /** - * The Constant KEY_PRESS indicates an event when the user presses - * a normal key. + /** + * The Constant KEY_PRESS indicates an event when the user presses a normal + * key. */ public static final int KEY_PRESS = 401; - /** - * The Constant KEY_RELEASE indicates an event when the user releases - * a normal key. + /** + * The Constant KEY_RELEASE indicates an event when the user releases a + * normal key. */ public static final int KEY_RELEASE = 402; - /** - * The Constant KEY_ACTION indicates an event when the user pressed - * a non-ASCII action key. + /** + * The Constant KEY_ACTION indicates an event when the user pressed a + * non-ASCII action key. */ public static final int KEY_ACTION = 403; /** - * The Constant KEY_ACTION_RELEASE indicates an event when the user released - * a non-ASCII action key. + * The Constant KEY_ACTION_RELEASE indicates an event when the user released + * a non-ASCII action key. */ public static final int KEY_ACTION_RELEASE = 404; - /** - * The Constant MOUSE_DOWN indicates an event when the user has pressed - * the mouse button. + /** + * The Constant MOUSE_DOWN indicates an event when the user has pressed the + * mouse button. */ public static final int MOUSE_DOWN = 501; - /** - * The Constant MOUSE_UP indicates an event when the user has released - * the mouse button. + /** + * The Constant MOUSE_UP indicates an event when the user has released the + * mouse button. */ public static final int MOUSE_UP = 502; - /** - * The Constant MOUSE_MOVE indicates an event when the user has moved - * the mouse with no button pressed. + /** + * The Constant MOUSE_MOVE indicates an event when the user has moved the + * mouse with no button pressed. */ public static final int MOUSE_MOVE = 503; - /** - * The Constant MOUSE_ENTER indicates an event when the mouse - * has entered a component. + /** + * The Constant MOUSE_ENTER indicates an event when the mouse has entered a + * component. */ public static final int MOUSE_ENTER = 504; - /** - * The Constant MOUSE_EXIT indicates an event when the mouse - * has exited a component. + /** + * The Constant MOUSE_EXIT indicates an event when the mouse has exited a + * component. */ public static final int MOUSE_EXIT = 505; - /** The Constant MOUSE_DRAG indicates an event when the user - * has moved a mouse with the pressed button. + /** + * The Constant MOUSE_DRAG indicates an event when the user has moved a + * mouse with the pressed button. */ public static final int MOUSE_DRAG = 506; - /** + /** * The Constant SCROLL_LINE_UP indicates an event when the user has * activated line-up area of scrollbar. */ @@ -243,101 +312,136 @@ public class Event implements Serializable { /** * The Constant SCROLL_LINE_DOWN indicates an event when the user has - * activated line-down area of scrollbar. + * activated line-down area of scrollbar. */ public static final int SCROLL_LINE_DOWN = 602; /** * The Constant SCROLL_PAGE_UP indicates an event when the user has - * activated page up area of scrollbar. + * activated page up area of scrollbar. */ public static final int SCROLL_PAGE_UP = 603; /** * The Constant SCROLL_PAGE_DOWN indicates an event when the user has - * activated page down area of scrollbar. + * activated page down area of scrollbar. */ public static final int SCROLL_PAGE_DOWN = 604; /** - * The Constant SCROLL_ABSOLUTE indicates an event when the user - * has moved the bubble in a scroll bar. + * The Constant SCROLL_ABSOLUTE indicates an event when the user has moved + * the bubble in a scroll bar. */ public static final int SCROLL_ABSOLUTE = 605; - /** The Constant SCROLL_BEGIN indicates a scroll begin event. */ + /** + * The Constant SCROLL_BEGIN indicates a scroll begin event. + */ public static final int SCROLL_BEGIN = 606; - /** The Constant SCROLL_END indicates a scroll end event. */ + /** + * The Constant SCROLL_END indicates a scroll end event. + */ public static final int SCROLL_END = 607; - /** - * The Constant LIST_SELECT indicates that an item in a list - * has been selected. + /** + * The Constant LIST_SELECT indicates that an item in a list has been + * selected. */ public static final int LIST_SELECT = 701; - /** - * The Constant LIST_DESELECT indicates that an item in a list - * has been deselected. + /** + * The Constant LIST_DESELECT indicates that an item in a list has been + * unselected. */ public static final int LIST_DESELECT = 702; - /** - * The Constant ACTION_EVENT indicates that the user wants some - * action to occur. + /** + * The Constant ACTION_EVENT indicates that the user wants some action to + * occur. */ public static final int ACTION_EVENT = 1001; - /** The Constant LOAD_FILE indicates a file loading event. */ + /** + * The Constant LOAD_FILE indicates a file loading event. + */ public static final int LOAD_FILE = 1002; - /** The Constant SAVE_FILE indicates a file saving event. */ + /** + * The Constant SAVE_FILE indicates a file saving event. + */ public static final int SAVE_FILE = 1003; - /** The Constant GOT_FOCUS indicates that a component got the focus. */ + /** + * The Constant GOT_FOCUS indicates that a component got the focus. + */ public static final int GOT_FOCUS = 1004; - /** The Constant LOST_FOCUS indicates that the component lost the focus. */ + /** + * The Constant LOST_FOCUS indicates that the component lost the focus. + */ public static final int LOST_FOCUS = 1005; - /** The target is the component with which the event is associated. */ + /** + * The target is the component with which the event is associated. + */ public Object target; - /** The when is timestamp when event has occured. */ + /** + * The when is timestamp when event has occured. + */ public long when; - /** The id indicates the type of the event. */ + /** + * The id indicates the type of the event. + */ public int id; - /** The x coordinate of event. */ + /** + * The x coordinate of event. + */ public int x; - /** The y coordinate of event. */ + /** + * The y coordinate of event. + */ public int y; - /** The key code of key event. */ + /** + * The key code of key event. + */ public int key; - /** The state of the modifier keys (given by a bitmask). */ + /** + * The state of the modifier keys (given by a bitmask). + */ public int modifiers; - /** The click count indicates the number of consecutive clicks. */ + /** + * The click count indicates the number of consecutive clicks. + */ public int clickCount; - /** The argument of the event. */ + /** + * The argument of the event. + */ public Object arg; - /** The next event. */ + /** + * The next event. + */ public Event evt; /** - * Instantiates a new event with the specified target component, - * event type, and argument. + * Instantiates a new event with the specified target component, event type, + * and argument. * - * @param target the target component. - * @param id the event type. - * @param arg the argument. + * @param target + * the target component. + * @param id + * the event type. + * @param arg + * the argument. */ public Event(Object target, int id, Object arg) { this(target, 0l, id, 0, 0, 0, 0, arg); @@ -348,13 +452,20 @@ public class Event implements Serializable { * event type, x and y coordinates, keyboard key, state of the modifier * keys, and an argument set to null. * - * @param target the target component. - * @param when the time stamp. - * @param id the event type. - * @param x the x coordinate. - * @param y the y coordinate. - * @param key the key. - * @param modifiers the modifier keys state. + * @param target + * the target component. + * @param when + * the time stamp. + * @param id + * the event type. + * @param x + * the x coordinate. + * @param y + * the y coordinate. + * @param key + * the key. + * @param modifiers + * the modifier keys state. */ public Event(Object target, long when, int id, int x, int y, int key, int modifiers) { this(target, when, id, x, y, key, modifiers, null); @@ -365,14 +476,22 @@ public class Event implements Serializable { * event type, x and y coordinates, keyboard key, state of the modifier * keys, and an argument. * - * @param target the target component. - * @param when the time stamp. - * @param id the event type. - * @param x the x coordinate. - * @param y the y coordinate. - * @param key the key. - * @param modifiers the modifier keys state. - * @param arg the specified argument. + * @param target + * the target component. + * @param when + * the time stamp. + * @param id + * the event type. + * @param x + * the x coordinate. + * @param y + * the y coordinate. + * @param key + * the key. + * @param modifiers + * the modifier keys state. + * @param arg + * the specified argument. */ public Event(Object target, long when, int id, int x, int y, int key, int modifiers, Object arg) { this.target = target; @@ -392,11 +511,10 @@ public class Event implements Serializable { */ @Override public String toString() { - /* The format is based on 1.5 release behavior - * which can be revealed by the following code: - * - * Event e = new Event(new Button(), 0l, Event.KEY_PRESS, - * 0, 0, Event.TAB, Event.SHIFT_MASK, "arg"); + /* + * The format is based on 1.5 release behavior which can be revealed by + * the following code: Event e = new Event(new Button(), 0l, + * Event.KEY_PRESS, 0, 0, Event.TAB, Event.SHIFT_MASK, "arg"); * System.out.println(e); */ @@ -410,15 +528,15 @@ public class Event implements Serializable { */ protected String paramString() { return "id=" + id + ",x=" + x + ",y=" + y + //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ - (key != 0 ? ",key=" + key + getModifiersString() : "") + //$NON-NLS-1$ //$NON-NLS-2$ - ",target=" + target + //$NON-NLS-1$ - (arg != null ? ",arg=" + arg : ""); //$NON-NLS-1$ //$NON-NLS-2$ + (key != 0 ? ",key=" + key + getModifiersString() : "") + //$NON-NLS-1$ //$NON-NLS-2$ + ",target=" + target + //$NON-NLS-1$ + (arg != null ? ",arg=" + arg : ""); //$NON-NLS-1$ //$NON-NLS-2$ } /** * Gets a string representation of the modifiers. * - * @return a string representation of the modifiers + * @return a string representation of the modifiers. */ private String getModifiersString() { String strMod = ""; //$NON-NLS-1$ @@ -435,13 +553,13 @@ public class Event implements Serializable { } /** - * Translates x and y coordinates of his event to the x+dx and x+dy + * Translates x and y coordinates of his event to the x+dx and x+dy * coordinates. * - * @param dx the dx - the distance by which the event's x coordinate - * is increased - * @param dy the dy - the distance by which the event's y coordinate - * is increased + * @param dx + * the distance by which the event's x coordinate is increased. + * @param dy + * the distance by which the event's y coordinate is increased. */ public void translate(int dx, int dy) { x += dx; @@ -476,4 +594,3 @@ public class Event implements Serializable { } } - diff --git a/awt/java/awt/EventQueue.java b/awt/java/awt/EventQueue.java index 3997546190c902900a78923e456b85117e5069fc..126a593061ed490d2038375e1e9db3d3eccb3a14 100644 --- a/awt/java/awt/EventQueue.java +++ b/awt/java/awt/EventQueue.java @@ -18,6 +18,7 @@ * @author Michael Danilov, Pavel Dolgov * @version $Revision$ */ + package java.awt; import java.awt.event.InvocationEvent; @@ -25,60 +26,69 @@ import java.lang.reflect.InvocationTargetException; import java.util.EmptyStackException; /** - * The EventQueue class manages events. It is a platform-independent class - * that queues events both from the underlying peer classes and from trusted + * The EventQueue class manages events. It is a platform-independent class that + * queues events both from the underlying peer classes and from trusted * application classes. + * + * @since Android 1.0 */ public class EventQueue { - - /** The core ref. */ - private final EventQueueCoreAtomicReference coreRef = - new EventQueueCoreAtomicReference(); - + + /** + * The core ref. + */ + private final EventQueueCoreAtomicReference coreRef = new EventQueueCoreAtomicReference(); + /** * The Class EventQueueCoreAtomicReference. */ private static final class EventQueueCoreAtomicReference { - - /** The core. */ + + /** + * The core. + */ private EventQueueCore core; - /*synchronized*/ /** + /* synchronized */ + /** * Gets the. * - * @return the event queue core + * @return the event queue core. */ - EventQueueCore get() { + EventQueueCore get() { return core; } - /*synchronized*/ /** + /* synchronized */ + /** * Sets the. * - * @param newCore the new core + * @param newCore + * the new core. */ - void set(EventQueueCore newCore) { + void set(EventQueueCore newCore) { core = newCore; } } /** - * Returns true if the calling thread is the current - * AWT EventQueue's dispatch thread. + * Returns true if the calling thread is the current AWT EventQueue's + * dispatch thread. * - * @return true, if the calling thread is the current - * AWT EventQueue's dispatch thread; false otherwise. + * @return true, if the calling thread is the current AWT EventQueue's + * dispatch thread; false otherwise. */ public static boolean isDispatchThread() { return Thread.currentThread() instanceof EventDispatchThread; } /** - * Posts an InvocationEvent which executes the run() method on a Runnable + * Posts an InvocationEvent which executes the run() method on a Runnable * when dispatched by the AWT event dispatcher thread. * - * @param runnable the Runnable whose run method should be executed - * synchronously on the EventQueue. + * @param runnable + * the Runnable whose run method should be executed synchronously + * on the EventQueue. */ public static void invokeLater(Runnable runnable) { Toolkit toolkit = Toolkit.getDefaultToolkit(); @@ -87,29 +97,28 @@ public class EventQueue { } /** - * Posts an InvocationEvent which executes the run() method on a Runnable - * when dispatched by the AWT event dispatcher thread and the - * notifyAll method is called on it immediately after run returns. - * - * @param runnable the Runnable whose run method should be executed - * synchronously on the EventQueue. + * Posts an InvocationEvent which executes the run() method on a Runnable + * when dispatched by the AWT event dispatcher thread and the notifyAll + * method is called on it immediately after run returns. * - * @throws InterruptedException if another thread has interrupted - * this thread. - * @throws InvocationTargetException if a throwable is thrown - * when running the runnable. + * @param runnable + * the Runnable whose run method should be executed synchronously + * on the EventQueue. + * @throws InterruptedException + * if another thread has interrupted this thread. + * @throws InvocationTargetException + * if an error occurred while running the runnable. */ - public static void invokeAndWait(Runnable runnable) - throws InterruptedException, InvocationTargetException { + public static void invokeAndWait(Runnable runnable) throws InterruptedException, + InvocationTargetException { if (isDispatchThread()) { throw new Error(); } final Toolkit toolkit = Toolkit.getDefaultToolkit(); - final Object notifier = new Object(); //$NON-LOCK-1$ - InvocationEvent event = new InvocationEvent( - toolkit, runnable, notifier, true); + final Object notifier = new Object(); // $NON-LOCK-1$ + InvocationEvent event = new InvocationEvent(toolkit, runnable, notifier, true); synchronized (notifier) { toolkit.getSystemEventQueueImpl().postEvent(event); @@ -126,7 +135,7 @@ public class EventQueue { /** * Gets the system event queue. * - * @return the system event queue + * @return the system event queue. */ private static EventQueue getSystemEventQueue() { Thread th = Thread.currentThread(); @@ -135,48 +144,45 @@ public class EventQueue { } return null; } - + /** - * Gets the most recent event's timestamp. - * This event was dispatched from the EventQueue associated with the - * calling thread. + * Gets the most recent event's timestamp. This event was dispatched from + * the EventQueue associated with the calling thread. * - * @return the timestamp of the last Event to be dispatched, - * or System.currentTimeMillis() if this method is invoked from - * a thread other than an event-dispatching thread. + * @return the timestamp of the last Event to be dispatched, or + * System.currentTimeMillis() if this method is invoked from a + * thread other than an event-dispatching thread. */ public static long getMostRecentEventTime() { EventQueue eq = getSystemEventQueue(); - return (eq != null) ? - eq.getMostRecentEventTimeImpl() : System.currentTimeMillis(); + return (eq != null) ? eq.getMostRecentEventTimeImpl() : System.currentTimeMillis(); } - + /** * Gets the most recent event time impl. * - * @return the most recent event time impl + * @return the most recent event time impl. */ private long getMostRecentEventTimeImpl() { return getCore().getMostRecentEventTime(); } /** - * Returns the the currently dispatched event by the EventQueue - * associated with the calling thread. + * Returns the the currently dispatched event by the EventQueue associated + * with the calling thread. * - * @return the currently dispatched event or null if this method - * is invoked from a thread other than an event-dispatching thread. + * @return the currently dispatched event or null if this method is invoked + * from a thread other than an event-dispatching thread. */ public static AWTEvent getCurrentEvent() { EventQueue eq = getSystemEventQueue(); - return (eq != null) ? - eq.getCurrentEventImpl() : null; + return (eq != null) ? eq.getCurrentEventImpl() : null; } /** * Gets the current event impl. * - * @return the current event impl + * @return the current event impl. */ private AWTEvent getCurrentEventImpl() { return getCore().getCurrentEvent(); @@ -192,7 +198,8 @@ public class EventQueue { /** * Instantiates a new event queue. * - * @param t the t + * @param t + * the t. */ EventQueue(Toolkit t) { setCore(new EventQueueCore(this, t)); @@ -201,7 +208,8 @@ public class EventQueue { /** * Posts a event to the EventQueue. * - * @param event AWTEvent. + * @param event + * AWTEvent. */ public void postEvent(AWTEvent event) { event.isPosted = true; @@ -209,29 +217,28 @@ public class EventQueue { } /** - * Returns an event from the EventQueue and removes it from this queue. - * - * @return the next AWTEvent. + * Returns an event from the EventQueue and removes it from this queue. * - * @throws InterruptedException is thrown if another thread - * interrupts this thread. + * @return the next AWTEvent. + * @throws InterruptedException + * is thrown if another thread interrupts this thread. */ public AWTEvent getNextEvent() throws InterruptedException { return getCore().getNextEvent(); } - + /** * Gets the next event no wait. * - * @return the next event no wait + * @return the next event no wait. */ AWTEvent getNextEventNoWait() { return getCore().getNextEventNoWait(); } /** - * Returns the first event of the EventQueue (without removing it - * from the queue). + * Returns the first event of the EventQueue (without removing it from the + * queue). * * @return the the first AWT event of the EventQueue. */ @@ -240,11 +247,11 @@ public class EventQueue { } /** - * Returns the first event of the EventQueue with the specified ID - * (without removing it from the queue). - * - * @param id the type ID of event. + * Returns the first event of the EventQueue with the specified ID (without + * removing it from the queue). * + * @param id + * the type ID of event. * @return the first event of the EventQueue with the specified ID. */ public AWTEvent peekEvent(int id) { @@ -252,21 +259,22 @@ public class EventQueue { } /** - * Replaces the existing EventQueue with the specified EventQueue. - * Any pending events are transferred to the new EventQueue. + * Replaces the existing EventQueue with the specified EventQueue. Any + * pending events are transferred to the new EventQueue. * - * @param newEventQueue the new event queue. + * @param newEventQueue + * the new event queue. */ public void push(EventQueue newEventQueue) { getCore().push(newEventQueue); } - + /** - * Stops dispatching events using this EventQueue. - * Any pending events are transferred to the previous EventQueue. + * Stops dispatching events using this EventQueue. Any pending events are + * transferred to the previous EventQueue. * - * @throws EmptyStackException is thrown if no previous push - * was made on this EventQueue. + * @throws EmptyStackException + * is thrown if no previous push was made on this EventQueue. */ protected void pop() throws EmptyStackException { getCore().pop(); @@ -275,7 +283,8 @@ public class EventQueue { /** * Dispatches the specified event. * - * @param event the AWTEvent. + * @param event + * the AWTEvent. */ protected void dispatchEvent(AWTEvent event) { getCore().dispatchEventImpl(event); @@ -284,7 +293,7 @@ public class EventQueue { /** * Checks if the queue is empty. * - * @return true, if is empty + * @return true, if is empty. */ boolean isEmpty() { return getCore().isEmpty(); @@ -293,16 +302,17 @@ public class EventQueue { /** * Gets the core. * - * @return the core + * @return the core. */ EventQueueCore getCore() { return coreRef.get(); } - + /** * Sets the core. * - * @param newCore the new core + * @param newCore + * the new core. */ void setCore(EventQueueCore newCore) { coreRef.set((newCore != null) ? newCore : new EventQueueCore(this)); diff --git a/awt/java/awt/Font.java b/awt/java/awt/Font.java index 139ae6827a37697385f66764a491024ca75ba7c0..4ed93438d3892cd6c8a429af08b25e1a558e8a4a 100644 --- a/awt/java/awt/Font.java +++ b/awt/java/awt/Font.java @@ -46,130 +46,165 @@ import org.apache.harmony.awt.gl.font.FontPeerImpl; import org.apache.harmony.awt.gl.font.FontMetricsImpl; import org.apache.harmony.awt.gl.font.LineMetricsImpl; import org.apache.harmony.awt.internal.nls.Messages; +import org.apache.harmony.luni.util.NotImplementedException; import org.apache.harmony.misc.HashCode; - /** - * The Font class represents fonts for rendering text. - * This class allow to map characters to glyphs. - *

- * A glyph is a shape used to render a character or a sequence of - * characters. For example one character of Latin writing system - * represented by one glyth, but in complex writing system such as - * South and South-East Asian there is more complicated correspondence - * between characters and glyphs. + * The Font class represents fonts for rendering text. This class allow to map + * characters to glyphs. + *

+ * A glyph is a shape used to render a character or a sequence of characters. + * For example one character of Latin writing system represented by one glyph, + * but in complex writing system such as South and South-East Asian there is + * more complicated correspondence between characters and glyphs. *

- * The Font object is identified by two types of names. The logical font name - * is the name that is used to construct the font. The font name - * is the name of a particular font face (for example, Arial Bold). - * The family name is the font's family name that specifies - * the typographic design across several faces (for example, Arial). In - * all the Font is identified by three attributes: the family name, - * the style (such as bold or italic), and the size. + * The Font object is identified by two types of names. The logical font name is + * the name that is used to construct the font. The font name is the name of a + * particular font face (for example, Arial Bold). The family name is the font's + * family name that specifies the typographic design across several faces (for + * example, Arial). In all the Font is identified by three attributes: the + * family name, the style (such as bold or italic), and the size. + * + * @since Android 1.0 */ public class Font implements Serializable { - /** The Constant serialVersionUID. */ + /** + * The Constant serialVersionUID. + */ private static final long serialVersionUID = -4206021311591459213L; // Identity Transform attribute - /** The Constant IDENTITY_TRANSFORM. */ + /** + * The Constant IDENTITY_TRANSFORM. + */ private static final TransformAttribute IDENTITY_TRANSFORM = new TransformAttribute( new AffineTransform()); - /** The Constant PLAIN indicates font's plain style. */ + /** + * The Constant PLAIN indicates font's plain style. + */ public static final int PLAIN = 0; - /** The Constant BOLD indicates font's bold style. */ + /** + * The Constant BOLD indicates font's bold style. + */ public static final int BOLD = 1; - /** The Constant ITALIC indicates font's italic style. */ + /** + * The Constant ITALIC indicates font's italic style. + */ public static final int ITALIC = 2; - /** The Constant ROMAN_BASELINE indicated roman baseline. */ + /** + * The Constant ROMAN_BASELINE indicated roman baseline. + */ public static final int ROMAN_BASELINE = 0; - /** The Constant CENTER_BASELINE indicates center baseline. */ + /** + * The Constant CENTER_BASELINE indicates center baseline. + */ public static final int CENTER_BASELINE = 1; - /** The Constant HANGING_BASELINE indicates hanging baseline. */ + /** + * The Constant HANGING_BASELINE indicates hanging baseline. + */ public static final int HANGING_BASELINE = 2; - /** - * The Constant TRUETYPE_FONT indicates a font resource of - * type TRUETYPE. + /** + * The Constant TRUETYPE_FONT indicates a font resource of type TRUETYPE. */ public static final int TRUETYPE_FONT = 0; - /** - * The Constant TYPE1_FONT indicates a font resource of - * type TYPE1. + /** + * The Constant TYPE1_FONT indicates a font resource of type TYPE1. */ public static final int TYPE1_FONT = 1; - /** - * The Constant LAYOUT_LEFT_TO_RIGHT indicates that text is - * left to right. + /** + * The Constant LAYOUT_LEFT_TO_RIGHT indicates that text is left to right. */ public static final int LAYOUT_LEFT_TO_RIGHT = 0; - /** - * The Constant LAYOUT_RIGHT_TO_LEFT indicates that text is - * right to left. + /** + * The Constant LAYOUT_RIGHT_TO_LEFT indicates that text is right to left. */ public static final int LAYOUT_RIGHT_TO_LEFT = 1; - /** - * The Constant LAYOUT_NO_START_CONTEXT indicates that the text - * in the char array before the indicated start should not be examined. + /** + * The Constant LAYOUT_NO_START_CONTEXT indicates that the text in the char + * array before the indicated start should not be examined. */ public static final int LAYOUT_NO_START_CONTEXT = 2; - /** The Constant LAYOUT_NO_LIMIT_CONTEXT indicates that text in - * the char array after the indicated limit should not be examined. */ + /** + * The Constant LAYOUT_NO_LIMIT_CONTEXT indicates that text in the char + * array after the indicated limit should not be examined. + */ public static final int LAYOUT_NO_LIMIT_CONTEXT = 4; - /** The Constant DEFAULT_FONT. */ + /** + * The Constant DEFAULT_FONT. + */ static final Font DEFAULT_FONT = new Font("Dialog", Font.PLAIN, 12); //$NON-NLS-1$ - /** The name of the Font. */ + /** + * The name of the Font. + */ protected String name; - /** The style of the Font. */ + /** + * The style of the Font. + */ protected int style; - /** The size of the Font. */ + /** + * The size of the Font. + */ protected int size; - /** The point size of the Font. */ + /** + * The point size of the Font. + */ protected float pointSize; // Flag if the Font object transformed - /** The transformed. */ + /** + * The transformed. + */ private boolean transformed; // Set of font attributes - /** The requested attributes. */ + /** + * The requested attributes. + */ private Hashtable fRequestedAttributes; // font peer object corresponding to this Font - /** The font peer. */ + /** + * The font peer. + */ private transient FontPeerImpl fontPeer; // number of glyphs in this Font - /** The num glyphs. */ + /** + * The num glyphs. + */ private transient int numGlyphs = -1; // code for missing glyph for this Font - /** The missing glyph code. */ + /** + * The missing glyph code. + */ private transient int missingGlyphCode = -1; /** * Writes object to ObjectOutputStream. * - * @param out ObjectOutputStream - * - * @throws IOException Signals that an I/O exception has occurred. + * @param out + * ObjectOutputStream. + * @throws IOException + * Signals that an I/O exception has occurred. */ private void writeObject(java.io.ObjectOutputStream out) throws IOException { out.defaultWriteObject(); @@ -179,10 +214,12 @@ public class Font implements Serializable { * Reads object from ObjectInputStream object and set native platform * dependent fields to default values. * - * @param in ObjectInputStream object - * - * @throws IOException Signals that an I/O exception has occurred. - * @throws ClassNotFoundException the class not found exception + * @param in + * ObjectInputStream object. + * @throws IOException + * Signals that an I/O exception has occurred. + * @throws ClassNotFoundException + * the class not found exception. */ private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException { @@ -194,11 +231,11 @@ public class Font implements Serializable { } /** - * Instantiates a new Font with the specified attributes. - * The Font will be created with default attributes - * if the attribute's parameter is null. + * Instantiates a new Font with the specified attributes. The Font will be + * created with default attributes if the attribute's parameter is null. * - * @param attributes the attributes to be assigned to the new Font, or null. + * @param attributes + * the attributes to be assigned to the new Font, or null. */ public Font(Map attributes) { Object currAttr; @@ -217,43 +254,38 @@ public class Font implements Serializable { currAttr = attributes.get(TextAttribute.SIZE); if (currAttr != null) { - this.pointSize = ((Float) currAttr).floatValue(); - this.size = (int) Math.ceil(this.pointSize); + this.pointSize = ((Float)currAttr).floatValue(); + this.size = (int)Math.ceil(this.pointSize); } currAttr = attributes.get(TextAttribute.POSTURE); - if (currAttr != null - && currAttr.equals(TextAttribute.POSTURE_OBLIQUE)) { + if (currAttr != null && currAttr.equals(TextAttribute.POSTURE_OBLIQUE)) { this.style |= Font.ITALIC; } currAttr = attributes.get(TextAttribute.WEIGHT); if ((currAttr != null) - && (((Float) currAttr).floatValue() >= (TextAttribute.WEIGHT_BOLD) - .floatValue())) { + && (((Float)currAttr).floatValue() >= (TextAttribute.WEIGHT_BOLD).floatValue())) { this.style |= Font.BOLD; } currAttr = attributes.get(TextAttribute.FAMILY); if (currAttr != null) { - this.name = (String) currAttr; + this.name = (String)currAttr; } currAttr = attributes.get(TextAttribute.TRANSFORM); if (currAttr != null) { if (currAttr instanceof TransformAttribute) { - this.transformed = !((TransformAttribute) currAttr) - .getTransform().isIdentity(); + this.transformed = !((TransformAttribute)currAttr).getTransform().isIdentity(); } else if (currAttr instanceof AffineTransform) { - this.transformed = !((AffineTransform) currAttr) - .isIdentity(); + this.transformed = !((AffineTransform)currAttr).isIdentity(); } } } else { fRequestedAttributes = new Hashtable(5); - fRequestedAttributes.put(TextAttribute.TRANSFORM, - IDENTITY_TRANSFORM); + fRequestedAttributes.put(TextAttribute.TRANSFORM, IDENTITY_TRANSFORM); this.transformed = false; @@ -262,18 +294,14 @@ public class Font implements Serializable { fRequestedAttributes.put(TextAttribute.SIZE, new Float(this.size)); if ((this.style & Font.BOLD) != 0) { - fRequestedAttributes.put(TextAttribute.WEIGHT, - TextAttribute.WEIGHT_BOLD); + fRequestedAttributes.put(TextAttribute.WEIGHT, TextAttribute.WEIGHT_BOLD); } else { - fRequestedAttributes.put(TextAttribute.WEIGHT, - TextAttribute.WEIGHT_REGULAR); + fRequestedAttributes.put(TextAttribute.WEIGHT, TextAttribute.WEIGHT_REGULAR); } if ((this.style & Font.ITALIC) != 0) { - fRequestedAttributes.put(TextAttribute.POSTURE, - TextAttribute.POSTURE_OBLIQUE); + fRequestedAttributes.put(TextAttribute.POSTURE, TextAttribute.POSTURE_OBLIQUE); } else { - fRequestedAttributes.put(TextAttribute.POSTURE, - TextAttribute.POSTURE_REGULAR); + fRequestedAttributes.put(TextAttribute.POSTURE, TextAttribute.POSTURE_REGULAR); } } @@ -282,9 +310,12 @@ public class Font implements Serializable { /** * Instantiates a new Font with the specified name, style and size. * - * @param name the name of font. - * @param style the style of font. - * @param size the size of font. + * @param name + * the name of font. + * @param style + * the style of font. + * @param size + * the size of font. */ public Font(String name, int style, int size) { @@ -303,46 +334,43 @@ public class Font implements Serializable { fRequestedAttributes.put(TextAttribute.SIZE, new Float(this.size)); if ((this.style & Font.BOLD) != 0) { - fRequestedAttributes.put(TextAttribute.WEIGHT, - TextAttribute.WEIGHT_BOLD); + fRequestedAttributes.put(TextAttribute.WEIGHT, TextAttribute.WEIGHT_BOLD); } else { - fRequestedAttributes.put(TextAttribute.WEIGHT, - TextAttribute.WEIGHT_REGULAR); + fRequestedAttributes.put(TextAttribute.WEIGHT, TextAttribute.WEIGHT_REGULAR); } if ((this.style & Font.ITALIC) != 0) { - fRequestedAttributes.put(TextAttribute.POSTURE, - TextAttribute.POSTURE_OBLIQUE); + fRequestedAttributes.put(TextAttribute.POSTURE, TextAttribute.POSTURE_OBLIQUE); } else { - fRequestedAttributes.put(TextAttribute.POSTURE, - TextAttribute.POSTURE_REGULAR); + fRequestedAttributes.put(TextAttribute.POSTURE, TextAttribute.POSTURE_REGULAR); } } /** * Returns true if this Font has a glyph for the specified character. * - * @param c the character. - * - * @return true if this Font has a glyph for the specified character, - * false otherwise. + * @param c + * the character. + * @return true if this Font has a glyph for the specified character, false + * otherwise. */ public boolean canDisplay(char c) { - FontPeerImpl peer = (FontPeerImpl) this.getPeer(); + FontPeerImpl peer = (FontPeerImpl)this.getPeer(); return peer.canDisplay(c); } /** - * Returns true if the Font can display the characters of the - * the specified text from the specified start position - * to the specified limit position. - * - * @param text the text. - * @param start the start offset (in the character array). - * @param limit the limit offset (in the character array). - * - * @return the a character's position in the text that this Font - * can not display, or -1 if this Font can display all characters - * in this text. + * Returns true if the Font can display the characters of the the specified + * text from the specified start position to the specified limit position. + * + * @param text + * the text. + * @param start + * the start offset (in the character array). + * @param limit + * the limit offset (in the character array). + * @return the a character's position in the text that this Font can not + * display, or -1 if this Font can display all characters in this + * text. */ public int canDisplayUpTo(char[] text, int start, int limit) { int st = start; @@ -361,17 +389,19 @@ public class Font implements Serializable { } /** - * Returns true if the Font can display the characters of the - * the specified CharacterIterator from the specified start position - * and the specified limit position. - * - * @param iter the CharacterIterator. - * @param start the start offset. - * @param limit the limit offset. - * - * @return the a character's position in the CharacterIterator - * that this Font can not display, or -1 if this Font can display - * all characters in this text. + * Returns true if the Font can display the characters of the the specified + * CharacterIterator from the specified start position and the specified + * limit position. + * + * @param iter + * the CharacterIterator. + * @param start + * the start offset. + * @param limit + * the limit offset. + * @return the a character's position in the CharacterIterator that this + * Font can not display, or -1 if this Font can display all + * characters in this text. */ public int canDisplayUpTo(CharacterIterator iter, int start, int limit) { int st = start; @@ -394,11 +424,11 @@ public class Font implements Serializable { /** * Returns true if this Font can display a specified String. * - * @param str the String. - * - * @return the a character's position in the String that - * this Font can not display, or -1 if this Font can display - * all characters in this text. + * @param str + * the String. + * @return the a character's position in the String that this Font can not + * display, or -1 if this Font can display all characters in this + * text. */ public int canDisplayUpTo(String str) { char[] chars = str.toCharArray(); @@ -406,45 +436,49 @@ public class Font implements Serializable { } /** - * Creates a GlyphVector of associating characters to glyphs - * based on the unicode map of this Font. - * - * @param frc the FontRenderContext. - * @param chars the characters array. + * Creates a GlyphVector of associating characters to glyphs based on the + * Unicode map of this Font. * - * @return the GlyphVector of associating characters to glyphs - * based on the unicode map of this Font. + * @param frc + * the FontRenderContext. + * @param chars + * the characters array. + * @return the GlyphVector of associating characters to glyphs based on the + * Unicode map of this Font. */ public GlyphVector createGlyphVector(FontRenderContext frc, char[] chars) { return new AndroidGlyphVector(chars, frc, this, 0); } /** - * Creates a GlyphVector of associating characters contained - * in the specified CharacterIterator to glyphs based on - * the unicode map of this Font. - * - * @param frc the FontRenderContext. - * @param iter the CharacterIterator. - * - * @return the GlyphVector of associating characters contained - * in the specified CharacterIterator to glyphs - * based on the unicode map of this Font. - */ - public GlyphVector createGlyphVector(FontRenderContext frc, - CharacterIterator iter) { - throw new RuntimeException("Not implemented!"); //$NON-NLS-1$ + * Creates a GlyphVector of associating characters contained in the + * specified CharacterIterator to glyphs based on the Unicode map of this + * Font. + * + * @param frc + * the FontRenderContext. + * @param iter + * the CharacterIterator. + * @return the GlyphVector of associating characters contained in the + * specified CharacterIterator to glyphs based on the Unicode map of + * this Font. + */ + public GlyphVector createGlyphVector(FontRenderContext frc, CharacterIterator iter) { + throw new RuntimeException("Not implemented!"); //$NON-NLS-1$ } /** - * Creates a GlyphVector of associating characters to glyphs based on - * the unicode map of this Font. - * - * @param frc the FontRenderContext. - * @param glyphCodes the specified integer array of glyph codes. - * - * @return the GlyphVector of associating characters to glyphs - * based on the unicode map of this Font. + * Creates a GlyphVector of associating characters to glyphs based on the + * Unicode map of this Font. + * + * @param frc + * the FontRenderContext. + * @param glyphCodes + * the specified integer array of glyph codes. + * @return the GlyphVector of associating characters to glyphs based on the + * Unicode map of this Font. + * @throws NotImplementedException + * if this method is not implemented by a subclass. */ public GlyphVector createGlyphVector(FontRenderContext frc, int[] glyphCodes) throws org.apache.harmony.luni.util.NotImplementedException { @@ -452,14 +486,15 @@ public class Font implements Serializable { } /** - * Creates a GlyphVector of associating characters to glyphs based on - * the unicode map of this Font. + * Creates a GlyphVector of associating characters to glyphs based on the + * Unicode map of this Font. * - * @param frc the FontRenderContext. - * @param str the specified String. - * - * @return the GlyphVector of associating characters to glyphs - * based on the unicode map of this Font. + * @param frc + * the FontRenderContext. + * @param str + * the specified String. + * @return the GlyphVector of associating characters to glyphs based on the + * Unicode map of this Font. */ public GlyphVector createGlyphVector(FontRenderContext frc, String str) { return new AndroidGlyphVector(str.toCharArray(), frc, this, 0); @@ -467,14 +502,14 @@ public class Font implements Serializable { } /** - * Returns the font style constant value corresponding to one of the font style - * names ("BOLD", "ITALIC", "BOLDITALIC"). This method returns Font.PLAIN if - * the argument is not one of the predefined style names. - * - * @param fontStyleName font style name + * Returns the font style constant value corresponding to one of the font + * style names ("BOLD", "ITALIC", "BOLDITALIC"). This method returns + * Font.PLAIN if the argument is not one of the predefined style names. * + * @param fontStyleName + * font style name. * @return font style constant value corresponding to the font style name - * specified. + * specified. */ private static int getFontStyle(String fontStyleName) { int result = Font.PLAIN; @@ -491,12 +526,12 @@ public class Font implements Serializable { } /** - * Decodes the specified string which described the Font. The string - * should have the following format: fontname-style-pointsize. - * The style can be PLAIN, BOLD, BOLDITALIC, or ITALIC. - * - * @param str the string which describes the font. + * Decodes the specified string which described the Font. The string should + * have the following format: fontname-style-pointsize. The style can be + * PLAIN, BOLD, BOLDITALIC, or ITALIC. * + * @param str + * the string which describes the font. * @return the Font from the specified string. */ public static Font decode(String str) { @@ -553,15 +588,14 @@ public class Font implements Serializable { } /** - * Perfoms the specified affine transform to the Font and returns - * a new Font. - * - * @param trans the AffineTransform. + * Performs the specified affine transform to the Font and returns a new + * Font. * + * @param trans + * the AffineTransform. * @return the Font object. - * - * @throws IllegalArgumentException if affine transform parameter - * is null. + * @throws IllegalArgumentException + * if affine transform parameter is null. */ @SuppressWarnings("unchecked") public Font deriveFont(AffineTransform trans) { @@ -571,55 +605,52 @@ public class Font implements Serializable { throw new IllegalArgumentException(Messages.getString("awt.94")); //$NON-NLS-1$ } - Hashtable derivefRequestedAttributes = (Hashtable) fRequestedAttributes + Hashtable derivefRequestedAttributes = (Hashtable)fRequestedAttributes .clone(); - derivefRequestedAttributes.put(TextAttribute.TRANSFORM, - new TransformAttribute(trans)); + derivefRequestedAttributes.put(TextAttribute.TRANSFORM, new TransformAttribute(trans)); return new Font(derivefRequestedAttributes); } /** - * Returns a new Font that is a copy of the current Font - * modified so that the size is the specified size. - * - * @param size the size of font. + * Returns a new Font that is a copy of the current Font modified so that + * the size is the specified size. * + * @param size + * the size of font. * @return the Font object. */ @SuppressWarnings("unchecked") public Font deriveFont(float size) { - Hashtable derivefRequestedAttributes = (Hashtable) fRequestedAttributes + Hashtable derivefRequestedAttributes = (Hashtable)fRequestedAttributes .clone(); derivefRequestedAttributes.put(TextAttribute.SIZE, new Float(size)); return new Font(derivefRequestedAttributes); } /** - * Returns a new Font that is a copy of the current Font - * modified so that the style is the specified style. - * - * @param style the style of font. + * Returns a new Font that is a copy of the current Font modified so that + * the style is the specified style. * + * @param style + * the style of font. * @return the Font object. */ @SuppressWarnings("unchecked") public Font deriveFont(int style) { - Hashtable derivefRequestedAttributes = (Hashtable) fRequestedAttributes + Hashtable derivefRequestedAttributes = (Hashtable)fRequestedAttributes .clone(); if ((style & Font.BOLD) != 0) { - derivefRequestedAttributes.put(TextAttribute.WEIGHT, - TextAttribute.WEIGHT_BOLD); + derivefRequestedAttributes.put(TextAttribute.WEIGHT, TextAttribute.WEIGHT_BOLD); } else if (derivefRequestedAttributes.get(TextAttribute.WEIGHT) != null) { derivefRequestedAttributes.remove(TextAttribute.WEIGHT); } if ((style & Font.ITALIC) != 0) { - derivefRequestedAttributes.put(TextAttribute.POSTURE, - TextAttribute.POSTURE_OBLIQUE); + derivefRequestedAttributes.put(TextAttribute.POSTURE, TextAttribute.POSTURE_OBLIQUE); } else if (derivefRequestedAttributes.get(TextAttribute.POSTURE) != null) { derivefRequestedAttributes.remove(TextAttribute.POSTURE); } @@ -628,13 +659,14 @@ public class Font implements Serializable { } /** - * Returns a new Font that is a copy of the current Font - * modified to match the specified style and with the specified - * affine transform applied to its glyphs. - * - * @param style the style of font. - * @param trans the AffineTransform. - * + * Returns a new Font that is a copy of the current Font modified to match + * the specified style and with the specified affine transform applied to + * its glyphs. + * + * @param style + * the style of font. + * @param trans + * the AffineTransform. * @return the Font object. */ @SuppressWarnings("unchecked") @@ -644,53 +676,48 @@ public class Font implements Serializable { // awt.94=transform can not be null throw new IllegalArgumentException(Messages.getString("awt.94")); //$NON-NLS-1$ } - Hashtable derivefRequestedAttributes = (Hashtable) fRequestedAttributes + Hashtable derivefRequestedAttributes = (Hashtable)fRequestedAttributes .clone(); if ((style & BOLD) != 0) { - derivefRequestedAttributes.put(TextAttribute.WEIGHT, - TextAttribute.WEIGHT_BOLD); + derivefRequestedAttributes.put(TextAttribute.WEIGHT, TextAttribute.WEIGHT_BOLD); } else if (derivefRequestedAttributes.get(TextAttribute.WEIGHT) != null) { derivefRequestedAttributes.remove(TextAttribute.WEIGHT); } if ((style & ITALIC) != 0) { - derivefRequestedAttributes.put(TextAttribute.POSTURE, - TextAttribute.POSTURE_OBLIQUE); + derivefRequestedAttributes.put(TextAttribute.POSTURE, TextAttribute.POSTURE_OBLIQUE); } else if (derivefRequestedAttributes.get(TextAttribute.POSTURE) != null) { derivefRequestedAttributes.remove(TextAttribute.POSTURE); } - derivefRequestedAttributes.put(TextAttribute.TRANSFORM, - new TransformAttribute(trans)); + derivefRequestedAttributes.put(TextAttribute.TRANSFORM, new TransformAttribute(trans)); return new Font(derivefRequestedAttributes); } /** - * Returns a new Font that is a copy of the current Font - * modified so that the size and style are the specified - * size and style. - * - * @param style the style of font. - * @param size the size of font. + * Returns a new Font that is a copy of the current Font modified so that + * the size and style are the specified size and style. * + * @param style + * the style of font. + * @param size + * the size of font. * @return the Font object. */ @SuppressWarnings("unchecked") public Font deriveFont(int style, float size) { - Hashtable derivefRequestedAttributes = (Hashtable) fRequestedAttributes + Hashtable derivefRequestedAttributes = (Hashtable)fRequestedAttributes .clone(); if ((style & BOLD) != 0) { - derivefRequestedAttributes.put(TextAttribute.WEIGHT, - TextAttribute.WEIGHT_BOLD); + derivefRequestedAttributes.put(TextAttribute.WEIGHT, TextAttribute.WEIGHT_BOLD); } else if (derivefRequestedAttributes.get(TextAttribute.WEIGHT) != null) { derivefRequestedAttributes.remove(TextAttribute.WEIGHT); } if ((style & ITALIC) != 0) { - derivefRequestedAttributes.put(TextAttribute.POSTURE, - TextAttribute.POSTURE_OBLIQUE); + derivefRequestedAttributes.put(TextAttribute.POSTURE, TextAttribute.POSTURE_OBLIQUE); } else if (derivefRequestedAttributes.get(TextAttribute.POSTURE) != null) { derivefRequestedAttributes.remove(TextAttribute.POSTURE); } @@ -703,15 +730,15 @@ public class Font implements Serializable { /** * Returns a new Font object with a new set of font attributes. * - * @param attributes the map of attributes. - * + * @param attributes + * the map of attributes. * @return the Font. */ @SuppressWarnings("unchecked") public Font deriveFont(Map attributes) { Attribute[] avalAttributes = this.getAvailableAttributes(); - Hashtable derivefRequestedAttributes = (Hashtable) fRequestedAttributes + Hashtable derivefRequestedAttributes = (Hashtable)fRequestedAttributes .clone(); Object currAttribute; for (Attribute element : avalAttributes) { @@ -726,10 +753,10 @@ public class Font implements Serializable { /** * Compares the specified Object with the current Font. * - * @param obj the Object to be compared. - * - * @return true, if the specified Object is an instance of Font - * with the same family, size, and style as this Font, false otherwise. + * @param obj + * the Object to be compared. + * @return true, if the specified Object is an instance of Font with the + * same family, size, and style as this Font, false otherwise. */ @Override public boolean equals(Object obj) { @@ -739,11 +766,10 @@ public class Font implements Serializable { if (obj != null) { try { - Font font = (Font) obj; + Font font = (Font)obj; return ((this.style == font.style) && (this.size == font.size) - && this.name.equals(font.name) - && (this.pointSize == font.pointSize) && (this + && this.name.equals(font.name) && (this.pointSize == font.pointSize) && (this .getTransform()).equals(font.getTransform())); } catch (ClassCastException e) { } @@ -759,7 +785,7 @@ public class Font implements Serializable { */ @SuppressWarnings("unchecked") public Map getAttributes() { - return (Map) fRequestedAttributes.clone(); + return (Map)fRequestedAttributes.clone(); } /** @@ -768,18 +794,19 @@ public class Font implements Serializable { * @return the keys array of all available attributes. */ public Attribute[] getAvailableAttributes() { - Attribute[] attrs = { TextAttribute.FAMILY, TextAttribute.POSTURE, - TextAttribute.SIZE, TextAttribute.TRANSFORM, - TextAttribute.WEIGHT, TextAttribute.SUPERSCRIPT, - TextAttribute.WIDTH }; + Attribute[] attrs = { + TextAttribute.FAMILY, TextAttribute.POSTURE, TextAttribute.SIZE, + TextAttribute.TRANSFORM, TextAttribute.WEIGHT, TextAttribute.SUPERSCRIPT, + TextAttribute.WIDTH + }; return attrs; } /** * Gets the baseline for this character. * - * @param c the character. - * + * @param c + * the character. * @return the baseline for this character. */ public byte getBaselineFor(char c) { @@ -800,19 +827,18 @@ public class Font implements Serializable { } /** - * Returns the family name of this Font associated with - * the specified locale. - * - * @param l the locale. + * Returns the family name of this Font associated with the specified + * locale. * - * @return the family name of this Font associated with - * the specified locale. + * @param l + * the locale. + * @return the family name of this Font associated with the specified + * locale. */ public String getFamily(Locale l) { if (l == null) { // awt.01='{0}' parameter is null - throw new NullPointerException(Messages.getString( - "awt.01", "Locale")); //$NON-NLS-1$ //$NON-NLS-2$ + throw new NullPointerException(Messages.getString("awt.01", "Locale")); //$NON-NLS-1$ //$NON-NLS-2$ } return getFamily(); } @@ -820,12 +846,12 @@ public class Font implements Serializable { /** * Gets a Font with the specified attribute set. * - * @param attributes the attributes to be assigned to the new Font. - * + * @param attributes + * the attributes to be assigned to the new Font. * @return the Font. */ public static Font getFont(Map attributes) { - Font fnt = (Font) attributes.get(TextAttribute.FONT); + Font fnt = (Font)attributes.get(TextAttribute.FONT); if (fnt != null) { return fnt; } @@ -833,14 +859,16 @@ public class Font implements Serializable { } /** - * Gets a Font object from the system properties list with the specified name - * or returns the specified Font if there is no such property. - * - * @param sp the specified property name. - * @param f the Font. + * Gets a Font object from the system properties list with the specified + * name or returns the specified Font if there is no such property. * - * @return the Font object from the system properties list with the specified name - * or the specified Font if there is no such property. + * @param sp + * the specified property name. + * @param f + * the Font. + * @return the Font object from the system properties list with the + * specified name or the specified Font if there is no such + * property. */ public static Font getFont(String sp, Font f) { String pr = System.getProperty(sp); @@ -851,12 +879,13 @@ public class Font implements Serializable { } /** - * Gets a Font object from the system properties list with the specified name. - * - * @param sp the system property name. + * Gets a Font object from the system properties list with the specified + * name. * - * @return the Font, or null if there is no shuch property - * with the specified name. + * @param sp + * the system property name. + * @return the Font, or null if there is no such property with the specified + * name. */ public static Font getFont(String sp) { return getFont(sp, null); @@ -877,8 +906,8 @@ public class Font implements Serializable { /** * Returns the font name associated with the specified locale. * - * @param l the locale. - * + * @param l + * the locale. * @return the font name associated with the specified locale. */ public String getFontName(Locale l) { @@ -888,38 +917,45 @@ public class Font implements Serializable { /** * Returns a LineMetrics object created with the specified parameters. * - * @param chars the chars array. - * @param start the start offset. - * @param end the end offset. - * @param frc the FontRenderContext. - * + * @param chars + * the chars array. + * @param start + * the start offset. + * @param end + * the end offset. + * @param frc + * the FontRenderContext. * @return the LineMetrics for the specified parameters. */ - public LineMetrics getLineMetrics(char[] chars, int start, int end, - FontRenderContext frc) { + public LineMetrics getLineMetrics(char[] chars, int start, int end, FontRenderContext frc) { if (frc == null) { // awt.00=FontRenderContext is null throw new NullPointerException(Messages.getString("awt.00")); //$NON-NLS-1$ } - //FontMetrics fm = AndroidGraphics2D.getInstance().getFontMetrics(); + // FontMetrics fm = AndroidGraphics2D.getInstance().getFontMetrics(); FontMetrics fm = new FontMetricsImpl(this); - float[] fmet = {fm.getAscent(), fm.getDescent(), fm.getLeading()}; + float[] fmet = { + fm.getAscent(), fm.getDescent(), fm.getLeading() + }; return new LineMetricsImpl(chars.length, fmet, null); } /** * Returns a LineMetrics object created with the specified parameters. * - * @param iter the CharacterIterator. - * @param start the start offset. - * @param end the end offset. - * @param frc the FontRenderContext. - * + * @param iter + * the CharacterIterator. + * @param start + * the start offset. + * @param end + * the end offset. + * @param frc + * the FontRenderContext. * @return the LineMetrics for the specified parameters. */ - public LineMetrics getLineMetrics(CharacterIterator iter, int start, - int end, FontRenderContext frc) { + public LineMetrics getLineMetrics(CharacterIterator iter, int start, int end, + FontRenderContext frc) { if (frc == null) { // awt.00=FontRenderContext is null @@ -935,8 +971,8 @@ public class Font implements Serializable { } else { char[] chars = new char[iterCount]; int i = 0; - for (char c = iter.setIndex(start); c != CharacterIterator.DONE - && (i < iterCount); c = iter.next()) { + for (char c = iter.setIndex(start); c != CharacterIterator.DONE && (i < iterCount); c = iter + .next()) { chars[i] = c; i++; } @@ -948,16 +984,19 @@ public class Font implements Serializable { /** * Returns a LineMetrics object created with the specified parameters. * - * @param str the String. - * @param frc the FontRenderContext. - * + * @param str + * the String. + * @param frc + * the FontRenderContext. * @return the LineMetrics for the specified parameters. */ public LineMetrics getLineMetrics(String str, FontRenderContext frc) { - //FontMetrics fm = AndroidGraphics2D.getInstance().getFontMetrics(); + // FontMetrics fm = AndroidGraphics2D.getInstance().getFontMetrics(); FontMetrics fm = new FontMetricsImpl(this); - float[] fmet = {fm.getAscent(), fm.getDescent(), fm.getLeading()}; - //Log.i("FONT FMET", fmet.toString()); + float[] fmet = { + fm.getAscent(), fm.getDescent(), fm.getLeading() + }; + // Log.i("FONT FMET", fmet.toString()); return new LineMetricsImpl(str.length(), fmet, null); } @@ -965,45 +1004,48 @@ public class Font implements Serializable { /** * Returns a LineMetrics object created with the specified parameters. * - * @param str the String. - * @param start the start offset. - * @param end the end offset. - * @param frc the FontRenderContext. - * + * @param str + * the String. + * @param start + * the start offset. + * @param end + * the end offset. + * @param frc + * the FontRenderContext. * @return the LineMetrics for the specified parameters. */ - public LineMetrics getLineMetrics(String str, int start, int end, - FontRenderContext frc) { + public LineMetrics getLineMetrics(String str, int start, int end, FontRenderContext frc) { return this.getLineMetrics(str.substring(start, end), frc); } /** - * Gets the logical bounds of the specified String in - * the specified FontRenderContext. The logical bounds contains - * the origin, ascent, advance, and height. - * - * @param ci the specified CharacterIterator. - * @param start the start offset. - * @param end the end offset. - * @param frc the FontRenderContext. - * + * Gets the logical bounds of the specified String in the specified + * FontRenderContext. The logical bounds contains the origin, ascent, + * advance, and height. + * + * @param ci + * the specified CharacterIterator. + * @param start + * the start offset. + * @param end + * the end offset. + * @param frc + * the FontRenderContext. * @return a Rectangle2D object. */ - public Rectangle2D getStringBounds(CharacterIterator ci, int start, - int end, FontRenderContext frc) { + public Rectangle2D getStringBounds(CharacterIterator ci, int start, int end, + FontRenderContext frc) { int first = ci.getBeginIndex(); int finish = ci.getEndIndex(); char[] chars; if (start < first) { // awt.95=Wrong start index: {0} - throw new IndexOutOfBoundsException(Messages.getString( - "awt.95", start)); //$NON-NLS-1$ + throw new IndexOutOfBoundsException(Messages.getString("awt.95", start)); //$NON-NLS-1$ } if (end > finish) { // awt.96=Wrong finish index: {0} - throw new IndexOutOfBoundsException(Messages.getString( - "awt.96", end)); //$NON-NLS-1$ + throw new IndexOutOfBoundsException(Messages.getString("awt.96", end)); //$NON-NLS-1$ } if (start > end) { // awt.97=Wrong range length: {0} @@ -1028,13 +1070,14 @@ public class Font implements Serializable { } /** - * Gets the logical bounds of the specified String in - * the specified FontRenderContext. The logical bounds contains - * the origin, ascent, advance, and height. - * - * @param str the specified String. - * @param frc the FontRenderContext. - * + * Gets the logical bounds of the specified String in the specified + * FontRenderContext. The logical bounds contains the origin, ascent, + * advance, and height. + * + * @param str + * the specified String. + * @param frc + * the FontRenderContext. * @return a Rectangle2D object. */ public Rectangle2D getStringBounds(String str, FontRenderContext frc) { @@ -1044,46 +1087,48 @@ public class Font implements Serializable { } /** - * Gets the logical bounds of the specified String in - * the specified FontRenderContext. The logical bounds contains - * the origin, ascent, advance, and height. - * - * @param str the specified String. - * @param start the start offset. - * @param end the end offset. - * @param frc the FontRenderContext. - * + * Gets the logical bounds of the specified String in the specified + * FontRenderContext. The logical bounds contains the origin, ascent, + * advance, and height. + * + * @param str + * the specified String. + * @param start + * the start offset. + * @param end + * the end offset. + * @param frc + * the FontRenderContext. * @return a Rectangle2D object. */ - public Rectangle2D getStringBounds(String str, int start, int end, - FontRenderContext frc) { + public Rectangle2D getStringBounds(String str, int start, int end, FontRenderContext frc) { return this.getStringBounds((str.substring(start, end)), frc); } /** - * Gets the logical bounds of the specified String in - * the specified FontRenderContext. The logical bounds contains - * the origin, ascent, advance, and height. - * - * @param chars the specified character array. - * @param start the start offset. - * @param end the end offset. - * @param frc the FontRenderContext. - * + * Gets the logical bounds of the specified String in the specified + * FontRenderContext. The logical bounds contains the origin, ascent, + * advance, and height. + * + * @param chars + * the specified character array. + * @param start + * the start offset. + * @param end + * the end offset. + * @param frc + * the FontRenderContext. * @return a Rectangle2D object. */ - public Rectangle2D getStringBounds(char[] chars, int start, int end, - FontRenderContext frc) { + public Rectangle2D getStringBounds(char[] chars, int start, int end, FontRenderContext frc) { if (start < 0) { // awt.95=Wrong start index: {0} - throw new IndexOutOfBoundsException(Messages.getString( - "awt.95", start)); //$NON-NLS-1$ + throw new IndexOutOfBoundsException(Messages.getString("awt.95", start)); //$NON-NLS-1$ } if (end > chars.length) { // awt.96=Wrong finish index: {0} - throw new IndexOutOfBoundsException(Messages.getString( - "awt.96", end)); //$NON-NLS-1$ + throw new IndexOutOfBoundsException(Messages.getString("awt.96", end)); //$NON-NLS-1$ } if (start > end) { // awt.97=Wrong range length: {0} @@ -1095,7 +1140,7 @@ public class Font implements Serializable { throw new NullPointerException(Messages.getString("awt.00")); //$NON-NLS-1$ } - FontPeerImpl peer = (FontPeerImpl) this.getPeer(); + FontPeerImpl peer = (FontPeerImpl)this.getPeer(); final int TRANSFORM_MASK = AffineTransform.TYPE_GENERAL_ROTATION | AffineTransform.TYPE_GENERAL_TRANSFORM; @@ -1110,13 +1155,13 @@ public class Font implements Serializable { for (int i = start; i < end; i++) { width += peer.charWidth(chars[i]); } - //LineMetrics nlm = peer.getLineMetrics(); - + // LineMetrics nlm = peer.getLineMetrics(); + LineMetrics nlm = getLineMetrics(chars, start, end, frc); - + bounds = transform.createTransformedShape( - new Rectangle2D.Float(0, -nlm.getAscent(), width, nlm - .getHeight())).getBounds2D(); + new Rectangle2D.Float(0, -nlm.getAscent(), width, nlm.getHeight())) + .getBounds2D(); } else { int len = end - start; char[] subChars = new char[len]; @@ -1127,11 +1172,11 @@ public class Font implements Serializable { } /** - * Gets the character's maximum bounds as defined in - * the specified FontRenderContext. - * - * @param frc the FontRenderContext. + * Gets the character's maximum bounds as defined in the specified + * FontRenderContext. * + * @param frc + * the FontRenderContext. * @return the character's maximum bounds. */ public Rectangle2D getMaxCharBounds(FontRenderContext frc) { @@ -1140,7 +1185,7 @@ public class Font implements Serializable { throw new NullPointerException(Messages.getString("awt.00")); //$NON-NLS-1$ } - FontPeerImpl peer = (FontPeerImpl) this.getPeer(); + FontPeerImpl peer = (FontPeerImpl)this.getPeer(); Rectangle2D bounds = peer.getMaxCharBounds(frc); AffineTransform transform = getTransform(); @@ -1155,42 +1200,40 @@ public class Font implements Serializable { } /** - * Returns a new GlyphVector object performing full layout of - * the text. - * - * @param frc the FontRenderContext. - * @param chars the character array to be layout. - * @param start the start offset of the text to use for - * the GlyphVector. - * @param count the count of characters to use for - * the GlyphVector. - * @param flags the flag indicating text direction: - * LAYOUT_RIGHT_TO_LEFT, LAYOUT_LEFT_TO_RIGHT. - * + * Returns a new GlyphVector object performing full layout of the text. + * + * @param frc + * the FontRenderContext. + * @param chars + * the character array to be layout. + * @param start + * the start offset of the text to use for the GlyphVector. + * @param count + * the count of characters to use for the GlyphVector. + * @param flags + * the flag indicating text direction: LAYOUT_RIGHT_TO_LEFT, + * LAYOUT_LEFT_TO_RIGHT. * @return the GlyphVector. */ - public GlyphVector layoutGlyphVector(FontRenderContext frc, char[] chars, - int start, int count, int flags) { + public GlyphVector layoutGlyphVector(FontRenderContext frc, char[] chars, int start, int count, + int flags) { // TODO: implement method for bidirectional text. // At the moment only LTR and RTL texts supported. if (start < 0) { // awt.95=Wrong start index: {0} - throw new ArrayIndexOutOfBoundsException(Messages.getString( - "awt.95", //$NON-NLS-1$ + throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.95", //$NON-NLS-1$ start)); } if (count < 0) { // awt.98=Wrong count value, can not be negative: {0} - throw new ArrayIndexOutOfBoundsException(Messages.getString( - "awt.98", //$NON-NLS-1$ + throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.98", //$NON-NLS-1$ count)); } if (start + count > chars.length) { // awt.99=Wrong [start + count] is out of range: {0} - throw new ArrayIndexOutOfBoundsException(Messages.getString( - "awt.99", //$NON-NLS-1$ + throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.99", //$NON-NLS-1$ (start + count))); } @@ -1234,7 +1277,7 @@ public class Font implements Serializable { * @return the postscript name of this Font. */ public String getPSName() { - FontPeerImpl peer = (FontPeerImpl) this.getPeer(); + FontPeerImpl peer = (FontPeerImpl)this.getPeer(); return peer.getPSName(); } @@ -1251,39 +1294,37 @@ public class Font implements Serializable { * Gets the peer of this Font. * * @return the peer of this Font. - * * @deprecated Font rendering is platform independent now. */ @Deprecated public java.awt.peer.FontPeer getPeer() { if (fontPeer == null) { - fontPeer = (FontPeerImpl) Toolkit.getDefaultToolkit() - .getGraphicsFactory().getFontPeer(this); + fontPeer = (FontPeerImpl)Toolkit.getDefaultToolkit().getGraphicsFactory().getFontPeer( + this); } return fontPeer; } /** - * Gets the transform acting on this Font (from the Font's - * attributes). + * Gets the transform acting on this Font (from the Font's attributes). * - * @return the transformation of this Font. + * @return the transformation of this Font. */ public AffineTransform getTransform() { Object transform = fRequestedAttributes.get(TextAttribute.TRANSFORM); if (transform != null) { if (transform instanceof TransformAttribute) { - return ((TransformAttribute) transform).getTransform(); + return ((TransformAttribute)transform).getTransform(); } if (transform instanceof AffineTransform) { - return new AffineTransform((AffineTransform) transform); + return new AffineTransform((AffineTransform)transform); } } else { transform = new AffineTransform(); } - return (AffineTransform) transform; + return (AffineTransform)transform; } @@ -1324,13 +1365,12 @@ public class Font implements Serializable { } /** - * Returns true if this Font has uniform line metrics. + * Returns true if this Font has uniform line metrics. * - * @return true if this Font has uniform line metrics, - * false otherwise. + * @return true if this Font has uniform line metrics, false otherwise. */ public boolean hasUniformLineMetrics() { - FontPeerImpl peer = (FontPeerImpl) this.getPeer(); + FontPeerImpl peer = (FontPeerImpl)this.getPeer(); return peer.hasUniformLineMetrics(); } @@ -1338,7 +1378,6 @@ public class Font implements Serializable { * Returns hash code of this Font object. * * @return the hash code of this Font object. - */ @Override public int hashCode() { @@ -1376,21 +1415,21 @@ public class Font implements Serializable { */ public int getNumGlyphs() { if (numGlyphs == -1) { - FontPeerImpl peer = (FontPeerImpl) this.getPeer(); + FontPeerImpl peer = (FontPeerImpl)this.getPeer(); this.numGlyphs = peer.getNumGlyphs(); } return this.numGlyphs; } /** - * Gets the glyphCode which is used as default glyph when this Font - * does not have a glyph for a specified unicode. + * Gets the glyphCode which is used as default glyph when this Font does not + * have a glyph for a specified Unicode. * * @return the missing glyph code. */ public int getMissingGlyphCode() { if (missingGlyphCode == -1) { - FontPeerImpl peer = (FontPeerImpl) this.getPeer(); + FontPeerImpl peer = (FontPeerImpl)this.getPeer(); this.missingGlyphCode = peer.getMissingGlyphCode(); } return this.missingGlyphCode; @@ -1407,29 +1446,30 @@ public class Font implements Serializable { /** * Gets the italic angle of this Font. - * + * * @return the italic angle of this Font. */ public float getItalicAngle() { - FontPeerImpl peer = (FontPeerImpl) this.getPeer(); + FontPeerImpl peer = (FontPeerImpl)this.getPeer(); return peer.getItalicAngle(); } /** * Creates the font with the specified font format and font file. * - * @param fontFormat the font format. - * @param fontFile the file object represented the input data - * for the font. - * + * @param fontFormat + * the font format. + * @param fontFile + * the file object represented the input data for the font. * @return the Font. - * - * @throws FontFormatException is thrown if fontFile does not contain - * the required font tables for the specified format. - * @throws IOException signals that an I/O exception has occurred. - */ - public static Font createFont(int fontFormat, File fontFile) - throws FontFormatException, IOException { + * @throws FontFormatException + * is thrown if fontFile does not contain the required font + * tables for the specified format. + * @throws IOException + * signals that an I/O exception has occurred. + */ + public static Font createFont(int fontFormat, File fontFile) throws FontFormatException, + IOException { // ???AWT not supported InputStream is = new FileInputStream(fontFile); try { @@ -1442,15 +1482,16 @@ public class Font implements Serializable { /** * Creates the font with the specified font format and input stream. * - * @param fontFormat the font format. - * @param fontStream the input stream represented input data for - * the font. - * + * @param fontFormat + * the font format. + * @param fontStream + * the input stream represented input data for the font. * @return the Font. - * - * @throws FontFormatException is thrown if fontFile does not contain - * the required font tables for the specified format. - * @throws IOException signals that an I/O exception has occurred. + * @throws FontFormatException + * is thrown if fontFile does not contain the required font + * tables for the specified format. + * @throws IOException + * signals that an I/O exception has occurred. */ public static Font createFont(int fontFormat, InputStream fontStream) throws FontFormatException, IOException { @@ -1466,15 +1507,15 @@ public class Font implements Serializable { if (fontFormat != TRUETYPE_FONT) { // awt.9A=Unsupported font format throw new IllegalArgumentException(Messages.getString("awt.9A")); //$NON-NLS-1$ } - + /* Get font file in system-specific directory */ - File fontFile = Toolkit.getDefaultToolkit().getGraphicsFactory() - .getFontManager().getTempFontFile(); + File fontFile = Toolkit.getDefaultToolkit().getGraphicsFactory().getFontManager() + .getTempFontFile(); - // BEGIN android-modified + // BEGIN android-modified buffStream = new BufferedInputStream(fontStream, 8192); - // END android-modified + // END android-modified FileOutputStream fOutStream = new FileOutputStream(fontFile); bRead = buffStream.read(buf, 0, size); diff --git a/awt/java/awt/FontFormatException.java b/awt/java/awt/FontFormatException.java index c017fd24a53a3b93dd9e0882939cbdae42085df2..806711a76429def80ea7d6f619861479d848f433 100644 --- a/awt/java/awt/FontFormatException.java +++ b/awt/java/awt/FontFormatException.java @@ -18,21 +18,27 @@ * @author Ilya S. Okomin * @version $Revision$ */ + package java.awt; /** - * The FontFormatException class is used to provide notification - * and information that font can't be created. + * The FontFormatException class is used to provide notification and information + * that font can't be created. + * + * @since Android 1.0 */ public class FontFormatException extends Exception { - - /** The Constant serialVersionUID. */ + + /** + * The Constant serialVersionUID. + */ private static final long serialVersionUID = -4481290147811361272L; /** * Instantiates a new font format exception with detailed message. * - * @param reason the detailed message. + * @param reason + * the detailed message. */ public FontFormatException(String reason) { super(reason); diff --git a/awt/java/awt/FontMetrics.java b/awt/java/awt/FontMetrics.java index 3948d736abeadc12d66c28d3587edb398d098033..90826265a7f15262f128e52d873a57702413593b 100644 --- a/awt/java/awt/FontMetrics.java +++ b/awt/java/awt/FontMetrics.java @@ -18,6 +18,7 @@ * @author Ilya S. Okomin * @version $Revision$ */ + package java.awt; import java.awt.font.FontRenderContext; @@ -29,34 +30,40 @@ import java.text.CharacterIterator; import org.apache.harmony.awt.internal.nls.Messages; /** - * The FontMetrics class contains information about the rendering - * of a particular font on a particular screen. + * The FontMetrics class contains information about the rendering of a + * particular font on a particular screen. *

- * Each character in the Font has three values that help define where - * to place it: an ascent, a descent, and an advance. The ascent is the - * distance the character extends above the baseline. The descent is - * the distance the character extends below the baseline. - * The advance width defines the position at which the next character - * should be placed. + * Each character in the Font has three values that help define where to place + * it: an ascent, a descent, and an advance. The ascent is the distance the + * character extends above the baseline. The descent is the distance the + * character extends below the baseline. The advance width defines the position + * at which the next character should be placed. *

- * An array of characters or a string has an ascent, a descent, - * and an advance width too. The ascent or descent of the array - * is specified by the maximum ascent or descent of the characters - * in the array. The advance width is the sum of the advance widths - * of each of the characters in the character array. + * An array of characters or a string has an ascent, a descent, and an advance + * width too. The ascent or descent of the array is specified by the maximum + * ascent or descent of the characters in the array. The advance width is the + * sum of the advance widths of each of the characters in the character array. + *

+ * + * @since Android 1.0 */ public abstract class FontMetrics implements Serializable { - - /** The Constant serialVersionUID. */ + + /** + * The Constant serialVersionUID. + */ private static final long serialVersionUID = 1681126225205050147L; - /** The font from which the FontMetrics is created. */ + /** + * The font from which the FontMetrics is created. + */ protected Font font; /** * Instantiates a new font metrics from the specified Font. * - * @param fnt the Font. + * @param fnt + * the Font. */ protected FontMetrics(Font fnt) { this.font = fnt; @@ -65,12 +72,11 @@ public abstract class FontMetrics implements Serializable { /** * Returns the String representation of this FontMetrics. * - * @return the string + * @return the string. */ @Override public String toString() { - return this.getClass().getName() + - "[font=" + this.getFont() + //$NON-NLS-1$ + return this.getClass().getName() + "[font=" + this.getFont() + //$NON-NLS-1$ "ascent=" + this.getAscent() + //$NON-NLS-1$ ", descent=" + this.getDescent() + //$NON-NLS-1$ ", height=" + this.getHeight() + "]"; //$NON-NLS-1$ //$NON-NLS-2$ @@ -95,9 +101,9 @@ public abstract class FontMetrics implements Serializable { } /** - * Gets the font ascent of the Font associated with this FontMetrics. - * The font ascent is the distance from the font's baseline to - * the top of most alphanumeric characters. + * Gets the font ascent of the Font associated with this FontMetrics. The + * font ascent is the distance from the font's baseline to the top of most + * alphanumeric characters. * * @return the ascent of the Font associated with this FontMetrics. */ @@ -106,9 +112,9 @@ public abstract class FontMetrics implements Serializable { } /** - * Gets the font descent of the Font associated with this FontMetrics. - * The font descent is the distance from the font's baseline to - * the bottom of most alphanumeric characters with descenders. + * Gets the font descent of the Font associated with this FontMetrics. The + * font descent is the distance from the font's baseline to the bottom of + * most alphanumeric characters with descenders. * * @return the descent of the Font associated with this FontMetrics. */ @@ -126,192 +132,198 @@ public abstract class FontMetrics implements Serializable { } /** - * Gets the LineMetrics object for the specified CharacterIterator - * in the specified Graphics. - * - * @param ci the CharacterIterator. - * @param beginIndex the offset. - * @param limit the number of characters to be used. - * @param context the Graphics. - * - * @return the LineMetrics object for the specified CharacterIterator - * in the specified Graphics. + * Gets the LineMetrics object for the specified CharacterIterator in the + * specified Graphics. + * + * @param ci + * the CharacterIterator. + * @param beginIndex + * the offset. + * @param limit + * the number of characters to be used. + * @param context + * the Graphics. + * @return the LineMetrics object for the specified CharacterIterator in the + * specified Graphics. */ - public LineMetrics getLineMetrics(CharacterIterator ci, int beginIndex, - int limit, Graphics context) { - return font.getLineMetrics(ci, beginIndex, limit, - this.getFRCFromGraphics(context)); + public LineMetrics getLineMetrics(CharacterIterator ci, int beginIndex, int limit, + Graphics context) { + return font.getLineMetrics(ci, beginIndex, limit, this.getFRCFromGraphics(context)); } /** - * Gets the LineMetrics object for the specified String - * in the specified Graphics. - * - * @param str the String. - * @param context the Graphics. - * - * @return the LineMetrics object for the specified String - * in the specified Graphics. + * Gets the LineMetrics object for the specified String in the specified + * Graphics. + * + * @param str + * the String. + * @param context + * the Graphics. + * @return the LineMetrics object for the specified String in the specified + * Graphics. */ public LineMetrics getLineMetrics(String str, Graphics context) { return font.getLineMetrics(str, this.getFRCFromGraphics(context)); } /** - * Gets the LineMetrics object for the specified character - * array in the specified Graphics. - * - * @param chars the character array. - * @param beginIndex the offset of array. - * @param limit the number of characters to be used. - * @param context the Graphics. - * - * @return the LineMetrics object for the specified character - * array in the specified Graphics. + * Gets the LineMetrics object for the specified character array in the + * specified Graphics. + * + * @param chars + * the character array. + * @param beginIndex + * the offset of array. + * @param limit + * the number of characters to be used. + * @param context + * the Graphics. + * @return the LineMetrics object for the specified character array in the + * specified Graphics. */ - public LineMetrics getLineMetrics(char[] chars, int beginIndex, int limit, - Graphics context) { - return font.getLineMetrics(chars, beginIndex, limit, - this.getFRCFromGraphics(context)); + public LineMetrics getLineMetrics(char[] chars, int beginIndex, int limit, Graphics context) { + return font.getLineMetrics(chars, beginIndex, limit, this.getFRCFromGraphics(context)); } /** - * Gets the LineMetrics object for the specified String - * in the specified Graphics. - * - * @param str the String. - * @param beginIndex the offset. - * @param limit the number of characters to be used. - * @param context the Graphics. - * - * @return the LineMetrics object for the specified String - * in the specified Graphics. + * Gets the LineMetrics object for the specified String in the specified + * Graphics. + * + * @param str + * the String. + * @param beginIndex + * the offset. + * @param limit + * the number of characters to be used. + * @param context + * the Graphics. + * @return the LineMetrics object for the specified String in the specified + * Graphics. */ - public LineMetrics getLineMetrics(String str, int beginIndex, int limit, - Graphics context) { - return font.getLineMetrics(str, beginIndex, limit, - this.getFRCFromGraphics(context)); + public LineMetrics getLineMetrics(String str, int beginIndex, int limit, Graphics context) { + return font.getLineMetrics(str, beginIndex, limit, this.getFRCFromGraphics(context)); } /** - * Returns the character's maximum bounds in the specified - * Graphics context. - * - * @param context the Graphics context. + * Returns the character's maximum bounds in the specified Graphics context. * - * @return the character's maximum bounds in the specified - * Graphics context. + * @param context + * the Graphics context. + * @return the character's maximum bounds in the specified Graphics context. */ public Rectangle2D getMaxCharBounds(Graphics context) { return this.font.getMaxCharBounds(this.getFRCFromGraphics(context)); } - + /** - * Gets the bounds of the specified CharacterIterator - * in the specified Graphics context. - * - * @param ci the CharacterIterator. - * @param beginIndex the begin offset of the array. - * @param limit the number of characters. - * @param context the Graphics. + * Gets the bounds of the specified CharacterIterator in the specified + * Graphics context. * - * @return the bounds of the specified CharacterIterator - * in the specified Graphics context. + * @param ci + * the CharacterIterator. + * @param beginIndex + * the begin offset of the array. + * @param limit + * the number of characters. + * @param context + * the Graphics. + * @return the bounds of the specified CharacterIterator in the specified + * Graphics context. */ - public Rectangle2D getStringBounds(CharacterIterator ci, int beginIndex, - int limit, Graphics context) { - return font.getStringBounds(ci, beginIndex, limit, - this.getFRCFromGraphics(context)); + public Rectangle2D getStringBounds(CharacterIterator ci, int beginIndex, int limit, + Graphics context) { + return font.getStringBounds(ci, beginIndex, limit, this.getFRCFromGraphics(context)); } /** - * Gets the bounds of the specified String - * in the specified Graphics context. - * - * @param str the String. - * @param beginIndex the begin offset of the array. - * @param limit the number of characters. - * @param context the Graphics. - * - * @return the bounds of the specified String - * in the specified Graphics context. + * Gets the bounds of the specified String in the specified Graphics + * context. + * + * @param str + * the String. + * @param beginIndex + * the begin offset of the array. + * @param limit + * the number of characters. + * @param context + * the Graphics. + * @return the bounds of the specified String in the specified Graphics + * context. */ - public Rectangle2D getStringBounds(String str, int beginIndex, int limit, - Graphics context) { - return font.getStringBounds(str, beginIndex, limit, - this.getFRCFromGraphics(context)); + public Rectangle2D getStringBounds(String str, int beginIndex, int limit, Graphics context) { + return font.getStringBounds(str, beginIndex, limit, this.getFRCFromGraphics(context)); } - /** - * Gets the bounds of the specified characters array - * in the specified Graphics context. - * - * @param chars the characters array. - * @param beginIndex the begin offset of the array. - * @param limit the number of characters. - * @param context the Graphics. + * Gets the bounds of the specified characters array in the specified + * Graphics context. * - * @return the bounds of the specified characters array - * in the specified Graphics context. + * @param chars + * the characters array. + * @param beginIndex + * the begin offset of the array. + * @param limit + * the number of characters. + * @param context + * the Graphics. + * @return the bounds of the specified characters array in the specified + * Graphics context. */ - public Rectangle2D getStringBounds(char[] chars, int beginIndex, int limit, - Graphics context) { - return font.getStringBounds(chars, beginIndex, limit, - this.getFRCFromGraphics(context)); + public Rectangle2D getStringBounds(char[] chars, int beginIndex, int limit, Graphics context) { + return font.getStringBounds(chars, beginIndex, limit, this.getFRCFromGraphics(context)); } /** - * Gets the bounds of the specified String - * in the specified Graphics context. - * - * @param str the String. - * @param context the Graphics. - * - * @return the bounds of the specified String - * in the specified Graphics context. + * Gets the bounds of the specified String in the specified Graphics + * context. + * + * @param str + * the String. + * @param context + * the Graphics. + * @return the bounds of the specified String in the specified Graphics + * context. */ public Rectangle2D getStringBounds(String str, Graphics context) { return font.getStringBounds(str, this.getFRCFromGraphics(context)); } /** - * Checks if the Font has uniform line metrics or not. - * The Font can contain characters of other fonts for - * covering character set. In this case the Font isn't - * uniform. - * - * @return true, if the Font has uniform line metrics, - * false otherwise. + * Checks if the Font has uniform line metrics or not. The Font can contain + * characters of other fonts for covering character set. In this case the + * Font isn't uniform. + * + * @return true, if the Font has uniform line metrics, false otherwise. */ public boolean hasUniformLineMetrics() { return this.font.hasUniformLineMetrics(); } /** - * Returns the distance from the leftmost point to the rightmost - * point on the string's baseline showing the specified array - * of bytes in this Font. - * - * @param data the array of bytes to be measured. - * @param off the start offset. - * @param len the number of bytes to be measured. - * + * Returns the distance from the leftmost point to the rightmost point on + * the string's baseline showing the specified array of bytes in this Font. + * + * @param data + * the array of bytes to be measured. + * @param off + * the start offset. + * @param len + * the number of bytes to be measured. * @return the advance width of the array. */ public int bytesWidth(byte[] data, int off, int len) { int width = 0; - if ((off >= data.length) || (off < 0)){ + if ((off >= data.length) || (off < 0)) { // awt.13B=offset off is out of range throw new IllegalArgumentException(Messages.getString("awt.13B")); //$NON-NLS-1$ } - if ((off+len > data.length)){ + if ((off + len > data.length)) { // awt.13C=number of elemets len is out of range throw new IllegalArgumentException(Messages.getString("awt.13C")); //$NON-NLS-1$ } - for (int i = off; i < off+len; i++){ + for (int i = off; i < off + len; i++) { width += charWidth(data[i]); } @@ -319,29 +331,31 @@ public abstract class FontMetrics implements Serializable { } /** - * Returns the distance from the leftmost point to the rightmost - * point on the string's baseline showing the specified array - * of characters in this Font. - * - * @param data the array of characters to be measured. - * @param off the start offset. - * @param len the number of bytes to be measured. - * + * Returns the distance from the leftmost point to the rightmost point on + * the string's baseline showing the specified array of characters in this + * Font. + * + * @param data + * the array of characters to be measured. + * @param off + * the start offset. + * @param len + * the number of bytes to be measured. * @return the advance width of the array. */ - public int charsWidth(char[] data, int off , int len){ + public int charsWidth(char[] data, int off, int len) { int width = 0; - if ((off >= data.length) || (off < 0)){ + if ((off >= data.length) || (off < 0)) { // awt.13B=offset off is out of range throw new IllegalArgumentException(Messages.getString("awt.13B")); //$NON-NLS-1$ } - if ((off+len > data.length)){ + if ((off + len > data.length)) { // awt.13C=number of elemets len is out of range throw new IllegalArgumentException(Messages.getString("awt.13C")); //$NON-NLS-1$ } - for (int i = off; i < off+len; i++){ + for (int i = off; i < off + len; i++) { width += charWidth(data[i]); } @@ -349,12 +363,11 @@ public abstract class FontMetrics implements Serializable { } /** - * Returns the distance from the leftmost point to the rightmost - * point of the specified character in this Font. - * - * @param ch the specified unicode point code of - * character to be measured. + * Returns the distance from the leftmost point to the rightmost point of + * the specified character in this Font. * + * @param ch + * the specified Unicode point code of character to be measured. * @return the advance width of the character. */ public int charWidth(int ch) { @@ -362,11 +375,11 @@ public abstract class FontMetrics implements Serializable { } /** - * Returns the distance from the leftmost point to the rightmost - * point of the specified character in this Font. - * - * @param ch the specified character to be measured. + * Returns the distance from the leftmost point to the rightmost point of + * the specified character in this Font. * + * @param ch + * the specified character to be measured. * @return the advance width of the character. */ public int charWidth(char ch) { @@ -383,11 +396,11 @@ public abstract class FontMetrics implements Serializable { } /** - * Gets the maximum font ascent of the Font associated with - * this FontMetrics. + * Gets the maximum font ascent of the Font associated with this + * FontMetrics. * - * @return the maximum font ascent of the Font associated with - * this FontMetrics. + * @return the maximum font ascent of the Font associated with this + * FontMetrics. */ public int getMaxAscent() { return 0; @@ -397,7 +410,6 @@ public abstract class FontMetrics implements Serializable { * Gets the maximum font descent of character in this Font. * * @return the maximum font descent of character in this Font. - * * @deprecated Replaced by getMaxDescent() method. */ @Deprecated @@ -426,23 +438,22 @@ public abstract class FontMetrics implements Serializable { /** * Returns the advance width for the specified String in this Font. * - * @param str String to be measured. - * - * @return the the advance width for the specified String - * in this Font. + * @param str + * String to be measured. + * @return the the advance width for the specified String in this Font. */ public int stringWidth(String str) { return 0; } - + /** - * Returns FontRenderContext instanse of the Graphics context specified. - * - * @param context the specified Graphics context + * Returns a FontRenderContext instance of the Graphics context specified. * + * @param context + * the specified Graphics context. * @return a FontRenderContext of the specified Graphics context. */ - private FontRenderContext getFRCFromGraphics(Graphics context){ + private FontRenderContext getFRCFromGraphics(Graphics context) { FontRenderContext frc; if (context instanceof Graphics2D) { frc = ((Graphics2D)context).getFontRenderContext(); @@ -453,4 +464,3 @@ public abstract class FontMetrics implements Serializable { return frc; } } - diff --git a/awt/java/awt/GradientPaint.java b/awt/java/awt/GradientPaint.java index 0e06528f988475557618bf440182d9affdf26ee0..3b32ef53040ecfa2f1d69dd0daae81fb3e436890 100644 --- a/awt/java/awt/GradientPaint.java +++ b/awt/java/awt/GradientPaint.java @@ -26,56 +26,71 @@ import org.apache.harmony.awt.internal.nls.Messages; /** * The GradientPaint class defines a way to fill a Shape with a linear color - * gradient pattern. + * gradient pattern. *

- * The GradientPaint's fill pattern is determined by two points and two colors, - * plus the cyclic mode option. - * Each of the two points is painted with its corresponding color, and on - * the line segment connecting the two points, the color is proportionally - * changed between the two colors. For points on the same line which are not - * between the two specified points (outside of the connecting segment) their - * color is determined by the cyclic mode option. If the mode is cyclic, then - * the rest of the line repeats the color pattern of the connecting segment, - * cycling back and forth between the two colors. If not, the mode is acyclic - * which means that all points - * on the line outside the connecting line segment are given the same - * color as the closest of the two specified points. + * The GradientPaint's fill pattern is determined by two points and two colors, + * plus the cyclic mode option. Each of the two points is painted with its + * corresponding color, and on the line segment connecting the two points, the + * color is proportionally changed between the two colors. For points on the + * same line which are not between the two specified points (outside of the + * connecting segment) their color is determined by the cyclic mode option. If + * the mode is cyclic, then the rest of the line repeats the color pattern of + * the connecting segment, cycling back and forth between the two colors. If + * not, the mode is acyclic which means that all points on the line outside the + * connecting line segment are given the same color as the closest of the two + * specified points. *

- * The color of points that are not on the line connecting the two - * specified points are given by perpendicular projection: by taking - * the set of lines perpendicular to the connecting line and for each - * one, the whole line is colored with the same color. + * The color of points that are not on the line connecting the two specified + * points are given by perpendicular projection: by taking the set of lines + * perpendicular to the connecting line and for each one, the whole line is + * colored with the same color. + * + * @since Android 1.0 */ public class GradientPaint implements Paint { - - /** The start point color. */ + + /** + * The start point color. + */ Color color1; - /** The end color point. */ + /** + * The end color point. + */ Color color2; - /** The location of the start point. */ + /** + * The location of the start point. + */ Point2D point1; - /** The location of the end point. */ + /** + * The location of the end point. + */ Point2D point2; - /** The indicator of cycle filling. If TRUE filling - * repeated outside points stripe, if FALSE solid color filling outside. */ + /** + * The indicator of cycle filling. If TRUE filling repeated outside points + * stripe, if FALSE solid color filling outside. + */ boolean cyclic; /** * Instantiates a new GradientPaint with cyclic or acyclic mode. * - * @param point1 the first specified point. - * @param color1 the Color of the first specified point. - * @param point2 the second specified point. - * @param color2 the Color of the second specified point. - * @param cyclic the cyclic mode - true if the gradient pattern should cycle - * repeatedly between the two colors; false otherwise. - */ - public GradientPaint(Point2D point1, Color color1, Point2D point2, - Color color2, boolean cyclic) { + * @param point1 + * the first specified point. + * @param color1 + * the Color of the first specified point. + * @param point2 + * the second specified point. + * @param color2 + * the Color of the second specified point. + * @param cyclic + * the cyclic mode - true if the gradient pattern should cycle + * repeatedly between the two colors; false otherwise. + */ + public GradientPaint(Point2D point1, Color color1, Point2D point2, Color color2, boolean cyclic) { if (point1 == null || point2 == null) { // awt.6D=Point is null throw new NullPointerException(Messages.getString("awt.6D")); //$NON-NLS-1$ @@ -93,17 +108,24 @@ public class GradientPaint implements Paint { } /** - * Instantiates a new GradientPaint with cyclic or acyclic mode; - * points are specified by coordinates. + * Instantiates a new GradientPaint with cyclic or acyclic mode; points are + * specified by coordinates. * - * @param x1 the X coordinate of the first point. - * @param y1 the Y coordinate of the first point. - * @param color1 the color of the first point. - * @param x2 the X coordinate of the second point. - * @param y2 the Y coordinate of the second point. - * @param color2 the color of the second point. - * @param cyclic the cyclic mode - true if the gradient pattern should cycle - * repeatedly between the two colors; false otherwise. + * @param x1 + * the X coordinate of the first point. + * @param y1 + * the Y coordinate of the first point. + * @param color1 + * the color of the first point. + * @param x2 + * the X coordinate of the second point. + * @param y2 + * the Y coordinate of the second point. + * @param color2 + * the color of the second point. + * @param cyclic + * the cyclic mode - true if the gradient pattern should cycle + * repeatedly between the two colors; false otherwise. */ public GradientPaint(float x1, float y1, Color color1, float x2, float y2, Color color2, boolean cyclic) { @@ -111,15 +133,21 @@ public class GradientPaint implements Paint { } /** - * Instantiates a new acyclic GradientPaint; - * points are specified by coordinates. + * Instantiates a new acyclic GradientPaint; points are specified by + * coordinates. * - * @param x1 the X coordinate of the first point. - * @param y1 the Y coordinate of the first point. - * @param color1 the color of the first point. - * @param x2 the X coordinate of the second point. - * @param y2 the Y coordinate of the second point. - * @param color2 the color of the second point. + * @param x1 + * the X coordinate of the first point. + * @param y1 + * the Y coordinate of the first point. + * @param color1 + * the color of the first point. + * @param x2 + * the X coordinate of the second point. + * @param y2 + * the Y coordinate of the second point. + * @param color2 + * the color of the second point. */ public GradientPaint(float x1, float y1, Color color1, float x2, float y2, Color color2) { this(x1, y1, color1, x2, y2, color2, false); @@ -128,29 +156,38 @@ public class GradientPaint implements Paint { /** * Instantiates a new acyclic GradientPaint. * - * @param point1 the first specified point. - * @param color1 the Color of the first specified point. - * @param point2 the second specified point. - * @param color2 the Color of the second specified point. + * @param point1 + * the first specified point. + * @param color1 + * the Color of the first specified point. + * @param point2 + * the second specified point. + * @param color2 + * the Color of the second specified point. */ public GradientPaint(Point2D point1, Color color1, Point2D point2, Color color2) { this(point1, color1, point2, color2, false); } /** - * Creates PaintContext for a color pattern generating. - * - * @param cm the ColorModel of the Paint data. - * @param deviceBounds the bounding Rectangle of graphics primitives - * being rendered in the device space. - * @param userBounds tthe bounding Rectangle of graphics primitives - * being rendered in the user space. - * @param t the AffineTransform from user space into device space. - * @param hints the RrenderingHints object. + * Creates PaintContext for a color pattern generating. * + * @param cm + * the ColorModel of the Paint data. + * @param deviceBounds + * the bounding Rectangle of graphics primitives being rendered + * in the device space. + * @param userBounds + * the bounding Rectangle of graphics primitives being rendered + * in the user space. + * @param t + * the AffineTransform from user space into device space. + * @param hints + * the RrenderingHints object. * @return the PaintContext for color pattern generating. - * - * @see java.awt.Paint#createContext(java.awt.image.ColorModel, java.awt.Rectangle, java.awt.geom.Rectangle2D, java.awt.geom.AffineTransform, java.awt.RenderingHints) + * @see java.awt.Paint#createContext(java.awt.image.ColorModel, + * java.awt.Rectangle, java.awt.geom.Rectangle2D, + * java.awt.geom.AffineTransform, java.awt.RenderingHints) */ public PaintContext createContext(ColorModel cm, Rectangle deviceBounds, Rectangle2D userBounds, AffineTransform t, RenderingHints hints) { @@ -178,7 +215,7 @@ public class GradientPaint implements Paint { /** * Gets the first point. * - * @return the Point object - the first point. + * @return the Point object - the first point. */ public Point2D getPoint1() { return point1; @@ -197,7 +234,6 @@ public class GradientPaint implements Paint { * Gets the transparency mode for the GradientPaint. * * @return the transparency mode for the GradientPaint. - * * @see java.awt.Transparency#getTransparency() */ public int getTransparency() { @@ -207,11 +243,11 @@ public class GradientPaint implements Paint { } /** - * Returns the GradientPaint mode: true for cyclic mode, false for - * acyclic mode. + * Returns the GradientPaint mode: true for cyclic mode, false for acyclic + * mode. * - * @return true if the gradient cycles repeatedly between the two colors; - * false otherwise. + * @return true if the gradient cycles repeatedly between the two colors; + * false otherwise. */ public boolean isCyclic() { return cyclic; diff --git a/awt/java/awt/Graphics.java b/awt/java/awt/Graphics.java index c20f6bc9e0ee7c3c44344727ddb30133366d872c..2d6e79fca4607dba40818f0ae2d9adafd6aa09db 100644 --- a/awt/java/awt/Graphics.java +++ b/awt/java/awt/Graphics.java @@ -18,26 +18,27 @@ * @author Alexey A. Petrenko * @version $Revision$ */ + package java.awt; import java.awt.image.ImageObserver; import java.text.AttributedCharacterIterator; /** - * The abstract Graphics class allows applications to draw on a screen - * or other rendering target. There are several properties which - * define rendering options: origin point, clipping area, color, font. - *

- * The origin point specifies the beggining of the clipping area coordinate - * system. All coordinates used in rendering operations are computed with - * respect to this point. The clipping area defines the boundaries where - * rendering operations can be performed. Rendering operations can't modify - * pixels outside of the clipping area. - *

- * The draw and fill methods allow applications to drawing shapes, text, - * images with specified font and color options in the specified part - * of the screen. - * + * The abstract Graphics class allows applications to draw on a screen or other + * rendering target. There are several properties which define rendering + * options: origin point, clipping area, color, font.
+ *
+ * The origin point specifies the beginning of the clipping area coordinate + * system. All coordinates used in rendering operations are computed with + * respect to this point. The clipping area defines the boundaries where + * rendering operations can be performed. Rendering operations can't modify + * pixels outside of the clipping area.
+ *
+ * The draw and fill methods allow applications to drawing shapes, text, images + * with specified font and color options in the specified part of the screen. + * + * @since Android 1.0 */ public abstract class Graphics { @@ -45,7 +46,7 @@ public abstract class Graphics { /** * Instantiates a new Graphics. This constructor is default for Graphics and - * can not be called directly. + * can not be called directly. */ protected Graphics() { } @@ -53,19 +54,22 @@ public abstract class Graphics { // Public methods /** - * Creates a copy of the Graphics object with a new origin and a new - * specified clip area. The new clip area is the rectangle defined by - * the origin point with coordinates X,Y and the given width and height. - * The coordinates of all subsequent rendering operations will be computed - * with respect to the new origin and can be performed only within the - * range of the clipping area dimentions. - * - * @param x the X coordinate of the original point - * @param y the Y coordinate of the original point - * @param width the width of clipping area - * @param height the height of clipping area + * Creates a copy of the Graphics object with a new origin and a new + * specified clip area. The new clip area is the rectangle defined by the + * origin point with coordinates X,Y and the given width and height. The + * coordinates of all subsequent rendering operations will be computed with + * respect to the new origin and can be performed only within the range of + * the clipping area dimensions. * - * @return the Graphics object with new origin point and clipping area. + * @param x + * the X coordinate of the original point. + * @param y + * the Y coordinate of the original point. + * @param width + * the width of clipping area. + * @param height + * the height of clipping area. + * @return the Graphics object with new origin point and clipping area. */ public Graphics create(int x, int y, int width, int height) { Graphics res = create(); @@ -75,18 +79,24 @@ public abstract class Graphics { } /** - * Draws the higlighted outline of a rectangle. + * Draws the highlighted outline of a rectangle. * - * @param x the X coordinate of the rectangle's top left corner. - * @param y the Y coordinate of the rectangle's top left corner. - * @param width the width of rectangle. - * @param height the height of rectangle. - * @param raised a boolean value that determines whether the rectangle - * is drawn as raised or indented. + * @param x + * the X coordinate of the rectangle's top left corner. + * @param y + * the Y coordinate of the rectangle's top left corner. + * @param width + * the width of rectangle. + * @param height + * the height of rectangle. + * @param raised + * a boolean value that determines whether the rectangle is drawn + * as raised or indented. */ public void draw3DRect(int x, int y, int width, int height, boolean raised) { // Note: lighter/darker colors should be used to draw 3d rect. - // The resulting rect is (width+1)x(height+1). Stroke and paint attributes of + // The resulting rect is (width+1)x(height+1). Stroke and paint + // attributes of // the Graphics2D should be reset to the default values. // fillRect is used instead of drawLine to bypass stroke // reset/set and rasterization. @@ -103,36 +113,46 @@ public abstract class Graphics { setColor(colorUp); fillRect(x, y, width, 1); - fillRect(x, y+1, 1, height); + fillRect(x, y + 1, 1, height); setColor(colorDown); - fillRect(x+width, y, 1, height); - fillRect(x+1, y+height, width, 1); + fillRect(x + width, y, 1, height); + fillRect(x + 1, y + height, width, 1); } /** - * Draws the text represented by byte array. This method uses the current + * Draws the text represented by byte array. This method uses the current * font and color for rendering. * - * @param bytes the byte array which contains the text to be drawn. - * @param off the offset within the byte array of the text to be drawn. - * @param len the number of bytes of text to draw. - * @param x the X coordinate where the text is to be drawn. - * @param y the Y coordinate where the text is to be drawn. + * @param bytes + * the byte array which contains the text to be drawn. + * @param off + * the offset within the byte array of the text to be drawn. + * @param len + * the number of bytes of text to draw. + * @param x + * the X coordinate where the text is to be drawn. + * @param y + * the Y coordinate where the text is to be drawn. */ public void drawBytes(byte[] bytes, int off, int len, int x, int y) { drawString(new String(bytes, off, len), x, y); } /** - * Draws the text represented by character array. This method uses the + * Draws the text represented by character array. This method uses the * current font and color for rendering. * - * @param chars the character array. - * @param off the offset within the character array of the text to be drawn. - * @param len the number of characters which will be drawn. - * @param x the X coordinate where the text is to be drawn. - * @param y the Y coordinate where the text is to be drawn. + * @param chars + * the character array. + * @param off + * the offset within the character array of the text to be drawn. + * @param len + * the number of characters which will be drawn. + * @param x + * the X coordinate where the text is to be drawn. + * @param y + * the Y coordinate where the text is to be drawn. */ public void drawChars(char[] chars, int off, int len, int x, int y) { drawString(new String(chars, off, len), x, y); @@ -141,37 +161,51 @@ public abstract class Graphics { /** * Draws the outline of a polygon which is defined by Polygon object. * - * @param p the Polygon object. + * @param p + * the Polygon object. */ public void drawPolygon(Polygon p) { drawPolygon(p.xpoints, p.ypoints, p.npoints); } /** - * Draws the rectangle with the specified width and length and top left + * Draws the rectangle with the specified width and length and top left * corner coordinates. * - * @param x the X coordinate of the rectangle's top left corner. - * @param y the Y coordinate of the rectangle's top left corner. - * @param width the width of the rectangle. - * @param height the height of the rectangle. + * @param x + * the X coordinate of the rectangle's top left corner. + * @param y + * the Y coordinate of the rectangle's top left corner. + * @param width + * the width of the rectangle. + * @param height + * the height of the rectangle. */ public void drawRect(int x, int y, int width, int height) { - int []xpoints = {x, x, x+width, x+width}; - int []ypoints = {y, y+height, y+height, y}; + int[] xpoints = { + x, x, x + width, x + width + }; + int[] ypoints = { + y, y + height, y + height, y + }; drawPolygon(xpoints, ypoints, 4); } /** - * Fills the higlighted outline of a rectangle. + * Fills the highlighted outline of a rectangle. * - * @param x the X coordinate of the rectangle's top left corner. - * @param y the Y coordinate of the rectangle's top left corner. - * @param width the width of the rectangle. - * @param height the height of the rectangle. - * @param raised a boolean value that determines whether the rectangle - * is drawn as raised or indented. + * @param x + * the X coordinate of the rectangle's top left corner. + * @param y + * the Y coordinate of the rectangle's top left corner. + * @param width + * the width of the rectangle. + * @param height + * the height of the rectangle. + * @param raised + * a boolean value that determines whether the rectangle is drawn + * as raised or indented. */ public void fill3DRect(int x, int y, int width, int height, boolean raised) { // Note: lighter/darker colors should be used to draw 3d rect. @@ -179,7 +213,7 @@ public abstract class Graphics { // Stroke and paint attributes of the Graphics2D should be reset // to the default values. fillRect is used instead of drawLine to // bypass stroke reset/set and line rasterization. - + Color color = getColor(); Color colorUp, colorDown; if (raised) { @@ -194,21 +228,22 @@ public abstract class Graphics { width--; height--; - fillRect(x+1, y+1, width-1, height-1); + fillRect(x + 1, y + 1, width - 1, height - 1); setColor(colorUp); fillRect(x, y, width, 1); - fillRect(x, y+1, 1, height); + fillRect(x, y + 1, 1, height); setColor(colorDown); - fillRect(x+width, y, 1, height); - fillRect(x+1, y+height, width, 1); + fillRect(x + width, y, 1, height); + fillRect(x + 1, y + height, width, 1); } /** * Fills the polygon with the current color. * - * @param p the Polygon object. + * @param p + * the Polygon object. */ public void fillPolygon(Polygon p) { fillPolygon(p.xpoints, p.ypoints, p.npoints); @@ -222,12 +257,12 @@ public abstract class Graphics { } /** - * Gets the bounds of the current clipping area as a rectangle - * and copies it to an existing rectangle. - * - * @param r a Rectangle object where the current clipping area - * bounds are to be copied. + * Gets the bounds of the current clipping area as a rectangle and copies it + * to an existing rectangle. * + * @param r + * a Rectangle object where the current clipping area bounds are + * to be copied. * @return the bounds of the current clipping area. */ public Rectangle getClipBounds(Rectangle r) { @@ -248,8 +283,7 @@ public abstract class Graphics { /** * Gets the bounds of the current clipping area as a rectangle. * - * @return a Rectangle object - * + * @return a Rectangle object. * @deprecated Use {@link #getClipBounds()} */ @Deprecated @@ -258,9 +292,8 @@ public abstract class Graphics { } /** - * Gets the font metrics of the current font. - * The font metrics object contains information about the rendering - * of a particular font. + * Gets the font metrics of the current font. The font metrics object + * contains information about the rendering of a particular font. * * @return the font metrics of current font. */ @@ -269,19 +302,23 @@ public abstract class Graphics { } /** - * Determines whether or not the specified rectangle intersects the - * current clipping area. - * - * @param x the X coordinate of the rectangle. - * @param y the Y coordinate of the rectangle. - * @param width the width of the rectangle. - * @param height the height of the rectangle. + * Determines whether or not the specified rectangle intersects the current + * clipping area. * - * @return true, if the specified rectangle intersects the current clipping area, - * overwise false. + * @param x + * the X coordinate of the rectangle. + * @param y + * the Y coordinate of the rectangle. + * @param width + * the width of the rectangle. + * @param height + * the height of the rectangle. + * @return true, if the specified rectangle intersects the current clipping + * area, false otherwise. */ public boolean hitClip(int x, int y, int width, int height) { - // TODO: Create package private method Rectangle.intersects(int, int, int, int); + // TODO: Create package private method Rectangle.intersects(int, int, + // int, int); return getClipBounds().intersects(new Rectangle(x, y, width, height)); } @@ -299,45 +336,56 @@ public abstract class Graphics { // Abstract methods /** - * Clears the specified rectangle. This method fills specified rectangle - * with background color. + * Clears the specified rectangle. This method fills specified rectangle + * with background color. * - * @param x the X coordinate of the rectangle. - * @param y the Y coordinate of the rectangle. - * @param width the width of the rectangle. - * @param height the height of the rectangle. + * @param x + * the X coordinate of the rectangle. + * @param y + * the Y coordinate of the rectangle. + * @param width + * the width of the rectangle. + * @param height + * the height of the rectangle. */ public abstract void clearRect(int x, int y, int width, int height); /** - * Intersects the current clipping area with a new rectangle. - * If the current clipping area is not defined, the rectangle - * becomes a new clipping area. Rendering operations are only allowed - * within the new the clipping area. - * - * @param x the X coordinate of the rectangle for intersection. - * @param y the Y coordinate of the rectangle for intersection. - * @param width the width of the rectangle for intersection. - * @param height the height of the rectangle for intersection. + * Intersects the current clipping area with a new rectangle. If the current + * clipping area is not defined, the rectangle becomes a new clipping area. + * Rendering operations are only allowed within the new the clipping area. + * + * @param x + * the X coordinate of the rectangle for intersection. + * @param y + * the Y coordinate of the rectangle for intersection. + * @param width + * the width of the rectangle for intersection. + * @param height + * the height of the rectangle for intersection. */ public abstract void clipRect(int x, int y, int width, int height); /** - * Copies the rectangle area to another area specified by - * a distance (dx, dy) from the original rectangle's location. - * Positive dx and dy values give a new location defined by - * translation to the right and down from the original location, - * negative dx and dy values - to the left and up. - *

- * - * @param sx the X coordinate of the rectangle which will be copied. - * @param sy the Y coordinate of the rectangle which will be copied. - * @param width the width of the rectangle which will be copied. - * @param height the height of the rectangle which will be copied. - * @param dx the horizontal distance from the source rectangle's - * location to the copy's location. - * @param dy the vertical distance from the source rectangle's - * location to the copy's location. + * Copies the rectangle area to another area specified by a distance (dx, + * dy) from the original rectangle's location. Positive dx and dy values + * give a new location defined by translation to the right and down from the + * original location, negative dx and dy values - to the left and up. + * + * @param sx + * the X coordinate of the rectangle which will be copied. + * @param sy + * the Y coordinate of the rectangle which will be copied. + * @param width + * the width of the rectangle which will be copied. + * @param height + * the height of the rectangle which will be copied. + * @param dx + * the horizontal distance from the source rectangle's location + * to the copy's location. + * @param dy + * the vertical distance from the source rectangle's location to + * the copy's location. */ public abstract void copyArea(int sx, int sy, int width, int height, int dx, int dy); @@ -349,215 +397,314 @@ public abstract class Graphics { public abstract Graphics create(); /** - * Disposes of the Graphics. This Graphics object can not be used after - * calling this method. + * Disposes of the Graphics. This Graphics object can not be used after + * calling this method. */ public abstract void dispose(); /** - * Draws the arc covering the specified rectangle and using the current color. - * The rectangle is defined by the origin point (X, Y) and dimentions - * (width and height). The arc center is the the center of specified rectangle. - * The angle origin is 3 o'clock position, the positive angle is counted as a - * counter-clockwise rotation, the negotive angle is counted as clockwise rotation. - * - * @param x the X origin coordinate of the rectangle which scales the arc. - * @param y the Y origin coordinate of the rectangle which scales the arc. - * @param width the width of the rectangle which scales the arc. - * @param height the height of the rectangle which scales the arc. - * @param sa start angle - the origin angle of arc. - * @param ea arc angle - the angular arc value relative to the start angle. + * Draws the arc covering the specified rectangle and using the current + * color. The rectangle is defined by the origin point (X, Y) and dimensions + * (width and height). The arc center is the the center of specified + * rectangle. The angle origin is 3 o'clock position, the positive angle is + * counted as a counter-clockwise rotation, the negative angle is counted as + * clockwise rotation. + * + * @param x + * the X origin coordinate of the rectangle which scales the arc. + * @param y + * the Y origin coordinate of the rectangle which scales the arc. + * @param width + * the width of the rectangle which scales the arc. + * @param height + * the height of the rectangle which scales the arc. + * @param sa + * start angle - the origin angle of arc. + * @param ea + * arc angle - the angular arc value relative to the start angle. */ public abstract void drawArc(int x, int y, int width, int height, int sa, int ea); /** - * Draws the specified image with the defined background color. - * The top left corner of image will be drawn at point (x, y) - * in current coordinate system. The image loading process notifies the - * specified Image Observer. This method returns true if the image - * has loaded, overwise it returns false. - * - * @param img the image which will be drawn. - * @param x the X coordinate of the image top left corner. - * @param y the Y coordinate of the image top left corner. - * @param bgcolor the background color. - * @param observer the ImageObserver object which should be notified about image loading process. - * - * @return true, if loading image is successful or image is null, overwise false. + * Draws the specified image with the defined background color. The top left + * corner of image will be drawn at point (x, y) in current coordinate + * system. The image loading process notifies the specified Image Observer. + * This method returns true if the image has loaded, otherwise it returns + * false. + * + * @param img + * the image which will be drawn. + * @param x + * the X coordinate of the image top left corner. + * @param y + * the Y coordinate of the image top left corner. + * @param bgcolor + * the background color. + * @param observer + * the ImageObserver object which should be notified about image + * loading process. + * @return true, if loading image is successful or image is null, false + * otherwise. */ public abstract boolean drawImage(Image img, int x, int y, Color bgcolor, ImageObserver observer); /** - * Draws the specified image. - * The top left corner of image will be drawn at point (x, y) - * in current coordinate system. The image loading process notifies the - * specified Image Observer. This method returns true if the image - * has loaded, overwise it returns false. + * Draws the specified image. The top left corner of image will be drawn at + * point (x, y) in current coordinate system. The image loading process + * notifies the specified Image Observer. This method returns true if the + * image has loaded, otherwise it returns false. * - * @param img the image which will be drawn. - * @param x the X coordinate of the image top left corner. - * @param y the Y coordinate of the image top left corner. - * @param observer the ImageObserver object which should be notified about image loading process. - * - * @return true, if loading image is successful or image is null, overwise false. + * @param img + * the image which will be drawn. + * @param x + * the X coordinate of the image top left corner. + * @param y + * the Y coordinate of the image top left corner. + * @param observer + * the ImageObserver object which should be notified about image + * loading process. + * @return true, if loading image is successful or image is null, otherwise + * false. */ public abstract boolean drawImage(Image img, int x, int y, ImageObserver observer); /** - * Scales the specified image to fit in the specified rectangle and - * draws it with the defined background color. The top left corner - * of the image will be drawn at the point (x, y) in current coordinate - * system. The non-opaque pixels will be drawn in the background color. - * The image loading process notifies the specified Image Observer. - * This method returns true if the image has loaded, overwise it returns false. - * - * @param img the image which will be drawn. - * @param x the X coordinate of the image's top left corner. - * @param y the Y coordinate of the image's top left corner. - * @param width the width of rectangle which scales the image. - * @param height the height of rectangle which scales the image. - * @param bgcolor the background color. - * @param observer the ImageObserver object which should be notified about image loading process. - * - * @return true, if loading image is successful or image is null, overwise false. - */ - public abstract boolean drawImage(Image img, int x, int y, int width, int height, Color bgcolor, ImageObserver observer); - - /** - * Scales the specified image to fit in the specified rectangle and - * draws it. The top left corner of the image will be drawn at the - * point (x, y) in current coordinate system. The image loading process - * notifies the specified Image Observer. - * This method returns true if the image has loaded, overwise it returns false. - * - * @param img the image which will be drawn. - * @param x the X coordinate of the image top left corner. - * @param y the Y coordinate of the image top left corner. - * @param width the width of rectangle which scales the image. - * @param height the height of rectangle which scales the image. - * @param observer the ImageObserver object which should be notified about image loading process. - * - * @return true, if loading image is successful or image is null, overwise false. - */ - public abstract boolean drawImage(Image img, int x, int y, int width, int height, ImageObserver observer); - - /** - * Scales the specified area of the specified image to fit in the rectangle area - * defined by its corners coordinates and draws the sub-image with the specified - * background color. The sub-image to be drawn is defined by its top left - * corner coordinates (sx1, sy1) and bottom right corner coordinates (sx2, sy2) - * computed with respect to the origin (top left corner) of the source image. - * The non opaque pixels will be drawn in the background color. The - * image loading process notifies specified Image Observer. - * This method returns true if the image - * has loaded, overwise it returns false. - * - * @param img the image which will be drawn. - * @param dx1 the X top left corner coordinate of the destination rectangle area. - * @param dy1 the Y top left corner coordinate of the destination rectangle area. - * @param dx2 the X bottom right corner coordinate of the destination rectangle area. - * @param dy2 the Y bottom right corner coordinate of the destination rectangle area. - * @param sx1 the X top left corner coordinate of the area to be drawn within the source image. - * @param sy1 the Y top left corner coordinate of the area to be drawn within the source image. - * @param sx2 the X bottom right corner coordinate of the area to be drawn within the source image. - * @param sy2 the Y bottom right corner coordinate of the area to be drawn within the source image. - * @param bgcolor the background color. - * @param observer the ImageObserver object which should be notified about image loading process. - * - * @return true, if loading image is successful or image is null, overwise false. - */ - public abstract boolean drawImage(Image img, int dx1, int dy1, int dx2, int dy2, int sx1, int sy1, int sx2, int sy2, Color bgcolor, ImageObserver observer); - - /** - * Scales the specified area of the specified image to fit in the rectangle area - * defined by its corners coordinates and draws the sub-image. The sub-image - * to be drawn is defined by its top left - * corner coordinates (sx1, sy1) and bottom right corner coordinates (sx2, sy2) - * computed with respect to the origin (top left corner) of the source image. - * The image loading process notifies specified Image Observer. - * This method returns true if the image - * has loaded, overwise it returns false. - * - * @param img the image which will be drawn. - * @param dx1 the X top left corner coordinate of the destination rectangle area. - * @param dy1 the Y top left corner coordinate of the destination rectangle area. - * @param dx2 the X bottom right corner coordinate of the destination rectangle area. - * @param dy2 the Y bottom right corner coordinate of the destination rectangle area. - * @param sx1 the X top left corner coordinate of the area to be drawn within the source image. - * @param sy1 the Y top left corner coordinate of the area to be drawn within the source image. - * @param sx2 the X bottom right corner coordinate of the area to be drawn within the source image. - * @param sy2 the Y bottom right corner coordinate of the area to be drawn within the source image. - * @param observer the ImageObserver object which should be notified about image loading process. - * - * @return true, if loading image is successful or image is null, overwise false. - */ - public abstract boolean drawImage(Image img, int dx1, int dy1, int dx2, int dy2, int sx1, int sy1, int sx2, int sy2, ImageObserver observer); - - /** - * Draws a line from the point (x1, y1) to the point (x2, y2). - * This method draws the line with current color - * which can be changed by setColor(Color c) method. - * - * @param x1 the X coordinate of the first point. - * @param y1 the Y coordinate of the first point. - * @param x2 the X coordinate of the second point. - * @param y2 the Y coordinate of the second point. + * Scales the specified image to fit in the specified rectangle and draws it + * with the defined background color. The top left corner of the image will + * be drawn at the point (x, y) in current coordinate system. The non-opaque + * pixels will be drawn in the background color. The image loading process + * notifies the specified Image Observer. This method returns true if the + * image has loaded, otherwise it returns false. + * + * @param img + * the image which will be drawn. + * @param x + * the X coordinate of the image's top left corner. + * @param y + * the Y coordinate of the image's top left corner. + * @param width + * the width of rectangle which scales the image. + * @param height + * the height of rectangle which scales the image. + * @param bgcolor + * the background color. + * @param observer + * the ImageObserver object which should be notified about image + * loading process. + * @return true, if loading image is successful or image is null, otherwise + * false. + */ + public abstract boolean drawImage(Image img, int x, int y, int width, int height, + Color bgcolor, ImageObserver observer); + + /** + * Scales the specified image to fit in the specified rectangle and draws + * it. The top left corner of the image will be drawn at the point (x, y) in + * current coordinate system. The image loading process notifies the + * specified Image Observer. This method returns true if the image has + * loaded, otherwise it returns false. + * + * @param img + * the image which will be drawn. + * @param x + * the X coordinate of the image top left corner. + * @param y + * the Y coordinate of the image top left corner. + * @param width + * the width of rectangle which scales the image. + * @param height + * the height of rectangle which scales the image. + * @param observer + * the ImageObserver object which should be notified about image + * loading process. + * @return true, if loading image is successful or image is null, otherwise + * false. + */ + public abstract boolean drawImage(Image img, int x, int y, int width, int height, + ImageObserver observer); + + /** + * Scales the specified area of the specified image to fit in the rectangle + * area defined by its corners coordinates and draws the sub-image with the + * specified background color. The sub-image to be drawn is defined by its + * top left corner coordinates (sx1, sy1) and bottom right corner + * coordinates (sx2, sy2) computed with respect to the origin (top left + * corner) of the source image. The non opaque pixels will be drawn in the + * background color. The image loading process notifies specified Image + * Observer. This method returns true if the image has loaded, otherwise it + * returns false. + * + * @param img + * the image which will be drawn. + * @param dx1 + * the X top left corner coordinate of the destination rectangle + * area. + * @param dy1 + * the Y top left corner coordinate of the destination rectangle + * area. + * @param dx2 + * the X bottom right corner coordinate of the destination + * rectangle area. + * @param dy2 + * the Y bottom right corner coordinate of the destination + * rectangle area. + * @param sx1 + * the X top left corner coordinate of the area to be drawn + * within the source image. + * @param sy1 + * the Y top left corner coordinate of the area to be drawn + * within the source image. + * @param sx2 + * the X bottom right corner coordinate of the area to be drawn + * within the source image. + * @param sy2 + * the Y bottom right corner coordinate of the area to be drawn + * within the source image. + * @param bgcolor + * the background color. + * @param observer + * the ImageObserver object which should be notified about image + * loading process. + * @return true, if loading image is successful or image is null, false + * otherwise. + */ + public abstract boolean drawImage(Image img, int dx1, int dy1, int dx2, int dy2, int sx1, + int sy1, int sx2, int sy2, Color bgcolor, ImageObserver observer); + + /** + * Scales the specified area of the specified image to fit in the rectangle + * area defined by its corners coordinates and draws the sub-image. The + * sub-image to be drawn is defined by its top left corner coordinates (sx1, + * sy1) and bottom right corner coordinates (sx2, sy2) computed with respect + * to the origin (top left corner) of the source image. The image loading + * process notifies specified Image Observer. This method returns true if + * the image has loaded, otherwise it returns false. + * + * @param img + * the image which will be drawn. + * @param dx1 + * the X top left corner coordinate of the destination rectangle + * area. + * @param dy1 + * the Y top left corner coordinate of the destination rectangle + * area. + * @param dx2 + * the X bottom right corner coordinate of the destination + * rectangle area. + * @param dy2 + * the Y bottom right corner coordinate of the destination + * rectangle area. + * @param sx1 + * the X top left corner coordinate of the area to be drawn + * within the source image. + * @param sy1 + * the Y top left corner coordinate of the area to be drawn + * within the source image. + * @param sx2 + * the X bottom right corner coordinate of the area to be drawn + * within the source image. + * @param sy2 + * the Y bottom right corner coordinate of the area to be drawn + * within the source image. + * @param observer + * the ImageObserver object which should be notified about image + * loading process. + * @return true, if loading image is successful or image is null, false + * otherwise. + */ + public abstract boolean drawImage(Image img, int dx1, int dy1, int dx2, int dy2, int sx1, + int sy1, int sx2, int sy2, ImageObserver observer); + + /** + * Draws a line from the point (x1, y1) to the point (x2, y2). This method + * draws the line with current color which can be changed by setColor(Color + * c) method. + * + * @param x1 + * the X coordinate of the first point. + * @param y1 + * the Y coordinate of the first point. + * @param x2 + * the X coordinate of the second point. + * @param y2 + * the Y coordinate of the second point. */ public abstract void drawLine(int x1, int y1, int x2, int y2); /** - * Draws the ouline of an oval to fit in the rectangle defined - * by the given width, height, and top left corner. + * Draws the outline of an oval to fit in the rectangle defined by the given + * width, height, and top left corner. * - * @param x the X top left corner oval coordinate - * @param y the Y top left corner oval coordinate - * @param width the oval width - * @param height the oval height + * @param x + * the X top left corner oval coordinate. + * @param y + * the Y top left corner oval coordinate. + * @param width + * the oval width. + * @param height + * the oval height. */ public abstract void drawOval(int x, int y, int width, int height); /** - * Draws the outline of a polygon. The polygon vertices are defined by points - * with xpoints[i], ypoints[i] as coordinates. The polygon edges are the - * lines from the points with (xpoints[i-1], ypoints[i-1]) coordinates to - * the points with (xpoints[i], ypoints[i]) coordinates, for 0 < i < npoints +1. + * Draws the outline of a polygon. The polygon vertices are defined by + * points with xpoints[i], ypoints[i] as coordinates. The polygon edges are + * the lines from the points with (xpoints[i-1], ypoints[i-1]) coordinates + * to the points with (xpoints[i], ypoints[i]) coordinates, for 0 < i < + * npoints +1. * - * @param xpoints the array of X coordinates of the polygon vertices. - * @param ypoints the array of Y coordinates of the polygon vertices. - * @param npoints the number of polygon vertices/points. + * @param xpoints + * the array of X coordinates of the polygon vertices. + * @param ypoints + * the array of Y coordinates of the polygon vertices. + * @param npoints + * the number of polygon vertices/points. */ public abstract void drawPolygon(int[] xpoints, int[] ypoints, int npoints); /** - * Draws a set of connected lines which are defined by the x and y coordinate arrays. - * The polyline is closed if coordinates of the first point are the same as - * coordinates of the last point. + * Draws a set of connected lines which are defined by the x and y + * coordinate arrays. The polyline is closed if coordinates of the first + * point are the same as coordinates of the last point. * - * @param xpoints the array of X point coordinates. - * @param ypoints the array of Y point coordinates. - * @param npoints the number of points. + * @param xpoints + * the array of X point coordinates. + * @param ypoints + * the array of Y point coordinates. + * @param npoints + * the number of points. */ public abstract void drawPolyline(int[] xpoints, int[] ypoints, int npoints); /** * Draws the outline of a rectangle with round corners. * - * @param x the X coordinate of the rectangle's top left corner. - * @param y the Y coordinate of the rectangle's top left corner. - * @param width the width of the rectangle. - * @param height the height of the rectangle. - * @param arcWidth the arc width for the corners. - * @param arcHeight the arc height for the corners. - */ - public abstract void drawRoundRect(int x, int y, int width, int height, int arcWidth, int arcHeight); - - /** - * Draws a text defined by an iterator. The iterator should specify the font - * for every character. - * - * @param iterator the iterator. - * @param x the X coordinate of the firt character. - * @param y the Y coordinate of the first character. + * @param x + * the X coordinate of the rectangle's top left corner. + * @param y + * the Y coordinate of the rectangle's top left corner. + * @param width + * the width of the rectangle. + * @param height + * the height of the rectangle. + * @param arcWidth + * the arc width for the corners. + * @param arcHeight + * the arc height for the corners. + */ + public abstract void drawRoundRect(int x, int y, int width, int height, int arcWidth, + int arcHeight); + + /** + * Draws a text defined by an iterator. The iterator should specify the font + * for every character. + * + * @param iterator + * the iterator. + * @param x + * the X coordinate of the first character. + * @param y + * the Y coordinate of the first character. */ public abstract void drawString(AttributedCharacterIterator iterator, int x, int y); @@ -565,86 +712,117 @@ public abstract class Graphics { * Draws a text defined by a string. This method draws the text with current * font and color. * - * @param str the string. - * @param x the X coordinate of the firt character. - * @param y the Y coordinate of the first character. + * @param str + * the string. + * @param x + * the X coordinate of the first character. + * @param y + * the Y coordinate of the first character. */ public abstract void drawString(String str, int x, int y); /** - * Fills the arc covering the rectangle and using the current color. - * The rectangle is defined by the origin point (X, Y) and dimentions (width and height). - * The arc center is the the center of specified rectangle. - * The angle origin is at the 3 o'clock position, and a positive angle gives + * Fills the arc covering the rectangle and using the current color. The + * rectangle is defined by the origin point (X, Y) and dimensions (width and + * height). The arc center is the the center of specified rectangle. The + * angle origin is at the 3 o'clock position, and a positive angle gives * counter-clockwise rotation, a negative angle gives clockwise rotation. - * - * @param x the X origin coordinate of the rectangle which scales the arc. - * @param y the Y origin coordinate of the rectangle which scales the arc. - * @param width the width of the rectangle which scales the arc. - * @param height the height of the rectangle which scales the arc. - * @param sa start angle - the origin angle of arc. - * @param ea arc angle - the angular arc value relative to the start angle. + * + * @param x + * the X origin coordinate of the rectangle which scales the arc. + * @param y + * the Y origin coordinate of the rectangle which scales the arc. + * @param width + * the width of the rectangle which scales the arc. + * @param height + * the height of the rectangle which scales the arc. + * @param sa + * start angle - the origin angle of arc. + * @param ea + * arc angle - the angular arc value relative to the start angle. */ public abstract void fillArc(int x, int y, int width, int height, int sa, int ea); /** - * Fills an oval with the current color where the oval is defined by the + * Fills an oval with the current color where the oval is defined by the * bounding rectangle with the given width, height, and top left corner. * - * @param x the X top left corner oval coordinate. - * @param y the Y top left corner oval coordinate. - * @param width the oval width. - * @param height the oval height. + * @param x + * the X top left corner oval coordinate. + * @param y + * the Y top left corner oval coordinate. + * @param width + * the oval width. + * @param height + * the oval height. */ public abstract void fillOval(int x, int y, int width, int height); /** - * Fills a polygon with the current color. The polygon vertices are defined by the points - * with xpoints[i], ypoints[i] as coordinates. The polygon edges are the - * lines from the points with (xpoints[i-1], ypoints[i-1]) coordinates to - * the points with (xpoints[i], ypoints[i]) coordinates, for 0 < i < npoints +1. + * Fills a polygon with the current color. The polygon vertices are defined + * by the points with xpoints[i], ypoints[i] as coordinates. The polygon + * edges are the lines from the points with (xpoints[i-1], ypoints[i-1]) + * coordinates to the points with (xpoints[i], ypoints[i]) coordinates, for + * 0 < i < npoints +1. * - * @param xpoints the array of X coordinates of the polygon vertices. - * @param ypoints the array of Y coordinates of the polygon vertices. - * @param npoints the number of polygon vertices/points. + * @param xpoints + * the array of X coordinates of the polygon vertices. + * @param ypoints + * the array of Y coordinates of the polygon vertices. + * @param npoints + * the number of polygon vertices/points. */ public abstract void fillPolygon(int[] xpoints, int[] ypoints, int npoints); /** - * Fills a rectangle with the current color. - * The rectangle is defined by its width and length and top left corner coordinates. + * Fills a rectangle with the current color. The rectangle is defined by its + * width and length and top left corner coordinates. * - * @param x the X coordinate of the rectangle's top left corner. - * @param y the Y coordinate of the rectangle's top left corner. - * @param width the width of rectangle. - * @param height the height of rectangle. + * @param x + * the X coordinate of the rectangle's top left corner. + * @param y + * the Y coordinate of the rectangle's top left corner. + * @param width + * the width of rectangle. + * @param height + * the height of rectangle. */ public abstract void fillRect(int x, int y, int width, int height); /** * Fills a round cornered rectangle with the current color. * - * @param x the X coordinate of the top left corner of the bounding rectangle. - * @param y the Y coordinate of the top left corner of the bounding rectangle. - * @param width the width of the bounding rectangle. - * @param height the height of the bounding rectangle. - * @param arcWidth the arc width at the corners. - * @param arcHeight the arc height at the corners. + * @param x + * the X coordinate of the top left corner of the bounding + * rectangle. + * @param y + * the Y coordinate of the top left corner of the bounding + * rectangle. + * @param width + * the width of the bounding rectangle. + * @param height + * the height of the bounding rectangle. + * @param arcWidth + * the arc width at the corners. + * @param arcHeight + * the arc height at the corners. */ - public abstract void fillRoundRect(int x, int y, int width, int height, int arcWidth, int arcHeight); + public abstract void fillRoundRect(int x, int y, int width, int height, int arcWidth, + int arcHeight); /** - * Gets the clipping area. - *

- * + * Gets the clipping area.
+ *
+ * * @return a Shape object of the clipping area or null if it is not set. */ public abstract Shape getClip(); /** * Gets the bounds of the current clipping area as a rectangle. - * - * @return a Rectangle object which represents the bounds of the current clipping area. + * + * @return a Rectangle object which represents the bounds of the current + * clipping area. */ public abstract Rectangle getClipBounds(); @@ -663,75 +841,84 @@ public abstract class Graphics { public abstract Font getFont(); /** - * Gets the font metrics of the specified font. - * The font metrics object contains information about the rendering of a particular font. - * - * @param font the specified font + * Gets the font metrics of the specified font. The font metrics object + * contains information about the rendering of a particular font. * + * @param font + * the specified font. * @return the font metrics for the specified font. */ public abstract FontMetrics getFontMetrics(Font font); /** - * Sets the new clipping area specified by rectangle. The new clipping area - * doesn't depend on the window's visibility. Rendering operations can't be performed - * outside new clipping area. + * Sets the new clipping area specified by rectangle. The new clipping area + * doesn't depend on the window's visibility. Rendering operations can't be + * performed outside new clipping area. * - * @param x the X coordinate of the new clipping rectangle. - * @param y the Y coordinate of the new clipping rectangle. - * @param width the width of the new clipping rectangle. - * @param height the height of the new clipping rectangle. + * @param x + * the X coordinate of the new clipping rectangle. + * @param y + * the Y coordinate of the new clipping rectangle. + * @param width + * the width of the new clipping rectangle. + * @param height + * the height of the new clipping rectangle. */ public abstract void setClip(int x, int y, int width, int height); /** - * Sets the new clipping area to be the area specified by Shape object. - * The new clipping area doesn't depend on the window's visibility. - * Rendering operations can't be performed outside new clipping area. + * Sets the new clipping area to be the area specified by Shape object. The + * new clipping area doesn't depend on the window's visibility. Rendering + * operations can't be performed outside new clipping area. * - * @param clip a Shape object which representes new clipping area. + * @param clip + * the Shape object which represents new clipping area. */ public abstract void setClip(Shape clip); /** - * Sets the current Graphics color. All rendering operations with this Graphics - * will use this color. + * Sets the current Graphics color. All rendering operations with this + * Graphics will use this color. * - * @param c the new color. + * @param c + * the new color. */ public abstract void setColor(Color c); /** - * Sets the current Graphics font. All rendering operations with this Graphics - * will use this font. + * Sets the current Graphics font. All rendering operations with this + * Graphics will use this font. * - * @param font the new font. + * @param font + * the new font. */ public abstract void setFont(Font font); /** - * Sets the paint mode for the Graphics which overwrites all rendering + * Sets the paint mode for the Graphics which overwrites all rendering * operations with the current color. - * */ public abstract void setPaintMode(); /** - * Sets the XOR mode for the Graphics which changes a pixel from - * the current color to the specified XOR color. - *

+ * Sets the XOR mode for the Graphics which changes a pixel from the current + * color to the specified XOR color.
+ *
* - * @param color the new XOR mode + * @param color + * the new XOR mode. */ public abstract void setXORMode(Color color); /** - * Translates the origin of Graphics current coordinate system - * to the point with X, Y coordinates in the current coordinate system. - * All rendering operation in this Graphics will be related to the new origin. + * Translates the origin of Graphics current coordinate system to the point + * with X, Y coordinates in the current coordinate system. All rendering + * operation in this Graphics will be related to the new origin. * - * @param x the X coordinate of the origin - * @param y the Y coordinate of the origin + * @param x + * the X coordinate of the origin. + * @param y + * the Y coordinate of the origin. */ public abstract void translate(int x, int y); } diff --git a/awt/java/awt/Graphics2D.java b/awt/java/awt/Graphics2D.java index 2ff5e0c9b90fe88979f11f9e56b72375fcca1737..04a7319de851d915cadc8b9e47a50014f15ede05 100644 --- a/awt/java/awt/Graphics2D.java +++ b/awt/java/awt/Graphics2D.java @@ -30,19 +30,22 @@ import java.util.Map; /** * The Graphics2D class extends Graphics class and provides more capabilities - * for rendering text, images, shapes. This provides methods to peform - * transformation of coordinate system, color management, and text layout. - * The following attributes exist for rendering: + * for rendering text, images, shapes. This provides methods to perform + * transformation of coordinate system, color management, and text layout. The + * following attributes exist for rendering: *

    *
  • Color - current Graphics2D color;
  • *
  • Font - current Graphics2D font;
  • - *
  • Stroke - pen with a width of 1 pixel;
  • + *
  • Stroke - pen with a width of 1 pixel;
  • *
  • Transform - current Graphics2D Transformation;
  • - *
  • Composite - alpha compositing rules for combining source and destination colors.
  • - *
+ *
  • Composite - alpha compositing rules for combining source and destination + * colors.
  • + * + * + * @since Android 1.0 */ public abstract class Graphics2D extends Graphics { - + /** * Instantiates a new Graphics2D object. This constructor should never be * called directly. @@ -52,41 +55,46 @@ public abstract class Graphics2D extends Graphics { } /** - * Adds preferences for the rendering algorithms. The preferences - * are arbitrary and specified by Map objects. All specified by Map object - * preferencies can be modified. + * Adds preferences for the rendering algorithms. The preferences are + * arbitrary and specified by Map objects. All specified by Map object + * preferences can be modified. * - * @param hints the rendering hints. + * @param hints + * the rendering hints. */ public abstract void addRenderingHints(Map hints); /** - * Intersects the current clipping area with the specified Shape - * and the result becomes a new clipping area. - * If current clipping area is not defined, the Shape - * becomes the new clipping area. No rendering operations - * are allowed outside the clipping area. + * Intersects the current clipping area with the specified Shape and the + * result becomes a new clipping area. If current clipping area is not + * defined, the Shape becomes the new clipping area. No rendering operations + * are allowed outside the clipping area. * - * @param s the specified Shape object which will be intersected - * with current clipping area. + * @param s + * the specified Shape object which will be intersected with + * current clipping area. */ public abstract void clip(Shape s); /** * Draws the outline of the specified Shape. * - * @param s the Shape which ouline is drawn. + * @param s + * the Shape which outline is drawn. */ public abstract void draw(Shape s); /** - * Draws the specified GlyphVector object's text at the point x, y. + * Draws the specified GlyphVector object's text at the point x, y. * - * @param g the GlyphVector object to be drawn. - * @param x the X position where the GlyphVector's text should - * be rendered. - * @param y the Y position where the GlyphVector's text should - * be rendered. + * @param g + * the GlyphVector object to be drawn. + * @param x + * the X position where the GlyphVector's text should be + * rendered. + * @param y + * the Y position where the GlyphVector's text should be + * rendered. */ public abstract void drawGlyphVector(GlyphVector g, float x, float y); @@ -94,87 +102,107 @@ public abstract class Graphics2D extends Graphics { * Draws the BufferedImage -- modified according to the operation * BufferedImageOp -- at the point x, y. * - * @param img the BufferedImage to be rendered. - * @param op the filter to be applied to the image before rendering. - * @param x the X coordinate of the point where the image's upper left corner - * will be placed. - * @param y the Y coordinate of the point where the image's upper left corner - * will be placed. + * @param img + * the BufferedImage to be rendered. + * @param op + * the filter to be applied to the image before rendering. + * @param x + * the X coordinate of the point where the image's upper left + * corner will be placed. + * @param y + * the Y coordinate of the point where the image's upper left + * corner will be placed. */ public abstract void drawImage(BufferedImage img, BufferedImageOp op, int x, int y); /** - * Draws BufferedImage transformed from image space into user space + * Draws BufferedImage transformed from image space into user space * according to the AffineTransform xform and notifies the ImageObserver. - * - * @param img the BufferedImage to be rendered. - * @param xform the affine transformation from the image to the user space. - * @param obs the ImageObserver to be notified about the image conversion. * - * @return true, if the image is successfully loaded and rendered, - * or it's null, otherwise false. + * @param img + * the BufferedImage to be rendered. + * @param xform + * the affine transformation from the image to the user space. + * @param obs + * the ImageObserver to be notified about the image conversion. + * @return true, if the image is successfully loaded and rendered, or it's + * null, otherwise false. */ public abstract boolean drawImage(Image img, AffineTransform xform, ImageObserver obs); /** - * Draws a RenderableImage which is transformed from image space into user + * Draws a RenderableImage which is transformed from image space into user * according to the AffineTransform xform. - * - * @param img the RenderableImage to be rendered. - * @param xform the affine transformation from image to user space. + * + * @param img + * the RenderableImage to be rendered. + * @param xform + * the affine transformation from image to user space. */ public abstract void drawRenderableImage(RenderableImage img, AffineTransform xform); /** - * Draws a RenderedImage which is transformed from image space into user + * Draws a RenderedImage which is transformed from image space into user * according to the AffineTransform xform. - * - * @param img the RenderedImage to be rendered. - * @param xform the affine transformation from image to user space. + * + * @param img + * the RenderedImage to be rendered. + * @param xform + * the affine transformation from image to user space. */ public abstract void drawRenderedImage(RenderedImage img, AffineTransform xform); /** - * Draws the string specified by the AttributedCharacterIterator. - * The first character's position is specified by the X, Y parameters. + * Draws the string specified by the AttributedCharacterIterator. The first + * character's position is specified by the X, Y parameters. * - * @param iterator whose text is drawn. - * @param x the X position where the first character is drawn. - * @param y the Y position where the first character is drawn. + * @param iterator + * whose text is drawn. + * @param x + * the X position where the first character is drawn. + * @param y + * the Y position where the first character is drawn. */ public abstract void drawString(AttributedCharacterIterator iterator, float x, float y); /** - * Draws the string specified by the AttributedCharacterIterator. - * The first character's position is specified by the X, Y parameters. - * - * @param iterator whose text is drawn. - * @param x the X position where the first character is drawn. - * @param y the Y position where the first character is drawn. + * Draws the string specified by the AttributedCharacterIterator. The first + * character's position is specified by the X, Y parameters. * + * @param iterator + * whose text is drawn. + * @param x + * the X position where the first character is drawn. + * @param y + * the Y position where the first character is drawn. * @see java.awt.Graphics#drawString(AttributedCharacterIterator, int, int) */ @Override public abstract void drawString(AttributedCharacterIterator iterator, int x, int y); /** - * Draws the String whose the first character position is specified - * by the parameters X, Y. + * Draws the String whose the first character position is specified by the + * parameters X, Y. * - * @param s the String to be drawn. - * @param x the X position of the first character. - * @param y the Y position of the first character. + * @param s + * the String to be drawn. + * @param x + * the X position of the first character. + * @param y + * the Y position of the first character. */ public abstract void drawString(String s, float x, float y); /** - * Draws the String whose the first character coordinates are specified - * by the parameters X, Y. - * - * @param str the String to be drawn. - * @param x the X coordinate of the first character. - * @param y the Y coordinate of the first character. + * Draws the String whose the first character coordinates are specified by + * the parameters X, Y. * + * @param str + * the String to be drawn. + * @param x + * the X coordinate of the first character. + * @param y + * the Y coordinate of the first character. * @see java.awt.Graphics#drawString(String, int, int) */ @Override @@ -183,7 +211,8 @@ public abstract class Graphics2D extends Graphics { /** * Fills the interior of the specified Shape. * - * @param s the Shape to be filled. + * @param s + * the Shape to be filled. */ public abstract void fill(Shape s); @@ -204,7 +233,7 @@ public abstract class Graphics2D extends Graphics { /** * Gets the device configuration. * - * @return the device configuration + * @return the device configuration. */ public abstract GraphicsConfiguration getDeviceConfiguration(); @@ -223,17 +252,17 @@ public abstract class Graphics2D extends Graphics { public abstract Paint getPaint(); /** - * Gets the value of single preference for specified key. - * - * @param key the specified key of the rendering hint. + * Gets the value of single preference for specified key. * + * @param key + * the specified key of the rendering hint. * @return the value of rendering hint for specified key. */ public abstract Object getRenderingHint(RenderingHints.Key key); /** - * Gets the set of the rendering preferences as a collection of - * key/value pairs. + * Gets the set of the rendering preferences as a collection of key/value + * pairs. * * @return the RenderingHints which contains the rendering preferences. */ @@ -254,172 +283,196 @@ public abstract class Graphics2D extends Graphics { public abstract AffineTransform getTransform(); /** - * Determines wether or not the specified Shape intersects the specified - * Rectangle. If the onStroke parameter is true, this method - * checks whether or not the specified Shape outline intersects the specified - * Rectangle, otherwise this method checks whether or not the specified - * Shape's interior intersects the specified Rectangle. + * Determines whether or not the specified Shape intersects the specified + * Rectangle. If the onStroke parameter is true, this method checks whether + * or not the specified Shape outline intersects the specified Rectangle, + * otherwise this method checks whether or not the specified Shape's + * interior intersects the specified Rectangle. * - * @param rect the specified Rectangle. - * @param s the Shape to check for intersection. - * @param onStroke the parameter determines whether or not this method checks - * for intersection of the Shape outline or of the Shape interior with - * the Rectangle. - * - * @return true, if there is a hit, otherwise false. + * @param rect + * the specified Rectangle. + * @param s + * the Shape to check for intersection. + * @param onStroke + * the parameter determines whether or not this method checks for + * intersection of the Shape outline or of the Shape interior + * with the Rectangle. + * @return true, if there is a hit, false otherwise. */ public abstract boolean hit(Rectangle rect, Shape s, boolean onStroke); /** * Performs a rotation transform relative to current Graphics2D Transform. - * The coordinate system is rotated by the specified angle in radians relative to - * current origin. + * The coordinate system is rotated by the specified angle in radians + * relative to current origin. * - * @param theta the angle of rotation in radians. + * @param theta + * the angle of rotation in radians. */ public abstract void rotate(double theta); /** - * Performs a translated rotation transform relative to current Graphics2D - * Transform. The coordinate system is rotated by the specified angle in radians - * relative to current origin and then moved to point (x, y). - * - * Is this right? + * Performs a translated rotation transform relative to current Graphics2D + * Transform. The coordinate system is rotated by the specified angle in + * radians relative to current origin and then moved to point (x, y). Is + * this right? * - * @param theta the angle of rotation in radians. - * @param x the X coordinate. - * @param y the Y coordinate. + * @param theta + * the angle of rotation in radians. + * @param x + * the X coordinate. + * @param y + * the Y coordinate. */ public abstract void rotate(double theta, double x, double y); /** - * Performs a linear scale transform relative to current Graphics2D Transform. - * The coordinate system is rescaled vertically and horizontally + * Performs a linear scale transform relative to current Graphics2D + * Transform. The coordinate system is rescaled vertically and horizontally * by the specified parameters. * - * @param sx the scaling factor by which the X coordinate is multiplied. - * @param sy the scaling factor by which the Y coordinate is multiplied. + * @param sx + * the scaling factor by which the X coordinate is multiplied. + * @param sy + * the scaling factor by which the Y coordinate is multiplied. */ public abstract void scale(double sx, double sy); /** - * Sets a new background color for clearing rectangular areas. - * The clearRect method uses the current background color. + * Sets a new background color for clearing rectangular areas. The clearRect + * method uses the current background color. * - * @param color the new background color. + * @param color + * the new background color. */ public abstract void setBackground(Color color); /** - * Sets the current composite for Graphics2D. + * Sets the current composite for Graphics2D. * - * @param comp the Composite object. + * @param comp + * the Composite object. */ public abstract void setComposite(Composite comp); /** * Sets the paint for Graphics2D. * - * @param paint the Paint object. + * @param paint + * the Paint object. */ public abstract void setPaint(Paint paint); /** * Sets a key-value pair in the current RenderingHints map. * - * @param key the key of the rendering hint to set. - * @param value the value to set for the rendering hint. + * @param key + * the key of the rendering hint to set. + * @param value + * the value to set for the rendering hint. */ public abstract void setRenderingHint(RenderingHints.Key key, Object value); /** - * Replaces the current rendering hints with the specified rendering preferences. + * Replaces the current rendering hints with the specified rendering + * preferences. * - * @param hints the new Map of rendering hints. + * @param hints + * the new Map of rendering hints. */ public abstract void setRenderingHints(Map hints); /** * Sets the stroke for the Graphics2D. * - * @param s the Stroke object. + * @param s + * the Stroke object. */ public abstract void setStroke(Stroke s); /** - * Overwrite the current Transform of the Graphics2D. The specified Transform - * should be received from the getTransform() method and should be used - * only for restoring the original Graphics2D transform after calling - * draw or fill methods. + * Overwrite the current Transform of the Graphics2D. The specified + * Transform should be received from the getTransform() method and should be + * used only for restoring the original Graphics2D transform after calling + * draw or fill methods. * - * @param Tx the specified Transform. + * @param Tx + * the specified Transform. */ public abstract void setTransform(AffineTransform Tx); /** - * Performs a shear transform relative to current Graphics2D Transform. - * The coordinate system is shifted by the specified multipliers relative to + * Performs a shear transform relative to current Graphics2D Transform. The + * coordinate system is shifted by the specified multipliers relative to * current position. * - * @param shx the multiplier by which the X coordinates shift position - * along X axis as a function of Y coordinates. - * @param shy the multiplier by which the Y coordinates shift position - * along Y axis as a function of X coordinates. + * @param shx + * the multiplier by which the X coordinates shift position along + * X axis as a function of Y coordinates. + * @param shy + * the multiplier by which the Y coordinates shift position along + * Y axis as a function of X coordinates. */ public abstract void shear(double shx, double shy); /** - * Concatenates the AffineTransform object with current Transform - * of this Graphics2D. The transforms are applied in reverse order - * with the last specified transform applied first and the next - * transformation applied to the result of previous transformation. - * More precisely, if Cx is the current Graphics2D transform, the - * transform method's result with Tx as the parameter - * is the transformation Rx, where Rx(p) = Cx(Tx(p)), for p - a point - * in current coordinate system. Rx becomes the current Transform + * Concatenates the AffineTransform object with current Transform of this + * Graphics2D. The transforms are applied in reverse order with the last + * specified transform applied first and the next transformation applied to + * the result of previous transformation. More precisely, if Cx is the + * current Graphics2D transform, the transform method's result with Tx as + * the parameter is the transformation Rx, where Rx(p) = Cx(Tx(p)), for p - + * a point in current coordinate system. Rx becomes the current Transform * for this Graphics2D. * - * @param Tx the AffineTransform object to be concatenated with - * current Transform. + * @param Tx + * the AffineTransform object to be concatenated with current + * Transform. */ public abstract void transform(AffineTransform Tx); /** * Performs a translate transform relative to current Graphics2D Transform. - * The coordinate system is moved by the specified distance relative - * to current position. + * The coordinate system is moved by the specified distance relative to + * current position. * - * @param tx the translation distance along the X axis. - * @param ty the translation distance along the Y axis. + * @param tx + * the translation distance along the X axis. + * @param ty + * the translation distance along the Y axis. */ public abstract void translate(double tx, double ty); /** - * Moves the origin Graphics2D Transform to the point with x, y - * coordinates in current coordinate system. The new origin of coordinate - * system is moved to the (x, y) point accordingly. All rendering and - * transform operations are performed relative to this new origin. - * - * @param x the X coordinate. - * @param y the Y coordinate. + * Moves the origin Graphics2D Transform to the point with x, y coordinates + * in current coordinate system. The new origin of coordinate system is + * moved to the (x, y) point accordingly. All rendering and transform + * operations are performed relative to this new origin. * + * @param x + * the X coordinate. + * @param y + * the Y coordinate. * @see java.awt.Graphics#translate(int, int) */ @Override public abstract void translate(int x, int y); /** - * Fills a 3D rectangle with the current color. - * The rectangle is specified by its width, height, and top left corner - * coordinates. - * - * @param x the X coordinate of the rectangle's top left corner. - * @param y the Y coordinate of the rectangle's top left corner. - * @param width the width of rectangle. - * @param height the height of rectangle. - * @param raised a boolean value that determines whether the rectangle - * is drawn as raised or indented. - * + * Fills a 3D rectangle with the current color. The rectangle is specified + * by its width, height, and top left corner coordinates. + * + * @param x + * the X coordinate of the rectangle's top left corner. + * @param y + * the Y coordinate of the rectangle's top left corner. + * @param width + * the width of rectangle. + * @param height + * the height of rectangle. + * @param raised + * a boolean value that determines whether the rectangle is drawn + * as raised or indented. * @see java.awt.Graphics#fill3DRect(int, int, int, int, boolean) */ @Override @@ -433,15 +486,19 @@ public abstract class Graphics2D extends Graphics { } /** - * Draws the higlighted outline of a rectangle. + * Draws the highlighted outline of a rectangle. * - * @param x the X coordinate of the rectangle's top left corner. - * @param y the Y coordinate of the rectangle's top left corner. - * @param width the width of rectangle. - * @param height the height of rectangle. - * @param raised a boolean value that determines whether the rectangle - * is drawn as raised or indented. - * + * @param x + * the X coordinate of the rectangle's top left corner. + * @param y + * the Y coordinate of the rectangle's top left corner. + * @param width + * the width of rectangle. + * @param height + * the height of rectangle. + * @param raised + * a boolean value that determines whether the rectangle is drawn + * as raised or indented. * @see java.awt.Graphics#draw3DRect(int, int, int, int, boolean) */ @Override diff --git a/awt/java/awt/GraphicsConfiguration.java b/awt/java/awt/GraphicsConfiguration.java index 8bec253b8c77bee621ba32c3934283313ea82438..d59e896abb715532c80b7ce9caddec2c467b8383 100644 --- a/awt/java/awt/GraphicsConfiguration.java +++ b/awt/java/awt/GraphicsConfiguration.java @@ -18,6 +18,7 @@ * @author Alexey A. Petrenko * @version $Revision$ */ + package java.awt; import java.awt.geom.AffineTransform; @@ -30,70 +31,76 @@ import org.apache.harmony.awt.internal.nls.Messages; /** * The GraphicsConfiguration class contains the characteristics of graphics * devices such as a printer or monitor, and represents device's capabilities - * and modes. Many GraphicsConfiguration objects can be associated with - * single graphics device. + * and modes. Many GraphicsConfiguration objects can be associated with single + * graphics device. + * + * @since Android 1.0 */ public abstract class GraphicsConfiguration { - - /** - * Constructor could not be used directly and should be obtained in - * extended classes. - */ + /** + * Constructor could not be used directly and should be obtained in extended + * classes. + */ protected GraphicsConfiguration() { } - - /** - * Creates BufferedImage image object with a data layout and color model - * compatible with this GraphicsConfiguration with specified width - * and height parameters. - * - * @param width the width of BufferedImage. - * @param height the height of BufferedImage. - * - * @return the BufferedImage object with specified width and height - * parameters. - */ + /** + * Creates BufferedImage image object with a data layout and color model + * compatible with this GraphicsConfiguration with specified width and + * height parameters. + * + * @param width + * the width of BufferedImage. + * @param height + * the height of BufferedImage. + * @return the BufferedImage object with specified width and height + * parameters. + */ public abstract BufferedImage createCompatibleImage(int width, int height); /** * Creates a BufferedImage that has the specified width, height, - * transparency and has a data layout and color model compatible with this - * GraphicsConfiguration. - * - * @param width the width of image. - * @param height the height of image. - * @param transparency the transparency mode. + * transparency and has a data layout and color model compatible with this + * GraphicsConfiguration. * + * @param width + * the width of image. + * @param height + * the height of image. + * @param transparency + * the transparency mode. * @return the BufferedImage object. */ public abstract BufferedImage createCompatibleImage(int width, int height, int transparency); /** - * Creates a VolatileImage that has the specified width and height - * and has a data layout and color model compatible with this - * GraphicsConfiguration. - * - * @param width the width of image. - * @param height the height of image. + * Creates a VolatileImage that has the specified width and height and has a + * data layout and color model compatible with this GraphicsConfiguration. * + * @param width + * the width of image. + * @param height + * the height of image. * @return the VolatileImage object. */ public abstract VolatileImage createCompatibleVolatileImage(int width, int height); /** * Creates a VolatileImage that supports the specified width, height, - * transparency and has a data layout and color model compatible with this - * GraphicsConfiguration. - * - * @param width the width of image. - * @param height the height of image. - * @param transparency the transparency mode. + * transparency and has a data layout and color model compatible with this + * GraphicsConfiguration. * + * @param width + * the width of image. + * @param height + * the height of image. + * @param transparency + * the transparency mode. * @return the VolatileImage object. */ - public abstract VolatileImage createCompatibleVolatileImage(int width, int height, int transparency); + public abstract VolatileImage createCompatibleVolatileImage(int width, int height, + int transparency); /** * Gets the bounds of area covered by the GraphicsConfiguration in the @@ -111,20 +118,19 @@ public abstract class GraphicsConfiguration { public abstract ColorModel getColorModel(); /** - * Gets the ColorModel of the GraphicsConfiguration which - * supports specified Transparency. + * Gets the ColorModel of the GraphicsConfiguration which supports specified + * Transparency. * - * @param transparency the Transparency mode: OPAQUE, BITMASK, or - * TRANSLUCENT. - * - * @return the ColorModel of the GraphicsConfiguration which - * supports specified Transparency. + * @param transparency + * the Transparency mode: OPAQUE, BITMASK, or TRANSLUCENT. + * @return the ColorModel of the GraphicsConfiguration which supports + * specified Transparency. */ public abstract ColorModel getColorModel(int transparency); /** - * Gets the default AffineTransform of the GraphicsConfiguration. - * This method translates user coordinates to device coordinates. + * Gets the default AffineTransform of the GraphicsConfiguration. This + * method translates user coordinates to device coordinates. * * @return the default AffineTransform of the GraphicsConfiguration. */ @@ -144,23 +150,24 @@ public abstract class GraphicsConfiguration { */ public abstract AffineTransform getNormalizingTransform(); - /** - * Creates VolatileImage with specified width, height, ImageCapabilities; - * a data layout and color model compatible with this GraphicsConfiguration. - * - * @param width the width of image. - * @param height the height of image. - * @param caps the ImageCapabilities object. - * - * @return the VolatileImage which data layout and color model compatible - * with this GraphicsConfiguration. - * - * @throws AWTException if ImageCapabilities is not supported by the - * GraphicsConfiguration. + * Creates VolatileImage with specified width, height, ImageCapabilities; a + * data layout and color model compatible with this GraphicsConfiguration. + * + * @param width + * the width of image. + * @param height + * the height of image. + * @param caps + * the ImageCapabilities object. + * @return the VolatileImage which data layout and color model compatible + * with this GraphicsConfiguration. + * @throws AWTException + * if ImageCapabilities is not supported by the + * GraphicsConfiguration. */ - public VolatileImage createCompatibleVolatileImage(int width, int height, - ImageCapabilities caps) throws AWTException { + public VolatileImage createCompatibleVolatileImage(int width, int height, ImageCapabilities caps) + throws AWTException { VolatileImage res = createCompatibleVolatileImage(width, height); if (!res.getCapabilities().equals(caps)) { // awt.14A=Can not create VolatileImage with specified capabilities @@ -170,21 +177,23 @@ public abstract class GraphicsConfiguration { } /** - * Creates a VolatileImage with specified width, height, transparency - * and ImageCapabilities; a data layout and color model compatible with - * this GraphicsConfiguration. - * - * @param width the width of image. - * @param height the height of image. - * @param caps the ImageCapabilities object. - * @param transparency the Transparency mode: OPAQUE, BITMASK, or - * TRANSLUCENT. - * - * @return the VolatileImage which data layout and color model compatible - * with this GraphicsConfiguration. - * - * @throws AWTException if ImageCapabilities is not supported by the + * Creates a VolatileImage with specified width, height, transparency and + * ImageCapabilities; a data layout and color model compatible with this * GraphicsConfiguration. + * + * @param width + * the width of image. + * @param height + * the height of image. + * @param caps + * the ImageCapabilities object. + * @param transparency + * the Transparency mode: OPAQUE, BITMASK, or TRANSLUCENT. + * @return the VolatileImage which data layout and color model compatible + * with this GraphicsConfiguration. + * @throws AWTException + * if ImageCapabilities is not supported by the + * GraphicsConfiguration. */ public VolatileImage createCompatibleVolatileImage(int width, int height, ImageCapabilities caps, int transparency) throws AWTException { @@ -199,7 +208,7 @@ public abstract class GraphicsConfiguration { /** * Gets the buffering capabilities of the GraphicsConfiguration. * - * @return the BufferCapabilities object. + * @return the BufferCapabilities object. */ public BufferCapabilities getBufferCapabilities() { return new BufferCapabilities(new ImageCapabilities(false), new ImageCapabilities(false), diff --git a/awt/java/awt/GraphicsDevice.java b/awt/java/awt/GraphicsDevice.java index 8cf700a95b841ad49e5dfae7cdcd641a15098c3b..9eda4e0eda796feb4869b6ce1dc7a6e797768f2f 100644 --- a/awt/java/awt/GraphicsDevice.java +++ b/awt/java/awt/GraphicsDevice.java @@ -18,50 +18,61 @@ * @author Alexey A. Petrenko * @version $Revision$ */ + package java.awt; import org.apache.harmony.awt.internal.nls.Messages; /** - * The GraphicsDevice class describes the graphics devices (such as screens - * or printers) which are available in a particular graphics environment. - * Many GraphicsDevice instances can be associated with a single - * GraphicsEnvironment. Each GraphicsDevice has one or more GraphicsConfiguration - * objects which specify the different configurations and modes of GraphicsDevice. + * The GraphicsDevice class describes the graphics devices (such as screens or + * printers) which are available in a particular graphics environment. Many + * GraphicsDevice instances can be associated with a single GraphicsEnvironment. + * Each GraphicsDevice has one or more GraphicsConfiguration objects which + * specify the different configurations and modes of GraphicsDevice. + * + * @since Android 1.0 */ public abstract class GraphicsDevice { - - /** The display mode. */ + + /** + * The display mode. + */ private DisplayMode displayMode; - //???AWT -// private Window fullScreenWindow = null; + // ???AWT + // private Window fullScreenWindow = null; - /** The Constant TYPE_IMAGE_BUFFER indicates a image buffer device. */ + /** + * The Constant TYPE_IMAGE_BUFFER indicates a image buffer device. + */ public static final int TYPE_IMAGE_BUFFER = 2; - /** The Constant TYPE_PRINTER indicates a printer device. */ + /** + * The Constant TYPE_PRINTER indicates a printer device. + */ public static final int TYPE_PRINTER = 1; - /** The Constant TYPE_RASTER_SCREEN indicates a raster screen device. */ + /** + * The Constant TYPE_RASTER_SCREEN indicates a raster screen device. + */ public static final int TYPE_RASTER_SCREEN = 0; - /** - * Constructor is not to be used directly as this class is abstract. - */ + /** + * Constructor is not to be used directly as this class is abstract. + */ protected GraphicsDevice() { - displayMode = new DisplayMode(0, 0, DisplayMode.BIT_DEPTH_MULTI, DisplayMode.REFRESH_RATE_UNKNOWN); + displayMode = new DisplayMode(0, 0, DisplayMode.BIT_DEPTH_MULTI, + DisplayMode.REFRESH_RATE_UNKNOWN); } - - /** - * Returns an array of GraphicsConfiguration objects associated - * with the GraphicsDevice. - * - * @return an array of GraphicsConfiguration objects associated - * with the GraphicsDevice. - */ + /** + * Returns an array of GraphicsConfiguration objects associated with the + * GraphicsDevice. + * + * @return an array of GraphicsConfiguration objects associated with the + * GraphicsDevice. + */ public abstract GraphicsConfiguration[] getConfigurations(); /** @@ -72,41 +83,39 @@ public abstract class GraphicsDevice { public abstract GraphicsConfiguration getDefaultConfiguration(); /** - * Gets the String identifier which associated with the GraphicsDevice in + * Gets the String identifier which associated with the GraphicsDevice in * the GraphicsEnvironment. * - * @return the String identifier of the GraphicsDevice in - * the GraphicsEnvironment. + * @return the String identifier of the GraphicsDevice in the + * GraphicsEnvironment. */ public abstract String getIDstring(); /** - * Gets the type of this GraphicsDevice: - * TYPE_IMAGE_BUFFER, TYPE_PRINTER or TYPE_RASTER_SCREEN. + * Gets the type of this GraphicsDevice: TYPE_IMAGE_BUFFER, TYPE_PRINTER or + * TYPE_RASTER_SCREEN. * - * @return the type of this GraphicsDevice: TYPE_IMAGE_BUFFER, - * TYPE_PRINTER or TYPE_RASTER_SCREEN. + * @return the type of this GraphicsDevice: TYPE_IMAGE_BUFFER, TYPE_PRINTER + * or TYPE_RASTER_SCREEN. */ public abstract int getType(); - - - /** - * Returns the number of bytes available in accelerated - * memory on this device. - * - * @return the number of bytes available accelerated memory. - */ + /** + * Returns the number of bytes available in accelerated memory on this + * device. + * + * @return the number of bytes available accelerated memory. + */ public int getAvailableAcceleratedMemory() { return 0; } - /* ???AWT - public GraphicsConfiguration getBestConfiguration(GraphicsConfigTemplate gct) { - return gct.getBestConfiguration(getConfigurations()); - } - */ - + /* + * ???AWT public GraphicsConfiguration + * getBestConfiguration(GraphicsConfigTemplate gct) { return + * gct.getBestConfiguration(getConfigurations()); } + */ + /** * Gets the current display mode of the GraphicsDevice. * @@ -122,43 +131,43 @@ public abstract class GraphicsDevice { * @return an array of display modes available in this GraphicsDevice. */ public DisplayMode[] getDisplayModes() { - DisplayMode []dms = {displayMode}; - return dms; + DisplayMode[] dms = { + displayMode + }; + return dms; } - /* ???AWT - public Window getFullScreenWindow() { - return fullScreenWindow; - } - */ - + /* + * ???AWT public Window getFullScreenWindow() { return fullScreenWindow; } + */ + /** - * Returns true if this GraphicsDevice supports low-level - * display changes. + * Returns true if this GraphicsDevice supports low-level display changes. * - * @return true, if this GraphicsDevice supports low-level - * display changes; false otherwise. + * @return true, if this GraphicsDevice supports low-level display changes; + * false otherwise. */ public boolean isDisplayChangeSupported() { return false; } /** - * Returns true if this GraphicsDevice supports full screen - * mode. + * Returns true if this GraphicsDevice supports full screen mode. * - * @return true, if this GraphicsDevice supports full screen - * mode; otherwise false. + * @return true, if this GraphicsDevice supports full screen mode, false + * otherwise. */ public boolean isFullScreenSupported() { return false; } - //an array of display modes available in this GraphicsDevice. - + + // an array of display modes available in this GraphicsDevice. + /** * Sets the display mode of this GraphicsDevice. * - * @param dm the new display mode of this GraphicsDevice. + * @param dm + * the new display mode of this GraphicsDevice. */ public void setDisplayMode(DisplayMode dm) { if (!isDisplayChangeSupported()) { @@ -166,7 +175,7 @@ public abstract class GraphicsDevice { throw new UnsupportedOperationException(Messages.getString("awt.122")); //$NON-NLS-1$ } - DisplayMode []dms = getDisplayModes(); + DisplayMode[] dms = getDisplayModes(); for (DisplayMode element : dms) { if (element.equals(dm)) { displayMode = dm; @@ -177,23 +186,11 @@ public abstract class GraphicsDevice { throw new IllegalArgumentException(Messages.getString("awt.123", dm)); //$NON-NLS-1$ } - /* ???AWT - public void setFullScreenWindow(Window w) { - if (w == null) { - fullScreenWindow = null; - return; - } - - fullScreenWindow = w; - - if (isFullScreenSupported()) { - w.enableInputMethods(false); - } else { - w.setSize(displayMode.getWidth(), displayMode.getHeight()); - w.setLocation(0, 0); - } - w.setVisible(true); - w.setAlwaysOnTop(true); - } - */ + /* + * ???AWT public void setFullScreenWindow(Window w) { if (w == null) { + * fullScreenWindow = null; return; } fullScreenWindow = w; if + * (isFullScreenSupported()) { w.enableInputMethods(false); } else { + * w.setSize(displayMode.getWidth(), displayMode.getHeight()); + * w.setLocation(0, 0); } w.setVisible(true); w.setAlwaysOnTop(true); } + */ } diff --git a/awt/java/awt/GraphicsEnvironment.java b/awt/java/awt/GraphicsEnvironment.java index 3b14f55b40b1650f9f236fe3fe7670db4e489d2f..d527417f732e9c2d205b578ef6067acd924fdd32 100644 --- a/awt/java/awt/GraphicsEnvironment.java +++ b/awt/java/awt/GraphicsEnvironment.java @@ -28,17 +28,20 @@ import org.apache.harmony.awt.ContextStorage; import org.apache.harmony.awt.gl.CommonGraphics2DFactory; /** - * The GraphicsEnvironment class defines a collection of GraphicsDevice - * objects and Font objects which are available for Java application on - * current platform. + * The GraphicsEnvironment class defines a collection of GraphicsDevice objects + * and Font objects which are available for Java application on current + * platform. + * + * @since Android 1.0 */ public abstract class GraphicsEnvironment { - + /** - * Constructor could not be used directly and should be obtained in - * extended classes. + * Constructor could not be used directly and should be obtained in extended + * classes. */ - protected GraphicsEnvironment() {} + protected GraphicsEnvironment() { + } /** * Gets the local GraphicsEnvironment. @@ -46,17 +49,16 @@ public abstract class GraphicsEnvironment { * @return the local GraphicsEnvironment. */ public static GraphicsEnvironment getLocalGraphicsEnvironment() { - synchronized(ContextStorage.getContextLock()) { + synchronized (ContextStorage.getContextLock()) { if (ContextStorage.getGraphicsEnvironment() == null) { - if (isHeadless()) { - ContextStorage.setGraphicsEnvironment(new HeadlessGraphicsEnvironment()); + if (isHeadless()) { + ContextStorage.setGraphicsEnvironment(new HeadlessGraphicsEnvironment()); } else { - CommonGraphics2DFactory g2df = - (CommonGraphics2DFactory) Toolkit.getDefaultToolkit().getGraphicsFactory(); - - ContextStorage.setGraphicsEnvironment( - g2df.createGraphicsEnvironment(ContextStorage.getWindowFactory()) - ); + CommonGraphics2DFactory g2df = (CommonGraphics2DFactory)Toolkit + .getDefaultToolkit().getGraphicsFactory(); + + ContextStorage.setGraphicsEnvironment(g2df + .createGraphicsEnvironment(ContextStorage.getWindowFactory())); } } @@ -65,24 +67,24 @@ public abstract class GraphicsEnvironment { } /** - * Returns whether or not a display, keyboard, and mouse are supported - * in this graphics environment. + * Returns whether or not a display, keyboard, and mouse are supported in + * this graphics environment. * - * @return true, if HeadlessException will be thrown from areas of - * the graphics environment that are dependent on a display, keyboard, - * or mouse; false otherwise. + * @return true, if HeadlessException will be thrown from areas of the + * graphics environment that are dependent on a display, keyboard, + * or mouse, false otherwise. */ public boolean isHeadlessInstance() { return false; } /** - * Checks whether or not a display, keyboard, and mouse are supported - * in this environment. + * Checks whether or not a display, keyboard, and mouse are supported in + * this environment. * - * @return true, if a HeadlessException is thrown from areas of - * the Toolkit and GraphicsEnvironment that are dependent on - * a display, keyboard, or mouse; false otherwise. + * @return true, if a HeadlessException is thrown from areas of the Toolkit + * and GraphicsEnvironment that are dependent on a display, + * keyboard, or mouse, false otherwise. */ public static boolean isHeadless() { return "true".equals(System.getProperty("java.awt.headless")); @@ -92,8 +94,8 @@ public abstract class GraphicsEnvironment { * Gets the maximum bounds of system centered windows. * * @return the maximum bounds of system centered windows. - * - * @throws HeadlessException if isHeadless() method returns true. + * @throws HeadlessException + * if isHeadless() method returns true. */ public Rectangle getMaximumWindowBounds() throws HeadlessException { return getDefaultScreenDevice().getDefaultConfiguration().getBounds(); @@ -103,8 +105,8 @@ public abstract class GraphicsEnvironment { * Gets the Point which should defines the center of system window. * * @return the Point where the system window should be centered. - * - * @throws HeadlessException if isHeadless() method returns true. + * @throws HeadlessException + * if isHeadless() method returns true. */ public Point getCenterPoint() throws HeadlessException { Rectangle mwb = getMaximumWindowBounds(); @@ -112,9 +114,8 @@ public abstract class GraphicsEnvironment { } /** - * Indicates that the primary font should be used. - * Primary font is specified by initial system locale or default encoding). - * + * Indicates that the primary font should be used. Primary font is specified + * by initial system locale or default encoding). */ public void preferLocaleFonts() { // Note: API specification says following: @@ -123,7 +124,8 @@ public abstract class GraphicsEnvironment { // it may have no effect at all." So, doing nothing is an // acceptable behavior for this method. - // For now FontManager uses 1.4 font.properties scheme for font mapping, so + // For now FontManager uses 1.4 font.properties scheme for font mapping, + // so // this method doesn't make any sense. The implementation of this method // which will influence font mapping is postponed until // 1.5 mapping scheme not implemented. @@ -141,7 +143,8 @@ public abstract class GraphicsEnvironment { // it may have no effect at all." So, doing nothing is an // acceptable behavior for this method. - // For now FontManager uses 1.4 font.properties scheme for font mapping, so + // For now FontManager uses 1.4 font.properties scheme for font mapping, + // so // this method doesn't make any sense. The implementation of this method // which will influence font mapping is postponed until // 1.5 mapping scheme not implemented. @@ -153,19 +156,19 @@ public abstract class GraphicsEnvironment { * Creates the Graphics2D object for rendering to the specified * BufferedImage. * - * @param bufferedImage the BufferedImage object. - * - * @return the Graphics2D object which allows to render to the specified - * BufferedImage. + * @param bufferedImage + * the BufferedImage object. + * @return the Graphics2D object which allows to render to the specified + * BufferedImage. */ public abstract Graphics2D createGraphics(BufferedImage bufferedImage); /** - * Gets the array of all available fonts instances in this + * Gets the array of all available fonts instances in this * GraphicsEnviroments. * - * @return the array of all available fonts instances in this - * GraphicsEnviroments. + * @return the array of all available fonts instances in this + * GraphicsEnviroments. */ public abstract Font[] getAllFonts(); @@ -180,11 +183,11 @@ public abstract class GraphicsEnvironment { * Gets the array of all available font family names for the specified * locale. * - * @param locale the Locale object which represents geographical - * region. The default locale is used if locale is null. - * - * @return the array of available font family names for the specified - * locale. + * @param locale + * the Locale object which represents geographical region. The + * default locale is used if locale is null. + * @return the array of available font family names for the specified + * locale. */ public abstract String[] getAvailableFontFamilyNames(Locale locale); @@ -192,18 +195,18 @@ public abstract class GraphicsEnvironment { * Gets the default screen device as GraphicDevice object. * * @return the GraphicDevice object which represents default screen device. - * - * @throws HeadlessException if isHeadless() returns true. + * @throws HeadlessException + * if isHeadless() returns true. */ public abstract GraphicsDevice getDefaultScreenDevice() throws HeadlessException; /** * Gets an array of all available screen devices. * - * @return the array of GraphicsDevice obgects which represents - * all available screen devices. - * - * @throws HeadlessException if isHeadless() returns true. + * @return the array of GraphicsDevice objects which represents all + * available screen devices. + * @throws HeadlessException + * if isHeadless() returns true. */ public abstract GraphicsDevice[] getScreenDevices() throws HeadlessException; } diff --git a/awt/java/awt/HeadlessException.java b/awt/java/awt/HeadlessException.java index 28e463b3e01ec2b6f185a6118f2728ec52c9d23b..ec111f1e4ee8a3b9f236d955c6187a8711261926 100644 --- a/awt/java/awt/HeadlessException.java +++ b/awt/java/awt/HeadlessException.java @@ -18,16 +18,21 @@ * @author Alexey A. Petrenko * @version $Revision$ */ + package java.awt; /** - * The HeadlessException class provides notifications and error messages - * when code that is dependent on a keyboard, display, or mouse is called - * in an environment that does not support a keyboard, display, or mouse. + * The HeadlessException class provides notifications and error messages when + * code that is dependent on a keyboard, display, or mouse is called in an + * environment that does not support a keyboard, display, or mouse. + * + * @since Android 1.0 */ public class HeadlessException extends UnsupportedOperationException { - - /** The Constant serialVersionUID. */ + + /** + * The Constant serialVersionUID. + */ private static final long serialVersionUID = 167183644944358563L; /** @@ -40,7 +45,8 @@ public class HeadlessException extends UnsupportedOperationException { /** * Instantiates a new headless exception with the specified message. * - * @param msg the String which represents error message. + * @param msg + * the String which represents error message. */ public HeadlessException(String msg) { super(msg); diff --git a/awt/java/awt/HeadlessGraphicsEnvironment.java b/awt/java/awt/HeadlessGraphicsEnvironment.java index 97f88d168de452951f967d660d2b8e38004b89b7..306393f33e9b92dab63fbd682ce429332b8618d6 100644 --- a/awt/java/awt/HeadlessGraphicsEnvironment.java +++ b/awt/java/awt/HeadlessGraphicsEnvironment.java @@ -14,6 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package java.awt; import java.awt.GraphicsDevice; @@ -23,30 +24,32 @@ import org.apache.harmony.awt.gl.CommonGraphicsEnvironment; /** * The HeadlessGraphicsEnvironment class is the CommonGraphicsEnvironment - * implementation to use in the case where the environment lacks display, + * implementation to use in the case where the environment lacks display, * keyboard, and mouse support. + * + * @since Android 1.0 */ public class HeadlessGraphicsEnvironment extends CommonGraphicsEnvironment { - + /** - * Returns whether or not a display, keyboard, and mouse are supported - * in this graphics environment. + * Returns whether or not a display, keyboard, and mouse are supported in + * this graphics environment. * - * @return true, if HeadlessException will be thrown from areas of - * the graphics environment that are dependent on a display, keyboard, - * or mouse; false otherwise. + * @return true, if HeadlessException will be thrown from areas of the + * graphics environment that are dependent on a display, keyboard, + * or mouse, false otherwise. */ @Override public boolean isHeadlessInstance() { return true; } - + /** * Gets the default screen device as GraphicDevice object. * * @return the GraphicDevice object which represents default screen device. - * - * @throws HeadlessException if isHeadless() returns true. + * @throws HeadlessException + * if isHeadless() returns true. */ @Override public GraphicsDevice getDefaultScreenDevice() throws HeadlessException { @@ -56,10 +59,10 @@ public class HeadlessGraphicsEnvironment extends CommonGraphicsEnvironment { /** * Gets an array of all available screen devices. * - * @return the array of GraphicsDevice objects which represents - * all available screen devices. - * - * @throws HeadlessException if isHeadless() returns true. + * @return the array of GraphicsDevice objects which represents all + * available screen devices. + * @throws HeadlessException + * if isHeadless() returns true. */ @Override public GraphicsDevice[] getScreenDevices() throws HeadlessException { diff --git a/awt/java/awt/HeadlessToolkit.java b/awt/java/awt/HeadlessToolkit.java index a7dd557a4456568af3281903190f16b0aa854882..c64a85a617ecd7ee14a227103c10d49532d94036 100644 --- a/awt/java/awt/HeadlessToolkit.java +++ b/awt/java/awt/HeadlessToolkit.java @@ -26,136 +26,75 @@ package java.awt; //import java.awt.dnd.InvalidDnDOperationException; //import java.awt.dnd.peer.DragSourceContextPeer; import java.awt.im.InputMethodHighlight; -import java.awt.image.ColorModel; -//import java.awt.peer.*; +import java.awt.image.ColorModel; //import java.awt.peer.*; //import java.beans.PropertyChangeSupport; import java.util.HashMap; import java.util.Map; import java.util.Properties; -import org.apache.harmony.awt.ComponentInternals; -//import org.apache.harmony.awt.datatransfer.DTK; +import org.apache.harmony.awt.ComponentInternals; //import org.apache.harmony.awt.datatransfer.DTK; import org.apache.harmony.awt.wtk.GraphicsFactory; import org.apache.harmony.awt.wtk.NativeEventQueue; import org.apache.harmony.awt.wtk.WindowFactory; /** - * The HeadlessToolkit class is a subclass of ToolkitImpl to - * be used for graphical environments that lack keyboard and - * mouse capabilities. + * The HeadlessToolkit class is a subclass of ToolkitImpl to be used for + * graphical environments that lack keyboard and mouse capabilities. + * + * @since Android 1.0 */ public final class HeadlessToolkit extends ToolkitImpl { - - //???AWT - /* - @Override - protected ButtonPeer createButton(Button a0) throws HeadlessException { - throw new HeadlessException(); - } - - @Override - protected CheckboxPeer createCheckbox(Checkbox a0) throws HeadlessException { - throw new HeadlessException(); - } - - @Override - protected CheckboxMenuItemPeer createCheckboxMenuItem(CheckboxMenuItem a0) throws HeadlessException { - throw new HeadlessException(); - } - - @Override - protected ChoicePeer createChoice(Choice a0) throws HeadlessException { - throw new HeadlessException(); - } - - public Cursor createCustomCursor(Image img, Point hotSpot, String name) - throws HeadlessException { - throw new HeadlessException(); - } - - @Override - protected DialogPeer createDialog(Dialog a0) throws HeadlessException { - throw new HeadlessException(); - } - - @Override - public T createDragGestureRecognizer( - Class recognizerAbstractClass, DragSource ds, Component c, int srcActions, - DragGestureListener dgl) { - return null; - } - - @Override - public DragSourceContextPeer createDragSourceContextPeer(DragGestureEvent dge) - throws InvalidDnDOperationException { - throw new InvalidDnDOperationException(); - } - - @Override - protected FileDialogPeer createFileDialog(FileDialog a0) throws HeadlessException { - throw new HeadlessException(); - } - - @Override - protected FramePeer createFrame(Frame a0) throws HeadlessException { - throw new HeadlessException(); - } - - @Override - protected LabelPeer createLabel(Label a0) throws HeadlessException { - throw new HeadlessException(); - } - - @Override - protected ListPeer createList(List a0) throws HeadlessException { - throw new HeadlessException(); - } - - @Override - protected MenuPeer createMenu(Menu a0) throws HeadlessException { - throw new HeadlessException(); - } - - @Override - protected MenuBarPeer createMenuBar(MenuBar a0) throws HeadlessException { - throw new HeadlessException(); - } - @Override - protected MenuItemPeer createMenuItem(MenuItem a0) throws HeadlessException { - throw new HeadlessException(); - } - - @Override - protected PopupMenuPeer createPopupMenu(PopupMenu a0) throws HeadlessException { - throw new HeadlessException(); - } - - @Override - protected ScrollbarPeer createScrollbar(Scrollbar a0) throws HeadlessException { - throw new HeadlessException(); - } - - @Override - protected ScrollPanePeer createScrollPane(ScrollPane a0) throws HeadlessException { - throw new HeadlessException(); - } - - @Override - protected TextAreaPeer createTextArea(TextArea a0) throws HeadlessException { - throw new HeadlessException(); - } - - @Override - protected TextFieldPeer createTextField(TextField a0) throws HeadlessException { - throw new HeadlessException(); - } - - @Override - protected WindowPeer createWindow(Window a0) throws HeadlessException { - throw new HeadlessException(); - } - */ + // ???AWT + /* + * @Override protected ButtonPeer createButton(Button a0) throws + * HeadlessException { throw new HeadlessException(); } + * @Override protected CheckboxPeer createCheckbox(Checkbox a0) throws + * HeadlessException { throw new HeadlessException(); } + * @Override protected CheckboxMenuItemPeer + * createCheckboxMenuItem(CheckboxMenuItem a0) throws HeadlessException { + * throw new HeadlessException(); } + * @Override protected ChoicePeer createChoice(Choice a0) throws + * HeadlessException { throw new HeadlessException(); } public Cursor + * createCustomCursor(Image img, Point hotSpot, String name) throws + * HeadlessException { throw new HeadlessException(); } + * @Override protected DialogPeer createDialog(Dialog a0) throws + * HeadlessException { throw new HeadlessException(); } + * @Override public T + * createDragGestureRecognizer( Class recognizerAbstractClass, DragSource + * ds, Component c, int srcActions, DragGestureListener dgl) { return null; + * } + * @Override public DragSourceContextPeer + * createDragSourceContextPeer(DragGestureEvent dge) throws + * InvalidDnDOperationException { throw new InvalidDnDOperationException(); + * } + * @Override protected FileDialogPeer createFileDialog(FileDialog a0) throws + * HeadlessException { throw new HeadlessException(); } + * @Override protected FramePeer createFrame(Frame a0) throws + * HeadlessException { throw new HeadlessException(); } + * @Override protected LabelPeer createLabel(Label a0) throws + * HeadlessException { throw new HeadlessException(); } + * @Override protected ListPeer createList(List a0) throws HeadlessException + * { throw new HeadlessException(); } + * @Override protected MenuPeer createMenu(Menu a0) throws HeadlessException + * { throw new HeadlessException(); } + * @Override protected MenuBarPeer createMenuBar(MenuBar a0) throws + * HeadlessException { throw new HeadlessException(); } + * @Override protected MenuItemPeer createMenuItem(MenuItem a0) throws + * HeadlessException { throw new HeadlessException(); } + * @Override protected PopupMenuPeer createPopupMenu(PopupMenu a0) throws + * HeadlessException { throw new HeadlessException(); } + * @Override protected ScrollbarPeer createScrollbar(Scrollbar a0) throws + * HeadlessException { throw new HeadlessException(); } + * @Override protected ScrollPanePeer createScrollPane(ScrollPane a0) throws + * HeadlessException { throw new HeadlessException(); } + * @Override protected TextAreaPeer createTextArea(TextArea a0) throws + * HeadlessException { throw new HeadlessException(); } + * @Override protected TextFieldPeer createTextField(TextField a0) throws + * HeadlessException { throw new HeadlessException(); } + * @Override protected WindowPeer createWindow(Window a0) throws + * HeadlessException { throw new HeadlessException(); } + */ @Override public Dimension getBestCursorSize(int prefWidth, int prefHeight) throws HeadlessException { @@ -186,25 +125,18 @@ public final class HeadlessToolkit extends ToolkitImpl { public int getMenuShortcutKeyMask() throws HeadlessException { throw new HeadlessException(); } - - //???AWT + + // ???AWT /* - @Override - NativeEventQueue getNativeEventQueue() throws HeadlessException { - throw new HeadlessException(); - } - - @Override - public PrintJob getPrintJob(Frame frame, String jobtitle, JobAttributes jobAttributes, - PageAttributes pageAttributes) throws IllegalArgumentException { - throw new IllegalArgumentException(); - } - - @Override - public PrintJob getPrintJob(Frame frame, String jobtitle, Properties props) throws NullPointerException { - throw new NullPointerException(); - } - */ + * @Override NativeEventQueue getNativeEventQueue() throws HeadlessException + * { throw new HeadlessException(); } + * @Override public PrintJob getPrintJob(Frame frame, String jobtitle, + * JobAttributes jobAttributes, PageAttributes pageAttributes) throws + * IllegalArgumentException { throw new IllegalArgumentException(); } + * @Override public PrintJob getPrintJob(Frame frame, String jobtitle, + * Properties props) throws NullPointerException { throw new + * NullPointerException(); } + */ @Override public Insets getScreenInsets(GraphicsConfiguration gc) throws HeadlessException { @@ -214,44 +146,37 @@ public final class HeadlessToolkit extends ToolkitImpl { @Override public int getScreenResolution() throws HeadlessException { throw new HeadlessException(); - } + } @Override public Dimension getScreenSize() throws HeadlessException { throw new HeadlessException(); } - - //???AWT + + // ???AWT /* - @Override - public Clipboard getSystemClipboard() throws HeadlessException { - throw new HeadlessException(); - } - - @Override - public Clipboard getSystemSelection() throws HeadlessException { - throw new HeadlessException(); - } - - @Override - WindowFactory getWindowFactory() throws HeadlessException { - throw new HeadlessException(); - } - */ + * @Override public Clipboard getSystemClipboard() throws HeadlessException + * { throw new HeadlessException(); } + * @Override public Clipboard getSystemSelection() throws HeadlessException + * { throw new HeadlessException(); } + * @Override WindowFactory getWindowFactory() throws HeadlessException { + * throw new HeadlessException(); } + */ @Override protected void init() { lockAWT(); try { ComponentInternals.setComponentInternals(new ComponentInternalsImpl()); - //???AWT: new EventQueue(this); // create the system EventQueue - //???AWT: dispatcher = new Dispatcher(this); + // ???AWT: new EventQueue(this); // create the system EventQueue + // ???AWT: dispatcher = new Dispatcher(this); desktopProperties = new HashMap(); - //???AWT: desktopPropsSupport = new PropertyChangeSupport(this); -// ???AWT: awtEventsManager = new AWTEventsManager(); -// ???AWT: dispatchThread = new HeadlessEventDispatchThread(this, dispatcher); -// ???AWT: dtk = DTK.getDTK(); - dispatchThread.start(); + // ???AWT: desktopPropsSupport = new PropertyChangeSupport(this); + // ???AWT: awtEventsManager = new AWTEventsManager(); + // ???AWT: dispatchThread = new HeadlessEventDispatchThread(this, + // dispatcher); + // ???AWT: dtk = DTK.getDTK(); + dispatchThread.start(); } finally { unlockAWT(); } @@ -284,8 +209,8 @@ public final class HeadlessToolkit extends ToolkitImpl { } @Override - Map mapInputMethodHighlightImpl( - InputMethodHighlight highlight) throws HeadlessException { + Map mapInputMethodHighlightImpl(InputMethodHighlight highlight) + throws HeadlessException { throw new HeadlessException(); } diff --git a/awt/java/awt/IllegalComponentStateException.java b/awt/java/awt/IllegalComponentStateException.java index 21dc35f220ed37ea555f242871b9cfdc438469f9..bed172998997fbd2b9813d863baf8b33a310345f 100644 --- a/awt/java/awt/IllegalComponentStateException.java +++ b/awt/java/awt/IllegalComponentStateException.java @@ -18,34 +18,38 @@ * @author Michael Danilov * @version $Revision$ */ + package java.awt; /** - * The IllegalComponentStateException class is used to provide - * notification that AWT component is not in an appropriate state - * for the requested operation. + * The IllegalComponentStateException class is used to provide notification that + * AWT component is not in an appropriate state for the requested operation. + * + * @since Android 1.0 */ public class IllegalComponentStateException extends IllegalStateException { - /** The Constant serialVersionUID. */ + /** + * The Constant serialVersionUID. + */ private static final long serialVersionUID = -1889339587208144238L; /** - * Instantiates a new IllegalComponentStateException with - * the specified message. + * Instantiates a new IllegalComponentStateException with the specified + * message. * - * @param s the String message which describes the exception. + * @param s + * the String message which describes the exception. */ public IllegalComponentStateException(String s) { super(s); } /** - * Instantiates a new IllegalComponentStateException without - * detailed message. + * Instantiates a new IllegalComponentStateException without detailed + * message. */ public IllegalComponentStateException() { } } - diff --git a/awt/java/awt/Image.java b/awt/java/awt/Image.java index c217e380c74ade64750b1f7c2df35f121502b0de..7ae3ed8836e5e9189b20a5a9518012989125abd7 100644 --- a/awt/java/awt/Image.java +++ b/awt/java/awt/Image.java @@ -18,6 +18,7 @@ * @author Igor V. Stolyarov * @version $Revision$ */ + package java.awt; import java.awt.image.AreaAveragingScaleFilter; @@ -30,64 +31,67 @@ import java.awt.image.ReplicateScaleFilter; import org.apache.harmony.awt.internal.nls.Messages; /** - * The Image abstract class represents the graphic images. + * The Image abstract class represents the graphic images. + * + * @since Android 1.0 */ public abstract class Image { - /** - * The UndefinedProperty object should be returned if - * property is not defined for a particular image. + /** + * The UndefinedProperty object should be returned if property is not + * defined for a particular image. */ - public static final Object UndefinedProperty = new Object(); //$NON-LOCK-1$ + public static final Object UndefinedProperty = new Object(); // $NON-LOCK-1$ - /** - * The Constant SCALE_DEFAULT indicates the default image - * scaling algorithm. + /** + * The Constant SCALE_DEFAULT indicates the default image scaling algorithm. */ public static final int SCALE_DEFAULT = 1; - /** - * The Constant SCALE_FAST indicates an image scaling algorithm which - * places a higher priority on scaling speed than on the image's smoothness. + /** + * The Constant SCALE_FAST indicates an image scaling algorithm which places + * a higher priority on scaling speed than on the image's smoothness. */ public static final int SCALE_FAST = 2; - /** - * The Constant SCALE_SMOOTH indicates an image scaling algorithm which - * places a higher priority on image smoothness than on scaling speed. + /** + * The Constant SCALE_SMOOTH indicates an image scaling algorithm which + * places a higher priority on image smoothness than on scaling speed. */ public static final int SCALE_SMOOTH = 4; - /** - * The Constant SCALE_REPLICATE indicates the image scaling - * algorithm in the ReplicateScaleFilter class. + /** + * The Constant SCALE_REPLICATE indicates the image scaling algorithm in the + * ReplicateScaleFilter class. */ public static final int SCALE_REPLICATE = 8; - /** - * The Constant SCALE_AREA_AVERAGING indicates - * the area averaging image scaling algorithm. + /** + * The Constant SCALE_AREA_AVERAGING indicates the area averaging image + * scaling algorithm. */ public static final int SCALE_AREA_AVERAGING = 16; - /** - * The acceleration priority indicates image acceleration. + /** + * The acceleration priority indicates image acceleration. */ protected float accelerationPriority = 0.5f; - /** The Constant capabilities. */ + /** + * The Constant capabilities. + */ private static final ImageCapabilities capabilities = new ImageCapabilities(false); /** - * Gets the image property with the specified name. - * The UndefinedProperty object should be return if the property is - * not specified for this image. The return value should be null if the - * property is currently unknown yet and the specified ImageObserver is - * to be notified later. - * - * @param name the name of image's property. - * @param observer the ImageObserver. + * Gets the image property with the specified name. The UndefinedProperty + * object should be return if the property is not specified for this image. + * The return value should be null if the property is currently unknown yet + * and the specified ImageObserver is to be notified later. * + * @param name + * the name of image's property. + * @param observer + * the ImageObserver. * @return the Object which represents value of the specified property. */ public abstract Object getProperty(String name, ImageObserver observer); @@ -100,39 +104,40 @@ public abstract class Image { public abstract ImageProducer getSource(); /** - * Gets the width of this image. The specified ImageObserver object - * is notified when the width of this image is available. - * - * @param observer the ImageObserver object which is - * is notified when the width of this image is available. + * Gets the width of this image. The specified ImageObserver object is + * notified when the width of this image is available. * - * @return the width of image, or -1 if the width of this image - * is not available. + * @param observer + * the ImageObserver object which is is notified when the width + * of this image is available. + * @return the width of image, or -1 if the width of this image is not + * available. */ public abstract int getWidth(ImageObserver observer); /** - * Gets the height of this image. The specified ImageObserver object - * is notified when the height of this image is available. + * Gets the height of this image. The specified ImageObserver object is + * notified when the height of this image is available. * - * @param observer the ImageObserver object which is - * is notified when the height of this image is available. - * - * @return the height of image, or -1 if the height of this image - * is not available. + * @param observer + * the ImageObserver object which is is notified when the height + * of this image is available. + * @return the height of image, or -1 if the height of this image is not + * available. */ public abstract int getHeight(ImageObserver observer); /** - * Gets the scaled instance of this Image. This method returns - * an Image object constructed from the source of this image - * with the specified width, height, and applied scaling - * alghorithm. - * - * @param width the width of scaled Image. - * @param height the height of scaled Image. - * @param hints the constant which indicates scaling algorithm. + * Gets the scaled instance of this Image. This method returns an Image + * object constructed from the source of this image with the specified + * width, height, and applied scaling algorithm. * + * @param width + * the width of scaled Image. + * @param height + * the height of scaled Image. + * @param hints + * the constant which indicates scaling algorithm. * @return the scaled Image. */ public Image getScaledInstance(int width, int height, int hints) { @@ -147,17 +152,16 @@ public abstract class Image { } /** - * Gets a Graphics object for rendering this image. - * This method can be used for off-screen images. + * Gets a Graphics object for rendering this image. This method can be used + * for off-screen images. * * @return a Graphics object for rendering to this image. */ public abstract Graphics getGraphics(); /** - * Flushes resources which are used by this Image object. - * This method resets the image to the reconstructered state - * from the image's source. + * Flushes resources which are used by this Image object. This method resets + * the image to the reconstructed state from the image's source. */ public abstract void flush(); @@ -171,10 +175,10 @@ public abstract class Image { } /** - * Sets the acceleration priority for this image. - * - * @param priority the new acceleration priority (value in the - * range 0-1). + * Sets the acceleration priority for this image. + * + * @param priority + * the new acceleration priority (value in the range 0-1). */ public void setAccelerationPriority(float priority) { if (priority < 0 || priority > 1) { @@ -185,19 +189,17 @@ public abstract class Image { } /** - * Gets an ImageCapabilities object of this Image object - * for the specified GraphicsConfiguration. - * - * @param gc the specified GraphicsConfiguration object - * (null value means default GraphicsConfiguration). + * Gets an ImageCapabilities object of this Image object for the specified + * GraphicsConfiguration. * - * @return an ImageCapabilities object of this Image object - * for the specified GraphicsConfiguration. + * @param gc + * the specified GraphicsConfiguration object (null value means + * default GraphicsConfiguration). + * @return an ImageCapabilities object of this Image object for the + * specified GraphicsConfiguration. */ public ImageCapabilities getCapabilities(GraphicsConfiguration gc) { // Note: common image is not accelerated. return capabilities; } } - - diff --git a/awt/java/awt/ImageCapabilities.java b/awt/java/awt/ImageCapabilities.java index 6e9ecfc3799b4cecdc3729da85d49013c0262622..c6d59462aea3a0e84ee1ea591fa4f4418b4ebb33 100644 --- a/awt/java/awt/ImageCapabilities.java +++ b/awt/java/awt/ImageCapabilities.java @@ -18,22 +18,27 @@ * @author Alexey A. Petrenko * @version $Revision$ */ + package java.awt; /** * The ImageCapabilities class gives information about an image's capabilities. + * + * @since Android 1.0 */ public class ImageCapabilities implements Cloneable { - - /** The accelerated. */ + + /** + * The accelerated. + */ private final boolean accelerated; /** - * Instantiates a new ImageCapabilities with the specified - * acceleration flag which indicates whether acceleration - * is desired or not. + * Instantiates a new ImageCapabilities with the specified acceleration flag + * which indicates whether acceleration is desired or not. * - * @param accelerated the accelerated flag. + * @param accelerated + * the accelerated flag. */ public ImageCapabilities(boolean accelerated) { this.accelerated = accelerated; @@ -50,23 +55,22 @@ public class ImageCapabilities implements Cloneable { } /** - * Returne true if the Image of this ImageCapabilities is or can be + * Returns true if the Image of this ImageCapabilities is or can be * accelerated. - * + * * @return true, if the Image of this ImageCapabilities is or can be - * accelerated, false otherwise. + * accelerated, false otherwise. */ public boolean isAccelerated() { return accelerated; } /** - * Returns true if this ImageCapabilities applies to - * the VolatileImage which can lose its surfaces. + * Returns true if this ImageCapabilities applies to the VolatileImage which + * can lose its surfaces. * - * @return true if this ImageCapabilities applies to - * the VolatileImage which can lose its surfaces, - * false otherwise. + * @return true if this ImageCapabilities applies to the VolatileImage which + * can lose its surfaces, false otherwise. */ public boolean isTrueVolatile() { return true; diff --git a/awt/java/awt/Insets.java b/awt/java/awt/Insets.java index 61f3fd8bf28f18082258d83fe8c7cbd152f0b976..04f198c619647ce693c4f5071eea96fc6972ad05 100644 --- a/awt/java/awt/Insets.java +++ b/awt/java/awt/Insets.java @@ -18,44 +18,49 @@ * @author Dmitry A. Durnev * @version $Revision$ */ + package java.awt; import java.io.Serializable; import org.apache.harmony.misc.HashCode; - /** - * The Insets class represents the borders of a container. - * This class describes the space that a container should leave at each edge: - * the top, the bottom, the right side, and the left side. - * The space can be filled with a border, a blank space, or a title. + * The Insets class represents the borders of a container. This class describes + * the space that a container should leave at each edge: the top, the bottom, + * the right side, and the left side. The space can be filled with a border, a + * blank space, or a title. + * + * @since Android 1.0 */ public class Insets implements Cloneable, Serializable { - /** The Constant serialVersionUID. */ + /** + * The Constant serialVersionUID. + */ private static final long serialVersionUID = -2272572637695466749L; /** - * The top inset indicates the size of the space added to the - * top of the rectangle. + * The top inset indicates the size of the space added to the top of the + * rectangle. */ public int top; - /** - * The left inset indicates the size of the space added to the - * left side of the rectangle. + /** + * The left inset indicates the size of the space added to the left side of + * the rectangle. */ public int left; - /** - * The bottom inset indicates the size of the space subtracted from - * the bottom of the rectangle. + /** + * The bottom inset indicates the size of the space subtracted from the + * bottom of the rectangle. */ public int bottom; - /** The right inset indicates the size of the space subtracted from - * the right side of the rectangle. + /** + * The right inset indicates the size of the space subtracted from the right + * side of the rectangle. */ public int right; @@ -63,10 +68,14 @@ public class Insets implements Cloneable, Serializable { * Instantiates a new Inset object with the specified top, left, bottom, * right parameters. * - * @param top the top inset. - * @param left the left inset. - * @param bottom the bottom inset. - * @param right the right inset. + * @param top + * the top inset. + * @param left + * the left inset. + * @param bottom + * the bottom inset. + * @param right + * the right inset. */ public Insets(int top, int left, int bottom, int right) { setValues(top, left, bottom, right); @@ -100,10 +109,10 @@ public class Insets implements Cloneable, Serializable { /** * Checks if this Insets object is equal to the specified object. * - * @param o the Object to be compared. - * - * @return true, if the object is an Insets object whose data values - * are equal to those of this object, false otherwise. + * @param o + * the Object to be compared. + * @return true, if the object is an Insets object whose data values are + * equal to those of this object, false otherwise. */ @Override public boolean equals(Object o) { @@ -111,9 +120,8 @@ public class Insets implements Cloneable, Serializable { return true; } if (o instanceof Insets) { - Insets i = (Insets) o; - return ((i.left == left) && (i.bottom == bottom) && - (i.right == right) && (i.top == top)); + Insets i = (Insets)o; + return ((i.left == left) && (i.bottom == bottom) && (i.right == right) && (i.top == top)); } return false; } @@ -125,23 +133,26 @@ public class Insets implements Cloneable, Serializable { */ @Override public String toString() { - /* The format is based on 1.5 release behavior - * which can be revealed by the following code: - * System.out.println(new Insets(1, 2, 3, 4)); + /* + * The format is based on 1.5 release behavior which can be revealed by + * the following code: System.out.println(new Insets(1, 2, 3, 4)); */ - return (getClass().getName() + - "[left=" + left + ",top=" + top + //$NON-NLS-1$ //$NON-NLS-2$ - ",right=" + right + ",bottom=" + bottom + "]"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + return (getClass().getName() + "[left=" + left + ",top=" + top + //$NON-NLS-1$ //$NON-NLS-2$ + ",right=" + right + ",bottom=" + bottom + "]"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ } /** * Sets top, left, bottom, and right insets to the specified values. * - * @param top the top inset. - * @param left the left inset. - * @param bottom the bottom inset. - * @param right the right inset. + * @param top + * the top inset. + * @param left + * the left inset. + * @param bottom + * the bottom inset. + * @param right + * the right inset. */ public void set(int top, int left, int bottom, int right) { setValues(top, left, bottom, right); @@ -150,10 +161,14 @@ public class Insets implements Cloneable, Serializable { /** * Sets the values. * - * @param top the top - * @param left the left - * @param bottom the bottom - * @param right the right + * @param top + * the top. + * @param left + * the left. + * @param bottom + * the bottom. + * @param right + * the right. */ private void setValues(int top, int left, int bottom, int right) { this.top = top; @@ -162,4 +177,3 @@ public class Insets implements Cloneable, Serializable { this.right = right; } } - diff --git a/awt/java/awt/ItemSelectable.java b/awt/java/awt/ItemSelectable.java index a46364b031c0720e44f5932cc302027d5bbb884a..212cf709e5232c28487f8f45b99682a4acad559b 100644 --- a/awt/java/awt/ItemSelectable.java +++ b/awt/java/awt/ItemSelectable.java @@ -18,35 +18,41 @@ * @author Michael Danilov * @version $Revision$ */ + package java.awt; import java.awt.event.ItemListener; /** * The ItemSelectable interface represents a set of items which can be selected. + * + * @since Android 1.0 */ public interface ItemSelectable { /** - * Adds an ItemListener for receiving item events when the state of an item - * is changed by the user. + * Adds an ItemListener for receiving item events when the state of an item + * is changed by the user. * - * @param l the ItemListener. + * @param l + * the ItemListener. */ public void addItemListener(ItemListener l); /** - * Gets an array of the selected objects or null if there is no selected object. - * - * @return an array of the selected objects or null if there is no selected + * Gets an array of the selected objects or null if there is no selected * object. + * + * @return an array of the selected objects or null if there is no selected + * object. */ public Object[] getSelectedObjects(); /** * Removes the specified ItemListener. * - * @param l the ItemListener which will be removed. + * @param l + * the ItemListener which will be removed. */ public void removeItemListener(ItemListener l); diff --git a/awt/java/awt/MenuComponent.java b/awt/java/awt/MenuComponent.java index 9eb4f3d8d21e1fe4275c33344f3124b818e8c4b6..9c1b120e66779e77793ca936ff05e1615e9c6e18 100644 --- a/awt/java/awt/MenuComponent.java +++ b/awt/java/awt/MenuComponent.java @@ -21,8 +21,7 @@ import java.awt.event.FocusListener; import java.awt.event.MouseEvent; import java.awt.peer.MenuComponentPeer; import java.io.Serializable; -import java.util.Locale; -//import javax.accessibility.Accessible; +import java.util.Locale; //import javax.accessibility.Accessible; //import javax.accessibility.AccessibleComponent; //import javax.accessibility.AccessibleContext; //import javax.accessibility.AccessibleRole; @@ -31,371 +30,172 @@ import java.util.Locale; import org.apache.harmony.awt.gl.MultiRectArea; import org.apache.harmony.awt.state.MenuItemState; import org.apache.harmony.awt.state.MenuState; +import org.apache.harmony.luni.util.NotImplementedException; /** - * The MenuComponent abstract class is the superclass for menu - * components. Menu components receive and process AWT events. + * The MenuComponent abstract class is the superclass for menu components. Menu + * components receive and process AWT events. + * + * @since Android 1.0 */ public abstract class MenuComponent implements Serializable { - - /** The Constant serialVersionUID. */ + + /** + * The Constant serialVersionUID. + */ private static final long serialVersionUID = -4536902356223894379L; - /** The name. */ + /** + * The name. + */ private String name; - /** The font. */ + /** + * The font. + */ private Font font; - /** The parent. */ + /** + * The parent. + */ MenuContainer parent; - /** The deprecated event handler. */ + /** + * The deprecated event handler. + */ boolean deprecatedEventHandler = true; - /** The selected item index. */ + /** + * The selected item index. + */ private int selectedItemIndex; - //???AWT: private AccessibleContext accessibleContext; + // ???AWT: private AccessibleContext accessibleContext; - /** The toolkit. */ + /** + * The toolkit. + */ final Toolkit toolkit = Toolkit.getDefaultToolkit(); - //???AWT + // ???AWT /* - protected abstract class AccessibleAWTMenuComponent extends AccessibleContext implements - Serializable, AccessibleComponent, AccessibleSelection { - private static final long serialVersionUID = -4269533416223798698L; - - public void addFocusListener(FocusListener listener) { - } - - public boolean contains(Point pt) { - return false; - } - - public Accessible getAccessibleAt(Point pt) { - return null; - } - - public Color getBackground() { - return null; - } - - public Rectangle getBounds() { - return null; - } - - public Cursor getCursor() { - return null; - } - - public Font getFont() { - return MenuComponent.this.getFont(); - } - - public FontMetrics getFontMetrics(Font font) { - return null; - } - - public Color getForeground() { - return null; - } - - public Point getLocation() { - return null; - } - - public Point getLocationOnScreen() { - return null; - } - - public Dimension getSize() { - return null; - } - - public boolean isEnabled() { - return true; // always enabled - } - - public boolean isFocusTraversable() { - return true; // always focus traversable - } - - public boolean isShowing() { - return true;// always showing - } - - public boolean isVisible() { - return true; // always visible - } - - public void removeFocusListener(FocusListener listener) { - } - - public void requestFocus() { - } - - public void setBackground(Color color) { - } - - public void setBounds(Rectangle rect) { - } - - public void setCursor(Cursor cursor) { - } - - public void setEnabled(boolean enabled) { - } - - public void setFont(Font font) { - MenuComponent.this.setFont(font); - } - - public void setForeground(Color color) { - } - - public void setLocation(Point pt) { - } - - public void setSize(Dimension pt) { - } - - public void setVisible(boolean visible) { - } - - public void addAccessibleSelection(int index) { - } - - public void clearAccessibleSelection() { - } - - public Accessible getAccessibleSelection(int index) { - return null; - } - - public int getAccessibleSelectionCount() { - return 0; - } - - public boolean isAccessibleChildSelected(int index) { - return false; - } - - public void removeAccessibleSelection(int index) { - } - - public void selectAllAccessibleSelection() { - } - - @Override - public Accessible getAccessibleChild(int index) { - return null; - } - - @Override - public int getAccessibleChildrenCount() { - return 0; - } - - @Override - public AccessibleComponent getAccessibleComponent() { - return this; - } - - @Override - public String getAccessibleDescription() { - return super.getAccessibleDescription(); - } - - @Override - public int getAccessibleIndexInParent() { - toolkit.lockAWT(); - try { - Accessible aParent = getAccessibleParent(); - int aIndex = -1; - if (aParent instanceof MenuComponent) { - MenuComponent parent = (MenuComponent) aParent; - int count = parent.getItemCount(); - for (int i = 0; i < count; i++) { - MenuComponent comp = parent.getItem(i); - if (comp instanceof Accessible) { - aIndex++; - if (comp == MenuComponent.this) { - return aIndex; - } - } - } - } - return -1; - } finally { - toolkit.unlockAWT(); - } - } - - @Override - public String getAccessibleName() { - return super.getAccessibleName(); - } - - @Override - public Accessible getAccessibleParent() { - toolkit.lockAWT(); - try { - Accessible aParent = super.getAccessibleParent(); - if (aParent != null) { - return aParent; - } - MenuContainer parent = getParent(); - if (parent instanceof Accessible) { - aParent = (Accessible) parent; - } - return aParent; - } finally { - toolkit.unlockAWT(); - } - } - - @Override - public AccessibleRole getAccessibleRole() { - return AccessibleRole.AWT_COMPONENT; - } - - @Override - public AccessibleSelection getAccessibleSelection() { - return this; - } - - @Override - public AccessibleStateSet getAccessibleStateSet() { - return new AccessibleStateSet(); - } - - @Override - public Locale getLocale() { - return Locale.getDefault(); - } - } - */ - - /** - * The accessor to MenuComponent internal state, - * utilized by the visual theme. - * - * @throws HeadlessException the headless exception - */ - //???AWT + * protected abstract class AccessibleAWTMenuComponent extends + * AccessibleContext implements Serializable, AccessibleComponent, + * AccessibleSelection { private static final long serialVersionUID = + * -4269533416223798698L; public void addFocusListener(FocusListener + * listener) { } public boolean contains(Point pt) { return false; } public + * Accessible getAccessibleAt(Point pt) { return null; } public Color + * getBackground() { return null; } public Rectangle getBounds() { return + * null; } public Cursor getCursor() { return null; } public Font getFont() + * { return MenuComponent.this.getFont(); } public FontMetrics + * getFontMetrics(Font font) { return null; } public Color getForeground() { + * return null; } public Point getLocation() { return null; } public Point + * getLocationOnScreen() { return null; } public Dimension getSize() { + * return null; } public boolean isEnabled() { return true; // always + * enabled } public boolean isFocusTraversable() { return true; // always + * focus traversable } public boolean isShowing() { return true;// always + * showing } public boolean isVisible() { return true; // always visible } + * public void removeFocusListener(FocusListener listener) { } public void + * requestFocus() { } public void setBackground(Color color) { } public void + * setBounds(Rectangle rect) { } public void setCursor(Cursor cursor) { } + * public void setEnabled(boolean enabled) { } public void setFont(Font + * font) { MenuComponent.this.setFont(font); } public void + * setForeground(Color color) { } public void setLocation(Point pt) { } + * public void setSize(Dimension pt) { } public void setVisible(boolean + * visible) { } public void addAccessibleSelection(int index) { } public + * void clearAccessibleSelection() { } public Accessible + * getAccessibleSelection(int index) { return null; } public int + * getAccessibleSelectionCount() { return 0; } public boolean + * isAccessibleChildSelected(int index) { return false; } public void + * removeAccessibleSelection(int index) { } public void + * selectAllAccessibleSelection() { } + * @Override public Accessible getAccessibleChild(int index) { return null; + * } + * @Override public int getAccessibleChildrenCount() { return 0; } + * @Override public AccessibleComponent getAccessibleComponent() { return + * this; } + * @Override public String getAccessibleDescription() { return + * super.getAccessibleDescription(); } + * @Override public int getAccessibleIndexInParent() { toolkit.lockAWT(); + * try { Accessible aParent = getAccessibleParent(); int aIndex = -1; if + * (aParent instanceof MenuComponent) { MenuComponent parent = + * (MenuComponent) aParent; int count = parent.getItemCount(); for (int i = + * 0; i < count; i++) { MenuComponent comp = parent.getItem(i); if (comp + * instanceof Accessible) { aIndex++; if (comp == MenuComponent.this) { + * return aIndex; } } } } return -1; } finally { toolkit.unlockAWT(); } } + * @Override public String getAccessibleName() { return + * super.getAccessibleName(); } + * @Override public Accessible getAccessibleParent() { toolkit.lockAWT(); + * try { Accessible aParent = super.getAccessibleParent(); if (aParent != + * null) { return aParent; } MenuContainer parent = getParent(); if (parent + * instanceof Accessible) { aParent = (Accessible) parent; } return aParent; + * } finally { toolkit.unlockAWT(); } } + * @Override public AccessibleRole getAccessibleRole() { return + * AccessibleRole.AWT_COMPONENT; } + * @Override public AccessibleSelection getAccessibleSelection() { return + * this; } + * @Override public AccessibleStateSet getAccessibleStateSet() { return new + * AccessibleStateSet(); } + * @Override public Locale getLocale() { return Locale.getDefault(); } } + */ + + /** + * The accessor to MenuComponent internal state, utilized by the visual + * theme. + * + * @throws HeadlessException + * the headless exception. + */ + // ???AWT /* - class State implements MenuState { - Dimension size; - - Dimension getSize() { - if (size == null) { - calculate(); - } - return size; - } - - public int getWidth() { - return getSize().width; - } - - public int getHeight() { - return getSize().height; - } - - public Font getFont() { - return MenuComponent.this.getFont(); - } - - public int getItemCount() { - return MenuComponent.this.getItemCount(); - } - - public int getSelectedItemIndex() { - return MenuComponent.this.getSelectedItemIndex(); - } - - public boolean isFontSet() { - return MenuComponent.this.isFontSet(); - } - - @SuppressWarnings("deprecation") - public FontMetrics getFontMetrics(Font f) { - return MenuComponent.this.toolkit.getFontMetrics(f); - } - - public Point getLocation() { - return MenuComponent.this.getLocation(); - } - - public MenuItemState getItem(int index) { - MenuItem item = MenuComponent.this.getItem(index); - return item.itemState; - } - - public void setSize(int w, int h) { - this.size = new Dimension(w, h); - } - - void calculate() { - size = new Dimension(); - size.setSize(toolkit.theme.calculateMenuSize(this)); - } - - void reset() { - for (int i = 0; i < getItemCount(); i++) { - ((MenuItem.State) getItem(i)).reset(); - } - } - - } - */ - - /** - * Pop-up box for menu. It transfers the paint events, - * keyboard and mouse events to the menu component itself - */ - //???AWT + * class State implements MenuState { Dimension size; Dimension getSize() { + * if (size == null) { calculate(); } return size; } public int getWidth() { + * return getSize().width; } public int getHeight() { return + * getSize().height; } public Font getFont() { return + * MenuComponent.this.getFont(); } public int getItemCount() { return + * MenuComponent.this.getItemCount(); } public int getSelectedItemIndex() { + * return MenuComponent.this.getSelectedItemIndex(); } public boolean + * isFontSet() { return MenuComponent.this.isFontSet(); } + * @SuppressWarnings("deprecation") public FontMetrics getFontMetrics(Font + * f) { return MenuComponent.this.toolkit.getFontMetrics(f); } public Point + * getLocation() { return MenuComponent.this.getLocation(); } public + * MenuItemState getItem(int index) { MenuItem item = + * MenuComponent.this.getItem(index); return item.itemState; } public void + * setSize(int w, int h) { this.size = new Dimension(w, h); } void + * calculate() { size = new Dimension(); + * size.setSize(toolkit.theme.calculateMenuSize(this)); } void reset() { for + * (int i = 0; i < getItemCount(); i++) { ((MenuItem.State) + * getItem(i)).reset(); } } } + */ + + /** + * Pop-up box for menu. It transfers the paint events, keyboard and mouse + * events to the menu component itself. + */ + // ???AWT /* - class MenuPopupBox extends PopupBox { - private final Point lastMousePos = new Point(); - - @Override - boolean isMenu() { - return true; - } - - @Override - void paint(Graphics gr) { - MenuComponent.this.paint(gr); - } - - @Override - void onKeyEvent(int eventId, int vKey, long when, int modifiers) { - MenuComponent.this.onKeyEvent(eventId, vKey, when, modifiers); - } + * class MenuPopupBox extends PopupBox { private final Point lastMousePos = + * new Point(); + * @Override boolean isMenu() { return true; } + * @Override void paint(Graphics gr) { MenuComponent.this.paint(gr); } + * @Override void onKeyEvent(int eventId, int vKey, long when, int + * modifiers) { MenuComponent.this.onKeyEvent(eventId, vKey, when, + * modifiers); } + * @Override void onMouseEvent(int eventId, Point where, int mouseButton, + * long when, int modifiers, int wheelRotation) { // prevent conflict of + * mouse and keyboard // when sub-menu drops down due to keyboard navigation + * if (lastMousePos.equals(where) && (eventId == MouseEvent.MOUSE_MOVED || + * eventId == MouseEvent.MOUSE_ENTERED)) { return; } + * lastMousePos.setLocation(where); MenuComponent.this.onMouseEvent(eventId, + * where, mouseButton, when, modifiers); } } + */ - @Override - void onMouseEvent(int eventId, Point where, int mouseButton, long when, int modifiers, - int wheelRotation) { - // prevent conflict of mouse and keyboard - // when sub-menu drops down due to keyboard navigation - if (lastMousePos.equals(where) - && (eventId == MouseEvent.MOUSE_MOVED || eventId == MouseEvent.MOUSE_ENTERED)) { - return; - } - lastMousePos.setLocation(where); - MenuComponent.this.onMouseEvent(eventId, where, mouseButton, when, modifiers); - } - } - */ - /** * Instantiates a new MenuComponent object. * - * @throws HeadlessException if the graphical interface - * environment can't support MenuComponents + * @throws HeadlessException + * if the graphical interface environment can't support + * MenuComponents. */ public MenuComponent() throws HeadlessException { toolkit.lockAWT(); @@ -438,9 +238,9 @@ public abstract class MenuComponent implements Serializable { } /** - * Gets the Parent menu Container . + * Gets the parent menu container. * - * @return the parent + * @return the parent. */ public MenuContainer getParent() { toolkit.lockAWT(); @@ -454,7 +254,8 @@ public abstract class MenuComponent implements Serializable { /** * Sets the name of the MenuComponent to the specified string. * - * @param name the new name of the MenuComponent object. + * @param name + * the new name of the MenuComponent object. */ public void setName(String name) { toolkit.lockAWT(); @@ -468,7 +269,8 @@ public abstract class MenuComponent implements Serializable { /** * Dispatches AWT event. * - * @param event the AWTEvent. + * @param event + * the AWTEvent. */ public final void dispatchEvent(AWTEvent event) { toolkit.lockAWT(); @@ -485,7 +287,8 @@ public abstract class MenuComponent implements Serializable { /** * Post deprecated event. * - * @param event the event + * @param event + * the event. */ void postDeprecatedEvent(AWTEvent event) { Event evt = event.getEvent(); @@ -495,11 +298,12 @@ public abstract class MenuComponent implements Serializable { } /** - * Gets the peer of the MenuComponent; an application must not - * use this method directly. + * Gets the peer of the MenuComponent; an application must not use this + * method directly. * * @return the MenuComponentPeer object. - * + * @throws NotImplementedException + * if this method is not implemented by a subclass. * @deprecated an application must not use this method directly. */ @Deprecated @@ -527,11 +331,9 @@ public abstract class MenuComponent implements Serializable { /** * Posts the Event to the MenuComponent. * - * @param e the Event. - * - * @return true, if the event is posted successfully; - * false otherwise. - * + * @param e + * the Event. + * @return true, if the event is posted successfully, false otherwise. * @deprecated Replaced dispatchEvent method. */ @SuppressWarnings("deprecation") @@ -551,8 +353,7 @@ public abstract class MenuComponent implements Serializable { /** * Returns the string representation of the MenuComponent state. * - * @return returns the string representation of the MenuComponent - * state. + * @return returns the string representation of the MenuComponent state. */ protected String paramString() { toolkit.lockAWT(); @@ -563,20 +364,13 @@ public abstract class MenuComponent implements Serializable { } } - //???AWT + // ???AWT /* - public AccessibleContext getAccessibleContext() { - toolkit.lockAWT(); - try { - if (accessibleContext == null) { - accessibleContext = createAccessibleContext(); - } - return accessibleContext; - } finally { - toolkit.unlockAWT(); - } - } - */ + * public AccessibleContext getAccessibleContext() { toolkit.lockAWT(); try + * { if (accessibleContext == null) { accessibleContext = + * createAccessibleContext(); } return accessibleContext; } finally { + * toolkit.unlockAWT(); } } + */ /** * Gets the font of the MenuComponent object. @@ -605,13 +399,13 @@ public abstract class MenuComponent implements Serializable { */ boolean isFontSet() { return font != null - || ((parent instanceof MenuComponent) && ((MenuComponent) parent).isFontSet()); + || ((parent instanceof MenuComponent) && ((MenuComponent)parent).isFontSet()); } /** * Checks for default font. * - * @return true, if successful + * @return true, if successful. */ boolean hasDefaultFont() { return false; @@ -620,7 +414,8 @@ public abstract class MenuComponent implements Serializable { /** * Processes an AWTEevent on this menu component. * - * @param event the AWTEvent. + * @param event + * the AWTEvent. */ protected void processEvent(AWTEvent event) { toolkit.lockAWT(); @@ -645,7 +440,8 @@ public abstract class MenuComponent implements Serializable { /** * Sets the Font for this MenuComponent object. * - * @param font the new Font to be used for this MenuComponent. + * @param font + * the new Font to be used for this MenuComponent. */ public void setFont(Font font) { toolkit.lockAWT(); @@ -659,7 +455,8 @@ public abstract class MenuComponent implements Serializable { /** * Sets the parent. * - * @param parent the new parent + * @param parent + * the new parent. */ void setParent(MenuContainer parent) { this.parent = parent; @@ -668,7 +465,7 @@ public abstract class MenuComponent implements Serializable { /** * Gets the location. * - * @return the location + * @return the location. */ Point getLocation() { // to be overridden @@ -678,7 +475,7 @@ public abstract class MenuComponent implements Serializable { /** * Gets the width. * - * @return the width + * @return the width. */ int getWidth() { // to be overridden @@ -688,7 +485,7 @@ public abstract class MenuComponent implements Serializable { /** * Gets the height. * - * @return the height + * @return the height. */ int getHeight() { // to be overridden @@ -698,31 +495,19 @@ public abstract class MenuComponent implements Serializable { /** * Recursively find the menu item for a menu shortcut. * - * @param gr the gr - * - * @return the menu item; - * or null if the item is not available for this shortcut + * @param gr + * the gr. + * @return the menu item; or null if the item is not available for this + * shortcut. */ - //???AWT + // ???AWT /* - MenuItem getShortcutMenuItemImpl(MenuShortcut ms) { - if (ms == null) { - return null; - } - for (int i = 0; i < getItemCount(); i++) { - MenuItem mi = getItem(i); - if (mi instanceof Menu) { - mi = ((Menu) mi).getShortcutMenuItemImpl(ms); - if (mi != null) { - return mi; - } - } else if (ms.equals(mi.getShortcut())) { - return mi; - } - } - return null; - } - */ + * MenuItem getShortcutMenuItemImpl(MenuShortcut ms) { if (ms == null) { + * return null; } for (int i = 0; i < getItemCount(); i++) { MenuItem mi = + * getItem(i); if (mi instanceof Menu) { mi = ((Menu) + * mi).getShortcutMenuItemImpl(ms); if (mi != null) { return mi; } } else if + * (ms.equals(mi.getShortcut())) { return mi; } } return null; } + */ void paint(Graphics gr) { gr.setColor(Color.LIGHT_GRAY); @@ -733,11 +518,16 @@ public abstract class MenuComponent implements Serializable { /** * Mouse events handler. * - * @param eventId - one of the MouseEvent.MOUSE_* constants - * @param where - mouse location - * @param mouseButton - mouse button that was pressed or released - * @param when - event time - * @param modifiers - input event modifiers + * @param eventId + * one of the MouseEvent.MOUSE_* constants. + * @param where + * mouse location. + * @param mouseButton + * mouse button that was pressed or released. + * @param when + * event time. + * @param modifiers + * input event modifiers. */ void onMouseEvent(int eventId, Point where, int mouseButton, long when, int modifiers) { // to be overridden @@ -746,159 +536,109 @@ public abstract class MenuComponent implements Serializable { /** * Keyboard event handler. * - * @param eventId - one of the KeyEvent.KEY_* constants - * @param vKey - the key code - * @param when - event time - * @param modifiers - input event modifiers + * @param eventId + * one of the KeyEvent.KEY_* constants. + * @param vKey + * the key code. + * @param when + * event time. + * @param modifiers + * input event modifiers. */ void onKeyEvent(int eventId, int vKey, long when, int modifiers) { // to be overridden } /** - * Post the ActionEvent or ItemEvent, - * depending on type of the menu item. + * Post the ActionEvent or ItemEvent, depending on type of the menu item. * - * @param index the index - * - * @return the item rect + * @param index + * the index. + * @return the item rect. */ - //???AWT + // ???AWT /* - void fireItemAction(int item, long when, int modifiers) { - MenuItem mi = getItem(item); - mi.itemSelected(when, modifiers); - } - - MenuItem getItem(int index) { - // to be overridden - return null; - } - - int getItemCount() { - return 0; - } - */ + * void fireItemAction(int item, long when, int modifiers) { MenuItem mi = + * getItem(item); mi.itemSelected(when, modifiers); } MenuItem getItem(int + * index) { // to be overridden return null; } int getItemCount() { return + * 0; } + */ /** - * @return The sub-menu of currently selecetd item, - * or null if such a sub-menu is not available + * @return The sub-menu of currently selecetd item, or null if such a + * sub-menu is not available. */ - //???AWT + // ???AWT /* - Menu getSelectedSubmenu() { - if (selectedItemIndex < 0) { - return null; - } - MenuItem item = getItem(selectedItemIndex); - return (item instanceof Menu) ? (Menu) item : null; - } - */ + * Menu getSelectedSubmenu() { if (selectedItemIndex < 0) { return null; } + * MenuItem item = getItem(selectedItemIndex); return (item instanceof Menu) + * ? (Menu) item : null; } + */ /** - * Convenience method for selectItem(index, true) + * Convenience method for selectItem(index, true). */ - //???AWT + // ???AWT /* - void selectItem(int index) { - selectItem(index, true); - } - */ + * void selectItem(int index) { selectItem(index, true); } + */ /** - * Change the selection in the menu - * @param index - new selecetd item's index - * @param showSubMenu - if new selected item has a sub-menu, - * should that sub-menu be displayed + * Change the selection in the menu. + * + * @param index + * new selecetd item's index. + * @param showSubMenu + * if new selected item has a sub-menu, should that sub-menu be + * displayed. */ - //???AWT + // ???AWT /* - void selectItem(int index, boolean showSubMenu) { - if (selectedItemIndex == index) { - return; - } - if (selectedItemIndex >= 0 && getItem(selectedItemIndex) instanceof Menu) { - ((Menu) getItem(selectedItemIndex)).hide(); - } - MultiRectArea clip = getUpdateClip(index, selectedItemIndex); - selectedItemIndex = index; - Graphics gr = getGraphics(clip); - if (gr != null) { - paint(gr); - } - if (showSubMenu) { - showSubMenu(selectedItemIndex); - } - } - */ + * void selectItem(int index, boolean showSubMenu) { if (selectedItemIndex + * == index) { return; } if (selectedItemIndex >= 0 && + * getItem(selectedItemIndex) instanceof Menu) { ((Menu) + * getItem(selectedItemIndex)).hide(); } MultiRectArea clip = + * getUpdateClip(index, selectedItemIndex); selectedItemIndex = index; + * Graphics gr = getGraphics(clip); if (gr != null) { paint(gr); } if + * (showSubMenu) { showSubMenu(selectedItemIndex); } } + */ /** * Change the selected item to the next one in the requested direction * moving cyclically, skipping separators - * @param forward - the direction to move the selection - * @param showSubMenu - if new selected item has a sub-menu, - * should that sub-menu be displayed + * + * @param forward + * the direction to move the selection. + * @param showSubMenu + * if new selected item has a sub-menu, should that sub-menu be + * displayed. */ - //???AWT + // ???AWT /* - void selectNextItem(boolean forward, boolean showSubMenu) { - int selected = getSelectedItemIndex(); - int count = getItemCount(); - if (count == 0) { - return; - } - if (selected < 0) { - selected = (forward ? count - 1 : 0); - } - int i = selected; - do { - i = (forward ? (i + 1) : (i + count - 1)) % count; - i %= count; - MenuItem item = getItem(i); - if (!"-".equals(item.getLabel())) { //$NON-NLS-1$ - selectItem(i, showSubMenu); - return; - } - } while (i != selected); - } - - - void showSubMenu(int index) { - if ((index < 0) || !isActive()) { - return; - } - MenuItem item = getItem(index); - if (item instanceof Menu) { - Menu menu = ((Menu) getItem(index)); - if (menu.getItemCount() == 0) { - return; - } - Point location = getSubmenuLocation(index); - menu.show(location.x, location.y, false); - } - } - */ + * void selectNextItem(boolean forward, boolean showSubMenu) { int selected + * = getSelectedItemIndex(); int count = getItemCount(); if (count == 0) { + * return; } if (selected < 0) { selected = (forward ? count - 1 : 0); } int + * i = selected; do { i = (forward ? (i + 1) : (i + count - 1)) % count; i + * %= count; MenuItem item = getItem(i); if (!"-".equals(item.getLabel())) { + * //$NON-NLS-1$ selectItem(i, showSubMenu); return; } } while (i != + * selected); } void showSubMenu(int index) { if ((index < 0) || + * !isActive()) { return; } MenuItem item = getItem(index); if (item + * instanceof Menu) { Menu menu = ((Menu) getItem(index)); if + * (menu.getItemCount() == 0) { return; } Point location = + * getSubmenuLocation(index); menu.show(location.x, location.y, false); } } + */ /** - * @return - the menu bar which is the root of crrent menu's hierarchy; - * or null if the hierarchy root is not a menu bar + * @return the menu bar which is the root of current menu's hierarchy; or + * null if the hierarchy root is not a menu bar. */ - //???AWT + // ???AWT /* - MenuBar getMenuBar() { - if (parent instanceof MenuBar) { - return (MenuBar) parent; - } - if (parent instanceof MenuComponent) { - return ((MenuComponent) parent).getMenuBar(); - } - return null; - } - - PopupBox getPopupBox() { - return null; - } - */ + * MenuBar getMenuBar() { if (parent instanceof MenuBar) { return (MenuBar) + * parent; } if (parent instanceof MenuComponent) { return ((MenuComponent) + * parent).getMenuBar(); } return null; } PopupBox getPopupBox() { return + * null; } + */ Rectangle getItemRect(int index) { // to be overridden @@ -906,13 +646,14 @@ public abstract class MenuComponent implements Serializable { } /** - * Determine the clip region when menu selection is changed - * from index1 to index2. - * - * @param index1 - old selected intem - * @param index2 - new selected item + * Determine the clip region when menu selection is changed from index1 to + * index2. * - * @return - the region to repaint + * @param index1 + * old selected item. + * @param index2 + * new selected item. + * @return the region to repaint. */ final MultiRectArea getUpdateClip(int index1, int index2) { MultiRectArea clip = new MultiRectArea(); @@ -928,9 +669,9 @@ public abstract class MenuComponent implements Serializable { /** * Gets the submenu location. * - * @param index the index - * - * @return the submenu location + * @param index + * the index. + * @return the submenu location. */ Point getSubmenuLocation(int index) { // to be overridden @@ -940,7 +681,7 @@ public abstract class MenuComponent implements Serializable { /** * Gets the selected item index. * - * @return the selected item index + * @return the selected item index. */ int getSelectedItemIndex() { return selectedItemIndex; @@ -952,14 +693,15 @@ public abstract class MenuComponent implements Serializable { void hide() { selectedItemIndex = -1; if (parent instanceof MenuComponent) { - ((MenuComponent) parent).itemHidden(this); + ((MenuComponent)parent).itemHidden(this); } } /** * Item hidden. * - * @param mc the mc + * @param mc + * the mc. */ void itemHidden(MenuComponent mc) { // to be overridden @@ -968,7 +710,7 @@ public abstract class MenuComponent implements Serializable { /** * Checks if is visible. * - * @return true, if is visible + * @return true, if is visible. */ boolean isVisible() { return true; @@ -977,7 +719,7 @@ public abstract class MenuComponent implements Serializable { /** * Checks if is active. * - * @return true, if is active + * @return true, if is active. */ boolean isActive() { return true; @@ -987,14 +729,16 @@ public abstract class MenuComponent implements Serializable { * Hide all menu hierarchy. */ void endMenu() { - //???AWT: toolkit.dispatcher.popupDispatcher.deactivateAll(); + // ???AWT: toolkit.dispatcher.popupDispatcher.deactivateAll(); } /** * Handle the mouse click or Enter key event on a menu's item. * - * @param when - the event time - * @param modifiers - input event modifiers + * @param when + * the event time. + * @param modifiers + * input event modifiers. */ void itemSelected(long when, int modifiers) { endMenu(); @@ -1003,14 +747,14 @@ public abstract class MenuComponent implements Serializable { /** * Auto name. * - * @return the string + * @return the string. */ String autoName() { String name = getClass().getName(); if (name.indexOf("$") != -1) { //$NON-NLS-1$ return null; } - //???AWT: int number = toolkit.autoNumber.nextMenuComponent++; + // ???AWT: int number = toolkit.autoNumber.nextMenuComponent++; int number = 0; name = name.substring(name.lastIndexOf(".") + 1) + Integer.toString(number); //$NON-NLS-1$ return name; @@ -1019,10 +763,10 @@ public abstract class MenuComponent implements Serializable { /** * Creates the Graphics object for the pop-up box of this menu component. * - * @param clip - the clip to set on this Graphics - * - * @return - the created Graphics object, - * or null if such object is not available. + * @param clip + * the clip to set on this Graphics. + * @return the created Graphics object, or null if such object is not + * available. */ Graphics getGraphics(MultiRectArea clip) { // to be overridden @@ -1030,12 +774,10 @@ public abstract class MenuComponent implements Serializable { } /** - * @return accessible context specific for particular menu component + * @return accessible context specific for particular menu component. */ - //???AWT + // ???AWT /* - AccessibleContext createAccessibleContext() { - return null; - } - */ + * AccessibleContext createAccessibleContext() { return null; } + */ } diff --git a/awt/java/awt/MenuContainer.java b/awt/java/awt/MenuContainer.java index 7a48f13c892973ed5402f38c74e904a2e16aa3e5..e509a1b1b7ec6ba6add67326f6787c60af1e3ca4 100644 --- a/awt/java/awt/MenuContainer.java +++ b/awt/java/awt/MenuContainer.java @@ -18,17 +18,21 @@ * @author Pavel Dolgov * @version $Revision$ */ + package java.awt; /** * The MenuContainer interface represents all menu containers. + * + * @since Android 1.0 */ public interface MenuContainer { /** * Removes the specified MenuComponent from the MenuContainer. * - * @param c the MenuComponent. + * @param c + * the MenuComponent. */ public void remove(MenuComponent c); @@ -42,15 +46,12 @@ public interface MenuContainer { /** * Posts an Event. * - * @param e the Event. - * - * @return true if the event is posted successfully; - * false otherwise. - * + * @param e + * the Event. + * @return true if the event is posted successfully, false otherwise. * @deprecated Replaced by dispatchEvent method. */ @Deprecated public boolean postEvent(Event e); } - diff --git a/awt/java/awt/Paint.java b/awt/java/awt/Paint.java index f8732c8efed37224c47156c81521efd39ec4cd20..dfea3a74bfed1961e058164e79e37c34dca50a5e 100644 --- a/awt/java/awt/Paint.java +++ b/awt/java/awt/Paint.java @@ -18,6 +18,7 @@ * @author Alexey A. Petrenko * @version $Revision$ */ + package java.awt; import java.awt.geom.AffineTransform; @@ -25,28 +26,32 @@ import java.awt.geom.Rectangle2D; import java.awt.image.ColorModel; /** - * The Paint interface provides possibility of generating - * color patterns in device space for fill, draw, or stroke operations - * in a Graphics2D. + * The Paint interface provides possibility of generating color patterns in + * device space for fill, draw, or stroke operations in a Graphics2D. + * + * @since Android 1.0 */ public interface Paint extends Transparency { - + /** - * Creates the PaintContext which is used to generate color - * patterns for rendering operations of Graphics2D. - * - * @param cm the ColorModel object, or null. - * @param deviceBounds the Rectangle represents the bounding box of - * device space for the graphics rendering operations. - * @param userBounds the Rectangle represents bounding box of - * user space for the graphics rendering operations. - * @param xform the AffineTransform for translation from user space - * to device space. - * @param hints the RenderingHints preferences. + * Creates the PaintContext which is used to generate color patterns for + * rendering operations of Graphics2D. * + * @param cm + * the ColorModel object, or null. + * @param deviceBounds + * the Rectangle represents the bounding box of device space for + * the graphics rendering operations. + * @param userBounds + * the Rectangle represents bounding box of user space for the + * graphics rendering operations. + * @param xform + * the AffineTransform for translation from user space to device + * space. + * @param hints + * the RenderingHints preferences. * @return the PaintContext for generating color patterns. */ - PaintContext createContext(ColorModel cm, Rectangle deviceBounds, - Rectangle2D userBounds, AffineTransform xform, - RenderingHints hints); + PaintContext createContext(ColorModel cm, Rectangle deviceBounds, Rectangle2D userBounds, + AffineTransform xform, RenderingHints hints); } diff --git a/awt/java/awt/PaintContext.java b/awt/java/awt/PaintContext.java index 647de8bbbc889e46931540b31b7a16a4c92dce11..966b6ca99e8254dff623c8d3c56a368b2321a39b 100644 --- a/awt/java/awt/PaintContext.java +++ b/awt/java/awt/PaintContext.java @@ -18,20 +18,22 @@ * @author Alexey A. Petrenko * @version $Revision$ */ + package java.awt; import java.awt.image.ColorModel; import java.awt.image.Raster; /** - * The PaintContext interface determines the specific environment for - * generating color patterns in device space for fill, draw, or stroke - * rendering operations using Graphics2D. This interface provides colors - * through the Raster object associated with the specific ColorModel - * for Graphics2D rendering operations. + * The PaintContext interface determines the specific environment for generating + * color patterns in device space for fill, draw, or stroke rendering operations + * using Graphics2D. This interface provides colors through the Raster object + * associated with the specific ColorModel for Graphics2D rendering operations. + * + * @since Android 1.0 */ public interface PaintContext { - + /** * Releases the resources allocated for the operation. */ @@ -45,20 +47,23 @@ public interface PaintContext { ColorModel getColorModel(); /** - * Gets the Raster which defines the colors of the specified rectangular + * Gets the Raster which defines the colors of the specified rectangular * area for Graphics2D rendering operations. * - * @param x the X coordinate of the device space area for which - * colors are generated. - * @param y the Y coordinate of the device space area for which - * colors are generated. - * @param w the width of the device space area for which - * colors are generated. - * @param h the height of the device space area for which - * colors are generated. - * - * @return the Raster object which contains the colors of the specified - * rectangular area for Graphics2D rendering operations. + * @param x + * the X coordinate of the device space area for which colors are + * generated. + * @param y + * the Y coordinate of the device space area for which colors are + * generated. + * @param w + * the width of the device space area for which colors are + * generated. + * @param h + * the height of the device space area for which colors are + * generated. + * @return the Raster object which contains the colors of the specified + * rectangular area for Graphics2D rendering operations. */ Raster getRaster(int x, int y, int w, int h); } diff --git a/awt/java/awt/Point.java b/awt/java/awt/Point.java index 99418ed8a74c4dedda09370664de8cab3ed250e4..8ec424121513a3b8b574d55097a4eb459cc4f483 100644 --- a/awt/java/awt/Point.java +++ b/awt/java/awt/Point.java @@ -18,28 +18,37 @@ * @author Denis M. Kishenko * @version $Revision$ */ + package java.awt; import java.awt.geom.Point2D; import java.io.Serializable; /** - * The Point class represents a point location with coordinates X, Y in - * current coordinate system. + * The Point class represents a point location with coordinates X, Y in current + * coordinate system. + * + * @since Android 1.0 */ public class Point extends Point2D implements Serializable { - /** The Constant serialVersionUID. */ + /** + * The Constant serialVersionUID. + */ private static final long serialVersionUID = -5276940640259749850L; - /** The X coordinate of Point. */ + /** + * The X coordinate of Point. + */ public int x; - - /** The Y coordinate of Point. */ + + /** + * The Y coordinate of Point. + */ public int y; /** - * Instantiates a new point with (0, O) coordinates, the origin of + * Instantiates a new point with (0, O) coordinates, the origin of * coordinate system. */ public Point() { @@ -49,18 +58,20 @@ public class Point extends Point2D implements Serializable { /** * Instantiates a new point with (x, y) coordinates. * - * @param x the X coordinate of Point. - * @param y the Y coordinate of Point. + * @param x + * the X coordinate of Point. + * @param y + * the Y coordinate of Point. */ public Point(int x, int y) { setLocation(x, y); } /** - * Instantiates a new point, giving it the same locaion as - * the parameter p. + * Instantiates a new point, giving it the same location as the parameter p. * - * @param p the Point object giving the coordinates of the new point. + * @param p + * the Point object giving the coordinates of the new point. */ public Point(Point p) { setLocation(p.x, p.y); @@ -69,12 +80,10 @@ public class Point extends Point2D implements Serializable { /** * Compares current Point with the specified object. * - * @param obj the Object to be compared. - * - * @return true, if the Object being compared is a Point - * whose coordinates are equal to the coordinates of this - * Point, otherwise false. - * + * @param obj + * the Object to be compared. + * @return true, if the Object being compared is a Point whose coordinates + * are equal to the coordinates of this Point, false otherwise. * @see java.awt.geom.Point2D#equals(Object) */ @Override @@ -103,7 +112,6 @@ public class Point extends Point2D implements Serializable { * Gets X coordinate of Point as a double. * * @return X coordinate of the point as a double. - * * @see java.awt.geom.Point2D#getX() */ @Override @@ -115,7 +123,6 @@ public class Point extends Point2D implements Serializable { * Gets Y coordinate of Point as a double. * * @return Y coordinate of the point as a double. - * * @see java.awt.geom.Point2D#getY() */ @Override @@ -135,7 +142,8 @@ public class Point extends Point2D implements Serializable { /** * Sets the location of the Point to the same coordinates as p. * - * @param p the Point that gives the new location. + * @param p + * the Point that gives the new location. */ public void setLocation(Point p) { setLocation(p.x, p.y); @@ -144,8 +152,10 @@ public class Point extends Point2D implements Serializable { /** * Sets the location of the Point to the coordinates X, Y. * - * @param x the X coordinate of the Point's new location. - * @param y the Y coordinate of the Point's new location. + * @param x + * the X coordinate of the Point's new location. + * @param y + * the Y coordinate of the Point's new location. */ public void setLocation(int x, int y) { this.x = x; @@ -155,36 +165,43 @@ public class Point extends Point2D implements Serializable { /** * Sets the location of Point to the specified double coordinates. * - * @param x the X the Point's new location. - * @param y the Y the Point's new location. - * + * @param x + * the X the Point's new location. + * @param y + * the Y the Point's new location. * @see java.awt.geom.Point2D#setLocation(double, double) */ @Override public void setLocation(double x, double y) { - x = x < Integer.MIN_VALUE ? Integer.MIN_VALUE : x > Integer.MAX_VALUE ? Integer.MAX_VALUE : x; - y = y < Integer.MIN_VALUE ? Integer.MIN_VALUE : y > Integer.MAX_VALUE ? Integer.MAX_VALUE : y; + x = x < Integer.MIN_VALUE ? Integer.MIN_VALUE : x > Integer.MAX_VALUE ? Integer.MAX_VALUE + : x; + y = y < Integer.MIN_VALUE ? Integer.MIN_VALUE : y > Integer.MAX_VALUE ? Integer.MAX_VALUE + : y; setLocation((int)Math.round(x), (int)Math.round(y)); } /** * Moves the Point to the specified (x, y) location. * - * @param x the X coordinate of the new location. - * @param y the Y coordinate of the new location. + * @param x + * the X coordinate of the new location. + * @param y + * the Y coordinate of the new location. */ public void move(int x, int y) { setLocation(x, y); } /** - * Translates current Point moving it from the position (x, y) - * to the new position given by (x+dx, x+dy) coordinates. - * - * @param dx the horizontal delta - the Point is moved to this distance along - * X axis. - * @param dy the vertical delta - the Point is moved to this distance along - * Y axis. + * Translates current Point moving it from the position (x, y) to the new + * position given by (x+dx, x+dy) coordinates. + * + * @param dx + * the horizontal delta - the Point is moved to this distance + * along X axis. + * @param dy + * the vertical delta - the Point is moved to this distance along + * Y axis. */ public void translate(int dx, int dy) { x += dx; @@ -192,4 +209,3 @@ public class Point extends Point2D implements Serializable { } } - diff --git a/awt/java/awt/Polygon.java b/awt/java/awt/Polygon.java index 6f3fc9778c918af1c6044e4428388ee57fc21b18..de31eb989229ff2e9201b13c05f2786331fa16a6 100644 --- a/awt/java/awt/Polygon.java +++ b/awt/java/awt/Polygon.java @@ -18,6 +18,7 @@ * @author Denis M. Kishenko * @version $Revision$ */ + package java.awt; import java.awt.Point; @@ -34,57 +35,78 @@ import org.apache.harmony.awt.gl.*; import org.apache.harmony.awt.internal.nls.Messages; /** - * The Polygon class defines an closed area specified by n vertices and - * n edges. The coordinates of the vertices are specified by x, y arrays. - * The edges are the line segments from the point (x[i], y[i]) to the point - * (x[i+1], y[i+1]), for -1 < i < (n-1) plus the line segment from - * the point (x[n-1], y[n-1]) to the point (x[0], y[0]) point. - * The Polygon is empty if the number of vertices is zero. + * The Polygon class defines an closed area specified by n vertices and n edges. + * The coordinates of the vertices are specified by x, y arrays. The edges are + * the line segments from the point (x[i], y[i]) to the point (x[i+1], y[i+1]), + * for -1 < i < (n-1) plus the line segment from the point (x[n-1], y[n-1]) to + * the point (x[0], y[0]) point. The Polygon is empty if the number of vertices + * is zero. + * + * @since Android 1.0 */ public class Polygon implements Shape, Serializable { - /** The Constant serialVersionUID. */ + /** + * The Constant serialVersionUID. + */ private static final long serialVersionUID = -6460061437900069969L; - /** The points buffer capacity. */ + /** + * The points buffer capacity. + */ private static final int BUFFER_CAPACITY = 4; - - /** The number of Polygon vertices.*/ + + /** + * The number of Polygon vertices. + */ public int npoints; - - /** The array of X coordinates of the vertices. */ + + /** + * The array of X coordinates of the vertices. + */ public int[] xpoints; - - /** The array of Y coordinates of the vertices. */ + + /** + * The array of Y coordinates of the vertices. + */ public int[] ypoints; - - /** - * The smallest Rectangle that completely contains this Polygon. + + /** + * The smallest Rectangle that completely contains this Polygon. */ protected Rectangle bounds; /* - * Polygon path iterator + * Polygon path iterator */ /** * The internal Class Iterator. */ class Iterator implements PathIterator { - /** The source Polygon object. */ + /** + * The source Polygon object. + */ public Polygon p; - - /** The path iterator transformation. */ + + /** + * The path iterator transformation. + */ public AffineTransform t; - - /** The current segmenet index. */ + + /** + * The current segment index. + */ public int index; /** - * Constructs a new Polygon.Iterator for the given polygon and transformation + * Constructs a new Polygon.Iterator for the given polygon and + * transformation * - * @param at - the AffineTransform object to apply rectangle path - * @param p the p + * @param at + * the AffineTransform object to apply rectangle path. + * @param p + * the p. */ public Iterator(AffineTransform at, Polygon p) { this.p = p; @@ -148,18 +170,21 @@ public class Polygon implements Shape, Serializable { } /** - * Instantiates a new polygon with the specified number of vertices, - * and the given arrays of x, y vertex coordinates. The length of - * each coordinate array may not be less than the specified number of - * vertices but may be greater. Only the first n elements are used from - * each coordinate array. - * - * @param xpoints the array of X vertex coordinates. - * @param ypoints the array of Y vertex coordinates. - * @param npoints the number vertices of the polygon. - * @throws IndexOutOfBoundsException if the length of xpoints or ypoints - * is less than n. - * @throws NegativeArraySizeException if n is negative. + * Instantiates a new polygon with the specified number of vertices, and the + * given arrays of x, y vertex coordinates. The length of each coordinate + * array may not be less than the specified number of vertices but may be + * greater. Only the first n elements are used from each coordinate array. + * + * @param xpoints + * the array of X vertex coordinates. + * @param ypoints + * the array of Y vertex coordinates. + * @param npoints + * the number vertices of the polygon. + * @throws IndexOutOfBoundsException + * if the length of xpoints or ypoints is less than n. + * @throws NegativeArraySizeException + * if n is negative. */ public Polygon(int[] xpoints, int[] ypoints, int npoints) { if (npoints > xpoints.length || npoints > ypoints.length) { @@ -178,9 +203,9 @@ public class Polygon implements Shape, Serializable { } /** - * Resets the current Polygon to an empty Polygon. More precisely, - * the number of Polygon vertices is set to zero, but x, y coordinates - * arrays are not affected. + * Resets the current Polygon to an empty Polygon. More precisely, the + * number of Polygon vertices is set to zero, but x, y coordinates arrays + * are not affected. */ public void reset() { npoints = 0; @@ -188,21 +213,22 @@ public class Polygon implements Shape, Serializable { } /** - * Invalidates the data that depends on the vertex coordinates. - * This method should be called after direct manipulations - * of the x, y vertex coordinates arrays to avoid unpredictable - * results of methods which rely on the bounding box. + * Invalidates the data that depends on the vertex coordinates. This method + * should be called after direct manipulations of the x, y vertex + * coordinates arrays to avoid unpredictable results of methods which rely + * on the bounding box. */ public void invalidate() { bounds = null; } /** - * Adds the point to the Polygon and updates the bounding box - * accordingly. + * Adds the point to the Polygon and updates the bounding box accordingly. * - * @param px the X coordinate of the added vertex. - * @param py the Y coordinate of the added vertex. + * @param px + * the X coordinate of the added vertex. + * @param py + * the Y coordinate of the added vertex. */ public void addPoint(int px, int py) { if (npoints == xpoints.length) { @@ -222,20 +248,16 @@ public class Polygon implements Shape, Serializable { npoints++; if (bounds != null) { - bounds.setFrameFromDiagonal( - Math.min(bounds.getMinX(), px), - Math.min(bounds.getMinY(), py), - Math.max(bounds.getMaxX(), px), - Math.max(bounds.getMaxY(), py)); + bounds.setFrameFromDiagonal(Math.min(bounds.getMinX(), px), Math.min(bounds.getMinY(), + py), Math.max(bounds.getMaxX(), px), Math.max(bounds.getMaxY(), py)); } } /** - * Gets the bounding rectangle of the Polygon. The bounding rectangle - * is the smallest rectangle which contains the Polygon. + * Gets the bounding rectangle of the Polygon. The bounding rectangle is the + * smallest rectangle which contains the Polygon. * * @return the bounding rectangle of the Polygon. - * * @see java.awt.Shape#getBounds() */ public Rectangle getBounds() { @@ -270,11 +292,10 @@ public class Polygon implements Shape, Serializable { } /** - * Gets the bounding rectangle of the Polygon. The bounding rectangle - * is the smallest rectangle which contains the Polygon. + * Gets the bounding rectangle of the Polygon. The bounding rectangle is the + * smallest rectangle which contains the Polygon. * * @return the bounding rectangle of the Polygon. - * * @deprecated Use getBounds() method. */ @Deprecated @@ -283,12 +304,10 @@ public class Polygon implements Shape, Serializable { } /** - * Gets the Rectangle2D which represents Polygon bounds. - * The bounding rectangle is the smallest rectangle which contains - * the Polygon. + * Gets the Rectangle2D which represents Polygon bounds. The bounding + * rectangle is the smallest rectangle which contains the Polygon. * * @return the bounding rectangle of the Polygon. - * * @see java.awt.Shape#getBounds2D() */ public Rectangle2D getBounds2D() { @@ -296,11 +315,13 @@ public class Polygon implements Shape, Serializable { } /** - * Translates all vertices of Polygon the specified distances - * along X, Y axis. + * Translates all vertices of Polygon the specified distances along X, Y + * axis. * - * @param mx the distance to translate horizontally. - * @param my the distance to translate vertically. + * @param mx + * the distance to translate horizontally. + * @param my + * the distance to translate vertically. */ public void translate(int mx, int my) { for (int i = 0; i < npoints; i++) { @@ -313,46 +334,47 @@ public class Polygon implements Shape, Serializable { } /** - * Checks whether or not the point given by the coordinates x, y lies inside + * Checks whether or not the point given by the coordinates x, y lies inside * the Polygon. * - * @param x the X coordinate of the point to check. - * @param y the Y coordinate of the point to check. - * - * @return true, if the specified point lies inside the Polygon, - * otherwise false. - * + * @param x + * the X coordinate of the point to check. + * @param y + * the Y coordinate of the point to check. + * @return true, if the specified point lies inside the Polygon, false + * otherwise. * @deprecated Use contains(int, int) method. */ @Deprecated public boolean inside(int x, int y) { - return contains((double) x, (double) y); + return contains((double)x, (double)y); } /** - * Checks whether or not the point given by the coordinates x, y lies inside + * Checks whether or not the point given by the coordinates x, y lies inside * the Polygon. * - * @param x the X coordinate of the point to check. - * @param y the Y coordinate of the point to check. - * - * @return true, if the specified point lies inside the Polygon, - * otherwise false. + * @param x + * the X coordinate of the point to check. + * @param y + * the Y coordinate of the point to check. + * @return true, if the specified point lies inside the Polygon, false + * otherwise. */ public boolean contains(int x, int y) { - return contains((double) x, (double) y); + return contains((double)x, (double)y); } /** - * Checks whether or not the point with specified double coordinates - * lies inside the Polygon. - * - * @param x the X coordinate of the point to check. - * @param y the Y coordinate of the point to check. - * - * @return true, if the point given by the double coordinates - * lies inside the Polygon, otherwise false. - * + * Checks whether or not the point with specified double coordinates lies + * inside the Polygon. + * + * @param x + * the X coordinate of the point to check. + * @param y + * the Y coordinate of the point to check. + * @return true, if the point given by the double coordinates lies inside + * the Polygon, false otherwise. * @see java.awt.Shape#contains(double, double) */ public boolean contains(double x, double y) { @@ -360,19 +382,21 @@ public class Polygon implements Shape, Serializable { } /** - * Checks whether or not the rectangle determined by the parameters - * [x, y, width, height] lies inside the Polygon. - * - * @param x the X coordinate of the rectangles's left upper - * corner as a double. - * @param y the Y coordinate of the rectangles's left upper - * corner as a double. - * @param width the width of rectangle as a double. - * @param width the height of rectangle as a double. - * - * @return true, if the specified rectangle lies inside the Polygon, - * otherwise false. - * + * Checks whether or not the rectangle determined by the parameters [x, y, + * width, height] lies inside the Polygon. + * + * @param x + * the X coordinate of the rectangles's left upper corner as a + * double. + * @param y + * the Y coordinate of the rectangles's left upper corner as a + * double. + * @param width + * the width of rectangle as a double. + * @param height + * the height of rectangle as a double. + * @return true, if the specified rectangle lies inside the Polygon, false + * otherwise. * @see java.awt.Shape#contains(double, double, double, double) */ public boolean contains(double x, double y, double width, double height) { @@ -381,20 +405,21 @@ public class Polygon implements Shape, Serializable { } /** - * Checks whether or not the rectangle determined by the parameters - * [x, y, width, height] intersects the interior of - * the Polygon. - * - * @param x the X coordinate of the rectangles's left upper - * corner as a double. - * @param y the Y coordinate of the rectangles's left upper - * corner as a double. - * @param width the width of rectangle as a double. - * @param width the height of rectangle as a double. - * - * @return true, if the specified rectangle intersects the interior of - * the Polygon, otherwise false. - * + * Checks whether or not the rectangle determined by the parameters [x, y, + * width, height] intersects the interior of the Polygon. + * + * @param x + * the X coordinate of the rectangles's left upper corner as a + * double. + * @param y + * the Y coordinate of the rectangles's left upper corner as a + * double. + * @param width + * the width of rectangle as a double. + * @param height + * the height of rectangle as a double. + * @return true, if the specified rectangle intersects the interior of the + * Polygon, false otherwise. * @see java.awt.Shape#intersects(double, double, double, double) */ public boolean intersects(double x, double y, double width, double height) { @@ -405,11 +430,10 @@ public class Polygon implements Shape, Serializable { /** * Checks whether or not the specified rectangle lies inside the Polygon. * - * @param rect the Rectangle2D object. - * - * @return true, if the specified rectangle lies inside the Polygon, - * otherwise false. - * + * @param rect + * the Rectangle2D object. + * @return true, if the specified rectangle lies inside the Polygon, false + * otherwise. * @see java.awt.Shape#contains(java.awt.geom.Rectangle2D) */ public boolean contains(Rectangle2D rect) { @@ -419,10 +443,10 @@ public class Polygon implements Shape, Serializable { /** * Checks whether or not the specified Point lies inside the Polygon. * - * @param point the Point object. - * - * @return true, if the specified Point lies inside the Polygon, - * otherwise false. + * @param point + * the Point object. + * @return true, if the specified Point lies inside the Polygon, false + * otherwise. */ public boolean contains(Point point) { return contains(point.getX(), point.getY()); @@ -431,11 +455,10 @@ public class Polygon implements Shape, Serializable { /** * Checks whether or not the specified Point2D lies inside the Polygon. * - * @param point the Point2D object. - * - * @return true, if the specified Point2D lies inside the Polygon, - * otherwise false. - * + * @param point + * the Point2D object. + * @return true, if the specified Point2D lies inside the Polygon, false + * otherwise. * @see java.awt.Shape#contains(java.awt.geom.Point2D) */ public boolean contains(Point2D point) { @@ -443,14 +466,13 @@ public class Polygon implements Shape, Serializable { } /** - * Checks whether or not the interior of rectangle specified by - * the Rectangle2D object intersects the interior of the Polygon. - * - * @param rect the Rectangle2D object. - * - * @return true, if the Rectangle2D intersects the interior of - * the Polygon, otherwise false. + * Checks whether or not the interior of rectangle specified by the + * Rectangle2D object intersects the interior of the Polygon. * + * @param rect + * the Rectangle2D object. + * @return true, if the Rectangle2D intersects the interior of the Polygon, + * false otherwise. * @see java.awt.Shape#intersects(java.awt.geom.Rectangle2D) */ public boolean intersects(Rectangle2D rect) { @@ -458,13 +480,12 @@ public class Polygon implements Shape, Serializable { } /** - * Gets the PathIterator object which gives the coordinates of - * the polygon, transformed according to the specified AffineTransform. - * - * @param t the specified AffineTransform object, or null. + * Gets the PathIterator object which gives the coordinates of the polygon, + * transformed according to the specified AffineTransform. * + * @param t + * the specified AffineTransform object or null. * @return PathIterator object for the Polygon. - * * @see java.awt.Shape#getPathIterator(java.awt.geom.AffineTransform) */ public PathIterator getPathIterator(AffineTransform t) { @@ -472,23 +493,23 @@ public class Polygon implements Shape, Serializable { } /** - * Gets the PathIterator object which gives the coordinates of - * the polygon, transformed according to the specified AffineTransform. - * The flatness parameter is ignored. - * - * @param t the specified AffineTransform object, or null. - * @param flatness the maximum number of the control points for - * a given curve which varies from colinear before a subdivided curve - * is replaced by a straight line connecting the endpoints. - * This parameter is ignored for the Polygon class. - * + * Gets the PathIterator object which gives the coordinates of the polygon, + * transformed according to the specified AffineTransform. The flatness + * parameter is ignored. + * + * @param t + * the specified AffineTransform object or null. + * @param flatness + * the maximum number of the control points for a given curve + * which varies from colinear before a subdivided curve is + * replaced by a straight line connecting the endpoints. This + * parameter is ignored for the Polygon class. * @return PathIterator object for the Polygon. - * - * @see java.awt.Shape#getPathIterator(java.awt.geom.AffineTransform, double) + * @see java.awt.Shape#getPathIterator(java.awt.geom.AffineTransform, + * double) */ public PathIterator getPathIterator(AffineTransform t, double flatness) { return new Iterator(t, this); } } - diff --git a/awt/java/awt/Rectangle.java b/awt/java/awt/Rectangle.java index 86c4dfca0d1ee175f02938e8a3d451188f6d9181..d8ebb3ad19eb94b4870aeb2a6443ba10e28c5015 100644 --- a/awt/java/awt/Rectangle.java +++ b/awt/java/awt/Rectangle.java @@ -18,36 +18,48 @@ * @author Denis M. Kishenko * @version $Revision$ */ + package java.awt; import java.awt.geom.Rectangle2D; import java.io.Serializable; /** - * The Rectangle class defines the rectangular area in terms of its - * upper left corner coordinates [x,y], its width, and its height. - * A Rectangle specified by [x, y, width, height] parameters has an - * outline path with corners at [x, y], [x + width,y], [x + width,y + height], - * and [x, y + height]. - *

    - * The rectangle is empty if the width or height is negative or zero. - * In this case the isEmpty method returns true. + * The Rectangle class defines the rectangular area in terms of its upper left + * corner coordinates [x,y], its width, and its height. A Rectangle specified by + * [x, y, width, height] parameters has an outline path with corners at [x, y], + * [x + width,y], [x + width,y + height], and [x, y + height].
    + *
    + * The rectangle is empty if the width or height is negative or zero. In this + * case the isEmpty method returns true. + * + * @since Android 1.0 */ public class Rectangle extends Rectangle2D implements Shape, Serializable { - /** The Constant serialVersionUID. */ + /** + * The Constant serialVersionUID. + */ private static final long serialVersionUID = -4345857070255674764L; - /** The X coordinate of the rectangle's left upper corner. */ + /** + * The X coordinate of the rectangle's left upper corner. + */ public int x; - - /** The Y coordinate of the rectangle's left upper corner. */ + + /** + * The Y coordinate of the rectangle's left upper corner. + */ public int y; - - /** The width of rectangle. */ + + /** + * The width of rectangle. + */ public int width; - - /** The height of rectangle. */ + + /** + * The height of rectangle. + */ public int height; /** @@ -60,73 +72,82 @@ public class Rectangle extends Rectangle2D implements Shape, Serializable { /** * Instantiates a new rectangle whose upper left corner coordinates are - * given by the Point object (p.X and p.Y), and the width and - * the height are zero. + * given by the Point object (p.X and p.Y), and the width and the height are + * zero. * - * @param p the Point specifies the upper left corner coordinates of - * the rectangle. + * @param p + * the Point specifies the upper left corner coordinates of the + * rectangle. */ public Rectangle(Point p) { setBounds(p.x, p.y, 0, 0); } /** - * Instantiates a new rectangle whose upper left corner coordinates are - * given by the Point object (p.X and p.Y), and the width and the height - * are given by Dimension object (d.width and d.height). + * Instantiates a new rectangle whose upper left corner coordinates are + * given by the Point object (p.X and p.Y), and the width and the height are + * given by Dimension object (d.width and d.height). * - * @param p the Point specifies the upper left corner coordinates of - * the rectangle. - * @param d the Dimention specifies the width and the height of the rectangle. + * @param p + * the point specifies the upper left corner coordinates of the + * rectangle. + * @param d + * the dimension specifies the width and the height of the + * rectangle. */ public Rectangle(Point p, Dimension d) { setBounds(p.x, p.y, d.width, d.height); } /** - * Instantiates a new rectangle determined by the upper left corner + * Instantiates a new rectangle determined by the upper left corner * coordinates (x, y), width and height. * - * @param x the X upper left corner coordinate of the rectangle. - * @param y the Y upper left corner coordinate of the rectangle. - * @param width the width of rectangle. - * @param height the height of rectangle. + * @param x + * the X upper left corner coordinate of the rectangle. + * @param y + * the Y upper left corner coordinate of the rectangle. + * @param width + * the width of rectangle. + * @param height + * the height of rectangle. */ public Rectangle(int x, int y, int width, int height) { setBounds(x, y, width, height); } /** - * Instantiates a new rectangle with [0, 0] as its upper left - * corner coordinates and the specified width and height. + * Instantiates a new rectangle with [0, 0] as its upper left corner + * coordinates and the specified width and height. * - * @param width the width of rectangle. - * @param height the height of rectangle. + * @param width + * the width of rectangle. + * @param height + * the height of rectangle. */ public Rectangle(int width, int height) { setBounds(0, 0, width, height); } /** - * Instantiates a new rectangle with the same coordinates - * as the given source rectangle. + * Instantiates a new rectangle with the same coordinates as the given + * source rectangle. * - * @param r the Rectangle object which parameters will be used for - * instantiating a new Rectangle. + * @param r + * the Rectangle object which parameters will be used for + * instantiating a new Rectangle. */ public Rectangle(Rectangle r) { setBounds(r.x, r.y, r.width, r.height); } -/* - public Rectangle(Dimension d) { - setBounds(0, 0, d.width, d.height); - } -*/ + + /* + * public Rectangle(Dimension d) { setBounds(0, 0, d.width, d.height); } + */ /** * Gets the X coordinate of bound as a double. * * @return the X coordinate of bound as a double. - * * @see java.awt.geom.RectangularShape#getX() */ @Override @@ -138,7 +159,6 @@ public class Rectangle extends Rectangle2D implements Shape, Serializable { * Gets the Y coordinate of bound as a double. * * @return the Y coordinate of bound as a double. - * * @see java.awt.geom.RectangularShape#getY() */ @Override @@ -149,8 +169,7 @@ public class Rectangle extends Rectangle2D implements Shape, Serializable { /** * Gets the height of the rectangle as a double. * - * @return the height of the rectangle as a double. - * + * @return the height of the rectangle as a double. * @see java.awt.geom.RectangularShape#getHeight() */ @Override @@ -162,7 +181,6 @@ public class Rectangle extends Rectangle2D implements Shape, Serializable { * Gets the width of the rectangle as a double. * * @return the width of the rectangle as a double. - * * @see java.awt.geom.RectangularShape#getWidth() */ @Override @@ -171,11 +189,10 @@ public class Rectangle extends Rectangle2D implements Shape, Serializable { } /** - * Determines whether or not the rectangle is empty. The rectangle is empty if - * its width or height is negative or zero. + * Determines whether or not the rectangle is empty. The rectangle is empty + * if its width or height is negative or zero. * * @return true, if the rectangle is empty, otherwise false. - * * @see java.awt.geom.RectangularShape#isEmpty() */ @Override @@ -184,9 +201,9 @@ public class Rectangle extends Rectangle2D implements Shape, Serializable { } /** - * Gets the size of a Rectangle as Dimention object. + * Gets the size of a Rectangle as Dimension object. * - * @return a Dimention object which represents size of the rectangle. + * @return a Dimension object which represents size of the rectangle. */ public Dimension getSize() { return new Dimension(width, height); @@ -195,8 +212,10 @@ public class Rectangle extends Rectangle2D implements Shape, Serializable { /** * Sets the size of the Rectangle. * - * @param width the new width of the rectangle. - * @param height the new height of the rectangle. + * @param width + * the new width of the rectangle. + * @param height + * the new height of the rectangle. */ public void setSize(int width, int height) { this.width = width; @@ -206,7 +225,8 @@ public class Rectangle extends Rectangle2D implements Shape, Serializable { /** * Sets the size of a Rectangle specified as Dimension object. * - * @param d a Dimension object which represents new size of a rectangle. + * @param d + * a Dimension object which represents new size of a rectangle. */ public void setSize(Dimension d) { setSize(d.width, d.height); @@ -215,19 +235,21 @@ public class Rectangle extends Rectangle2D implements Shape, Serializable { /** * Gets the location of a rectangle's upper left corner as a Point object. * - * @return the Point object with coordinates equal to the upper left corner - * of the rectangle. + * @return the Point object with coordinates equal to the upper left corner + * of the rectangle. */ public Point getLocation() { return new Point(x, y); } /** - * Sets the location of the rectangle in terms of its upper left - * corner coordinates X and Y. + * Sets the location of the rectangle in terms of its upper left corner + * coordinates X and Y. * - * @param x the X coordinate of the rectangle's upper left corner. - * @param y the Y coordinate of the rectangle's upper left corner. + * @param x + * the X coordinate of the rectangle's upper left corner. + * @param y + * the Y coordinate of the rectangle's upper left corner. */ public void setLocation(int x, int y) { this.x = x; @@ -235,23 +257,25 @@ public class Rectangle extends Rectangle2D implements Shape, Serializable { } /** - * Sets the location of a rectangle using a Point object to give the + * Sets the location of a rectangle using a Point object to give the * coordinates of the upper left corner. * - * @param p the Point object which represents the new upper left corner - * coordinates of rectangle. + * @param p + * the Point object which represents the new upper left corner + * coordinates of rectangle. */ public void setLocation(Point p) { setLocation(p.x, p.y); } /** - * Moves a rectangle to the new location by moving its upper left corner - * to the point with coordinates X and Y. - * - * @param x the new X coordinate of the rectangle's upper left corner. - * @param y the new Y coordinate of the rectangle's upper left corner. + * Moves a rectangle to the new location by moving its upper left corner to + * the point with coordinates X and Y. * + * @param x + * the new X coordinate of the rectangle's upper left corner. + * @param y + * the new Y coordinate of the rectangle's upper left corner. * @deprecated Use setLocation(int, int) method. */ @Deprecated @@ -260,16 +284,19 @@ public class Rectangle extends Rectangle2D implements Shape, Serializable { } /** - * Sets the rectangle to be the nearest rectangle with integer coordinates + * Sets the rectangle to be the nearest rectangle with integer coordinates * bounding the rectangle defined by the double-valued parameters. * - * @param x the X coordinate of the upper left corner of the double-valued - * rectangle to be bounded. - * @param y the Y coordinate of the upper left corner of the double-valued - * rectangle to be bounded. - * @param width the width of the rectangle to be bounded. - * @param height the height of the rectangle to be bounded. - * + * @param x + * the X coordinate of the upper left corner of the double-valued + * rectangle to be bounded. + * @param y + * the Y coordinate of the upper left corner of the double-valued + * rectangle to be bounded. + * @param width + * the width of the rectangle to be bounded. + * @param height + * the height of the rectangle to be bounded. * @see java.awt.geom.Rectangle2D#setRect(double, double, double, double) */ @Override @@ -284,9 +311,10 @@ public class Rectangle extends Rectangle2D implements Shape, Serializable { /** * Sets a new size for the rectangle. * - * @param width the rectangle's new width. - * @param height the rectangle's new height. - * + * @param width + * the rectangle's new width. + * @param height + * the rectangle's new height. * @deprecated use the setSize(int, int) method. */ @Deprecated @@ -295,14 +323,17 @@ public class Rectangle extends Rectangle2D implements Shape, Serializable { } /** - * Resets the bounds of a rectangle to the specified x, y, width and height + * Resets the bounds of a rectangle to the specified x, y, width and height * parameters. * - * @param x the new X coordinate of the upper left corner. - * @param y the new Y coordinate of the upper left corner. - * @param width the new width of rectangle. - * @param height the new height of rectangle. - * + * @param x + * the new X coordinate of the upper left corner. + * @param y + * the new Y coordinate of the upper left corner. + * @param width + * the new width of rectangle. + * @param height + * the new height of rectangle. * @deprecated use setBounds(int, int, int, int) method */ @Deprecated @@ -312,10 +343,9 @@ public class Rectangle extends Rectangle2D implements Shape, Serializable { /** * Gets bounds of the rectangle as a new Rectangle object. - * - * @return the Rectangle object with the same bounds as - * the original rectangle. * + * @return the Rectangle object with the same bounds as the original + * rectangle. * @see java.awt.geom.RectangularShape#getBounds() */ @Override @@ -325,10 +355,9 @@ public class Rectangle extends Rectangle2D implements Shape, Serializable { /** * Gets the bounds of the original rectangle as a Rectangle2D object. - * - * @return the Rectangle2D object which represents the bounds of - * the original rectangle. * + * @return the Rectangle2D object which represents the bounds of the + * original rectangle. * @see java.awt.geom.Rectangle2D#getBounds2D() */ @Override @@ -337,13 +366,17 @@ public class Rectangle extends Rectangle2D implements Shape, Serializable { } /** - * Sets the bounds of a rectangle to the specified x, y, width, and height + * Sets the bounds of a rectangle to the specified x, y, width, and height * parameters. * - * @param x the X coordinate of the upper left corner. - * @param y the Y coordinate of the upper left corner. - * @param width the width of rectangle. - * @param height the height of rectangle. + * @param x + * the X coordinate of the upper left corner. + * @param y + * the Y coordinate of the upper left corner. + * @param width + * the width of rectangle. + * @param height + * the height of rectangle. */ public void setBounds(int x, int y, int width, int height) { this.x = x; @@ -353,25 +386,26 @@ public class Rectangle extends Rectangle2D implements Shape, Serializable { } /** - * Sets the bounds of the rectangle to match the bounds of the - * Rectangle object sent as a parameter. + * Sets the bounds of the rectangle to match the bounds of the Rectangle + * object sent as a parameter. * - * @param r the Rectangle object which specifies the new bounds. + * @param r + * the Rectangle object which specifies the new bounds. */ public void setBounds(Rectangle r) { setBounds(r.x, r.y, r.width, r.height); } /** - * Enlarges the rectangle by moving each corner outward from the - * center by a distance of dx horizonally and a distance of dy - * vertically. Specifically, changes a rectangle with - * [x, y, width, height] parameters to - * a rectangle with [x-dx, y-dy, width+2*dx, height+2*dy] - * parameters. - * - * @param dx the horizontal distance to move each corner coordinate. - * @param dy the vertical distance to move each corner coordinate. + * Enlarges the rectangle by moving each corner outward from the center by a + * distance of dx horizonally and a distance of dy vertically. Specifically, + * changes a rectangle with [x, y, width, height] parameters to a rectangle + * with [x-dx, y-dy, width+2*dx, height+2*dy] parameters. + * + * @param dx + * the horizontal distance to move each corner coordinate. + * @param dy + * the vertical distance to move each corner coordinate. */ public void grow(int dx, int dy) { x -= dx; @@ -381,11 +415,13 @@ public class Rectangle extends Rectangle2D implements Shape, Serializable { } /** - * Moves a rectangle a distance of mx along the x coordinate axis - * and a distance of my along y coordinate axis. + * Moves a rectangle a distance of mx along the x coordinate axis and a + * distance of my along y coordinate axis. * - * @param mx the horizontal translation increment. - * @param my the vertical translation increment. + * @param mx + * the horizontal translation increment. + * @param my + * the vertical translation increment. */ public void translate(int mx, int my) { x += mx; @@ -395,8 +431,12 @@ public class Rectangle extends Rectangle2D implements Shape, Serializable { /** * Enlarges the rectangle to cover the specified point. * - * @param px the X coordinate of the new point to be covered by the rectangle. - * @param py the Y coordinate of the new point to be covered by the rectangle. + * @param px + * the X coordinate of the new point to be covered by the + * rectangle. + * @param py + * the Y coordinate of the new point to be covered by the + * rectangle. */ public void add(int px, int py) { int x1 = Math.min(x, px); @@ -407,11 +447,12 @@ public class Rectangle extends Rectangle2D implements Shape, Serializable { } /** - * Enlarges the rectangle to cover the specified point with the - * new point given as a Point object. + * Enlarges the rectangle to cover the specified point with the new point + * given as a Point object. * - * @param p the Point object that specifies the new point to - * be covered by the rectangle. + * @param p + * the Point object that specifies the new point to be covered by + * the rectangle. */ public void add(Point p) { add(p.x, p.y); @@ -421,7 +462,8 @@ public class Rectangle extends Rectangle2D implements Shape, Serializable { * Adds a new rectangle to the original rectangle, the result is an union of * the specified specified rectangle and original rectangle. * - * @param r the Rectangle which is added to the original rectangle. + * @param r + * the Rectangle which is added to the original rectangle. */ public void add(Rectangle r) { int x1 = Math.min(x, r.x); @@ -432,14 +474,15 @@ public class Rectangle extends Rectangle2D implements Shape, Serializable { } /** - * Determines whether or not the point with specified coordinates [px, py] + * Determines whether or not the point with specified coordinates [px, py] * is within the bounds of the rectangle. * - * @param px the X coordinate of point. - * @param py the Y coordinate of point. - * - * @return true, if the point with specified coordinates [px, py] is - * within the bounds of the rectangle, otherwise false. + * @param px + * the X coordinate of point. + * @param py + * the Y coordinate of point. + * @return true, if the point with specified coordinates [px, py] is within + * the bounds of the rectangle, false otherwise. */ public boolean contains(int px, int py) { if (isEmpty()) { @@ -454,29 +497,32 @@ public class Rectangle extends Rectangle2D implements Shape, Serializable { } /** - * Determines whether or not the point given as a Point object - * is within the bounds of the rectangle. - * - * @param p the Point object + * Determines whether or not the point given as a Point object is within the + * bounds of the rectangle. * - * @return true, if the point p is within the bounds of the - * rectangle, otherwise false. + * @param p + * the Point object + * @return true, if the point p is within the bounds of the rectangle, + * otherwise false. */ public boolean contains(Point p) { return contains(p.x, p.y); } /** - * Determines whether or not the rectangle specified by [rx, ry, rw, rh] + * Determines whether or not the rectangle specified by [rx, ry, rw, rh] * parameters is located inside the original rectangle. * - * @param rx the X coordinate of the rectangle to compare. - * @param ry the Y coordinate of the rectangle to compare. - * @param rw the width of the rectangle to compare. - * @param rh the height of the rectangle to compare. - * + * @param rx + * the X coordinate of the rectangle to compare. + * @param ry + * the Y coordinate of the rectangle to compare. + * @param rw + * the width of the rectangle to compare. + * @param rh + * the height of the rectangle to compare. * @return true, if a rectangle with [rx, ry, rw, rh] parameters is entirely - * contained in the original rectangle, otherwise false. + * contained in the original rectangle, false otherwise. */ public boolean contains(int rx, int ry, int rw, int rh) { return contains(rx, ry) && contains(rx + rw - 1, ry + rh - 1); @@ -486,25 +532,25 @@ public class Rectangle extends Rectangle2D implements Shape, Serializable { * Compares whether or not the rectangle specified by the Rectangle object * is located inside the original rectangle. * - * @param r the Rectangle object. - * + * @param r + * the Rectangle object. * @return true, if the rectangle specified by Rectangle object is entirely - * contained in the original rectangle, otherwise false. + * contained in the original rectangle, false otherwise. */ public boolean contains(Rectangle r) { return contains(r.x, r.y, r.width, r.height); } /** - * Compares whether or not a point with specified coordinates [px, py] belongs - * to a rectangle. - * - * @param px the X coordinate of a point. - * @param py the Y coordinate of a point. - * - * @return true, if a point with specified coordinates [px, py] belongs - * to a rectangle, otherwise false. + * Compares whether or not a point with specified coordinates [px, py] + * belongs to a rectangle. * + * @param px + * the X coordinate of a point. + * @param py + * the Y coordinate of a point. + * @return true, if a point with specified coordinates [px, py] belongs to a + * rectangle, otherwise false. * @deprecated use contains(int, int) method. */ @Deprecated @@ -513,20 +559,19 @@ public class Rectangle extends Rectangle2D implements Shape, Serializable { } /** - * Returns the intersection of the original rectangle with the - * specified Rectangle2D. - * - * @param r the Rectangle2D object. - * - * @return the Rectangle2D object that is the result of intersecting - * the original rectangle with the specified Rectangle2D. + * Returns the intersection of the original rectangle with the specified + * Rectangle2D. * + * @param r + * the Rectangle2D object. + * @return the Rectangle2D object that is the result of intersecting the + * original rectangle with the specified Rectangle2D. * @see java.awt.geom.Rectangle2D#createIntersection(java.awt.geom.Rectangle2D) */ @Override public Rectangle2D createIntersection(Rectangle2D r) { if (r instanceof Rectangle) { - return intersection((Rectangle) r); + return intersection((Rectangle)r); } Rectangle2D dst = new Rectangle2D.Double(); Rectangle2D.intersect(this, r, dst); @@ -534,14 +579,13 @@ public class Rectangle extends Rectangle2D implements Shape, Serializable { } /** - * Returns the intersection of the original rectangle with the - * specified rectangle. An empty rectangle is returned if there is no - * intersection. - * - * @param r the Rectangle object. + * Returns the intersection of the original rectangle with the specified + * rectangle. An empty rectangle is returned if there is no intersection. * - * @return the Rectangle object is result of the original rectangle with the - * specified rectangle. + * @param r + * the Rectangle object. + * @return the Rectangle object is result of the original rectangle with the + * specified rectangle. */ public Rectangle intersection(Rectangle r) { int x1 = Math.max(x, r.x); @@ -552,39 +596,38 @@ public class Rectangle extends Rectangle2D implements Shape, Serializable { } /** - * Determines whether or not the original rectangle intersects - * the specified rectangle. + * Determines whether or not the original rectangle intersects the specified + * rectangle. * - * @param r the Rectangle object. - * - * @return true, if the two rectangles overlap; otherwise false. + * @param r + * the Rectangle object. + * @return true, if the two rectangles overlap, false otherwise. */ public boolean intersects(Rectangle r) { return !intersection(r).isEmpty(); } /** - * Determines where the specified Point is located with respect to - * the rectangle. This method computes whether the point is to the - * right or to the left of the rectangle and whether it is above - * or below the rectangle, and packs the result into an int by - * using a binary OR operation with the following masks: + * Determines where the specified Point is located with respect to the + * rectangle. This method computes whether the point is to the right or to + * the left of the rectangle and whether it is above or below the rectangle, + * and packs the result into an integer by using a binary OR operation with + * the following masks: *
      *
    • Rectangle2D.OUT_LEFT
    • *
    • Rectangle2D.OUT_TOP
    • *
    • Rectangle2D.OUT_RIGHT
    • *
    • Rectangle2D.OUT_BOTTOM
    • *
    - * - * If the rectangle is empty, all masks are set, and if the - * point is inside the rectangle, none are set. - * - * @param px the X coordinate of the specified point. - * @param py the Y coordinate of the specified point. - * - * @return the location of the Point relative to the rectangle - * as the result of logical OR operation with all out masks. - * + * If the rectangle is empty, all masks are set, and if the point is inside + * the rectangle, none are set. + * + * @param px + * the X coordinate of the specified point. + * @param py + * the Y coordinate of the specified point. + * @return the location of the Point relative to the rectangle as the result + * of logical OR operation with all out masks. * @see java.awt.geom.Rectangle2D#outcode(double, double) */ @Override @@ -593,23 +636,19 @@ public class Rectangle extends Rectangle2D implements Shape, Serializable { if (width <= 0) { code |= OUT_LEFT | OUT_RIGHT; - } else - if (px < x) { - code |= OUT_LEFT; - } else - if (px > x + width) { - code |= OUT_RIGHT; - } + } else if (px < x) { + code |= OUT_LEFT; + } else if (px > x + width) { + code |= OUT_RIGHT; + } if (height <= 0) { code |= OUT_TOP | OUT_BOTTOM; - } else - if (py < y) { - code |= OUT_TOP; - } else - if (py > y + height) { - code |= OUT_BOTTOM; - } + } else if (py < y) { + code |= OUT_TOP; + } else if (py > y + height) { + code |= OUT_BOTTOM; + } return code; } @@ -617,10 +656,9 @@ public class Rectangle extends Rectangle2D implements Shape, Serializable { /** * Enlarges the rectangle to cover the specified Rectangle2D. * - * @param r the Rectangle2D object. - * + * @param r + * the Rectangle2D object. * @return the union of the original and the specified Rectangle2D. - * * @see java.awt.geom.Rectangle2D#createUnion(java.awt.geom.Rectangle2D) */ @Override @@ -636,8 +674,8 @@ public class Rectangle extends Rectangle2D implements Shape, Serializable { /** * Enlarges the rectangle to cover the specified rectangle. * - * @param r the Rectangle. - * + * @param r + * the Rectangle. * @return the union of the original and the specified rectangle. */ public Rectangle union(Rectangle r) { @@ -649,11 +687,10 @@ public class Rectangle extends Rectangle2D implements Shape, Serializable { /** * Compares the original Rectangle with the specified object. * - * @param obj the specified Object for comparison. - * - * @return true, if the specified Object is a rectangle with the - * same dimensions as the original rectangle, otherwise false. - * + * @param obj + * the specified Object for comparison. + * @return true, if the specified Object is a rectangle with the same + * dimensions as the original rectangle, false otherwise. * @see java.awt.geom.Rectangle2D#equals(Object) */ @Override @@ -669,18 +706,18 @@ public class Rectangle extends Rectangle2D implements Shape, Serializable { } /** - * Returns a string representation of the rectangle; the string contains - * [x, y, width, height] parameters of the rectangle. + * Returns a string representation of the rectangle; the string contains [x, + * y, width, height] parameters of the rectangle. * * @return the string representation of the rectangle. */ @Override public String toString() { - // The output format based on 1.5 release behaviour. It could be obtained in the following way + // The output format based on 1.5 release behaviour. It could be + // obtained in the following way // System.out.println(new Rectangle().toString()) return getClass().getName() + "[x=" + x + ",y=" + y + //$NON-NLS-1$ //$NON-NLS-2$ - ",width=" + width + ",height=" + height + "]"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + ",width=" + width + ",height=" + height + "]"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ } } - diff --git a/awt/java/awt/RenderingHints.java b/awt/java/awt/RenderingHints.java index 495788490ac36191cb63949560c940b4f0ed889c..acf6fa15de07d112850dcbfa33cf6fa6227500f3 100644 --- a/awt/java/awt/RenderingHints.java +++ b/awt/java/awt/RenderingHints.java @@ -18,6 +18,7 @@ * @author Alexey A. Petrenko * @version $Revision$ */ + package java.awt; import java.util.Collection; @@ -27,224 +28,219 @@ import java.util.Map; import java.util.Set; /** - * The RenderingHints class represents preferences for the rendering algorithms. - * The preferences are arbitrary and can be specified by Map objects or by - * key-value pairs. + * The RenderingHints class represents preferences for the rendering algorithms. + * The preferences are arbitrary and can be specified by Map objects or by + * key-value pairs. + * + * @since Android 1.0 */ public class RenderingHints implements Map, Cloneable { - + /** - * The Constant KEY_ALPHA_INTERPOLATION - alpha interpolation rendering - * hint key. + * The Constant KEY_ALPHA_INTERPOLATION - alpha interpolation rendering hint + * key. */ public static final Key KEY_ALPHA_INTERPOLATION = new KeyImpl(1); - - /** + + /** * The Constant VALUE_ALPHA_INTERPOLATION_DEFAULT - alpha interpolation * rendering hint value. */ - public static final Object VALUE_ALPHA_INTERPOLATION_DEFAULT = new KeyValue(KEY_ALPHA_INTERPOLATION); - - /** + public static final Object VALUE_ALPHA_INTERPOLATION_DEFAULT = new KeyValue( + KEY_ALPHA_INTERPOLATION); + + /** * The Constant VALUE_ALPHA_INTERPOLATION_SPEED - alpha interpolation * rendering hint value. */ - public static final Object VALUE_ALPHA_INTERPOLATION_SPEED = new KeyValue(KEY_ALPHA_INTERPOLATION); - - /** + public static final Object VALUE_ALPHA_INTERPOLATION_SPEED = new KeyValue( + KEY_ALPHA_INTERPOLATION); + + /** * The Constant VALUE_ALPHA_INTERPOLATION_QUALITY - alpha interpolation * rendering hint value. */ - public static final Object VALUE_ALPHA_INTERPOLATION_QUALITY = new KeyValue(KEY_ALPHA_INTERPOLATION); + public static final Object VALUE_ALPHA_INTERPOLATION_QUALITY = new KeyValue( + KEY_ALPHA_INTERPOLATION); - /** - * The Constant KEY_ANTIALIASING - antialiasing rendering - * hint key. + /** + * The Constant KEY_ANTIALIASING - antialiasing rendering hint key. */ public static final Key KEY_ANTIALIASING = new KeyImpl(2); - + /** - * The Constant VALUE_ANTIALIAS_DEFAULT - antialiasing - * rendering hint value. + * The Constant VALUE_ANTIALIAS_DEFAULT - antialiasing rendering hint value. */ public static final Object VALUE_ANTIALIAS_DEFAULT = new KeyValue(KEY_ANTIALIASING); - - /** - * The Constant VALUE_ANTIALIAS_ON - antialiasing - * rendering hint value. + + /** + * The Constant VALUE_ANTIALIAS_ON - antialiasing rendering hint value. */ public static final Object VALUE_ANTIALIAS_ON = new KeyValue(KEY_ANTIALIASING); - + /** - * The Constant VALUE_ANTIALIAS_OFF - antialiasing - * rendering hint value. + * The Constant VALUE_ANTIALIAS_OFF - antialiasing rendering hint value. */ public static final Object VALUE_ANTIALIAS_OFF = new KeyValue(KEY_ANTIALIASING); - /** - * The Constant KEY_COLOR_RENDERING - color rendering - * hint key. + /** + * The Constant KEY_COLOR_RENDERING - color rendering hint key. */ public static final Key KEY_COLOR_RENDERING = new KeyImpl(3); - + /** - * The Constant VALUE_COLOR_RENDER_DEFAULT - color - * rendering hint value. + * The Constant VALUE_COLOR_RENDER_DEFAULT - color rendering hint value. */ public static final Object VALUE_COLOR_RENDER_DEFAULT = new KeyValue(KEY_COLOR_RENDERING); - - /** - * The Constant VALUE_COLOR_RENDER_SPEED - color - * rendering hint value. + + /** + * The Constant VALUE_COLOR_RENDER_SPEED - color rendering hint value. */ public static final Object VALUE_COLOR_RENDER_SPEED = new KeyValue(KEY_COLOR_RENDERING); - - /** - * The Constant VALUE_COLOR_RENDER_QUALITY - color - * rendering hint value. + + /** + * The Constant VALUE_COLOR_RENDER_QUALITY - color rendering hint value. */ public static final Object VALUE_COLOR_RENDER_QUALITY = new KeyValue(KEY_COLOR_RENDERING); /** - * The Constant KEY_DITHERING - dithering - * rendering hint key. + * The Constant KEY_DITHERING - dithering rendering hint key. */ public static final Key KEY_DITHERING = new KeyImpl(4); - + /** - * The Constant VALUE_DITHER_DEFAULT - dithering - * rendering hint value. + * The Constant VALUE_DITHER_DEFAULT - dithering rendering hint value. */ public static final Object VALUE_DITHER_DEFAULT = new KeyValue(KEY_DITHERING); - - /** - * The Constant VALUE_DITHER_DISABLE - dithering - * rendering hint value. + + /** + * The Constant VALUE_DITHER_DISABLE - dithering rendering hint value. */ public static final Object VALUE_DITHER_DISABLE = new KeyValue(KEY_DITHERING); - - /** - * The Constant VALUE_DITHER_DISABLE - dithering - * rendering hint value. + + /** + * The Constant VALUE_DITHER_DISABLE - dithering rendering hint value. */ public static final Object VALUE_DITHER_ENABLE = new KeyValue(KEY_DITHERING); - /** - * The Constant KEY_FRACTIONALMETRICS - fractional metrics - * rendering hint key. + /** + * The Constant KEY_FRACTIONALMETRICS - fractional metrics rendering hint + * key. */ public static final Key KEY_FRACTIONALMETRICS = new KeyImpl(5); - + /** * The Constant VALUE_FRACTIONALMETRICS_DEFAULT - fractional metrics * rendering hint value. */ public static final Object VALUE_FRACTIONALMETRICS_DEFAULT = new KeyValue(KEY_FRACTIONALMETRICS); - + /** - * The Constant VALUE_FRACTIONALMETRICS_ON - fractional metrics - * rendering hint value. + * The Constant VALUE_FRACTIONALMETRICS_ON - fractional metrics rendering + * hint value. */ public static final Object VALUE_FRACTIONALMETRICS_ON = new KeyValue(KEY_FRACTIONALMETRICS); - + /** - * The Constant VALUE_FRACTIONALMETRICS_OFF - fractional metrics - * rendering hint value. + * The Constant VALUE_FRACTIONALMETRICS_OFF - fractional metrics rendering + * hint value. */ public static final Object VALUE_FRACTIONALMETRICS_OFF = new KeyValue(KEY_FRACTIONALMETRICS); - /** - * The Constant KEY_INTERPOLATION - interpolation - * rendering hint key. + /** + * The Constant KEY_INTERPOLATION - interpolation rendering hint key. */ public static final Key KEY_INTERPOLATION = new KeyImpl(6); - - /** - * The Constant VALUE_INTERPOLATION_BICUBIC - interpolation - * rendering hint value. + + /** + * The Constant VALUE_INTERPOLATION_BICUBIC - interpolation rendering hint + * value. */ public static final Object VALUE_INTERPOLATION_BICUBIC = new KeyValue(KEY_INTERPOLATION); - + /** - * The Constant VALUE_INTERPOLATION_BILINEAR - interpolation - * rendering hint value. + * The Constant VALUE_INTERPOLATION_BILINEAR - interpolation rendering hint + * value. */ public static final Object VALUE_INTERPOLATION_BILINEAR = new KeyValue(KEY_INTERPOLATION); - - /** The Constant VALUE_INTERPOLATION_NEAREST_NEIGHBOR - interpolation + + /** + * The Constant VALUE_INTERPOLATION_NEAREST_NEIGHBOR - interpolation * rendering hint value. */ - public static final Object VALUE_INTERPOLATION_NEAREST_NEIGHBOR = new KeyValue(KEY_INTERPOLATION); + public static final Object VALUE_INTERPOLATION_NEAREST_NEIGHBOR = new KeyValue( + KEY_INTERPOLATION); /** * The Constant KEY_RENDERING - rendering hint key. */ public static final Key KEY_RENDERING = new KeyImpl(7); - - /** - * The Constant VALUE_RENDER_DEFAULT - rendering hint value. + + /** + * The Constant VALUE_RENDER_DEFAULT - rendering hint value. */ public static final Object VALUE_RENDER_DEFAULT = new KeyValue(KEY_RENDERING); - - /** - * The Constant VALUE_RENDER_SPEED - rendering hint value. + + /** + * The Constant VALUE_RENDER_SPEED - rendering hint value. */ public static final Object VALUE_RENDER_SPEED = new KeyValue(KEY_RENDERING); - - /** - * The Constant VALUE_RENDER_QUALITY - rendering hint value. + + /** + * The Constant VALUE_RENDER_QUALITY - rendering hint value. */ public static final Object VALUE_RENDER_QUALITY = new KeyValue(KEY_RENDERING); - /** - * The Constant KEY_STROKE_CONTROL - stroke control hint key. + /** + * The Constant KEY_STROKE_CONTROL - stroke control hint key. */ public static final Key KEY_STROKE_CONTROL = new KeyImpl(8); - - /** - * The Constant VALUE_STROKE_DEFAULT - stroke hint value. + + /** + * The Constant VALUE_STROKE_DEFAULT - stroke hint value. */ public static final Object VALUE_STROKE_DEFAULT = new KeyValue(KEY_STROKE_CONTROL); - - /** - * The Constant VALUE_STROKE_NORMALIZE - stroke hint value. + + /** + * The Constant VALUE_STROKE_NORMALIZE - stroke hint value. */ public static final Object VALUE_STROKE_NORMALIZE = new KeyValue(KEY_STROKE_CONTROL); - - /** - * The Constant VALUE_STROKE_PURE - stroke hint value. + + /** + * The Constant VALUE_STROKE_PURE - stroke hint value. */ public static final Object VALUE_STROKE_PURE = new KeyValue(KEY_STROKE_CONTROL); - /** - * The Constant KEY_TEXT_ANTIALIASING - text antialiasing hint key. + /** + * The Constant KEY_TEXT_ANTIALIASING - text antialiasing hint key. */ public static final Key KEY_TEXT_ANTIALIASING = new KeyImpl(9); - + /** - * The Constant VALUE_TEXT_ANTIALIAS_DEFAULT - text antialiasing hint key. + * The Constant VALUE_TEXT_ANTIALIAS_DEFAULT - text antialiasing hint key. */ public static final Object VALUE_TEXT_ANTIALIAS_DEFAULT = new KeyValue(KEY_TEXT_ANTIALIASING); - + /** * The Constant VALUE_TEXT_ANTIALIAS_ON - text antialiasing hint key. */ public static final Object VALUE_TEXT_ANTIALIAS_ON = new KeyValue(KEY_TEXT_ANTIALIASING); - + /** - * The Constant VALUE_TEXT_ANTIALIAS_OFF - text antialiasing hint key. + * The Constant VALUE_TEXT_ANTIALIAS_OFF - text antialiasing hint key. */ public static final Object VALUE_TEXT_ANTIALIAS_OFF = new KeyValue(KEY_TEXT_ANTIALIASING); /** The map. */ private HashMap map = new HashMap(); - + /** - * Instantiates a new rendering hints object from specified Map object with defined - * key/value pairs or null for empty RenderingHints. + * Instantiates a new rendering hints object from specified Map object with + * defined key/value pairs or null for empty RenderingHints. * - * @param map the Map object with defined key/value pairs or null for - * empty RenderingHints. + * @param map + * the Map object with defined key/value pairs or null for empty + * RenderingHints. */ public RenderingHints(Map map) { super(); @@ -254,10 +250,13 @@ public class RenderingHints implements Map, Cloneable { } /** - * Instantiates a new rendering hints object with the specified key/value pair. + * Instantiates a new rendering hints object with the specified key/value + * pair. * - * @param key the key of hint property. - * @param value the value of hint property. + * @param key + * the key of hint property. + * @param value + * the value of hint property. */ public RenderingHints(Key key, Object value) { super(); @@ -268,21 +267,22 @@ public class RenderingHints implements Map, Cloneable { * Adds the properties represented by key/value pairs from the specified * RenderingHints object to current object. * - * @param hints the RenderingHints to be added. + * @param hints + * the RenderingHints to be added. */ public void add(RenderingHints hints) { map.putAll(hints.map); } /** - * Puts the specified value to the specified key. Neither the key nor - * the value can be null. - * - * @param key the rendering hint key. - * @param value the rendering hint value. + * Puts the specified value to the specified key. Neither the key nor the + * value can be null. * + * @param key + * the rendering hint key. + * @param value + * the rendering hint value. * @return the previous rendering hint value assigned to the key or null. - * */ public Object put(Object key, Object value) { if (!((Key)key).isCompatibleValue(value)) { @@ -293,13 +293,13 @@ public class RenderingHints implements Map, Cloneable { } /** - * Removes the specified key and corresponding value from - * the RenderingHints object. + * Removes the specified key and corresponding value from the RenderingHints + * object. * - * @param key the specified hint key to be removed. - * - * @return the object of previous rendering hint value which is - * assigned to the specified key, or null. + * @param key + * the specified hint key to be removed. + * @return the object of previous rendering hint value which is assigned to + * the specified key, or null. */ public Object remove(Object key) { return map.remove(key); @@ -308,8 +308,8 @@ public class RenderingHints implements Map, Cloneable { /** * Gets the value assigned to the specified key. * - * @param key the rendering hint key. - * + * @param key + * the rendering hint key. * @return the object assigned to the specified key. */ public Object get(Object key) { @@ -319,7 +319,7 @@ public class RenderingHints implements Map, Cloneable { /** * Returns a set of rendering hints keys for current RenderingHints object. * - * @return the set of rendering hints keys. + * @return the set of rendering hints keys. */ public Set keySet() { return map.keySet(); @@ -336,23 +336,23 @@ public class RenderingHints implements Map, Cloneable { } /** - * Puts all of the preferences from the specified Map into - * the current RenderingHints object. These mappings replace - * all existing preferences. + * Puts all of the preferences from the specified Map into the current + * RenderingHints object. These mappings replace all existing preferences. * - * @param m the specified Map of preferences. + * @param m + * the specified Map of preferences. */ public void putAll(Map m) { if (m instanceof RenderingHints) { - map.putAll(((RenderingHints) m).map); + map.putAll(((RenderingHints)m).map); } else { Set entries = m.entrySet(); - if (entries != null){ + if (entries != null) { Iterator it = entries.iterator(); while (it.hasNext()) { - Map.Entry entry = (Map.Entry) it.next(); - Key key = (Key) entry.getKey(); + Map.Entry entry = (Map.Entry)it.next(); + Key key = (Key)entry.getKey(); Object val = entry.getValue(); put(key, val); } @@ -361,7 +361,8 @@ public class RenderingHints implements Map, Cloneable { } /** - * Returns a Collection of values contained in current RenderingHints object. + * Returns a Collection of values contained in current RenderingHints + * object. * * @return the Collection of RenderingHints's values. */ @@ -373,10 +374,10 @@ public class RenderingHints implements Map, Cloneable { * Checks whether or not current RenderingHints object contains at least one * the value which is equal to the specified Object. * - * @param value the specified Object. - * + * @param value + * the specified Object. * @return true, if the specified object is assigned to at least one - * RenderingHint's key, false otherwise. + * RenderingHint's key, false otherwise. */ public boolean containsValue(Object value) { return map.containsValue(value); @@ -386,11 +387,10 @@ public class RenderingHints implements Map, Cloneable { * Checks whether or not current RenderingHints object contains the key * which is equal to the specified Object. * - * @param key the specified Object. - * + * @param key + * the specified Object. * @return true, if the RenderingHints object contains the specified Object - * as a key, false otherwise. - * + * as a key, false otherwise. */ public boolean containsKey(Object key) { if (key == null) { @@ -401,8 +401,8 @@ public class RenderingHints implements Map, Cloneable { } /** - * Checks whether or not the RenderingHints object contains any - * key/value pairs. + * Checks whether or not the RenderingHints object contains any key/value + * pairs. * * @return true, if the RenderingHints object is empty, false otherwise. */ @@ -429,11 +429,10 @@ public class RenderingHints implements Map, Cloneable { /** * Compares the RenderingHints object with the specified object. * - * @param o the specified Object to be compaired. - * - * @return true, if the Object is a Map whose key/value pairs - * match this RenderingHints' key/value pairs, - * false otherwise. + * @param o + * the specified Object to be compared. + * @return true, if the Object is a Map whose key/value pairs match this + * RenderingHints' key/value pairs, false otherwise. */ @Override public boolean equals(Object o) { @@ -452,7 +451,7 @@ public class RenderingHints implements Map, Cloneable { Key key = (Key)it.next(); Object v1 = get(key); Object v2 = m.get(key); - if (!(v1==null?v2==null:v1.equals(v2))) { + if (!(v1 == null ? v2 == null : v1.equals(v2))) { return false; } } @@ -485,28 +484,30 @@ public class RenderingHints implements Map, Cloneable { /** * Returns the string representation of the RenderingHints object. * - * @return the String object which represents RenderingHints object. + * @return the String object which represents RenderingHints object. */ @Override public String toString() { - return "RenderingHints["+map.toString()+"]"; //$NON-NLS-1$ //$NON-NLS-2$ + return "RenderingHints[" + map.toString() + "]"; //$NON-NLS-1$ //$NON-NLS-2$ } /** - * The RenderingHints.Key class is abstract and defines a base type for - * all RenderingHints keys. + * The RenderingHints.Key class is abstract and defines a base type for all + * RenderingHints keys. + * + * @since Android 1.0 */ public abstract static class Key { - + /** The key. */ private final int key; /** - * Instantiates a new key with unique int identifier. - * No two objects of the same subclass with the same integer key - * can be instantiated. + * Instantiates a new key with unique integer identifier. No two objects + * of the same subclass with the same integer key can be instantiated. * - * @param key the unique key. + * @param key + * the unique key. */ protected Key(int key) { this.key = key; @@ -515,10 +516,10 @@ public class RenderingHints implements Map, Cloneable { /** * Compares the Key object with the specified object. * - * @param o the specified Object to be compaired. - * - * @return true, if the Key is equal to the specified object, - * false otherwise. + * @param o + * the specified Object to be compared. + * @return true, if the Key is equal to the specified object, false + * otherwise. */ @Override public final boolean equals(Object o) { @@ -536,11 +537,11 @@ public class RenderingHints implements Map, Cloneable { } /** - * Returns int unique key with which this Key object has been + * Returns integer unique key with which this Key object has been * instantiated. * - * @return the int unique key with which this Key object has been - * instantiated. + * @return the integer unique key with which this Key object has been + * instantiated. */ protected final int intKey() { return key; @@ -549,10 +550,10 @@ public class RenderingHints implements Map, Cloneable { /** * Checks whether or not specified value is compatible with the Key. * - * @param val the Object. - * + * @param val + * the Object. * @return true, if the specified value is compatible with the Key, - * false otherwise. + * false otherwise. */ public abstract boolean isCompatibleValue(Object val); } @@ -563,9 +564,10 @@ public class RenderingHints implements Map, Cloneable { private static class KeyImpl extends Key { /** - * Instantiates a new key impl. + * Instantiates a new key implementation. * - * @param key the key + * @param key + * the key. */ protected KeyImpl(int key) { super(key); @@ -585,14 +587,17 @@ public class RenderingHints implements Map, Cloneable { * Private class KeyValue is used as value for Key class instance. */ private static class KeyValue { - - /** The key. */ + + /** + * The key. + */ private final Key key; /** * Instantiates a new key value. * - * @param key the key + * @param key + * the key. */ protected KeyValue(Key key) { this.key = key; diff --git a/awt/java/awt/Shape.java b/awt/java/awt/Shape.java index 3dbad25a84beee2eee702a1ddba9fcedb70b6164..59bc623b8161cbcfec3a733f526509f42dbc5068 100644 --- a/awt/java/awt/Shape.java +++ b/awt/java/awt/Shape.java @@ -18,6 +18,7 @@ * @author Alexey A. Petrenko * @version $Revision$ */ + package java.awt; import java.awt.geom.AffineTransform; @@ -26,137 +27,136 @@ import java.awt.geom.Point2D; import java.awt.geom.Rectangle2D; /** - * The Shape interface defines a geometric shape defined by a boundary - * (outline) path. The path outline can be accessed through a - * PathIterator object. The Shape - * interface provides methods for obtaining the bounding box (which is - * the smallest rectangle containing the shape and for obtaining a PathIterator - * object for current Shape, as well as utility methods which - * determine if the Shape contains or intersects a Rectangle or contains a Point. + * The Shape interface defines a geometric shape defined by a boundary (outline) + * path. The path outline can be accessed through a PathIterator object. The + * Shape interface provides methods for obtaining the bounding box (which is the + * smallest rectangle containing the shape and for obtaining a PathIterator + * object for current Shape, as well as utility methods which determine if the + * Shape contains or intersects a Rectangle or contains a Point. + * + * @since Android 1.0 */ public interface Shape { - + /** - * Checks whether or not the point with specified coordinates lies inside + * Checks whether or not the point with specified coordinates lies inside * the Shape. * - * @param x the X coordinate. - * @param y the Y coordinate. - * - * @return true, if the specified coordinates lie inside the Shape, - * otherwise false. + * @param x + * the X coordinate. + * @param y + * the Y coordinate. + * @return true, if the specified coordinates lie inside the Shape, false + * otherwise. */ public boolean contains(double x, double y); /** - * Checks whether or not the rectangle with specified - * [x, y, width, height] parameters lies inside the Shape. - * - * @param x the X double coordinate of the rectangle's upper left - * corner. - * @param y the Y double coordinate of the rectangle's upper left - * corner. - * @param w the width of rectangle. - * @param h the height of rectangle. - * - * @return true, if the specified rectangle lies inside the Shape, - * otherwise false. + * Checks whether or not the rectangle with specified [x, y, width, height] + * parameters lies inside the Shape. + * + * @param x + * the X double coordinate of the rectangle's upper left corner. + * @param y + * the Y double coordinate of the rectangle's upper left corner. + * @param w + * the width of rectangle. + * @param h + * the height of rectangle. + * @return true, if the specified rectangle lies inside the Shape, false + * otherwise. */ public boolean contains(double x, double y, double w, double h); /** * Checks whether or not the specified Point2D lies inside the Shape. * - * @param point the Point2D object. - * - * @return true, if the specified Point2D lies inside the Shape, - * otherwise false. + * @param point + * the Point2D object. + * @return true, if the specified Point2D lies inside the Shape, false + * otherwise. */ public boolean contains(Point2D point); /** * Checks whether or not the specified rectangle lies inside the Shape. * - * @param r the Rectangle2D object. - * - * @return true, if the specified rectangle lies inside the Shape, - * otherwise false. + * @param r + * the Rectangle2D object. + * @return true, if the specified rectangle lies inside the Shape, false + * otherwise. */ public boolean contains(Rectangle2D r); /** - * Gets the bounding rectangle of the Shape. The bounding rectangle - * is the smallest rectangle which contains the Shape. + * Gets the bounding rectangle of the Shape. The bounding rectangle is the + * smallest rectangle which contains the Shape. * * @return the bounding rectangle of the Shape. */ public Rectangle getBounds(); /** - * Gets the Rectangle2D which represents Shape bounds. - * The bounding rectangle is the smallest rectangle which contains - * the Shape. + * Gets the Rectangle2D which represents Shape bounds. The bounding + * rectangle is the smallest rectangle which contains the Shape. * * @return the bounding rectangle of the Shape. */ public Rectangle2D getBounds2D(); /** - * Gets the PathIterator object of the Shape which provides - * access to the shape's boundary modified - * by the specified AffineTransform. - * - * @param at the specified AffineTransform object, or null. + * Gets the PathIterator object of the Shape which provides access to the + * shape's boundary modified by the specified AffineTransform. * + * @param at + * the specified AffineTransform object or null. * @return PathIterator object for the Shape. */ public PathIterator getPathIterator(AffineTransform at); /** - * Gets the PathIterator object of the Shape which provides - * access to the coordinates of the shapes boundary modified - * by the specified AffineTransform. The flatness parameter - * defines the amount of subdivision of the curved segments and - * specifies the maximum distance which every point on the - * unflattened transformed curve can deviate from the returned - * flattened path segments. - * - * @param at the specified AffineTransform object, or null. - * @param flatness the maximum number of the control points for - * a given curve which varies from colinear before a subdivided - * curve is replaced by a straight line connecting the endpoints. - * + * Gets the PathIterator object of the Shape which provides access to the + * coordinates of the shapes boundary modified by the specified + * AffineTransform. The flatness parameter defines the amount of subdivision + * of the curved segments and specifies the maximum distance which every + * point on the unflattened transformed curve can deviate from the returned + * flattened path segments. + * + * @param at + * the specified AffineTransform object or null. + * @param flatness + * the maximum number of the control points for a given curve + * which varies from colinear before a subdivided curve is + * replaced by a straight line connecting the endpoints. * @return PathIterator object for the Shape. */ public PathIterator getPathIterator(AffineTransform at, double flatness); /** - * Checks whether or not the interior of rectangular specified by - * [x, y, width, height] parameters intersects the interior of - * the Shape. - * - * @param x the X double coordinate of the rectangle's upper left - * corner. - * @param y the Y double coordinate of the rectangle's upper left - * corner. - * @param w the width of rectangle. - * @param h the height of rectangle. - * - * @return true, if the rectangle specified by - * [x, y, width, height] parameters intersects the interior of - * the Shape, otherwise false. - * + * Checks whether or not the interior of rectangular specified by [x, y, + * width, height] parameters intersects the interior of the Shape. + * + * @param x + * the X double coordinate of the rectangle's upper left corner. + * @param y + * the Y double coordinate of the rectangle's upper left corner. + * @param w + * the width of rectangle. + * @param h + * the height of rectangle. + * @return true, if the rectangle specified by [x, y, width, height] + * parameters intersects the interior of the Shape, false otherwise. */ public boolean intersects(double x, double y, double w, double h); /** - * Checks whether or not the interior of rectangl specified by - * Rectangle2D object intersects the interior of the Shape. - * - * @param r the Rectangle2D object. + * Checks whether or not the interior of rectangle specified by Rectangle2D + * object intersects the interior of the Shape. * - * @return true, if the Rectangle2D intersects the interior of - * the Shape, otherwise false. + * @param r + * the Rectangle2D object. + * @return true, if the Rectangle2D intersects the interior of the Shape, + * otherwise false. */ public boolean intersects(Rectangle2D r); } diff --git a/awt/java/awt/Stroke.java b/awt/java/awt/Stroke.java index e6d683d733c2bc131698dc0d6d6275f0dc1e7cc1..6d17a23bd7d9e3d29f6cb5f08fbc8d9493673903 100644 --- a/awt/java/awt/Stroke.java +++ b/awt/java/awt/Stroke.java @@ -18,29 +18,32 @@ * @author Alexey A. Petrenko * @version $Revision$ */ + package java.awt; /** - * The Stroke interface gives a pen style to be used by the - * Graphics2D interface. It provides a means for getting a stroked version - * of a shape, which is the version that is suitable for drawing via - * the Graphics2D interface. Stroking a shape gives the shape's outline - * a width or drawing style. + * The Stroke interface gives a pen style to be used by the Graphics2D + * interface. It provides a means for getting a stroked version of a shape, + * which is the version that is suitable for drawing via the Graphics2D + * interface. Stroking a shape gives the shape's outline a width or drawing + * style. *

    - * The Draw methods from Graphics2D interface should use the Stroke object for - * rendering the shape's outline. The stroke should be set by - * setStroke(java.awt.Stroke) method of the Graphics2D interface. + * The Draw methods from Graphics2D interface should use the Stroke object for + * rendering the shape's outline. The stroke should be set by + * setStroke(java.awt.Stroke) method of the Graphics2D interface. + * * @see java.awt.Graphics2D#setStroke(java.awt.Stroke) + * @since Android 1.0 */ public interface Stroke { - + /** - * Creates the stroked shape, which is the version that is suitable for drawing via - * the Graphics2D interface. Stroking a shape gives the shape's outline - * a width or drawing style. - * - * @param p the original shape. + * Creates the stroked shape, which is the version that is suitable for + * drawing via the Graphics2D interface. Stroking a shape gives the shape's + * outline a width or drawing style. * + * @param p + * the original shape. * @return the stroked shape. */ public Shape createStrokedShape(Shape p); diff --git a/awt/java/awt/Toolkit.java b/awt/java/awt/Toolkit.java index 0c066b2a0bdcf4800782ef2564acfcfed16d4ab9..e38d5240208ecbf27ba521009b290df80f15ee76 100644 --- a/awt/java/awt/Toolkit.java +++ b/awt/java/awt/Toolkit.java @@ -56,34 +56,50 @@ import org.apache.harmony.awt.wtk.NativeEventThread; import org.apache.harmony.awt.wtk.ShutdownWatchdog; import org.apache.harmony.awt.wtk.Synchronizer; import org.apache.harmony.awt.wtk.WTK; +import org.apache.harmony.luni.util.NotImplementedException; /** - * The Toolkit class is the representation of the platform-specific - * Abstract Window Toolkit implementation. Toolkit's subclasses - * are used to bind the various components to particular native - * toolkit implementations. + * The Toolkit class is the representation of the platform-specific Abstract + * Window Toolkit implementation. Toolkit's subclasses are used to bind the + * various components to particular native toolkit implementations. + * + * @since Android 1.0 */ public abstract class Toolkit { - - /** The Constant RECOURCE_PATH. */ + + /** + * The Constant RECOURCE_PATH. + */ private static final String RECOURCE_PATH = "org.apache.harmony.awt.resources.AWTProperties"; //$NON-NLS-1$ - - /** The Constant properties. */ + + /** + * The Constant properties. + */ private static final ResourceBundle properties = loadResources(RECOURCE_PATH); - - /** The dispatcher. */ + + /** + * The dispatcher. + */ Dispatcher dispatcher; - /** The system event queue core. */ + /** + * The system event queue core. + */ private EventQueueCore systemEventQueueCore; - /** The dispatch thread. */ + /** + * The dispatch thread. + */ EventDispatchThread dispatchThread; - /** The native thread. */ + /** + * The native thread. + */ NativeEventThread nativeThread; - /** The awt events manager. */ + /** + * The AWT events manager. + */ protected AWTEventsManager awtEventsManager; /** @@ -92,47 +108,68 @@ public abstract class Toolkit { private class AWTTreeLock { } - /** The awt tree lock. */ + /** + * The AWT tree lock. + */ final Object awtTreeLock = new AWTTreeLock(); - /** The synchronizer. */ + /** + * The synchronizer. + */ private final Synchronizer synchronizer = ContextStorage.getSynchronizer(); - /** The shutdown watchdog. */ + /** + * The shutdown watchdog. + */ final ShutdownWatchdog shutdownWatchdog = new ShutdownWatchdog(); - /** The auto number. */ + /** + * The auto number. + */ final AutoNumber autoNumber = new AutoNumber(); - /** The event type lookup. */ + /** + * The event type lookup. + */ final AWTEvent.EventTypeLookup eventTypeLookup = new AWTEvent.EventTypeLookup(); - /** The b dynamic layout set. */ + /** + * The b dynamic layout set. + */ private boolean bDynamicLayoutSet = true; - /** The set of desktop properties that user set directly. */ + /** + * The set of desktop properties that user set directly. + */ private final HashSet userPropSet = new HashSet(); - /** The desktop properties. */ + /** + * The desktop properties. + */ protected Map desktopProperties; - /** The desktop props support. */ + /** + * The desktop props support. + */ protected PropertyChangeSupport desktopPropsSupport; /** - * For this component the native window is being created - * It is used in the callback-driven window creation - * (e.g. on Windows in the handler of WM_CREATE event) - * to establish the connection between this component - * and its native window. + * For this component the native window is being created It is used in the + * callback-driven window creation (e.g. on Windows in the handler of + * WM_CREATE event) to establish the connection between this component and + * its native window. */ private Object recentNativeWindowComponent; - /** The wtk. */ + /** + * The wtk. + */ private WTK wtk; /** * The Class ComponentInternalsImpl. + * + * @since Android 1.0 */ protected final class ComponentInternalsImpl extends ComponentInternals { @@ -143,13 +180,15 @@ public abstract class Toolkit { public void shutdown() { dispatchThread.shutdown(); } - + /** - * Sets the desktop property to the specified value and fires a property - * change event. + * Sets the desktop property to the specified value and fires a property + * change event. * - * @param name the name of property. - * @param value the new value of property. + * @param name + * the name of property. + * @param value + * the new value of property. */ @Override public void setDesktopProperty(String name, Object value) { @@ -157,12 +196,12 @@ public abstract class Toolkit { } } - /** - * A lot of methods must throw HeadlessException - * if GraphicsEnvironment.isHeadless() returns true. + * A lot of methods must throw HeadlessException if + * GraphicsEnvironment.isHeadless() returns true. * - * @throws HeadlessException the headless exception + * @throws HeadlessException + * the headless exception. */ static void checkHeadless() throws HeadlessException { if (GraphicsEnvironment.getLocalGraphicsEnvironment().isHeadlessInstance()) @@ -170,51 +209,49 @@ public abstract class Toolkit { } /** - * Lock awt. + * Lock AWT. */ final void lockAWT() { synchronizer.lock(); } /** - * Static lock awt. + * Static lock AWT. */ static final void staticLockAWT() { ContextStorage.getSynchronizer().lock(); } /** - * Unlock awt. + * Unlock AWT. */ final void unlockAWT() { synchronizer.unlock(); } /** - * Static unlock awt. + * Static unlock AWT. */ static final void staticUnlockAWT() { ContextStorage.getSynchronizer().unlock(); - } - - /** - * InvokeAndWait under AWT lock. W/o this method system can hang up. - * Added to support modality (Dialog.show() & PopupMenu.show()) from - * not event dispatch thread. Use in other cases is not recommended. - * - * Still can be called only for whole API methods that - * cannot be called from other classes API methods. - * Examples: - * show() for modal dialogs - correct, only user can call it, - * directly or through setVisible(true) - * setBounds() for components - incorrect, setBounds() - * can be called from layoutContainer() - * for layout managers - * - * @param runnable the runnable + } + + /** + * InvokeAndWait under AWT lock. W/o this method system can hang up. Added + * to support modality (Dialog.show() & PopupMenu.show()) from not event + * dispatch thread. Use in other cases is not recommended. Still can be + * called only for whole API methods that cannot be called from other + * classes API methods. Examples: show() for modal dialogs - correct, only + * user can call it, directly or through setVisible(true) setBounds() for + * components - incorrect, setBounds() can be called from layoutContainer() + * for layout managers * - * @throws InterruptedException the interrupted exception - * @throws InvocationTargetException the invocation target exception + * @param runnable + * the runnable. + * @throws InterruptedException + * the interrupted exception. + * @throws InvocationTargetException + * the invocation target exception. */ final void unsafeInvokeAndWait(Runnable runnable) throws InterruptedException, InvocationTargetException { @@ -229,7 +266,7 @@ public abstract class Toolkit { /** * Gets the synchronizer. * - * @return the synchronizer + * @return the synchronizer. */ final Synchronizer getSynchronizer() { return synchronizer; @@ -238,19 +275,20 @@ public abstract class Toolkit { /** * Gets the wTK. * - * @return the wTK + * @return the wTK. */ final WTK getWTK() { return wtk; } /** - * Gets the property with the specified key and default value. - * This method returns the defValue if the property is not found. - * - * @param propName the name of property. - * @param defVal the default value. + * Gets the property with the specified key and default value. This method + * returns the defValue if the property is not found. * + * @param propName + * the name of property. + * @param defVal + * the default value. * @return the property value. */ public static String getProperty(String propName, String defVal) { @@ -273,11 +311,11 @@ public abstract class Toolkit { staticUnlockAWT(); } } - + /** * Gets the default Toolkit. * - * @return the default Toolkit + * @return the default Toolkit. */ public static Toolkit getDefaultToolkit() { synchronized (ContextStorage.getContextLock()) { @@ -290,34 +328,34 @@ public abstract class Toolkit { } staticLockAWT(); try { - defToolkit = GraphicsEnvironment.isHeadless() ? - new HeadlessToolkit() : new ToolkitImpl(); + defToolkit = GraphicsEnvironment.isHeadless() ? new HeadlessToolkit() + : new ToolkitImpl(); ContextStorage.setDefaultToolkit(defToolkit); return defToolkit; } finally { staticUnlockAWT(); } - //TODO: read system property named awt.toolkit - //and create an instance of the specified class, - //by default use ToolkitImpl + // TODO: read system property named awt.toolkit + // and create an instance of the specified class, + // by default use ToolkitImpl } } - + /** * Gets the default Font. * - * @return the derault Font for Toolkit. + * @return the default Font for Toolkit. */ Font getDefaultFont() { return wtk.getSystemProperties().getDefaultFont(); } - + /** * Load resources. * - * @param path the path - * - * @return the resource bundle + * @param path + * the path. + * @return the resource bundle. */ private static ResourceBundle loadResources(String path) { try { @@ -330,7 +368,7 @@ public abstract class Toolkit { /** * Gets the wTK class name. * - * @return the wTK class name + * @return the wTK class name. */ private static String getWTKClassName() { return "com.android.internal.awt.AndroidWTK"; @@ -339,9 +377,9 @@ public abstract class Toolkit { /** * Gets the component by id. * - * @param id the id - * - * @return the component by id + * @param id + * the id. + * @return the component by id. */ Component getComponentById(long id) { if (id == 0) { @@ -362,12 +400,12 @@ public abstract class Toolkit { /** * Instantiates a new toolkit. */ - public Toolkit() { + public Toolkit() { init(); } /** - * Inits AWT. + * Initiates AWT. */ protected void init() { lockAWT(); @@ -397,43 +435,52 @@ public abstract class Toolkit { unlockAWT(); } } - + /** * Synchronizes this toolkit's graphics. */ public abstract void sync(); /** - * Returns the construction status of a specified image that is being created. - * - * @param a0 the image to be checked. - * @param a1 the width of scaled image for which the status is being checked, or -1. - * @param a2 the height of scaled image for which the status is being checked, or -1. - * @param a3 the ImageObserver object to be notified while - * the image is being prepared. + * Returns the construction status of a specified image that is being + * created. * - * @return the ImageObserver flags which give the current state of the image data. + * @param a0 + * the image to be checked. + * @param a1 + * the width of scaled image for which the status is being + * checked or -1. + * @param a2 + * the height of scaled image for which the status is being + * checked or -1. + * @param a3 + * the ImageObserver object to be notified while the image is + * being prepared. + * @return the ImageObserver flags which give the current state of the image + * data. */ public abstract int checkImage(Image a0, int a1, int a2, ImageObserver a3); - + /** * Creates the image with the specified ImageProducer. * - * @param a0 the ImageProducer to be used for image creation. - * + * @param a0 + * the ImageProducer to be used for image creation. * @return the image with the specified ImageProducer. */ public abstract Image createImage(ImageProducer a0); /** - * Creates the image from the specified byte array, offset and length. - * The byte array should contain data with image format supported by - * Toolkit such as JPEG, GIF, or PNG. - * - * @param a0 the byte array with the image data. - * @param a1 the offset of the beggining the image data in the byte array. - * @param a2 the length of the image data in the byte array. + * Creates the image from the specified byte array, offset and length. The + * byte array should contain data with image format supported by Toolkit + * such as JPEG, GIF, or PNG. * + * @param a0 + * the byte array with the image data. + * @param a1 + * the offset of the beginning the image data in the byte array. + * @param a2 + * the length of the image data in the byte array. * @return the created Image. */ public abstract Image createImage(byte[] a0, int a1, int a2); @@ -441,8 +488,8 @@ public abstract class Toolkit { /** * Creates the image using image data from the specified URL. * - * @param a0 the URL for extracting image data. - * + * @param a0 + * the URL for extracting image data. * @return the Image. */ public abstract Image createImage(URL a0); @@ -450,8 +497,8 @@ public abstract class Toolkit { /** * Creates the image using image data from the specified file. * - * @param a0 the file name which contains image data of supported format. - * + * @param a0 + * the file name which contains image data of supported format. * @return the Image. */ public abstract Image createImage(String a0); @@ -460,22 +507,20 @@ public abstract class Toolkit { * Gets the color model. * * @return the ColorModel of Toolkit's screen. - * - * @throws HeadlessException if the - * GraphicsEnvironment.isHeadless() method returns true. + * @throws HeadlessException + * if the GraphicsEnvironment.isHeadless() method returns true. */ public abstract ColorModel getColorModel() throws HeadlessException; - + /** * Gets the screen device metrics for the specified font. * - * @param font the Font. - * + * @param font + * the Font. * @return the FontMetrics for the specified Font. - * * @deprecated Use getLineMetrics method from Font class. */ - + @Deprecated public abstract FontMetrics getFontMetrics(Font font); @@ -483,13 +528,18 @@ public abstract class Toolkit { * Prepares the specified image for rendering on the screen with the * specified size. * - * @param a0 the Image to be prepared. - * @param a1 the width of the screen representation or -1 for the current screen. - * @param a2 the height of the screen representation or -1 for the current screen. - * @param a3 the ImageObserver object to be notified as soon as - * the image is prepared. - * - * @return true, if image is fully prepared; false otherwise. + * @param a0 + * the Image to be prepared. + * @param a1 + * the width of the screen representation or -1 for the current + * screen. + * @param a2 + * the height of the screen representation or -1 for the current + * screen. + * @param a3 + * the ImageObserver object to be notified as soon as the image + * is prepared. + * @return true, if image is fully prepared, false otherwise. */ public abstract boolean prepareImage(Image a0, int a1, int a2, ImageObserver a3); @@ -502,21 +552,19 @@ public abstract class Toolkit { * Returns the array of font names which are available in this Toolkit. * * @return the array of font names which are available in this Toolkit. - * * @deprecated use GraphicsEnvironment.getAvailableFontFamilyNames() method. */ @Deprecated public abstract String[] getFontList(); - + /** - * Gets the the Font implementation using the specified peer - * interface. - * - * @param a0 the Font name to be implemented. - * @param a1 the the font style: PLAIN, BOLD, ITALIC. + * Gets the the Font implementation using the specified peer interface. * + * @param a0 + * the Font name to be implemented. + * @param a1 + * the the font style: PLAIN, BOLD, ITALIC. * @return the FontPeer implementation of the specified Font. - * * @deprecated use java.awt.GraphicsEnvironment.getAllFonts method. */ @@ -524,27 +572,27 @@ public abstract class Toolkit { protected abstract FontPeer getFontPeer(String a0, int a1); /** - * Gets the image from the specified file which contains image data in - * a supported image format (such as JPEG, GIF, or PNG); this method - * should return the same Image for multiple calls of this method with - * the same image file name. - * - * @param a0 the file name which contains image data in - * a supported image format (such as JPEG, GIF, or PNG). + * Gets the image from the specified file which contains image data in a + * supported image format (such as JPEG, GIF, or PNG); this method should + * return the same Image for multiple calls of this method with the same + * image file name. * + * @param a0 + * the file name which contains image data in a supported image + * format (such as JPEG, GIF, or PNG). * @return the Image. */ public abstract Image getImage(String a0); /** - * Gets the image from the specified URL which contains image data in - * a supported image format (such as JPEG, GIF, or PNG); this method - * should return the same Image for multiple calls of this method with - * the same image URL. - * - * @param a0 the URL which contains image data in - * a supported image format (such as JPEG, GIF, or PNG). + * Gets the image from the specified URL which contains image data in a + * supported image format (such as JPEG, GIF, or PNG); this method should + * return the same Image for multiple calls of this method with the same + * image URL. * + * @param a0 + * the URL which contains image data in a supported image format + * (such as JPEG, GIF, or PNG). * @return the Image. */ public abstract Image getImage(URL a0); @@ -553,20 +601,17 @@ public abstract class Toolkit { * Gets the screen resolution. * * @return the screen resolution. - * - * @throws HeadlessException if the GraphicsEnvironment.isHeadless() - * method returns true. + * @throws HeadlessException + * if the GraphicsEnvironment.isHeadless() method returns true. */ public abstract int getScreenResolution() throws HeadlessException; /** * Gets the screen size. * - * @return a Dimension object containing the width and height of - * the screen. - * - * @throws HeadlessException if the GraphicsEnvironment.isHeadless() - * method returns true. + * @return a Dimension object containing the width and height of the screen. + * @throws HeadlessException + * if the GraphicsEnvironment.isHeadless() method returns true. */ public abstract Dimension getScreenSize() throws HeadlessException; @@ -578,15 +623,14 @@ public abstract class Toolkit { protected abstract EventQueue getSystemEventQueueImpl(); /** - * Returns a map of text attributes for the abstract level description - * of the specified input method highlight, or null if no mapping is found. - * - * @param highlight the InputMethodHighlight. + * Returns a map of text attributes for the abstract level description of + * the specified input method highlight, or null if no mapping is found. * - * @return the Map - * - * @throws HeadlessException if the GraphicsEnvironment.isHeadless() - * method returns true. + * @param highlight + * the InputMethodHighlight. + * @return the Map. + * @throws HeadlessException + * if the GraphicsEnvironment.isHeadless() method returns true. */ public abstract Map mapInputMethodHighlight( InputMethodHighlight highlight) throws HeadlessException; @@ -594,14 +638,14 @@ public abstract class Toolkit { /** * Map input method highlight impl. * - * @param highlight the highlight - * - * @return the map - * - * @throws HeadlessException the headless exception + * @param highlight + * the highlight. + * @return the map. + * @throws HeadlessException + * the headless exception. */ - Map mapInputMethodHighlightImpl( - InputMethodHighlight highlight) throws HeadlessException { + Map mapInputMethodHighlightImpl(InputMethodHighlight highlight) + throws HeadlessException { HashMap map = new HashMap(); wtk.getSystemProperties().mapInputMethodHighlight(highlight, map); return Collections. unmodifiableMap(map); @@ -611,9 +655,11 @@ public abstract class Toolkit { * Adds the specified PropertyChangeListener listener for the specified * property. * - * @param propName the property name for which the specified PropertyChangeListener - * will be added. - * @param l the PropertyChangeListener object. + * @param propName + * the property name for which the specified + * PropertyChangeListener will be added. + * @param l + * the PropertyChangeListener object. */ public void addPropertyChangeListener(String propName, PropertyChangeListener l) { lockAWT(); @@ -624,31 +670,32 @@ public abstract class Toolkit { } finally { unlockAWT(); } - if (l != null) { // there is no guarantee that null listener will not be added + if (l != null) { // there is no guarantee that null listener will not be + // added desktopPropsSupport.addPropertyChangeListener(propName, l); } } /** - * Returns an array of the property change listeners registered with - * this Toolkit. + * Returns an array of the property change listeners registered with this + * Toolkit. * - * @return an array of the property change listeners registered with - * this Toolkit. + * @return an array of the property change listeners registered with this + * Toolkit. */ public PropertyChangeListener[] getPropertyChangeListeners() { return desktopPropsSupport.getPropertyChangeListeners(); } /** - * Returns an array of the property change listeners registered with - * this Toolkit for notification regarding the specified property. - * - * @param propName the property name for which the PropertyChangeListener - * was registered. + * Returns an array of the property change listeners registered with this + * Toolkit for notification regarding the specified property. * - * @return the array of PropertyChangeListeners registered for the specified - * property name. + * @param propName + * the property name for which the PropertyChangeListener was + * registered. + * @return the array of PropertyChangeListeners registered for the specified + * property name. */ public PropertyChangeListener[] getPropertyChangeListeners(String propName) { return desktopPropsSupport.getPropertyChangeListeners(propName); @@ -658,28 +705,33 @@ public abstract class Toolkit { * Removes the specified property change listener registered for the * specified property name. * - * @param propName the property name. - * @param l the PropertyChangeListener registered for the specified property name. + * @param propName + * the property name. + * @param l + * the PropertyChangeListener registered for the specified + * property name. */ public void removePropertyChangeListener(String propName, PropertyChangeListener l) { desktopPropsSupport.removePropertyChangeListener(propName, l); } - + /** * Creates a custom cursor with the specified Image, hot spot, and cursor * description. * - * @param img the image of activated cursor. - * @param hotSpot the Point giving the coordinates of the cursor's hot spot. - * @param name the cursor description. - * + * @param img + * the image of activated cursor. + * @param hotSpot + * the Point giving the coordinates of the cursor's hot spot. + * @param name + * the cursor description. * @return the cursor with the specified Image, hot spot, and cursor - * description. - * - * @throws IndexOutOfBoundsException if the hot spot values are outside - * the bounds of the cursor. - * @throws HeadlessException if isHeadless() method of GraphicsEnvironment - * class returns true. + * description. + * @throws IndexOutOfBoundsException + * if the hot spot values are outside the bounds of the cursor. + * @throws HeadlessException + * if isHeadless() method of GraphicsEnvironment class returns + * true. */ public Cursor createCustomCursor(Image img, Point hotSpot, String name) throws IndexOutOfBoundsException, HeadlessException { @@ -698,20 +750,19 @@ public abstract class Toolkit { } /** - * Returns the supported cursor dimension which is closest to the - * specified width and height. If the Toolkit only supports a single - * cursor size, this method should return the supported cursor size. - * If custom cursor is not supported, a dimension of 0, 0 should be - * returned. - * - * @param prefWidth the preffered cursor width. - * @param prefHeight the preffered cursor height. + * Returns the supported cursor dimension which is closest to the specified + * width and height. If the Toolkit only supports a single cursor size, this + * method should return the supported cursor size. If custom cursor is not + * supported, a dimension of 0, 0 should be returned. * - * @return the supported cursor dimension which is closest to the - * specified width and height. - * - * @throws HeadlessException if GraphicsEnvironment.isHeadless() - * returns true. + * @param prefWidth + * the preferred cursor width. + * @param prefHeight + * the preferred cursor height. + * @return the supported cursor dimension which is closest to the specified + * width and height. + * @throws HeadlessException + * if GraphicsEnvironment.isHeadless() returns true. */ public Dimension getBestCursorSize(int prefWidth, int prefHeight) throws HeadlessException { lockAWT(); @@ -723,10 +774,10 @@ public abstract class Toolkit { } /** - * Gets the value for the specified desktop property. - * - * @param propName the property name. + * Gets the value for the specified desktop property. * + * @param propName + * the property name. * @return the Object that is the property's value. */ public final Object getDesktopProperty(String propName) { @@ -754,17 +805,19 @@ public abstract class Toolkit { /** * Returns the locking key state for the specified key. * - * @param a0 the key code: VK_CAPS_LOCK, VK_NUM_LOCK, VK_SCROLL_LOCK, - * or VK_KANA_LOCK. - * - * @return true if the specified key code is in the locked state, - * false otherwise. - * - * @throws UnsupportedOperationException if the state of this key - * can't be retrieved, or if the keyboard doesn't have this key. - * @throws NotImplementedException if this method is not implemented. - */ - public boolean getLockingKeyState(int a0) throws UnsupportedOperationException, org.apache.harmony.luni.util.NotImplementedException { + * @param a0 + * the key code: VK_CAPS_LOCK, VK_NUM_LOCK, VK_SCROLL_LOCK, or + * VK_KANA_LOCK. + * @return true if the specified key code is in the locked state, false + * otherwise. + * @throws UnsupportedOperationException + * if the state of this key can't be retrieved, or if the + * keyboard doesn't have this key. + * @throws NotImplementedException + * if this method is not implemented. + */ + public boolean getLockingKeyState(int a0) throws UnsupportedOperationException, + org.apache.harmony.luni.util.NotImplementedException { lockAWT(); try { } finally { @@ -781,9 +834,8 @@ public abstract class Toolkit { * custom cursor. * * @return the maximum cursor colors. - * - * @throws HeadlessException if the GraphicsEnvironment.isHeadless() - * method returns true. + * @throws HeadlessException + * if the GraphicsEnvironment.isHeadless() method returns true. */ public int getMaximumCursorColors() throws HeadlessException { lockAWT(); @@ -796,11 +848,10 @@ public abstract class Toolkit { /** * Gets the menu shortcut key mask. - * - * @return the menu shortcut key mask. * - * @throws HeadlessException if the GraphicsEnvironment.isHeadless() - * method returns true. + * @return the menu shortcut key mask. + * @throws HeadlessException + * if the GraphicsEnvironment.isHeadless() method returns true. */ public int getMenuShortcutKeyMask() throws HeadlessException { lockAWT(); @@ -814,12 +865,11 @@ public abstract class Toolkit { /** * Gets the screen insets. * - * @param gc the GraphicsConfiguration. - * + * @param gc + * the GraphicsConfiguration. * @return the insets of this toolkit. - * - * @throws HeadlessException if the GraphicsEnvironment.isHeadless() - * method returns true. + * @throws HeadlessException + * if the GraphicsEnvironment.isHeadless() method returns true. */ public Insets getScreenInsets(GraphicsConfiguration gc) throws HeadlessException { if (gc == null) { @@ -827,17 +877,17 @@ public abstract class Toolkit { } lockAWT(); try { - return new Insets(0, 0, 0, 0); //TODO: get real screen insets + return new Insets(0, 0, 0, 0); // TODO: get real screen insets } finally { unlockAWT(); } } /** - * Gets the system EventQueue instance. - * If the default implementation of checkAwtEventQueueAccess is used, - * then this results of a call to the security manager's checkPermission - * method with an AWTPermission("accessEventQueue") permission. + * Gets the system EventQueue instance. If the default implementation of + * checkAwtEventQueueAccess is used, then this results of a call to the + * security manager's checkPermission method with an + * AWTPermission("accessEventQueue") permission. * * @return the system EventQueue instance. */ @@ -849,19 +899,20 @@ public abstract class Toolkit { return getSystemEventQueueImpl(); } - /** + /** * Gets the system event queue core. * - * @return the system event queue core + * @return the system event queue core. */ EventQueueCore getSystemEventQueueCore() { return systemEventQueueCore; } - + /** * Sets the system event queue core. * - * @param core the new system event queue core + * @param core + * the new system event queue core. */ void setSystemEventQueueCore(EventQueueCore core) { systemEventQueueCore = core; @@ -882,11 +933,10 @@ public abstract class Toolkit { /** * Checks if dynamic layout of Containers is active or not. * - * @return true, if is dynamic layout of Containers is active, - * false otherwise. - * - * @throws HeadlessException if the GraphicsEnvironment.isHeadless() - * method returns true. + * @return true, if is dynamic layout of Containers is active, false + * otherwise. + * @throws HeadlessException + * if the GraphicsEnvironment.isHeadless() method returns true. */ public boolean isDynamicLayoutActive() throws HeadlessException { lockAWT(); @@ -898,17 +948,15 @@ public abstract class Toolkit { } } - /** - * Returns if the layout of Containers is checked dynamically during resizing, - * or statically after resizing is completed. - * - * @return true, if if the layout of Containers is checked dynamically during - * resizing; false, if the layout of Containers is checked statically after - * resizing is completed. + * Returns if the layout of Containers is checked dynamically during + * resizing, or statically after resizing is completed. * - * @throws HeadlessException if the GraphicsEnvironment.isHeadless() - * method returns true. + * @return true, if if the layout of Containers is checked dynamically + * during resizing; false, if the layout of Containers is checked + * statically after resizing is completed. + * @throws HeadlessException + * if the GraphicsEnvironment.isHeadless() method returns true. */ protected boolean isDynamicLayoutSet() throws HeadlessException { lockAWT(); @@ -922,12 +970,11 @@ public abstract class Toolkit { /** * Checks if the specified frame state is supported by Toolkit or not. * - * @param state the frame state. - * - * @return true, if frame state is supported; false othrwise. - * - * @throws HeadlessException if the GraphicsEnvironment.isHeadless() - * method returns true. + * @param state + * the frame state. + * @return true, if frame state is supported, false otherwise. + * @throws HeadlessException + * if the GraphicsEnvironment.isHeadless() method returns true. */ public boolean isFrameStateSupported(int state) throws HeadlessException { lockAWT(); @@ -941,8 +988,8 @@ public abstract class Toolkit { /** * Loads the value of the desktop property with the specified property name. * - * @param propName the property name. - * + * @param propName + * the property name. * @return the desktop property values. */ protected Object lazilyLoadDesktopProperty(String propName) { @@ -952,11 +999,11 @@ public abstract class Toolkit { /** * Loads the current system color values to the specified array. * - * @param colors the array where the current system color values - * are written by this method. - * - * @throws HeadlessException if the GraphicsEnvironment.isHeadless() - * method returns true. + * @param colors + * the array where the current system color values are written by + * this method. + * @throws HeadlessException + * if the GraphicsEnvironment.isHeadless() method returns true. */ protected void loadSystemColors(int[] colors) throws HeadlessException { lockAWT(); @@ -969,8 +1016,10 @@ public abstract class Toolkit { /** * Sets the value of the desktop property with the specified name. * - * @param propName the property's name. - * @param value the property's value. + * @param propName + * the property's name. + * @param value + * the property's value. */ protected final void setDesktopProperty(String propName, Object value) { Object oldVal; @@ -986,15 +1035,15 @@ public abstract class Toolkit { } /** - * Sets the layout state, whether the Container layout is checked - * dynamically during resizing, or statically after resizing is completed. - * - * @param dynamic the new dynamic layout state - if true the layout of - * Containers is checked dynamically during resizing, if false - - * statically after resizing is completed. + * Sets the layout state, whether the Container layout is checked + * dynamically during resizing, or statically after resizing is completed. * - * @throws HeadlessException if the GraphicsEnvironment.isHeadless() - * method returns true. + * @param dynamic + * the new dynamic layout state - if true the layout of + * Containers is checked dynamically during resizing, if false - + * statically after resizing is completed. + * @throws HeadlessException + * if the GraphicsEnvironment.isHeadless() method returns true. */ public void setDynamicLayout(boolean dynamic) throws HeadlessException { lockAWT(); @@ -1008,16 +1057,20 @@ public abstract class Toolkit { /** * Sets the locking key state for the specified key code. * - * @param a0 the key code: VK_CAPS_LOCK, VK_NUM_LOCK, VK_SCROLL_LOCK, - * or VK_KANA_LOCK. - * @param a1 the state - true to set the specified key code to the locked state, - * false - to unlock it. - * - * @throws UnsupportedOperationException if the state of this key - * can't be set, or if the keyboard doesn't have this key. - * @throws NotImplementedException if this method is not implemented. - */ - public void setLockingKeyState(int a0, boolean a1) throws UnsupportedOperationException, org.apache.harmony.luni.util.NotImplementedException { + * @param a0 + * the key code: VK_CAPS_LOCK, VK_NUM_LOCK, VK_SCROLL_LOCK, or + * VK_KANA_LOCK. + * @param a1 + * the state - true to set the specified key code to the locked + * state, false - to unlock it. + * @throws UnsupportedOperationException + * if the state of this key can't be set, or if the keyboard + * doesn't have this key. + * @throws NotImplementedException + * if this method is not implemented. + */ + public void setLockingKeyState(int a0, boolean a1) throws UnsupportedOperationException, + org.apache.harmony.luni.util.NotImplementedException { lockAWT(); try { } finally { @@ -1029,7 +1082,6 @@ public abstract class Toolkit { return; } - /** * On queue empty. */ @@ -1040,14 +1092,14 @@ public abstract class Toolkit { /** * Creates the wtk. * - * @param clsName the cls name - * - * @return the wTK + * @param clsName + * the cls name. + * @return the wTK. */ private WTK createWTK(String clsName) { WTK newWTK = null; try { - newWTK = (WTK) Class.forName(clsName).newInstance(); + newWTK = (WTK)Class.forName(clsName).newInstance(); } catch (Exception e) { throw new RuntimeException(e); } @@ -1056,7 +1108,9 @@ public abstract class Toolkit { /** * Connect the component to its native window - * @param winId - id of native window just created + * + * @param winId + * the id of native window just created. */ boolean onWindowCreated(long winId) { return false; @@ -1065,45 +1119,50 @@ public abstract class Toolkit { /** * Gets the native event queue. * - * @return the native event queue + * @return the native event queue. */ NativeEventQueue getNativeEventQueue() { return wtk.getNativeEventQueue(); } /** - * Returns a shared instance of implementation of org.apache.harmony.awt.wtk.NativeCursor - * for current platform for + * Returns a shared instance of implementation of + * org.apache.harmony.awt.wtk.NativeCursor for current platform for. * - * @param type - Java Cursor type - * - * @return new instance of implementation of NativeCursor + * @param type + * the Java Cursor type. + * @return new instance of implementation of NativeCursor. */ NativeCursor createNativeCursor(int type) { return wtk.getCursorFactory().getCursor(type); } /** - * Returns a shared instance of implementation of org.apache.harmony.awt.wtk.NativeCursor - * for current platform for custom cursor - * - * @param img the img - * @param hotSpot the hot spot - * @param name the name + * Returns a shared instance of implementation of + * org.apache.harmony.awt.wtk.NativeCursor for current platform for custom + * cursor * - * @return new instance of implementation of NativeCursor + * @param img + * the img. + * @param hotSpot + * the hot spot. + * @param name + * the name. + * @return new instance of implementation of NativeCursor. */ NativeCursor createCustomNativeCursor(Image img, Point hotSpot, String name) { return wtk.getCursorFactory().createCustomCursor(img, hotSpot.x, hotSpot.y); } /** - * Adds an AWTEventListener to the Toolkit to listen for events - * of types corresponding to bits in the specified event mask. - * Event masks are defined in AWTEvent class. + * Adds an AWTEventListener to the Toolkit to listen for events of types + * corresponding to bits in the specified event mask. Event masks are + * defined in AWTEvent class. * - * @param listener the AWTEventListener. - * @param eventMask he bitmask of event types. + * @param listener + * the AWTEventListener. + * @param eventMask + * the bitmask of event types. */ public void addAWTEventListener(AWTEventListener listener, long eventMask) { lockAWT(); @@ -1119,9 +1178,10 @@ public abstract class Toolkit { } /** - * Removes the specified awt event listener. + * Removes the specified AWT event listener. * - * @param listener the AWTEventListener to be removed. + * @param listener + * the AWTEventListener to be removed. */ public void removeAWTEventListener(AWTEventListener listener) { lockAWT(); @@ -1139,7 +1199,8 @@ public abstract class Toolkit { /** * Gets the array of all AWT event listeners registered with this Toolkit. * - * @return the array of all AWT event listeners registered with this Toolkit. + * @return the array of all AWT event listeners registered with this + * Toolkit. */ public AWTEventListener[] getAWTEventListeners() { lockAWT(); @@ -1155,13 +1216,13 @@ public abstract class Toolkit { } /** - * Returns the array of the AWT event listeners registered with this Toolkit + * Returns the array of the AWT event listeners registered with this Toolkit * for the event types corresponding to the specified event mask. * - * @param eventMask the bit mask of event type. - * - * @return the array of the AWT event listeners registered in this Toolkit - * for the event types corresponding to the specified event mask. + * @param eventMask + * the bit mask of event type. + * @return the array of the AWT event listeners registered in this Toolkit + * for the event types corresponding to the specified event mask. */ public AWTEventListener[] getAWTEventListeners(long eventMask) { lockAWT(); @@ -1177,30 +1238,37 @@ public abstract class Toolkit { } /** - * Dispatch awt event. + * Dispatch AWT event. * - * @param event the event + * @param event + * the event. */ void dispatchAWTEvent(AWTEvent event) { awtEventsManager.dispatchAWTEvent(event); } - + /** * The Class AWTEventsManager. */ final class AWTEventsManager { - /** The permission. */ + /** + * The permission. + */ AWTPermission permission = new AWTPermission("listenToAllAWTEvents"); //$NON-NLS-1$ - /** The listeners. */ + /** + * The listeners. + */ private final AWTListenerList listeners = new AWTListenerList(); /** - * Adds the awt event listener. + * Adds the AWT event listener. * - * @param listener the listener - * @param eventMask the event mask + * @param listener + * the listener. + * @param eventMask + * the event mask. */ void addAWTEventListener(AWTEventListener listener, long eventMask) { if (listener != null) { @@ -1209,9 +1277,10 @@ public abstract class Toolkit { } /** - * Removes the awt event listener. + * Removes the AWT event listener. * - * @param listener the listener + * @param listener + * the listener. */ void removeAWTEventListener(AWTEventListener listener) { if (listener != null) { @@ -1225,9 +1294,9 @@ public abstract class Toolkit { } /** - * Gets the aWT event listeners. + * Gets the AWT event listeners. * - * @return the aWT event listeners + * @return the AWT event listeners. */ AWTEventListener[] getAWTEventListeners() { HashSet listenersSet = new HashSet(); @@ -1238,11 +1307,11 @@ public abstract class Toolkit { } /** - * Gets the aWT event listeners. + * Gets the AWT event listeners. * - * @param eventMask the event mask - * - * @return the aWT event listeners + * @param eventMask + * the event mask. + * @return the AWT event listeners. */ AWTEventListener[] getAWTEventListeners(long eventMask) { HashSet listenersSet = new HashSet(); @@ -1255,9 +1324,10 @@ public abstract class Toolkit { } /** - * Dispatch awt event. + * Dispatch AWT event. * - * @param event the event + * @param event + * the event. */ void dispatchAWTEvent(AWTEvent event) { AWTEvent.EventDescriptor descriptor = eventTypeLookup.getEventDescriptor(event); @@ -1271,68 +1341,104 @@ public abstract class Toolkit { } } } - + /** * The Class AutoNumber. */ static final class AutoNumber { - /** The next component. */ + /** + * The next component. + */ int nextComponent = 0; - /** The next canvas. */ + /** + * The next canvas. + */ int nextCanvas = 0; - /** The next panel. */ + /** + * The next panel. + */ int nextPanel = 0; - /** The next window. */ + /** + * The next window. + */ int nextWindow = 0; - /** The next frame. */ + /** + * The next frame. + */ int nextFrame = 0; - /** The next dialog. */ + /** + * The next dialog. + */ int nextDialog = 0; - /** The next button. */ + /** + * The next button. + */ int nextButton = 0; - /** The next menu component. */ + /** + * The next menu component. + */ int nextMenuComponent = 0; - /** The next label. */ + /** + * The next label. + */ int nextLabel = 0; - /** The next check box. */ + /** + * The next check box. + */ int nextCheckBox = 0; - /** The next scrollbar. */ + /** + * The next scrollbar. + */ int nextScrollbar = 0; - /** The next scroll pane. */ + /** + * The next scroll pane. + */ int nextScrollPane = 0; - /** The next list. */ + /** + * The next list. + */ int nextList = 0; - /** The next choice. */ + /** + * The next choice. + */ int nextChoice = 0; - /** The next file dialog. */ + /** + * The next file dialog. + */ int nextFileDialog = 0; - /** The next text area. */ + /** + * The next text area. + */ int nextTextArea = 0; - /** The next text field. */ + /** + * The next text field. + */ int nextTextField = 0; } - + private class Lock { } - /** The lock. */ + /** + * The lock. + */ private final Object lock = new Lock(); - + } diff --git a/awt/java/awt/Transparency.java b/awt/java/awt/Transparency.java index 97931141aa1f7a91fe8267c2b62630d14e07fbf9..44a1e7f2e46e160501f3975e3c4c81702e0de56d 100644 --- a/awt/java/awt/Transparency.java +++ b/awt/java/awt/Transparency.java @@ -18,34 +18,40 @@ * @author Pavel Dolgov * @version $Revision$ */ + package java.awt; /** * The Transparency interface defines transparency's general modes. + * + * @since Android 1.0 */ public interface Transparency { - /** The Constant OPAQUE represents completely opaque data, - * all pixels have an alpha value of 1.0. + /** + * The Constant OPAQUE represents completely opaque data, all pixels have an + * alpha value of 1.0. */ public static final int OPAQUE = 1; - /** The Constant BITMASK represents data which can be either - * completely opaque, with an alpha value of 1.0, or completely - * transparent, with an alpha value of 0.0. + /** + * The Constant BITMASK represents data which can be either completely + * opaque, with an alpha value of 1.0, or completely transparent, with an + * alpha value of 0.0. */ public static final int BITMASK = 2; - /** The Constant TRANSLUCENT represents data which alpha value - * can vary between and including 0.0 and 1.0. */ + /** + * The Constant TRANSLUCENT represents data which alpha value can vary + * between and including 0.0 and 1.0. + */ public static final int TRANSLUCENT = 3; /** * Gets the transparency mode. * - * @return the transparency mode: OPAQUE, BITMASK or TRANSLUCENT. + * @return the transparency mode: OPAQUE, BITMASK or TRANSLUCENT. */ public int getTransparency(); } - diff --git a/awt/java/awt/color/CMMException.java b/awt/java/awt/color/CMMException.java index 16fe76eae94cffa6ba10e0dc38340e33286d2b57..18b9a7e563960b28a434fbfb68e3048596a3637a 100644 --- a/awt/java/awt/color/CMMException.java +++ b/awt/java/awt/color/CMMException.java @@ -21,18 +21,22 @@ package java.awt.color; /** - * The CMMException is thrown as soon as a native CMM error - * occures. + * The CMMException is thrown as soon as a native CMM error occurs. + * + * @since Android 1.0 */ public class CMMException extends java.lang.RuntimeException { - /** The Constant serialVersionUID. */ + /** + * The Constant serialVersionUID. + */ private static final long serialVersionUID = 5775558044142994965L; /** * Instantiates a new CMM exception with detail message. * - * @param s the String - detail message. + * @param s + * the detail message of the exception. */ public CMMException (String s) { super (s); diff --git a/awt/java/awt/color/ColorSpace.java b/awt/java/awt/color/ColorSpace.java index f961514106ef6c04b7ce038f87cebbabdee88ea8..44c491b7492994b26e8df5c5267d3838a81de220 100644 --- a/awt/java/awt/color/ColorSpace.java +++ b/awt/java/awt/color/ColorSpace.java @@ -26,131 +26,209 @@ import org.apache.harmony.awt.gl.color.LUTColorConverter; import org.apache.harmony.awt.internal.nls.Messages; /** - * The ColorSpace class defines a color space type for a Color and provides methods - * for arrays of color component operations. + * The ColorSpace class defines a color space type for a Color and provides + * methods for arrays of color component operations. + * + * @since Android 1.0 */ public abstract class ColorSpace implements Serializable { /** The Constant serialVersionUID. */ private static final long serialVersionUID = -409452704308689724L; - /** The Constant TYPE_XYZ indicates XYZ color space type. */ + /** + * The Constant TYPE_XYZ indicates XYZ color space type. + */ public static final int TYPE_XYZ = 0; - /** The Constant TYPE_Lab indicates Lab color space type. */ + /** + * The Constant TYPE_Lab indicates Lab color space type. + */ public static final int TYPE_Lab = 1; - /** The Constant TYPE_Luv indicates Luv color space type. */ + /** + * The Constant TYPE_Luv indicates Luv color space type. + */ public static final int TYPE_Luv = 2; - /** The Constant TYPE_YCbCr indicates YCbCr color space type. */ + /** + * The Constant TYPE_YCbCr indicates YCbCr color space type. + */ public static final int TYPE_YCbCr = 3; - /** The Constant TYPE_Yxy indicates Yxy color space type. */ + /** + * The Constant TYPE_Yxy indicates Yxy color space type. + */ public static final int TYPE_Yxy = 4; - /** The Constant TYPE_RGB indicates RGB color space type. */ + /** + * The Constant TYPE_RGB indicates RGB color space type. + */ public static final int TYPE_RGB = 5; - /** The Constant TYPE_GRAY indicates Gray color space type. */ + /** + * The Constant TYPE_GRAY indicates Gray color space type. + */ public static final int TYPE_GRAY = 6; - /** The Constant TYPE_HSV indicates HSV color space type. */ + /** + * The Constant TYPE_HSV indicates HSV color space type. + */ public static final int TYPE_HSV = 7; - /** The Constant TYPE_HLS indicates HLS color space type. */ + /** + * The Constant TYPE_HLS indicates HLS color space type. + */ public static final int TYPE_HLS = 8; - /** The Constant TYPE_CMYK indicates CMYK color space type. */ + /** + * The Constant TYPE_CMYK indicates CMYK color space type. + */ public static final int TYPE_CMYK = 9; - /** The Constant TYPE_CMY indicates CMY color space type. */ + /** + * The Constant TYPE_CMY indicates CMY color space type. + */ public static final int TYPE_CMY = 11; - /** The Constant TYPE_2CLR indicates color spaces with 2 components. */ + /** + * The Constant TYPE_2CLR indicates color spaces with 2 components. + */ public static final int TYPE_2CLR = 12; - /** The Constant TYPE_3CLR indicates color spaces with 3 components. */ + /** + * The Constant TYPE_3CLR indicates color spaces with 3 components. + */ public static final int TYPE_3CLR = 13; - /** The Constant TYPE_4CLR indicates color spaces with 4 components. */ + /** + * The Constant TYPE_4CLR indicates color spaces with 4 components. + */ public static final int TYPE_4CLR = 14; - /** The Constant TYPE_5CLR indicates color spaces with 5 components. */ + /** + * The Constant TYPE_5CLR indicates color spaces with 5 components. + */ public static final int TYPE_5CLR = 15; - /** The Constant TYPE_6CLR indicates color spaces with 6 components. */ + /** + * The Constant TYPE_6CLR indicates color spaces with 6 components. + */ public static final int TYPE_6CLR = 16; - /** The Constant TYPE_7CLR indicates color spaces with 7 components. */ + /** + * The Constant TYPE_7CLR indicates color spaces with 7 components. + */ public static final int TYPE_7CLR = 17; - /** The Constant TYPE_8CLR indicates color spaces with 8 components. */ + /** + * The Constant TYPE_8CLR indicates color spaces with 8 components. + */ public static final int TYPE_8CLR = 18; - /** The Constant TYPE_9CLR indicates color spaces with 9 components. */ + /** + * The Constant TYPE_9CLR indicates color spaces with 9 components. + */ public static final int TYPE_9CLR = 19; - /** The Constant TYPE_ACLR indicates color spaces with 10 components. */ + /** + * The Constant TYPE_ACLR indicates color spaces with 10 components. + */ public static final int TYPE_ACLR = 20; - /** The Constant TYPE_BCLR indicates color spaces with 11 components. */ + /** + * The Constant TYPE_BCLR indicates color spaces with 11 components. + */ public static final int TYPE_BCLR = 21; - /** The Constant TYPE_CCLR indicates color spaces with 12 components. */ + /** + * The Constant TYPE_CCLR indicates color spaces with 12 components. + */ public static final int TYPE_CCLR = 22; - /** The Constant TYPE_DCLR indicates color spaces with 13 components. */ + /** + * The Constant TYPE_DCLR indicates color spaces with 13 components. + */ public static final int TYPE_DCLR = 23; - /** The Constant TYPE_ECLR indicates color spaces with 14 components. */ + /** + * The Constant TYPE_ECLR indicates color spaces with 14 components. + */ public static final int TYPE_ECLR = 24; - /** The Constant TYPE_FCLR indicates color spaces with 15 components. */ + /** + * The Constant TYPE_FCLR indicates color spaces with 15 components. + */ public static final int TYPE_FCLR = 25; - /** The Constant CS_sRGB indicates standard RGB color space.*/ + /** + * The Constant CS_sRGB indicates standard RGB color space. + */ public static final int CS_sRGB = 1000; - /** The Constant CS_LINEAR_RGB indicates linear RGB color space. */ + /** + * The Constant CS_LINEAR_RGB indicates linear RGB color space. + */ public static final int CS_LINEAR_RGB = 1004; - /** The Constant CS_CIEXYZ indicates CIEXYZ conversion color space. */ + /** + * The Constant CS_CIEXYZ indicates CIEXYZ conversion color space. + */ public static final int CS_CIEXYZ = 1001; - /** The Constant CS_PYCC indicates Photo YCC conversion color space. */ + /** + * The Constant CS_PYCC indicates Photo YCC conversion color space. + */ public static final int CS_PYCC = 1002; - /** The Constant CS_GRAY indicates linear gray scale color space. */ + /** + * The Constant CS_GRAY indicates linear gray scale color space. + */ public static final int CS_GRAY = 1003; - /** The cs_ gray. */ + /** + * The cs_ gray. + */ private static ColorSpace cs_Gray = null; - /** The cs_ pycc. */ + /** + * The cs_ pycc. + */ private static ColorSpace cs_PYCC = null; - /** The cs_ ciexyz. */ + /** + * The cs_ ciexyz. + */ private static ColorSpace cs_CIEXYZ = null; - /** The cs_ lrgb. */ + /** + * The cs_ lrgb. + */ private static ColorSpace cs_LRGB = null; - /** The cs_s rgb. */ + /** + * The cs_s rgb. + */ private static ColorSpace cs_sRGB = null; - /** The type. */ + /** + * The type. + */ private int type; - /** The num components. */ + /** + * The num components. + */ private int numComponents; /** - * Instantiates a ColorSpace with the specified - * ColorSpace type and number of components. + * Instantiates a ColorSpace with the specified ColorSpace type and number + * of components. * - * @param type the type of color space. - * @param numcomponents the number of components. + * @param type + * the type of color space. + * @param numcomponents + * the number of components. */ protected ColorSpace(int type, int numcomponents) { this.numComponents = numcomponents; @@ -160,8 +238,8 @@ public abstract class ColorSpace implements Serializable { /** * Gets the name of the component for the specified component index. * - * @param idx the index of the component. - * + * @param idx + * the index of the component. * @return the name of the component. */ public String getName(int idx) { @@ -174,56 +252,54 @@ public abstract class ColorSpace implements Serializable { } /** - * Perform transformation a color from this ColorSpace - * into the RGB color space. - * - * @param colorvalue the color value in this ColorSpace. + * Performs the transformation of a color from this ColorSpace into the RGB + * color space. * - * @return the float array with color components in the - * RGB color space. + * @param colorvalue + * the color value in this ColorSpace. + * @return the float array with color components in the RGB color space. */ public abstract float[] toRGB(float[] colorvalue); /** - * Perform transformation a color from this ColorSpace - * into the CS_CIEXYZ color space. + * Performs the transformation of a color from this ColorSpace into the + * CS_CIEXYZ color space. * - * @param colorvalue the color value in this ColorSpace. - * - * @return the float array with color components in the - * CS_CIEXYZ color space. + * @param colorvalue + * the color value in this ColorSpace. + * @return the float array with color components in the CS_CIEXYZ color + * space. */ public abstract float[] toCIEXYZ(float[] colorvalue); /** - * Performs color transformation from the RGB color space - * into this ColorSpace. + * Performs the transformation of a color from the RGB color space into this + * ColorSpace. * - * @param rgbvalue a float array in the RGB color space. - * - * @return the float[] an array of transformed color - * components. + * @param rgbvalue + * the float array representing a color in the RGB color space. + * @return the float array with the transformed color components. */ public abstract float[] fromRGB(float[] rgbvalue); /** - * Performs color transformation from the CS_CIEXYZ color space + * Performs the transformation of a color from the CS_CIEXYZ color space * into this ColorSpace. * - * @param colorvalue a float array in the CS_CIEXYZ color space. - * - * @return the float[] an array of transformed color - * components. + * @param colorvalue + * the float array representing a color in the CS_CIEXYZ color + * space. + * @return the float array with the transformed color components. */ public abstract float[] fromCIEXYZ(float[] colorvalue); /** - * Gets the minimum normalized color component value for - * the specified component. - * - * @param component the component. + * Gets the minimum normalized color component value for the specified + * component. * - * @return the miniimum normalized value of the component. + * @param component + * the component to determine the minimum value. + * @return the minimum normalized value of the component. */ public float getMinValue(int component) { if (component < 0 || component > numComponents - 1) { @@ -234,11 +310,11 @@ public abstract class ColorSpace implements Serializable { } /** - * Gets the maximum normalized color component value for - * the specified component. - * - * @param component the component. + * Gets the maximum normalized color component value for the specified + * component. * + * @param component + * the component to determine the maximum value. * @return the maximum normalized value of the component. */ public float getMaxValue(int component) { @@ -252,8 +328,7 @@ public abstract class ColorSpace implements Serializable { /** * Checks if this ColorSpace has CS_sRGB type or not. * - * @return true, if this ColorSpace has CS_sRGB type, - * false otherwise. + * @return true, if this ColorSpace has CS_sRGB type, false otherwise. */ public boolean isCS_sRGB() { // If our color space is sRGB, then cs_sRGB @@ -281,12 +356,11 @@ public abstract class ColorSpace implements Serializable { /** - * Gets the single instance of ColorSpace with the specified - * ColorSpace: CS_sRGB, CS_LINEAR_RGB, CS_CIEXYZ, CS_GRAY, - * or CS_PYCC. - * - * @param colorspace the identifier of the specified Colorspace. + * Gets the single instance of ColorSpace with the specified ColorSpace: + * CS_sRGB, CS_LINEAR_RGB, CS_CIEXYZ, CS_GRAY, or CS_PYCC. * + * @param colorspace + * the identifier of the specified Colorspace. * @return the single instance of the desired ColorSpace. */ public static ColorSpace getInstance(int colorspace) { diff --git a/awt/java/awt/color/ICC_ColorSpace.java b/awt/java/awt/color/ICC_ColorSpace.java index 5ece2efe1935ee9c66f44307dee39aaa906e5971..5b4d7e99f5cb1ec72879ee34d2575cda8048c54c 100644 --- a/awt/java/awt/color/ICC_ColorSpace.java +++ b/awt/java/awt/color/ICC_ColorSpace.java @@ -28,19 +28,24 @@ import org.apache.harmony.awt.internal.nls.Messages; import java.io.*; /** - * ICC_ColorSpace class implements ColorSpace abstract class and - * represents device independent and device dependent color spaces. - * This color space is based on the International Color Consortium - * Specification (ICC) File Format for Color Profiles: - * http://www.color.org + * This class implements the abstract class ColorSpace and represents device + * independent and device dependent color spaces. This color space is based on + * the International Color Consortium Specification (ICC) File Format for Color + * Profiles: http://www.color.org + * + * @since Android 1.0 */ public class ICC_ColorSpace extends ColorSpace { - /** The Constant serialVersionUID. */ + /** + * The Constant serialVersionUID. + */ private static final long serialVersionUID = 3455889114070431483L; // Need to keep compatibility with serialized form - /** The Constant serialPersistentFields. */ + /** + * The Constant serialPersistentFields. + */ private static final ObjectStreamField[] serialPersistentFields = { new ObjectStreamField("thisProfile", ICC_Profile.class), //$NON-NLS-1$ @@ -53,63 +58,94 @@ public class ICC_ColorSpace extends ColorSpace { /** - * According to ICC specification (from http://www.color.org) - * "For the CIEXYZ encoding, each component (X, Y, and Z) - * is encoded as a u1Fixed15Number". - * This means that max value for this encoding is 1 + (32767/32768) - */ + * According to ICC specification (from http://www.color.org) "For the + * CIEXYZ encoding, each component (X, Y, and Z) is encoded as a + * u1Fixed15Number". This means that max value for this encoding is 1 + + * (32767/32768) + */ private static final float MAX_XYZ = 1f + (32767f/32768f); - /** The Constant MAX_SHORT. */ + /** + * The Constant MAX_SHORT. + */ private static final float MAX_SHORT = 65535f; - /** The Constant INV_MAX_SHORT. */ + /** + * The Constant INV_MAX_SHORT. + */ private static final float INV_MAX_SHORT = 1f/MAX_SHORT; - /** The Constant SHORT2XYZ_FACTOR. */ + /** + * The Constant SHORT2XYZ_FACTOR. + */ private static final float SHORT2XYZ_FACTOR = MAX_XYZ/MAX_SHORT; - /** The Constant XYZ2SHORT_FACTOR. */ + /** + * The Constant XYZ2SHORT_FACTOR. + */ private static final float XYZ2SHORT_FACTOR = MAX_SHORT/MAX_XYZ; - /** The profile. */ + /** + * The profile. + */ private ICC_Profile profile = null; - /** The min values. */ + /** + * The min values. + */ private float minValues[] = null; - /** The max values. */ + /** + * The max values. + */ private float maxValues[] = null; // cache transforms here - performance gain - /** The to rgb transform. */ + /** + * The to rgb transform. + */ private ICC_Transform toRGBTransform = null; - /** The from rgb transform. */ + /** + * The from rgb transform. + */ private ICC_Transform fromRGBTransform = null; - /** The to xyz transform. */ + /** + * The to xyz transform. + */ private ICC_Transform toXYZTransform = null; - /** The from xyz transform. */ + /** + * The from xyz transform. + */ private ICC_Transform fromXYZTransform = null; - /** The converter. */ + /** + * The converter. + */ private final ColorConverter converter = new ColorConverter(); - /** The scaler. */ + /** + * The scaler. + */ private final ColorScaler scaler = new ColorScaler(); - /** The scaling data loaded. */ + /** + * The scaling data loaded. + */ private boolean scalingDataLoaded = false; - /** The resolved deserialized inst. */ + /** + * The resolved deserialized inst. + */ private ICC_ColorSpace resolvedDeserializedInst; /** * Instantiates a new ICC color space from an ICC_Profile object. * - * @param pf the ICC_Profile object. + * @param pf + * the ICC_Profile object. */ public ICC_ColorSpace(ICC_Profile pf) { super(pf.getColorSpaceType(), pf.getNumComponents()); @@ -132,7 +168,7 @@ public class ICC_ColorSpace extends ColorSpace { } /** - * Returns the ICC_Profile for this ICC_ColorSpace. + * Gets the ICC_Profile for this ICC_ColorSpace. * * @return the ICC_Profile for this ICC_ColorSpace. */ @@ -144,6 +180,14 @@ public class ICC_ColorSpace extends ColorSpace { return profile; } + /** + * Performs the transformation of a color from this ColorSpace into the RGB + * color space. + * + * @param colorvalue + * the color value in this ColorSpace. + * @return the float array with color components in the RGB color space. + */ @Override public float[] toRGB(float[] colorvalue) { if (toRGBTransform == null) { @@ -174,6 +218,15 @@ public class ICC_ColorSpace extends ColorSpace { return res; } + /** + * Performs the transformation of a color from this ColorSpace into the + * CS_CIEXYZ color space. + * + * @param colorvalue + * the color value in this ColorSpace. + * @return the float array with color components in the CS_CIEXYZ color + * space. + */ @Override public float[] toCIEXYZ(float[] colorvalue) { if (toXYZTransform == null) { @@ -212,6 +265,14 @@ public class ICC_ColorSpace extends ColorSpace { return res; } + /** + * Performs the transformation of a color from the RGB color space into this + * ColorSpace. + * + * @param rgbvalue + * the float array representing a color in the RGB color space. + * @return the float array with the transformed color components. + */ @Override public float[] fromRGB(float[] rgbvalue) { if (fromRGBTransform == null) { @@ -241,6 +302,15 @@ public class ICC_ColorSpace extends ColorSpace { return res; } + /** + * Performs the transformation of a color from the CS_CIEXYZ color space + * into this ColorSpace. + * + * @param xyzvalue + * the float array representing a color in the CS_CIEXYZ color + * space. + * @return the float array with the transformed color components. + */ @Override public float[] fromCIEXYZ(float[] xyzvalue) { if (fromXYZTransform == null) { @@ -279,6 +349,14 @@ public class ICC_ColorSpace extends ColorSpace { return res; } + /** + * Gets the minimum normalized color component value for the specified + * component. + * + * @param component + * the component to determine the minimum value. + * @return the minimum normalized value of the component. + */ @Override public float getMinValue(int component) { if ((component < 0) || (component > this.getNumComponents() - 1)) { @@ -289,6 +367,14 @@ public class ICC_ColorSpace extends ColorSpace { return minValues[component]; } + /** + * Gets the maximum normalized color component value for the specified + * component. + * + * @param component + * the component to determine the maximum value. + * @return the maximum normalized value of the component. + */ @Override public float getMaxValue(int component) { if ((component < 0) || (component > this.getNumComponents() - 1)) { @@ -334,9 +420,10 @@ public class ICC_ColorSpace extends ColorSpace { /** * Write object. * - * @param out the out - * - * @throws IOException Signals that an I/O exception has occurred. + * @param out + * the out + * @throws IOException + * Signals that an I/O exception has occurred. */ private void writeObject(ObjectOutputStream out) throws IOException { ObjectOutputStream.PutField fields = out.putFields(); @@ -354,10 +441,12 @@ public class ICC_ColorSpace extends ColorSpace { /** * Read object. * - * @param in the in - * - * @throws IOException Signals that an I/O exception has occurred. - * @throws ClassNotFoundException the class not found exception + * @param in + * the in + * @throws IOException + * Signals that an I/O exception has occurred. + * @throws ClassNotFoundException + * the class not found exception */ private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { ObjectInputStream.GetField fields = in.readFields(); @@ -369,8 +458,8 @@ public class ICC_ColorSpace extends ColorSpace { * Read resolve. * * @return the object - * - * @throws ObjectStreamException the object stream exception + * @throws ObjectStreamException + * the object stream exception */ Object readResolve() throws ObjectStreamException { return resolvedDeserializedInst; diff --git a/awt/java/awt/color/ICC_Profile.java b/awt/java/awt/color/ICC_Profile.java index ad704e05ea3789e6b70a113721aadcd686da5aa4..8ffee6c4b321877f65dee1e50d69a49892135524 100644 --- a/awt/java/awt/color/ICC_Profile.java +++ b/awt/java/awt/color/ICC_Profile.java @@ -18,6 +18,7 @@ * @author Oleg V. Khaschansky * @version $Revision$ */ + package java.awt.color; import java.io.File; @@ -40,427 +41,681 @@ import org.apache.harmony.awt.gl.color.NativeCMM; import org.apache.harmony.awt.internal.nls.Messages; /** - * The ICC_Profile class represents a color profile data for color spaces - * based on the International Color Consortium Specification ICC.1:2001-12, - * File Format for Color Profiles. + * The ICC_Profile class represents a color profile data for color spaces based + * on the International Color Consortium Specification ICC.1:2001-12, File + * Format for Color Profiles. + * + * @since Android 1.0 */ public class ICC_Profile implements Serializable { - /** The Constant serialVersionUID. */ + /** + * The Constant serialVersionUID. + */ private static final long serialVersionUID = -3938515861990936766L; // NOTE: Constant field values are noted in 1.5 specification. /** - * The Constant CLASS_INPUT indicates that profile class is input. + * The Constant CLASS_INPUT indicates that profile class is input. */ public static final int CLASS_INPUT = 0; - /** - * The Constant CLASS_DISPLAY indicates that profile class is display. + /** + * The Constant CLASS_DISPLAY indicates that profile class is display. */ public static final int CLASS_DISPLAY = 1; - /** - * The Constant CLASS_OUTPUT indicates that profile class is output. + /** + * The Constant CLASS_OUTPUT indicates that profile class is output. */ public static final int CLASS_OUTPUT = 2; - /** - * The Constant CLASS_DEVICELINK indicates that profile class - * is device link. + /** + * The Constant CLASS_DEVICELINK indicates that profile class is device + * link. */ public static final int CLASS_DEVICELINK = 3; - /** - * The Constant CLASS_COLORSPACECONVERSION indicates that profile class - * is color space conversion. + /** + * The Constant CLASS_COLORSPACECONVERSION indicates that profile class is + * color space conversion. */ public static final int CLASS_COLORSPACECONVERSION = 4; - /** The Constant CLASS_ABSTRACT indicates that profile class is abstract. */ + /** + * The Constant CLASS_ABSTRACT indicates that profile class is abstract. + */ public static final int CLASS_ABSTRACT = 5; - /** - * The Constant CLASS_NAMEDCOLOR indicates that profile class - * is named color. + /** + * The Constant CLASS_NAMEDCOLOR indicates that profile class is named + * color. */ public static final int CLASS_NAMEDCOLOR = 6; - /** The Constant icSigXYZData - ICC Profile Color Space Type Signature. */ + /** + * The Constant icSigXYZData - ICC Profile Color Space Type Signature. + */ public static final int icSigXYZData = 1482250784; - /** The Constant icSigLabData - ICC Profile Color Space Type Signature. */ + /** + * The Constant icSigLabData - ICC Profile Color Space Type Signature. + */ public static final int icSigLabData = 1281450528; - /** The Constant icSigLuvData - ICC Profile Color Space Type Signature. */ + /** + * The Constant icSigLuvData - ICC Profile Color Space Type Signature. + */ public static final int icSigLuvData = 1282766368; - /** The Constant icSigYCbCrData - ICC Profile Color Space Type Signature. */ + /** + * The Constant icSigYCbCrData - ICC Profile Color Space Type Signature. + */ public static final int icSigYCbCrData = 1497588338; - /** The Constant icSigYxyData - ICC Profile Color Space Type Signature. */ + /** + * The Constant icSigYxyData - ICC Profile Color Space Type Signature. + */ public static final int icSigYxyData = 1501067552; - /** The Constant icSigRgbData - ICC Profile Color Space Type Signature. */ + /** + * The Constant icSigRgbData - ICC Profile Color Space Type Signature. + */ public static final int icSigRgbData = 1380401696; - /** The Constant icSigGrayData - ICC Profile Color Space Type Signature. */ + /** + * The Constant icSigGrayData - ICC Profile Color Space Type Signature. + */ public static final int icSigGrayData = 1196573017; - /** The Constant icSigHsvData - ICC Profile Color Space Type Signature. */ + /** + * The Constant icSigHsvData - ICC Profile Color Space Type Signature. + */ public static final int icSigHsvData = 1213421088; - /** The Constant icSigHlsData - ICC Profile Color Space Type Signature. */ + /** + * The Constant icSigHlsData - ICC Profile Color Space Type Signature. + */ public static final int icSigHlsData = 1212961568; - /** The Constant icSigCmykData - ICC Profile Color Space Type Signature. */ + /** + * The Constant icSigCmykData - ICC Profile Color Space Type Signature. + */ public static final int icSigCmykData = 1129142603; - /** The Constant icSigCmyData - ICC Profile Color Space Type Signature. */ + /** + * The Constant icSigCmyData - ICC Profile Color Space Type Signature. + */ public static final int icSigCmyData = 1129142560; - /** The Constant icSigSpace2CLR - ICC Profile Color Space Type Signature. */ + /** + * The Constant icSigSpace2CLR - ICC Profile Color Space Type Signature. + */ public static final int icSigSpace2CLR = 843271250; - /** The Constant icSigSpace3CLR - ICC Profile Color Space Type Signature. */ + /** + * The Constant icSigSpace3CLR - ICC Profile Color Space Type Signature. + */ public static final int icSigSpace3CLR = 860048466; - /** The Constant icSigSpace4CLR - ICC Profile Color Space Type Signature. */ + /** + * The Constant icSigSpace4CLR - ICC Profile Color Space Type Signature. + */ public static final int icSigSpace4CLR = 876825682; - /** The Constant icSigSpace5CLR - ICC Profile Color Space Type Signature. */ + /** + * The Constant icSigSpace5CLR - ICC Profile Color Space Type Signature. + */ public static final int icSigSpace5CLR = 893602898; - /** The Constant icSigSpace6CLR - ICC Profile Color Space Type Signature. */ + /** + * The Constant icSigSpace6CLR - ICC Profile Color Space Type Signature. + */ public static final int icSigSpace6CLR = 910380114; - /** The Constant icSigSpace7CLR - ICC Profile Color Space Type Signature. */ + /** + * The Constant icSigSpace7CLR - ICC Profile Color Space Type Signature. + */ public static final int icSigSpace7CLR = 927157330; - /** The Constant icSigSpace8CLR - ICC Profile Color Space Type Signature. */ + /** + * The Constant icSigSpace8CLR - ICC Profile Color Space Type Signature. + */ public static final int icSigSpace8CLR = 943934546; - /** The Constant icSigSpace9CLR - ICC Profile Color Space Type Signature. */ + /** + * The Constant icSigSpace9CLR - ICC Profile Color Space Type Signature. + */ public static final int icSigSpace9CLR = 960711762; - /** The Constant icSigSpaceACLR - ICC Profile Color Space Type Signature. */ + /** + * The Constant icSigSpaceACLR - ICC Profile Color Space Type Signature. + */ public static final int icSigSpaceACLR = 1094929490; - /** The Constant icSigSpaceBCLR - ICC Profile Color Space Type Signature. */ + /** + * The Constant icSigSpaceBCLR - ICC Profile Color Space Type Signature. + */ public static final int icSigSpaceBCLR = 1111706706; - /** The Constant icSigSpaceCCLR - ICC Profile Color Space Type Signature. */ + /** + * The Constant icSigSpaceCCLR - ICC Profile Color Space Type Signature. + */ public static final int icSigSpaceCCLR = 1128483922; - /** The Constant icSigSpaceDCLR - ICC Profile Color Space Type Signature. */ + /** + * The Constant icSigSpaceDCLR - ICC Profile Color Space Type Signature. + */ public static final int icSigSpaceDCLR = 1145261138; - /** The Constant icSigSpaceECLR - ICC Profile Color Space Type Signature. */ + /** + * The Constant icSigSpaceECLR - ICC Profile Color Space Type Signature. + */ public static final int icSigSpaceECLR = 1162038354; - /** The Constant icSigSpaceFCLR - ICC Profile Color Space Type Signature. */ + /** + * The Constant icSigSpaceFCLR - ICC Profile Color Space Type Signature. + */ public static final int icSigSpaceFCLR = 1178815570; - /** The Constant icSigInputClass - ICC Profile Class Signature. */ + /** + * The Constant icSigInputClass - ICC Profile Class Signature. + */ public static final int icSigInputClass = 1935896178; - /** The Constant icSigDisplayClass - ICC Profile Class Signature. */ + /** + * The Constant icSigDisplayClass - ICC Profile Class Signature. + */ public static final int icSigDisplayClass = 1835955314; - /** The Constant icSigOutputClass - ICC Profile Class Signature. */ + /** + * The Constant icSigOutputClass - ICC Profile Class Signature. + */ public static final int icSigOutputClass = 1886549106; - /** The Constant icSigLinkClass - ICC Profile Class Signature. */ + /** + * The Constant icSigLinkClass - ICC Profile Class Signature. + */ public static final int icSigLinkClass = 1818848875; - /** The Constant icSigAbstractClass - ICC Profile Class Signature. */ + /** + * The Constant icSigAbstractClass - ICC Profile Class Signature. + */ public static final int icSigAbstractClass = 1633842036; - /** The Constant icSigColorantOrderTag - ICC Profile Tag Signature. */ + /** + * The Constant icSigColorantOrderTag - ICC Profile Tag Signature. + */ public static final int icSigColorantOrderTag = 1668051567; - /** The Constant icSigColorantTableTag - ICC Profile Tag Signature. */ + /** + * The Constant icSigColorantTableTag - ICC Profile Tag Signature. + */ public static final int icSigColorantTableTag = 1668051572; - /** The Constant icSigColorSpaceClass - ICC Profile Tag Signature. */ + /** + * The Constant icSigColorSpaceClass - ICC Profile Tag Signature. + */ public static final int icSigColorSpaceClass = 1936744803; - /** The Constant icSigNamedColorClass - ICC Profile Tag Signature. */ + /** + * The Constant icSigNamedColorClass - ICC Profile Tag Signature. + */ public static final int icSigNamedColorClass = 1852662636; - /** The Constant icPerceptual - ICC Profile Rendering Intent. */ + /** + * The Constant icPerceptual - ICC Profile Rendering Intent. + */ public static final int icPerceptual = 0; - /** The Constant icRelativeColorimetric - ICC Profile Rendering Intent. */ + /** + * The Constant icRelativeColorimetric - ICC Profile Rendering Intent. + */ public static final int icRelativeColorimetric = 1; - /** The Constant icSaturation - ICC Profile Rendering Intent. */ + /** + * The Constant icSaturation - ICC Profile Rendering Intent. + */ public static final int icSaturation = 2; - /** The Constant icAbsoluteColorimetric - ICC Profile Rendering Intent. */ + /** + * The Constant icAbsoluteColorimetric - ICC Profile Rendering Intent. + */ public static final int icAbsoluteColorimetric = 3; - /** The Constant icSigHead - ICC Profile Tag Signature. */ + /** + * The Constant icSigHead - ICC Profile Tag Signature. + */ public static final int icSigHead = 1751474532; - /** The Constant icSigAToB0Tag - ICC Profile Tag Signature. */ + /** + * The Constant icSigAToB0Tag - ICC Profile Tag Signature. + */ public static final int icSigAToB0Tag = 1093812784; - /** The Constant icSigAToB1Tag - ICC Profile Tag Signature. */ + /** + * The Constant icSigAToB1Tag - ICC Profile Tag Signature. + */ public static final int icSigAToB1Tag = 1093812785; - /** The Constant icSigAToB2Tag - ICC Profile Tag Signature. */ + /** + * The Constant icSigAToB2Tag - ICC Profile Tag Signature. + */ public static final int icSigAToB2Tag = 1093812786; - /** The Constant icSigBlueColorantTag - ICC Profile Tag Signature. */ + /** + * The Constant icSigBlueColorantTag - ICC Profile Tag Signature. + */ public static final int icSigBlueColorantTag = 1649957210; - /** The Constant icSigBlueMatrixColumnTag - ICC Profile Tag Signature. */ + /** + * The Constant icSigBlueMatrixColumnTag - ICC Profile Tag Signature. + */ public static final int icSigBlueMatrixColumnTag = 1649957210; - /** The Constant icSigBlueTRCTag - ICC Profile Tag Signature. */ + /** + * The Constant icSigBlueTRCTag - ICC Profile Tag Signature. + */ public static final int icSigBlueTRCTag = 1649693251; - /** The Constant icSigBToA0Tag - ICC Profile Tag Signature. */ + /** + * The Constant icSigBToA0Tag - ICC Profile Tag Signature. + */ public static final int icSigBToA0Tag = 1110589744; - /** The Constant icSigBToA1Tag - ICC Profile Tag Signature. */ + /** + * The Constant icSigBToA1Tag - ICC Profile Tag Signature. + */ public static final int icSigBToA1Tag = 1110589745; - /** The Constant icSigBToA2Tag - ICC Profile Tag Signature. */ + /** + * The Constant icSigBToA2Tag - ICC Profile Tag Signature. + */ public static final int icSigBToA2Tag = 1110589746; - /** The Constant icSigCalibrationDateTimeTag - ICC Profile Tag Signature. */ + /** + * The Constant icSigCalibrationDateTimeTag - ICC Profile Tag Signature. + */ public static final int icSigCalibrationDateTimeTag = 1667329140; - /** The Constant icSigCharTargetTag - ICC Profile Tag Signature. */ + /** + * The Constant icSigCharTargetTag - ICC Profile Tag Signature. + */ public static final int icSigCharTargetTag = 1952543335; - /** The Constant icSigCopyrightTag - ICC Profile Tag Signature. */ + /** + * The Constant icSigCopyrightTag - ICC Profile Tag Signature. + */ public static final int icSigCopyrightTag = 1668313716; - /** The Constant icSigCrdInfoTag - ICC Profile Tag Signature. */ + /** + * The Constant icSigCrdInfoTag - ICC Profile Tag Signature. + */ public static final int icSigCrdInfoTag = 1668441193; - /** The Constant icSigDeviceMfgDescTag - ICC Profile Tag Signature. */ + /** + * The Constant icSigDeviceMfgDescTag - ICC Profile Tag Signature. + */ public static final int icSigDeviceMfgDescTag = 1684893284; - /** The Constant icSigDeviceModelDescTag - ICC Profile Tag Signature. */ + /** + * The Constant icSigDeviceModelDescTag - ICC Profile Tag Signature. + */ public static final int icSigDeviceModelDescTag = 1684890724; - /** The Constant icSigDeviceSettingsTag - ICC Profile Tag Signature. */ + /** + * The Constant icSigDeviceSettingsTag - ICC Profile Tag Signature. + */ public static final int icSigDeviceSettingsTag = 1684371059; - /** The Constant icSigGamutTag - ICC Profile Tag Signature. */ + /** + * The Constant icSigGamutTag - ICC Profile Tag Signature. + */ public static final int icSigGamutTag = 1734438260; - /** The Constant icSigGrayTRCTag - ICC Profile Tag Signature. */ + /** + * The Constant icSigGrayTRCTag - ICC Profile Tag Signature. + */ public static final int icSigGrayTRCTag = 1800688195; - /** The Constant icSigGreenColorantTag - ICC Profile Tag Signature. */ + /** + * The Constant icSigGreenColorantTag - ICC Profile Tag Signature. + */ public static final int icSigGreenColorantTag = 1733843290; - /** The Constant icSigGreenMatrixColumnTag - ICC Profile Tag Signature. */ + /** + * The Constant icSigGreenMatrixColumnTag - ICC Profile Tag Signature. + */ public static final int icSigGreenMatrixColumnTag = 1733843290; - /** The Constant icSigGreenTRCTag - ICC Profile Tag Signature. */ + /** + * The Constant icSigGreenTRCTag - ICC Profile Tag Signature. + */ public static final int icSigGreenTRCTag = 1733579331; - /** The Constant icSigLuminanceTag - ICC Profile Tag Signature. */ + /** + * The Constant icSigLuminanceTag - ICC Profile Tag Signature. + */ public static final int icSigLuminanceTag = 1819635049; - /** The Constant icSigMeasurementTag - ICC Profile Tag Signature. */ + /** + * The Constant icSigMeasurementTag - ICC Profile Tag Signature. + */ public static final int icSigMeasurementTag = 1835360627; - /** The Constant icSigMediaBlackPointTag - ICC Profile Tag Signature. */ + /** + * The Constant icSigMediaBlackPointTag - ICC Profile Tag Signature. + */ public static final int icSigMediaBlackPointTag = 1651208308; - /** The Constant icSigMediaWhitePointTag - ICC Profile Tag Signature. */ + /** + * The Constant icSigMediaWhitePointTag - ICC Profile Tag Signature. + */ public static final int icSigMediaWhitePointTag = 2004119668; - /** The Constant icSigNamedColor2Tag - ICC Profile Tag Signature. */ + /** + * The Constant icSigNamedColor2Tag - ICC Profile Tag Signature. + */ public static final int icSigNamedColor2Tag = 1852009522; - /** The Constant icSigOutputResponseTag - ICC Profile Tag Signature. */ + /** + * The Constant icSigOutputResponseTag - ICC Profile Tag Signature. + */ public static final int icSigOutputResponseTag = 1919251312; - /** The Constant icSigPreview0Tag - ICC Profile Tag Signature. */ + /** + * The Constant icSigPreview0Tag - ICC Profile Tag Signature. + */ public static final int icSigPreview0Tag = 1886545200; - /** The Constant icSigPreview1Tag - ICC Profile Tag Signature. */ + /** + * The Constant icSigPreview1Tag - ICC Profile Tag Signature. + */ public static final int icSigPreview1Tag = 1886545201; - /** The Constant icSigPreview2Tag - ICC Profile Tag Signature. */ + /** + * The Constant icSigPreview2Tag - ICC Profile Tag Signature. + */ public static final int icSigPreview2Tag = 1886545202; - /** The Constant icSigProfileDescriptionTag - ICC Profile Tag Signature. */ + /** + * The Constant icSigProfileDescriptionTag - ICC Profile Tag Signature. + */ public static final int icSigProfileDescriptionTag = 1684370275; - /** The Constant icSigProfileSequenceDescTag - ICC Profile Tag Signature. */ + /** + * The Constant icSigProfileSequenceDescTag - ICC Profile Tag Signature. + */ public static final int icSigProfileSequenceDescTag = 1886610801; - /** The Constant icSigPs2CRD0Tag - ICC Profile Tag Signature. */ + /** + * The Constant icSigPs2CRD0Tag - ICC Profile Tag Signature. + */ public static final int icSigPs2CRD0Tag = 1886610480; - /** The Constant icSigPs2CRD1Tag - ICC Profile Tag Signature. */ + /** + * The Constant icSigPs2CRD1Tag - ICC Profile Tag Signature. + */ public static final int icSigPs2CRD1Tag = 1886610481; - /** The Constant icSigPs2CRD2Tag - ICC Profile Tag Signature. */ + /** + * The Constant icSigPs2CRD2Tag - ICC Profile Tag Signature. + */ public static final int icSigPs2CRD2Tag = 1886610482; - /** The Constant icSigPs2CRD3Tag - ICC Profile Tag Signature. */ + /** + * The Constant icSigPs2CRD3Tag - ICC Profile Tag Signature. + */ public static final int icSigPs2CRD3Tag = 1886610483; - /** The Constant icSigPs2CSATag - ICC Profile Tag Signature. */ + /** + * The Constant icSigPs2CSATag - ICC Profile Tag Signature. + */ public static final int icSigPs2CSATag = 1886597747; - /** The Constant icSigPs2RenderingIntentTag - ICC Profile Tag Signature. */ + /** + * The Constant icSigPs2RenderingIntentTag - ICC Profile Tag Signature. + */ public static final int icSigPs2RenderingIntentTag = 1886597737; - /** The Constant icSigRedColorantTag - ICC Profile Tag Signature. */ + /** + * The Constant icSigRedColorantTag - ICC Profile Tag Signature. + */ public static final int icSigRedColorantTag = 1918392666; - /** The Constant icSigRedMatrixColumnTag - ICC Profile Tag Signature. */ + /** + * The Constant icSigRedMatrixColumnTag - ICC Profile Tag Signature. + */ public static final int icSigRedMatrixColumnTag = 1918392666; - /** The Constant icSigRedTRCTag - ICC Profile Tag Signature. */ + /** + * The Constant icSigRedTRCTag - ICC Profile Tag Signature. + */ public static final int icSigRedTRCTag = 1918128707; - /** The Constant icSigScreeningDescTag - ICC Profile Tag Signature. */ + /** + * The Constant icSigScreeningDescTag - ICC Profile Tag Signature. + */ public static final int icSigScreeningDescTag = 1935897188; - /** The Constant icSigScreeningTag - ICC Profile Tag Signature. */ + /** + * The Constant icSigScreeningTag - ICC Profile Tag Signature. + */ public static final int icSigScreeningTag = 1935897198; - /** The Constant icSigTechnologyTag - ICC Profile Tag Signature. */ + /** + * The Constant icSigTechnologyTag - ICC Profile Tag Signature. + */ public static final int icSigTechnologyTag = 1952801640; - /** The Constant icSigUcrBgTag - ICC Profile Tag Signature. */ + /** + * The Constant icSigUcrBgTag - ICC Profile Tag Signature. + */ public static final int icSigUcrBgTag = 1650877472; - /** The Constant icSigViewingCondDescTag - ICC Profile Tag Signature. */ + /** + * The Constant icSigViewingCondDescTag - ICC Profile Tag Signature. + */ public static final int icSigViewingCondDescTag = 1987405156; - /** The Constant icSigViewingConditionsTag - ICC Profile Tag Signature. */ + /** + * The Constant icSigViewingConditionsTag - ICC Profile Tag Signature. + */ public static final int icSigViewingConditionsTag = 1986618743; - /** The Constant icSigChromaticAdaptationTag - ICC Profile Tag Signature. */ + /** + * The Constant icSigChromaticAdaptationTag - ICC Profile Tag Signature. + */ public static final int icSigChromaticAdaptationTag = 1667785060; - /** The Constant icSigChromaticityTag - ICC Profile Tag Signature. */ + /** + * The Constant icSigChromaticityTag - ICC Profile Tag Signature. + */ public static final int icSigChromaticityTag = 1667789421; - /** The Constant icHdrSize - ICC Profile Header Location. */ + /** + * The Constant icHdrSize - ICC Profile Header Location. + */ public static final int icHdrSize = 0; - /** The Constant icHdrCmmId - ICC Profile Header Location. */ + /** + * The Constant icHdrCmmId - ICC Profile Header Location. + */ public static final int icHdrCmmId = 4; - /** The Constant icHdrVersion - ICC Profile Header Location. */ + /** + * The Constant icHdrVersion - ICC Profile Header Location. + */ public static final int icHdrVersion = 8; - /** The Constant icHdrDeviceClass - ICC Profile Header Location. */ + /** + * The Constant icHdrDeviceClass - ICC Profile Header Location. + */ public static final int icHdrDeviceClass = 12; - /** The Constant icHdrColorSpace - ICC Profile Header Location. */ + /** + * The Constant icHdrColorSpace - ICC Profile Header Location. + */ public static final int icHdrColorSpace = 16; - /** The Constant icHdrPcs - ICC Profile Header Location. */ + /** + * The Constant icHdrPcs - ICC Profile Header Location. + */ public static final int icHdrPcs = 20; - /** The Constant icHdrDate - ICC Profile Header Location. */ + /** + * The Constant icHdrDate - ICC Profile Header Location. + */ public static final int icHdrDate = 24; - /** The Constant icHdrMagic - ICC Profile Header Location. */ + /** + * The Constant icHdrMagic - ICC Profile Header Location. + */ public static final int icHdrMagic = 36; - /** The Constant icHdrPlatform - ICC Profile Header Location. */ + /** + * The Constant icHdrPlatform - ICC Profile Header Location. + */ public static final int icHdrPlatform = 40; - /** The Constant icHdrProfileID - ICC Profile Header Location. */ + /** + * The Constant icHdrProfileID - ICC Profile Header Location. + */ public static final int icHdrProfileID = 84; - /** The Constant icHdrFlags - ICC Profile Header Location. */ + /** + * The Constant icHdrFlags - ICC Profile Header Location. + */ public static final int icHdrFlags = 44; - /** The Constant icHdrManufacturer - ICC Profile Header Location. */ + /** + * The Constant icHdrManufacturer - ICC Profile Header Location. + */ public static final int icHdrManufacturer = 48; - /** The Constant icHdrModel - ICC Profile Header Location. */ + /** + * The Constant icHdrModel - ICC Profile Header Location. + */ public static final int icHdrModel = 52; - /** The Constant icHdrAttributes - ICC Profile Header Location. */ + /** + * The Constant icHdrAttributes - ICC Profile Header Location. + */ public static final int icHdrAttributes = 56; - /** The Constant icHdrRenderingIntent - ICC Profile Header Location. */ + /** + * The Constant icHdrRenderingIntent - ICC Profile Header Location. + */ public static final int icHdrRenderingIntent = 64; - /** The Constant icHdrIlluminant - ICC Profile Header Location. */ + /** + * The Constant icHdrIlluminant - ICC Profile Header Location. + */ public static final int icHdrIlluminant = 68; - /** The Constant icHdrCreator - ICC Profile Header Location. */ + /** + * The Constant icHdrCreator - ICC Profile Header Location. + */ public static final int icHdrCreator = 80; - /** The Constant icICCAbsoluteColorimetric - ICC Profile Rendering Intent. */ + /** + * The Constant icICCAbsoluteColorimetric - ICC Profile Rendering Intent. + */ public static final int icICCAbsoluteColorimetric = 3; - /** The Constant icMediaRelativeColorimetric - ICC Profile Rendering Intent. */ + /** + * The Constant icMediaRelativeColorimetric - ICC Profile Rendering Intent. + */ public static final int icMediaRelativeColorimetric = 1; - /** The Constant icTagType - ICC Profile Constant. */ + /** + * The Constant icTagType - ICC Profile Constant. + */ public static final int icTagType = 0; - /** The Constant icTagReserved - ICC Profile Constant. */ + /** + * The Constant icTagReserved - ICC Profile Constant. + */ public static final int icTagReserved = 4; - /** The Constant icCurveCount - ICC Profile Constant. */ + /** + * The Constant icCurveCount - ICC Profile Constant. + */ public static final int icCurveCount = 8; - /** The Constant icCurveData - ICC Profile Constant. */ + /** + * The Constant icCurveData - ICC Profile Constant. + */ public static final int icCurveData = 12; - /** The Constant icXYZNumberX - ICC Profile Constant. */ + /** + * The Constant icXYZNumberX - ICC Profile Constant. + */ public static final int icXYZNumberX = 8; - /** Size of a profile header. */ + /** + * Size of a profile header. + */ private static final int headerSize = 128; - /** header magic number. */ + /** + * header magic number. + */ private static final int headerMagicNumber = 0x61637370; // Cache of predefined profiles - /** The s rgb profile. */ + /** + * The s rgb profile. + */ private static ICC_Profile sRGBProfile; - - /** The xyz profile. */ + + /** + * The xyz profile. + */ private static ICC_Profile xyzProfile; - - /** The gray profile. */ + + /** + * The gray profile. + */ private static ICC_Profile grayProfile; - - /** The pycc profile. */ + + /** + * The pycc profile. + */ private static ICC_Profile pyccProfile; - - /** The linear rgb profile. */ + + /** + * The linear rgb profile. + */ private static ICC_Profile linearRGBProfile; - /** Handle to the current profile. */ + /** + * Handle to the current profile. + */ private transient long profileHandle = 0; - /** If handle is used by another class this object is not responsible for closing profile. */ + /** + * If handle is used by another class this object is not responsible for + * closing profile. + */ private transient boolean handleStolen = false; - /** Cached header data. */ + /** + * Cached header data. + */ private transient byte[] headerData = null; - /** Serialization support. */ + /** + * Serialization support. + */ private transient ICC_Profile openedProfileObject; /** - * Instantiates a new iC c_ profile. + * Instantiates a new ICC profile with the given data. * - * @param data the data + * @param data + * the data. */ private ICC_Profile(byte[] data) { profileHandle = NativeCMM.cmmOpenProfile(data); @@ -476,7 +731,8 @@ public class ICC_Profile implements Serializable { /** * Used to instantiate subclasses (ICC_ProfileGrey and ICC_ProfileRGB). * - * @param profileHandle - should be valid handle to opened color profile + * @param profileHandle + * - should be valid handle to opened color profile */ ICC_Profile(long profileHandle) { this.profileHandle = profileHandle; @@ -487,10 +743,11 @@ public class ICC_Profile implements Serializable { /** * Writes the ICC_Profile to a file with the specified name. * - * @param fileName the file name. - * - * @throws IOException signals that an I/O exception has occurred during - * writing or opening the file. + * @param fileName + * the file name. + * @throws IOException + * if an I/O exception has occurred during writing or opening + * the file. */ public void write(String fileName) throws IOException { FileOutputStream oStream = new FileOutputStream(fileName); @@ -501,9 +758,10 @@ public class ICC_Profile implements Serializable { /** * Serializable implementation. * - * @param s the s - * - * @throws IOException Signals that an I/O exception has occurred. + * @param s + * the s + * @throws IOException + * Signals that an I/O exception has occurred. */ private void writeObject(ObjectOutputStream s) throws IOException { s.defaultWriteObject(); @@ -514,10 +772,12 @@ public class ICC_Profile implements Serializable { /** * Serializable implementation. * - * @param s the s - * - * @throws IOException Signals that an I/O exception has occurred. - * @throws ClassNotFoundException the class not found exception + * @param s + * the s + * @throws IOException + * Signals that an I/O exception has occurred. + * @throws ClassNotFoundException + * the class not found exception */ private void readObject(ObjectInputStream s) throws IOException, ClassNotFoundException { s.defaultReadObject(); @@ -547,9 +807,9 @@ public class ICC_Profile implements Serializable { * Resolves instances being deserialized into instances registered with CMM. * * @return ICC_Profile object for profile registered with CMM. - * - * @throws ObjectStreamException if there is an error in the serialized - * files or during the process of reading them. + * @throws ObjectStreamException + * if there is an error in the serialized files or during the + * process of reading them. */ protected Object readResolve() throws ObjectStreamException { return openedProfileObject; @@ -558,20 +818,23 @@ public class ICC_Profile implements Serializable { /** * Writes the ICC_Profile to an OutputStream. * - * @param s the OutputStream. - * - * @throws IOException signals that an I/O exception has occurred during - * writing or opening OutputStream. + * @param s + * the OutputStream. + * @throws IOException + * signals that an I/O exception has occurred during writing or + * opening OutputStream. */ public void write(OutputStream s) throws IOException { s.write(getData()); } /** - * Sets a tagged data element in the profile from a byte array. + * Sets a tagged data element in the profile from a byte array. * - * @param tagSignature the ICC tag signature for the data element to be set. - * @param tagData the data to be set for the specified tag signature. + * @param tagSignature + * the ICC tag signature for the data element to be set. + * @param tagData + * the data to be set for the specified tag signature. */ public void setData(int tagSignature, byte[] tagData) { NativeCMM.cmmSetProfileElement(profileHandle, tagSignature, tagData); @@ -582,21 +845,17 @@ public class ICC_Profile implements Serializable { } /** - * Gets a tagged data element from the profile as a byte array. - * Elements are identified by tag signatures as defined in - * the ICC specification. - * - * @param tagSignature the ICC tag signature for the data element to get. + * Gets a tagged data element from the profile as a byte array. Elements are + * identified by tag signatures as defined in the ICC specification. * + * @param tagSignature + * the ICC tag signature for the data element to get. * @return a byte array that contains the tagged data element. */ public byte[] getData(int tagSignature) { int tagSize = 0; try { - tagSize = NativeCMM.cmmGetProfileElementSize( - profileHandle, - tagSignature - ); + tagSize = NativeCMM.cmmGetProfileElementSize(profileHandle, tagSignature); } catch (CMMException e) { // We'll get this exception if there's no element with // the specified tag signature @@ -625,7 +884,7 @@ public class ICC_Profile implements Serializable { */ @Override protected void finalize() { - if (profileHandle!=0 && !handleStolen) { + if (profileHandle != 0 && !handleStolen) { NativeCMM.cmmCloseProfile(profileHandle); } @@ -663,16 +922,16 @@ public class ICC_Profile implements Serializable { // Not an ICC profile class // awt.15F=Profile class does not comply with ICC specification throw new IllegalArgumentException(Messages.getString("awt.15F")); //$NON-NLS-1$ - + } /** - * Returns the color space type of the Profile Connection Space (PCS). + * Gets the color space type of the Profile Connection Space (PCS). * * @return the PCS type. */ public int getPCSType() { - return csFromSignature(getIntFromHeader(icHdrPcs)); + return csFromSignature(getIntFromHeader(icHdrPcs)); } /** @@ -740,7 +999,7 @@ public class ICC_Profile implements Serializable { * @return the minor version of this ICC profile. */ public int getMinorVersion() { - return getByteFromHeader(icHdrVersion+1); + return getByteFromHeader(icHdrVersion + 1); } /** @@ -762,13 +1021,14 @@ public class ICC_Profile implements Serializable { } /** - * Tries to open file at the specified path. Path entries can be - * divided by a separator character. + * Tries to open the file at the specified path. Path entries can be divided + * by a separator character. * - * @param path the path - * @param fileName the file name - * - * @return the file input stream + * @param path + * the path to the file. + * @param fileName + * the file name. + * @return the input stream to read the file. */ private static FileInputStream tryPath(String path, String fileName) { FileInputStream fiStream = null; @@ -786,7 +1046,8 @@ public class ICC_Profile implements Serializable { if (fiStream != null) { return fiStream; } - } catch (FileNotFoundException e) {} + } catch (FileNotFoundException e) { + } } return fiStream; @@ -795,18 +1056,18 @@ public class ICC_Profile implements Serializable { /** * Gets the single instance of ICC_Profile from data in the specified file. * - * @param fileName the specified name of file with ICC profile data. - * + * @param fileName + * the specified name of file with ICC profile data. * @return single instance of ICC_Profile. - * - * @throws IOException signals that an I/O error occured while reading the file - * or the file doesn't exist. + * @throws IOException + * signals that an I/O error occurred while reading the file or + * the file does not exist. */ public static ICC_Profile getInstance(String fileName) throws IOException { final String fName = fileName; // to use in the privileged block - FileInputStream fiStream = (FileInputStream) AccessController.doPrivileged( - new PrivilegedAction() { + FileInputStream fiStream = (FileInputStream)AccessController + .doPrivileged(new PrivilegedAction() { public FileInputStream run() { FileInputStream fiStream = null; @@ -816,7 +1077,8 @@ public class ICC_Profile implements Serializable { if (fiStream != null) { return fiStream; } - } catch (FileNotFoundException e) {} + } catch (FileNotFoundException e) { + } // Check java.iccprofile.path entries fiStream = tryPath(System.getProperty("java.iccprofile.path"), fName); //$NON-NLS-1$ @@ -833,9 +1095,8 @@ public class ICC_Profile implements Serializable { // Check directory with java sample profiles String home = System.getProperty("java.home"); //$NON-NLS-1$ if (home != null) { - fiStream = tryPath( - home + File.separatorChar + - "lib" + File.separatorChar + "cmm", fName //$NON-NLS-1$ //$NON-NLS-2$ + fiStream = tryPath(home + File.separatorChar + + "lib" + File.separatorChar + "cmm", fName //$NON-NLS-1$ //$NON-NLS-2$ ); } @@ -854,17 +1115,17 @@ public class ICC_Profile implements Serializable { } /** - * Gets the single instance of ICC_Profile with data in - * the specified InputStream. - * - * @param s the InputStream with ICC profile data. + * Gets the single instance of ICC_Profile with data in the specified + * InputStream. * + * @param s + * the InputStream with ICC profile data. * @return single instance of ICC_Profile. - * - * @throws IOException if an I/O exception has occurred during reading - * from InputStream. - * @throws IllegalArgumentException if the file does not contain valid - * ICC Profile data. + * @throws IOException + * if an I/O exception has occurred during reading from + * InputStream. + * @throws IllegalArgumentException + * if the file does not contain valid ICC Profile data. */ public static ICC_Profile getInstance(InputStream s) throws IOException { byte[] header = new byte[headerSize]; @@ -877,10 +1138,7 @@ public class ICC_Profile implements Serializable { } // Check the profile data for consistency - if ( - ICC_ProfileHelper.getBigEndianFromByteArray(header, icHdrMagic) != - headerMagicNumber - ) { + if (ICC_ProfileHelper.getBigEndianFromByteArray(header, icHdrMagic) != headerMagicNumber) { throw new IllegalArgumentException(invalidDataMessage); } @@ -892,10 +1150,7 @@ public class ICC_Profile implements Serializable { System.arraycopy(header, 0, profileData, 0, headerSize); // Read the profile itself - if ( - s.read(profileData, headerSize, profileSize - headerSize) != - profileSize - headerSize - ) { + if (s.read(profileData, headerSize, profileSize - headerSize) != profileSize - headerSize) { throw new IllegalArgumentException(invalidDataMessage); } @@ -903,16 +1158,15 @@ public class ICC_Profile implements Serializable { } /** - * Gets the single instance of ICC_Profile from the specified data in - * a byte array. + * Gets the single instance of ICC_Profile from the specified data in a byte + * array. * - * @param data the byte array of ICC profile. - * - * @return single instance of ICC_Profile from the specified data in - * a byte array. - * - * @throws IllegalArgumentException if the file does not contain valid - * ICC Profile data. + * @param data + * the byte array of ICC profile. + * @return single instance of ICC_Profile from the specified data in a byte + * array. + * @throws IllegalArgumentException + * if the file does not contain valid ICC Profile data. */ public static ICC_Profile getInstance(byte[] data) { ICC_Profile res = null; @@ -924,29 +1178,28 @@ public class ICC_Profile implements Serializable { throw new IllegalArgumentException(Messages.getString("awt.162")); //$NON-NLS-1$ } - if (System.getProperty("os.name").toLowerCase().indexOf("windows") >= 0) { //$NON-NLS-1$ //$NON-NLS-2$ - try { - if ( res.getColorSpaceType () == ColorSpace.TYPE_RGB && - res.getDataSize(icSigMediaWhitePointTag) > 0 && - res.getDataSize(icSigRedColorantTag) > 0 && - res.getDataSize(icSigGreenColorantTag) > 0 && - res.getDataSize(icSigBlueColorantTag) > 0 && - res.getDataSize(icSigRedTRCTag) > 0 && - res.getDataSize(icSigGreenTRCTag) > 0 && - res.getDataSize(icSigBlueTRCTag) > 0 - ) { - res = new ICC_ProfileRGB(res.getProfileHandle()); - } else if ( res.getColorSpaceType () == ColorSpace.TYPE_GRAY && - res.getDataSize(icSigMediaWhitePointTag) > 0 && - res.getDataSize(icSigGrayTRCTag) > 0 - ) { - res = new ICC_ProfileGray (res.getProfileHandle()); - } + if (System.getProperty("os.name").toLowerCase().indexOf("windows") >= 0) { //$NON-NLS-1$ //$NON-NLS-2$ + try { + if (res.getColorSpaceType() == ColorSpace.TYPE_RGB + && res.getDataSize(icSigMediaWhitePointTag) > 0 + && res.getDataSize(icSigRedColorantTag) > 0 + && res.getDataSize(icSigGreenColorantTag) > 0 + && res.getDataSize(icSigBlueColorantTag) > 0 + && res.getDataSize(icSigRedTRCTag) > 0 + && res.getDataSize(icSigGreenTRCTag) > 0 + && res.getDataSize(icSigBlueTRCTag) > 0) { + res = new ICC_ProfileRGB(res.getProfileHandle()); + } else if (res.getColorSpaceType() == ColorSpace.TYPE_GRAY + && res.getDataSize(icSigMediaWhitePointTag) > 0 + && res.getDataSize(icSigGrayTRCTag) > 0) { + res = new ICC_ProfileGray(res.getProfileHandle()); + } - } catch (CMMException e) { /* return res in this case */ } - } + } catch (CMMException e) { /* return res in this case */ + } + } - return res; + return res; } /** @@ -954,80 +1207,77 @@ public class ICC_Profile implements Serializable { * defined by the ColorSpace class: CS_sRGB, CS_LINEAR_RGB, CS_CIEXYZ, * CS_PYCC, CS_GRAY. * - * @param cspace the type of color space defined in the ColorSpace class. - * + * @param cspace + * the type of color space defined in the ColorSpace class. * @return single instance of ICC_Profile. - * - * @throws IllegalArgumentException is not one of the defined color - * space types. + * @throws IllegalArgumentException + * is not one of the defined color space types. */ public static ICC_Profile getInstance(int cspace) { - try { - switch (cspace) { + try { + switch (cspace) { - case ColorSpace.CS_sRGB: - if (sRGBProfile == null) { - sRGBProfile = getInstance("sRGB.pf"); //$NON-NLS-1$ - } - return sRGBProfile; + case ColorSpace.CS_sRGB: + if (sRGBProfile == null) { + sRGBProfile = getInstance("sRGB.pf"); //$NON-NLS-1$ + } + return sRGBProfile; - case ColorSpace.CS_CIEXYZ: - if (xyzProfile == null) { - xyzProfile = getInstance("CIEXYZ.pf"); //$NON-NLS-1$ - } - return xyzProfile; + case ColorSpace.CS_CIEXYZ: + if (xyzProfile == null) { + xyzProfile = getInstance("CIEXYZ.pf"); //$NON-NLS-1$ + } + return xyzProfile; - case ColorSpace.CS_GRAY: - if (grayProfile == null) { - grayProfile = getInstance("GRAY.pf"); //$NON-NLS-1$ - } - return grayProfile; + case ColorSpace.CS_GRAY: + if (grayProfile == null) { + grayProfile = getInstance("GRAY.pf"); //$NON-NLS-1$ + } + return grayProfile; - case ColorSpace.CS_PYCC: - if (pyccProfile == null) { - pyccProfile = getInstance("PYCC.pf"); //$NON-NLS-1$ - } - return pyccProfile; + case ColorSpace.CS_PYCC: + if (pyccProfile == null) { + pyccProfile = getInstance("PYCC.pf"); //$NON-NLS-1$ + } + return pyccProfile; - case ColorSpace.CS_LINEAR_RGB: - if (linearRGBProfile == null) { - linearRGBProfile = getInstance("LINEAR_RGB.pf"); //$NON-NLS-1$ + case ColorSpace.CS_LINEAR_RGB: + if (linearRGBProfile == null) { + linearRGBProfile = getInstance("LINEAR_RGB.pf"); //$NON-NLS-1$ + } + return linearRGBProfile; + } + + } catch (IOException e) { + // awt.163=Can't open color profile + throw new IllegalArgumentException(Messages.getString("Can't open color profile")); //$NON-NLS-1$ } - return linearRGBProfile; - } - } catch (IOException e) { - // awt.163=Can't open color profile - throw new IllegalArgumentException(Messages.getString("Can't open color profile")); //$NON-NLS-1$ + // awt.164=Not a predefined color space + throw new IllegalArgumentException(Messages.getString("Not a predefined color space")); //$NON-NLS-1$ } - // awt.164=Not a predefined color space - throw new IllegalArgumentException(Messages.getString("Not a predefined color space")); //$NON-NLS-1$ - } - /** * Reads an integer from the profile header at the specified position. * - * @param idx - offset in bytes from the beginning of the header - * - * @return the int from header + * @param idx + * - offset in bytes from the beginning of the header + * @return the integer value from header */ private int getIntFromHeader(int idx) { if (headerData == null) { headerData = getData(icSigHead); } - return ((headerData[idx] & 0xFF) << 24)| - ((headerData[idx+1] & 0xFF) << 16)| - ((headerData[idx+2] & 0xFF) << 8) | - ((headerData[idx+3] & 0xFF)); + return ((headerData[idx] & 0xFF) << 24) | ((headerData[idx + 1] & 0xFF) << 16) + | ((headerData[idx + 2] & 0xFF) << 8) | ((headerData[idx + 3] & 0xFF)); } /** * Reads byte from the profile header at the specified position. * - * @param idx - offset in bytes from the beginning of the header - * + * @param idx + * - offset in bytes from the beginning of the header * @return the byte from header */ private byte getByteFromHeader(int idx) { @@ -1039,11 +1289,11 @@ public class ICC_Profile implements Serializable { } /** - * Converts ICC color space signature to the java predefined - * color space type. - * - * @param signature the signature + * Converts ICC color space signature to the java predefined color space + * type. * + * @param signature + * the signature * @return the int */ private int csFromSignature(int signature) { @@ -1102,7 +1352,7 @@ public class ICC_Profile implements Serializable { } // awt.165=Color space doesn't comply with ICC specification - throw new IllegalArgumentException (Messages.getString("awt.165")); //$NON-NLS-1$ + throw new IllegalArgumentException(Messages.getString("awt.165")); //$NON-NLS-1$ } /** @@ -1118,22 +1368,19 @@ public class ICC_Profile implements Serializable { /** * Gets the data size. * - * @param tagSignature the tag signature - * + * @param tagSignature + * the tag signature * @return the data size */ private int getDataSize(int tagSignature) { - return NativeCMM.cmmGetProfileElementSize( - profileHandle, - tagSignature - ); + return NativeCMM.cmmGetProfileElementSize(profileHandle, tagSignature); } /** * Reads XYZ value from the tag data. * - * @param tagSignature the tag signature - * + * @param tagSignature + * the tag signature * @return the XYZ value */ float[] getXYZValue(int tagSignature) { @@ -1153,20 +1400,20 @@ public class ICC_Profile implements Serializable { /** * Gets the media white point. * - * @return the media white point + * @return the media white point. */ float[] getMediaWhitePoint() { return getXYZValue(icSigMediaWhitePointTag); } /** - * If TRC is not a table returns gamma via return value - * and sets dataTRC to null. If TRC is a table returns 0 - * and fills dataTRC with values. - * - * @param tagSignature the tag signature - * @param dataTRC the data trc + * If TRC is not a table returns gamma via return value and sets dataTRC to + * null. If TRC is a table returns 0 and fills dataTRC with values. * + * @param tagSignature + * the tag signature + * @param dataTRC + * the data trc * @return - gamma or zero if TRC is a table */ private float getGammaOrTRC(int tagSignature, short[] dataTRC) { @@ -1195,8 +1442,8 @@ public class ICC_Profile implements Serializable { /** * Gets the gamma. * - * @param tagSignature the tag signature - * + * @param tagSignature + * the tag signature * @return the gamma */ float getGamma(int tagSignature) { @@ -1211,10 +1458,10 @@ public class ICC_Profile implements Serializable { } /** - * Gets the tRC. - * - * @param tagSignature the tag signature + * Gets the TRC. * + * @param tagSignature + * the tag signature * @return the tRC */ short[] getTRC(int tagSignature) { @@ -1228,4 +1475,3 @@ public class ICC_Profile implements Serializable { return dataTRC; } } - diff --git a/awt/java/awt/color/ICC_ProfileGray.java b/awt/java/awt/color/ICC_ProfileGray.java index f009b18fcd1ad9d52aca74df204d1e1e9bcf348b..f74810174298a0d347c54bbcc7502cf09beb1f5c 100644 --- a/awt/java/awt/color/ICC_ProfileGray.java +++ b/awt/java/awt/color/ICC_ProfileGray.java @@ -22,21 +22,26 @@ package java.awt.color; /** * The ICC_ProfileGray class represent profiles with TYPE_GRAY color space type, - * and includes the grayTRCTag and mediaWhitePointTag tags. + * and includes the grayTRCTag and mediaWhitePointTag tags. The gray component + * can be transformed from a GRAY device profile color space to the CIEXYZ + * Profile through the tone reproduction curve (TRC): + *

    + * PCSY = grayTRC[deviceGray] * - * The gray component can be transformed from a GRAY device profile color space - * to the CIEXYZ Profile through the tone reproduction curve (TRC): - *

    PCSY = grayTRC[deviceGray] + * @since Android 1.0 */ public class ICC_ProfileGray extends ICC_Profile { - /** The Constant serialVersionUID. */ + /** + * The Constant serialVersionUID. + */ private static final long serialVersionUID = -1124721290732002649L; /** * Instantiates a new iC c_ profile gray. * - * @param profileHandle the profile handle + * @param profileHandle + * the profile handle */ ICC_ProfileGray(long profileHandle) { super(profileHandle); @@ -45,12 +50,17 @@ public class ICC_ProfileGray extends ICC_Profile { /** * Gets the TRC as an array of shorts. * - * @return a short array of the TRC. + * @return the short array of the TRC. */ public short[] getTRC() { return super.getTRC(icSigGrayTRCTag); } + /** + * Gets the media white point. + * + * @return the media white point + */ @Override public float[] getMediaWhitePoint() { return super.getMediaWhitePoint(); diff --git a/awt/java/awt/color/ICC_ProfileRGB.java b/awt/java/awt/color/ICC_ProfileRGB.java index beb1a0c24b44d3747d062037dfc85a6e4cd9846d..9c6010fcde63c2114dd50d014df8f11ef5a20f3f 100644 --- a/awt/java/awt/color/ICC_ProfileRGB.java +++ b/awt/java/awt/color/ICC_ProfileRGB.java @@ -23,38 +23,58 @@ package java.awt.color; import org.apache.harmony.awt.internal.nls.Messages; /** - * The ICC_ProfileRGB class represents profiles with RGB color space type and - * contains the redColorantTag, greenColorantTag, blueColorantTag, redTRCTag, + * The ICC_ProfileRGB class represents profiles with RGB color space type and + * contains the redColorantTag, greenColorantTag, blueColorantTag, redTRCTag, * greenTRCTag, blueTRCTag, and mediaWhitePointTag tags. + * + * @since Android 1.0 */ public class ICC_ProfileRGB extends ICC_Profile { - /** The Constant serialVersionUID. */ + /** + * The Constant serialVersionUID. + */ private static final long serialVersionUID = 8505067385152579334L; /** - * Instantiates a new iC c_ profile rgb. + * Instantiates a new RGB ICC_Profile. * - * @param profileHandle the profile handle + * @param profileHandle + * the profile handle */ ICC_ProfileRGB(long profileHandle) { super(profileHandle); } - /** The Constant REDCOMPONENT indicates the red component. */ + /** + * The Constant REDCOMPONENT indicates the red component. + */ public static final int REDCOMPONENT = 0; - /** The Constant GREENCOMPONENT indicates the green component. */ + /** + * The Constant GREENCOMPONENT indicates the green component. + */ public static final int GREENCOMPONENT = 1; - /** The Constant BLUECOMPONENT indicates the blue component. */ + /** + * The Constant BLUECOMPONENT indicates the blue component. + */ public static final int BLUECOMPONENT = 2; // awt.15E=Unknown component. Must be REDCOMPONENT, GREENCOMPONENT or BLUECOMPONENT. - /** The Constant UNKNOWN_COMPONENT_MSG. */ + /** + * The Constant UNKNOWN_COMPONENT_MSG. + */ private static final String UNKNOWN_COMPONENT_MSG = Messages .getString("awt.15E"); //$NON-NLS-1$ + /** + * Gets the TRC. + * + * @param component + * the tag signature. + * @return the TRC value. + */ @Override public short[] getTRC(int component) { switch (component) { @@ -70,6 +90,13 @@ public class ICC_ProfileRGB extends ICC_Profile { throw new IllegalArgumentException(UNKNOWN_COMPONENT_MSG); } + /** + * Gets the gamma. + * + * @param component + * the tag signature. + * @return the gamma value. + */ @Override public float getGamma(int component) { switch (component) { @@ -86,11 +113,11 @@ public class ICC_ProfileRGB extends ICC_Profile { } /** - * Gets a float matrix which contains the X, Y, and Z components of - * the profile's redColorantTag, greenColorantTag, and blueColorantTag. + * Gets a float matrix which contains the X, Y, and Z components of the + * profile's redColorantTag, greenColorantTag, and blueColorantTag. * - * @return a float matrix which contains the X, Y, and Z components of - * the profile's redColorantTag, greenColorantTag, and blueColorantTag. + * @return the float matrix which contains the X, Y, and Z components of the + * profile's redColorantTag, greenColorantTag, and blueColorantTag. */ public float[][] getMatrix() { float [][] m = new float[3][3]; // The matrix @@ -114,6 +141,11 @@ public class ICC_ProfileRGB extends ICC_Profile { return m; } + /** + * Gets the media white point. + * + * @return the media white point. + */ @Override public float[] getMediaWhitePoint() { return super.getMediaWhitePoint(); diff --git a/awt/java/awt/color/ProfileDataException.java b/awt/java/awt/color/ProfileDataException.java index ca169fe756699c4b1b404e664796f4d3caadfe2f..335f314caf1cdcd5e8c4bdbfa5844103de219b88 100644 --- a/awt/java/awt/color/ProfileDataException.java +++ b/awt/java/awt/color/ProfileDataException.java @@ -21,18 +21,23 @@ package java.awt.color; /** - * The ProfileDataException class represents an error which occurs - * while accessing or processing an ICC_Profile object. + * The ProfileDataException class represents an error which occurs while + * accessing or processing an ICC_Profile object. + * + * @since Android 1.0 */ public class ProfileDataException extends RuntimeException { - /** The Constant serialVersionUID. */ + /** + * The Constant serialVersionUID. + */ private static final long serialVersionUID = 7286140888240322498L; /** * Instantiates a new profile data exception with detailed message. * - * @param s the detailed message. + * @param s + * the detailed message of the exception. */ public ProfileDataException(String s) { super(s); diff --git a/awt/java/awt/color/package.html b/awt/java/awt/color/package.html new file mode 100644 index 0000000000000000000000000000000000000000..609d963a80a3f60f597278ba1062105374ae91c4 --- /dev/null +++ b/awt/java/awt/color/package.html @@ -0,0 +1,8 @@ + + +

    + This package contains classes representing color spaces and profiles based on the International Color Consortium (ICC) Profile Format Specification. +

    + @since Android 1.0 + + diff --git a/awt/java/awt/event/AWTEventListener.java b/awt/java/awt/event/AWTEventListener.java index f621c9b1559ca41e4d1d6a3414e194393d927649..76293b3a7d3d01e0aca249f5b951a03a682ca63a 100644 --- a/awt/java/awt/event/AWTEventListener.java +++ b/awt/java/awt/event/AWTEventListener.java @@ -23,6 +23,12 @@ package java.awt.event; import java.awt.AWTEvent; import java.util.EventListener; +/** + * This class is not supported in Android 1.0. It is merely provided to maintain + * interface compatibility with desktop Java implementations. + * + * @since Android 1.0 + */ public interface AWTEventListener extends EventListener { public void eventDispatched(AWTEvent event); diff --git a/awt/java/awt/event/AWTEventListenerProxy.java b/awt/java/awt/event/AWTEventListenerProxy.java index 5ee5e59a901b6d610d0a8de311918f9c461564e0..3edc41f3e6576026e7ea8744cce26a38a501fd25 100644 --- a/awt/java/awt/event/AWTEventListenerProxy.java +++ b/awt/java/awt/event/AWTEventListenerProxy.java @@ -26,6 +26,12 @@ import java.util.EventListenerProxy; import org.apache.harmony.awt.internal.nls.Messages; +/** + * This class is not supported in Android 1.0. It is merely provided to maintain + * interface compatibility with desktop Java implementations. + * + * @since Android 1.0 + */ public class AWTEventListenerProxy extends EventListenerProxy implements AWTEventListener { private AWTEventListener listener; diff --git a/awt/java/awt/event/ActionEvent.java b/awt/java/awt/event/ActionEvent.java index c32fc4bd292b1874f33f779abb0fedf5153dc89a..e882e0db9e376588f88facecf0ac30aad6b235a8 100644 --- a/awt/java/awt/event/ActionEvent.java +++ b/awt/java/awt/event/ActionEvent.java @@ -22,6 +22,12 @@ package java.awt.event; import java.awt.AWTEvent; +/** + * This class is not supported in Android 1.0. It is merely provided to maintain + * interface compatibility with desktop Java implementations. + * + * @since Android 1.0 + */ public class ActionEvent extends AWTEvent { private static final long serialVersionUID = -7671078796273832149L; diff --git a/awt/java/awt/event/ActionListener.java b/awt/java/awt/event/ActionListener.java index 473d2b682846cd1ff57282175eae77c40ead5a3c..a6eee7a1659ae0a95dc4ba7cf19ac9e79e3f5bd4 100644 --- a/awt/java/awt/event/ActionListener.java +++ b/awt/java/awt/event/ActionListener.java @@ -22,6 +22,12 @@ package java.awt.event; import java.util.EventListener; +/** + * This class is not supported in Android 1.0. It is merely provided to maintain + * interface compatibility with desktop Java implementations. + * + * @since Android 1.0 + */ public interface ActionListener extends EventListener { public void actionPerformed(ActionEvent e); diff --git a/awt/java/awt/event/AdjustmentEvent.java b/awt/java/awt/event/AdjustmentEvent.java index a2b11a8f304483060a2de71dad44f9a32f90fabd..be2d6c4baf44ede4e2626359f601affad64faf3d 100644 --- a/awt/java/awt/event/AdjustmentEvent.java +++ b/awt/java/awt/event/AdjustmentEvent.java @@ -23,6 +23,12 @@ package java.awt.event; import java.awt.AWTEvent; import java.awt.Adjustable; +/** + * This class is not supported in Android 1.0. It is merely provided to maintain + * interface compatibility with desktop Java implementations. + * + * @since Android 1.0 + */ public class AdjustmentEvent extends AWTEvent { private static final long serialVersionUID = 5700290645205279921L; diff --git a/awt/java/awt/event/AdjustmentListener.java b/awt/java/awt/event/AdjustmentListener.java index ef7c378635ff4bd550da727e27960ea8f9f97d1d..5f6a72473f900d098f63bc2fa32939f4cd58c42d 100644 --- a/awt/java/awt/event/AdjustmentListener.java +++ b/awt/java/awt/event/AdjustmentListener.java @@ -22,6 +22,12 @@ package java.awt.event; import java.util.EventListener; +/** + * This class is not supported in Android 1.0. It is merely provided to maintain + * interface compatibility with desktop Java implementations. + * + * @since Android 1.0 + */ public interface AdjustmentListener extends EventListener { public void adjustmentValueChanged(AdjustmentEvent e); diff --git a/awt/java/awt/event/ComponentAdapter.java b/awt/java/awt/event/ComponentAdapter.java index 4f0bd90fd968a77e3eb58c89edceba91f18eb97d..c42235f9678eb34fe8b3e23fa56717b75534acf0 100644 --- a/awt/java/awt/event/ComponentAdapter.java +++ b/awt/java/awt/event/ComponentAdapter.java @@ -20,6 +20,12 @@ */ package java.awt.event; +/** + * This class is not supported in Android 1.0. It is merely provided to maintain + * interface compatibility with desktop Java implementations. + * + * @since Android 1.0 + */ public abstract class ComponentAdapter implements ComponentListener { public ComponentAdapter() { diff --git a/awt/java/awt/event/ComponentEvent.java b/awt/java/awt/event/ComponentEvent.java index d0bca542db64e092f963e32e5dc5f1f94225fd51..760d3abf2a86c178671b7f55f4e2c25d494cb205 100644 --- a/awt/java/awt/event/ComponentEvent.java +++ b/awt/java/awt/event/ComponentEvent.java @@ -23,6 +23,12 @@ package java.awt.event; import java.awt.AWTEvent; import java.awt.Component; +/** + * This class is not supported in Android 1.0. It is merely provided to maintain + * interface compatibility with desktop Java implementations. + * + * @since Android 1.0 + */ public class ComponentEvent extends AWTEvent { private static final long serialVersionUID = 8101406823902992965L; diff --git a/awt/java/awt/event/ComponentListener.java b/awt/java/awt/event/ComponentListener.java index 147e9e07de75ece47584ecb6b605d594fc502d5e..a5adba2e9b235d40c0a82a3e56c3266832a814c8 100644 --- a/awt/java/awt/event/ComponentListener.java +++ b/awt/java/awt/event/ComponentListener.java @@ -22,6 +22,12 @@ package java.awt.event; import java.util.EventListener; +/** + * This class is not supported in Android 1.0. It is merely provided to maintain + * interface compatibility with desktop Java implementations. + * + * @since Android 1.0 + */ public interface ComponentListener extends EventListener { public void componentHidden(ComponentEvent e); diff --git a/awt/java/awt/event/ContainerAdapter.java b/awt/java/awt/event/ContainerAdapter.java index 12dc3dea0150af12b147c31717f60c518cfb4940..44983c7930fc00e02e7795477985396efb201184 100644 --- a/awt/java/awt/event/ContainerAdapter.java +++ b/awt/java/awt/event/ContainerAdapter.java @@ -20,6 +20,12 @@ */ package java.awt.event; +/** + * This class is not supported in Android 1.0. It is merely provided to maintain + * interface compatibility with desktop Java implementations. + * + * @since Android 1.0 + */ public abstract class ContainerAdapter implements ContainerListener { public ContainerAdapter() { diff --git a/awt/java/awt/event/ContainerEvent.java b/awt/java/awt/event/ContainerEvent.java index 1a1055c4c9d85123dd2ada67b1d20f902e6565ea..372c9e4775760680e5488f5005d025e1ac27dd6a 100644 --- a/awt/java/awt/event/ContainerEvent.java +++ b/awt/java/awt/event/ContainerEvent.java @@ -23,6 +23,12 @@ package java.awt.event; import java.awt.Component; //???AWT: import java.awt.Container; +/** + * This class is not supported in Android 1.0. It is merely provided to maintain + * interface compatibility with desktop Java implementations. + * + * @since Android 1.0 + */ public class ContainerEvent extends ComponentEvent { private static final long serialVersionUID = -4114942250539772041L; diff --git a/awt/java/awt/event/ContainerListener.java b/awt/java/awt/event/ContainerListener.java index bf47664fc71f08ce3a3fb86dfc079399b01fe208..517859e431028d1ba57af69d2de4ef8a60aaa967 100644 --- a/awt/java/awt/event/ContainerListener.java +++ b/awt/java/awt/event/ContainerListener.java @@ -22,6 +22,12 @@ package java.awt.event; import java.util.EventListener; +/** + * This class is not supported in Android 1.0. It is merely provided to maintain + * interface compatibility with desktop Java implementations. + * + * @since Android 1.0 + */ public interface ContainerListener extends EventListener { public void componentAdded(ContainerEvent e); diff --git a/awt/java/awt/event/FocusAdapter.java b/awt/java/awt/event/FocusAdapter.java index 3489e110a9aed30363c545f60ae47e323d4804ad..3a3e37fb052d4c61e0e75b8634d899232640a1af 100644 --- a/awt/java/awt/event/FocusAdapter.java +++ b/awt/java/awt/event/FocusAdapter.java @@ -20,6 +20,12 @@ */ package java.awt.event; +/** + * This class is not supported in Android 1.0. It is merely provided to maintain + * interface compatibility with desktop Java implementations. + * + * @since Android 1.0 + */ public abstract class FocusAdapter implements FocusListener { public FocusAdapter() { diff --git a/awt/java/awt/event/FocusEvent.java b/awt/java/awt/event/FocusEvent.java index 1db5263f4b1e410a2a7a87292c725256dd66fe32..4a1868957906578251e1d9521f3a39014c399247 100644 --- a/awt/java/awt/event/FocusEvent.java +++ b/awt/java/awt/event/FocusEvent.java @@ -22,6 +22,12 @@ package java.awt.event; import java.awt.Component; +/** + * This class is not supported in Android 1.0. It is merely provided to maintain + * interface compatibility with desktop Java implementations. + * + * @since Android 1.0 + */ public class FocusEvent extends ComponentEvent { private static final long serialVersionUID = 523753786457416396L; diff --git a/awt/java/awt/event/FocusListener.java b/awt/java/awt/event/FocusListener.java index ee98d9042d23b85c5a66c5afa5d0eef187607274..6bbbd001f78841ce5103464fa366743fcdba140c 100644 --- a/awt/java/awt/event/FocusListener.java +++ b/awt/java/awt/event/FocusListener.java @@ -22,6 +22,12 @@ package java.awt.event; import java.util.EventListener; +/** + * This class is not supported in Android 1.0. It is merely provided to maintain + * interface compatibility with desktop Java implementations. + * + * @since Android 1.0 + */ public interface FocusListener extends EventListener { public void focusGained(FocusEvent e); diff --git a/awt/java/awt/event/HierarchyBoundsAdapter.java b/awt/java/awt/event/HierarchyBoundsAdapter.java index 24e3d9d0013c7250fd218c8c97100ca80df59baf..bbfe8ff2d8137494fb4898b0e5e748d1f4565a7c 100644 --- a/awt/java/awt/event/HierarchyBoundsAdapter.java +++ b/awt/java/awt/event/HierarchyBoundsAdapter.java @@ -20,6 +20,12 @@ */ package java.awt.event; +/** + * This class is not supported in Android 1.0. It is merely provided to maintain + * interface compatibility with desktop Java implementations. + * + * @since Android 1.0 + */ public abstract class HierarchyBoundsAdapter implements HierarchyBoundsListener { public HierarchyBoundsAdapter() { diff --git a/awt/java/awt/event/HierarchyBoundsListener.java b/awt/java/awt/event/HierarchyBoundsListener.java index 4288f52d6b2c5eca2387ea92702a8e266e2d4409..3e8f2e7907370dc7b5e2f3f5d9061ae9bbea061c 100644 --- a/awt/java/awt/event/HierarchyBoundsListener.java +++ b/awt/java/awt/event/HierarchyBoundsListener.java @@ -22,6 +22,12 @@ package java.awt.event; import java.util.EventListener; +/** + * This class is not supported in Android 1.0. It is merely provided to maintain + * interface compatibility with desktop Java implementations. + * + * @since Android 1.0 + */ public interface HierarchyBoundsListener extends EventListener { public void ancestorMoved(HierarchyEvent e); diff --git a/awt/java/awt/event/HierarchyEvent.java b/awt/java/awt/event/HierarchyEvent.java index 188166715a48deba5b30794448096962c3d365fa..c1d22f44cef665b14c8bbe98b761562d86a1c5af 100644 --- a/awt/java/awt/event/HierarchyEvent.java +++ b/awt/java/awt/event/HierarchyEvent.java @@ -24,6 +24,12 @@ import java.awt.AWTEvent; import java.awt.Component; //???AWT: import java.awt.Container; +/** + * This class is not supported in Android 1.0. It is merely provided to maintain + * interface compatibility with desktop Java implementations. + * + * @since Android 1.0 + */ public class HierarchyEvent extends AWTEvent { private static final long serialVersionUID = -5337576970038043990L; diff --git a/awt/java/awt/event/HierarchyListener.java b/awt/java/awt/event/HierarchyListener.java index e01ba11b41638366ea04fae57978030b2ba07289..ff3d9bcfcdbad11c372390592acc5920d9156c18 100644 --- a/awt/java/awt/event/HierarchyListener.java +++ b/awt/java/awt/event/HierarchyListener.java @@ -22,6 +22,12 @@ package java.awt.event; import java.util.EventListener; +/** + * This class is not supported in Android 1.0. It is merely provided to maintain + * interface compatibility with desktop Java implementations. + * + * @since Android 1.0 + */ public interface HierarchyListener extends EventListener { public void hierarchyChanged(HierarchyEvent e); diff --git a/awt/java/awt/event/InputEvent.java b/awt/java/awt/event/InputEvent.java index c98382d803e99296d9aa61afea28b5248f197c52..343b7a3b05411045492ea8d9ff76bd632e93428c 100644 --- a/awt/java/awt/event/InputEvent.java +++ b/awt/java/awt/event/InputEvent.java @@ -22,6 +22,12 @@ package java.awt.event; import java.awt.Component; +/** + * This class is not supported in Android 1.0. It is merely provided to maintain + * interface compatibility with desktop Java implementations. + * + * @since Android 1.0 + */ public abstract class InputEvent extends ComponentEvent { private static final long serialVersionUID = -2482525981698309786L; diff --git a/awt/java/awt/event/InputMethodEvent.java b/awt/java/awt/event/InputMethodEvent.java index a5cac4e034b5229dc3ba691add824351321d040d..be001a580572e476023fbea30b39bde768c56885 100644 --- a/awt/java/awt/event/InputMethodEvent.java +++ b/awt/java/awt/event/InputMethodEvent.java @@ -27,6 +27,12 @@ import java.text.AttributedCharacterIterator; import org.apache.harmony.awt.internal.nls.Messages; +/** + * This class is not supported in Android 1.0. It is merely provided to maintain + * interface compatibility with desktop Java implementations. + * + * @since Android 1.0 + */ public class InputMethodEvent extends AWTEvent { private static final long serialVersionUID = 4727190874778922661L; diff --git a/awt/java/awt/event/InputMethodListener.java b/awt/java/awt/event/InputMethodListener.java index 0ab69180a8d4f964a4fa445ae3b53ebc2a542eaa..85eaa7e6c19b22ea72894e9059133dd23ed2a7c3 100644 --- a/awt/java/awt/event/InputMethodListener.java +++ b/awt/java/awt/event/InputMethodListener.java @@ -22,6 +22,12 @@ package java.awt.event; import java.util.EventListener; +/** + * This class is not supported in Android 1.0. It is merely provided to maintain + * interface compatibility with desktop Java implementations. + * + * @since Android 1.0 + */ public interface InputMethodListener extends EventListener { public void caretPositionChanged(InputMethodEvent e); diff --git a/awt/java/awt/event/InvocationEvent.java b/awt/java/awt/event/InvocationEvent.java index 59346ed47f5821db817ad511af949e760bbc0813..58e3b7298769c954ee909f6c6d24cfce1d1a6adc 100644 --- a/awt/java/awt/event/InvocationEvent.java +++ b/awt/java/awt/event/InvocationEvent.java @@ -25,6 +25,12 @@ import java.awt.ActiveEvent; import org.apache.harmony.awt.internal.nls.Messages; +/** + * This class is not supported in Android 1.0. It is merely provided to maintain + * interface compatibility with desktop Java implementations. + * + * @since Android 1.0 + */ public class InvocationEvent extends AWTEvent implements ActiveEvent { private static final long serialVersionUID = 436056344909459450L; diff --git a/awt/java/awt/event/ItemEvent.java b/awt/java/awt/event/ItemEvent.java index 842da14b06210a35132f34037d27e56732697da8..09908f24f8ef465742e4c9e522f1539852df0d22 100644 --- a/awt/java/awt/event/ItemEvent.java +++ b/awt/java/awt/event/ItemEvent.java @@ -23,6 +23,12 @@ package java.awt.event; import java.awt.AWTEvent; import java.awt.ItemSelectable; +/** + * This class is not supported in Android 1.0. It is merely provided to maintain + * interface compatibility with desktop Java implementations. + * + * @since Android 1.0 + */ public class ItemEvent extends AWTEvent { private static final long serialVersionUID = -608708132447206933L; diff --git a/awt/java/awt/event/ItemListener.java b/awt/java/awt/event/ItemListener.java index 33633be35d4626a7ea7edda3a806f4f03c11b782..8dec67322a858c75b2aa0d7f76736d0c5caa6ff6 100644 --- a/awt/java/awt/event/ItemListener.java +++ b/awt/java/awt/event/ItemListener.java @@ -22,6 +22,12 @@ package java.awt.event; import java.util.EventListener; +/** + * This class is not supported in Android 1.0. It is merely provided to maintain + * interface compatibility with desktop Java implementations. + * + * @since Android 1.0 + */ public interface ItemListener extends EventListener { public void itemStateChanged(ItemEvent e); diff --git a/awt/java/awt/event/KeyAdapter.java b/awt/java/awt/event/KeyAdapter.java index 423b5c9cd987b5eb47448352d31f5524cefc0d06..a96cca8d8c2b07dbb180f66f2413f1d95fe45f68 100644 --- a/awt/java/awt/event/KeyAdapter.java +++ b/awt/java/awt/event/KeyAdapter.java @@ -20,6 +20,12 @@ */ package java.awt.event; +/** + * This class is not supported in Android 1.0. It is merely provided to maintain + * interface compatibility with desktop Java implementations. + * + * @since Android 1.0 + */ public abstract class KeyAdapter implements KeyListener { public KeyAdapter() { diff --git a/awt/java/awt/event/KeyEvent.java b/awt/java/awt/event/KeyEvent.java index 056c64cbe8fc55c30f6e045ea5989a44b95889cd..8627f708d05f09f75ee53297fa13e8bd40429ee6 100644 --- a/awt/java/awt/event/KeyEvent.java +++ b/awt/java/awt/event/KeyEvent.java @@ -27,6 +27,12 @@ import java.lang.reflect.Modifier; import org.apache.harmony.awt.internal.nls.Messages; +/** + * This class is not supported in Android 1.0. It is merely provided to maintain + * interface compatibility with desktop Java implementations. + * + * @since Android 1.0 + */ public class KeyEvent extends InputEvent { private static final long serialVersionUID = -2352130953028126954L; diff --git a/awt/java/awt/event/KeyListener.java b/awt/java/awt/event/KeyListener.java index f20fc90d1987b24c8dd941769f96a65dc959c9db..ec144dfefc436013612452429f77a71db03bec9b 100644 --- a/awt/java/awt/event/KeyListener.java +++ b/awt/java/awt/event/KeyListener.java @@ -22,6 +22,12 @@ package java.awt.event; import java.util.EventListener; +/** + * This class is not supported in Android 1.0. It is merely provided to maintain + * interface compatibility with desktop Java implementations. + * + * @since Android 1.0 + */ public interface KeyListener extends EventListener { public void keyPressed(KeyEvent e); diff --git a/awt/java/awt/event/MouseAdapter.java b/awt/java/awt/event/MouseAdapter.java index 4973956a268fa319d38bfcab9a2a0277ae3565f8..dc19173c348997811202292e3e18ae9922b42142 100644 --- a/awt/java/awt/event/MouseAdapter.java +++ b/awt/java/awt/event/MouseAdapter.java @@ -20,6 +20,12 @@ */ package java.awt.event; +/** + * This class is not supported in Android 1.0. It is merely provided to maintain + * interface compatibility with desktop Java implementations. + * + * @since Android 1.0 + */ public abstract class MouseAdapter implements MouseListener { public MouseAdapter() { diff --git a/awt/java/awt/event/MouseEvent.java b/awt/java/awt/event/MouseEvent.java index 0b776f9f0c7caa1db0f8670b34849223e7fe5156..2b1fa8b2aae853aafcc62ba924c9f51e153d25d0 100644 --- a/awt/java/awt/event/MouseEvent.java +++ b/awt/java/awt/event/MouseEvent.java @@ -26,6 +26,12 @@ import java.awt.Toolkit; import org.apache.harmony.awt.internal.nls.Messages; +/** + * This class is not supported in Android 1.0. It is merely provided to maintain + * interface compatibility with desktop Java implementations. + * + * @since Android 1.0 + */ public class MouseEvent extends InputEvent { private static final long serialVersionUID = -991214153494842848L; diff --git a/awt/java/awt/event/MouseListener.java b/awt/java/awt/event/MouseListener.java index 5d32b0f921dd3f368b879cfe2d7fb13550b4f6d3..95879b90e6c38b89c435e655756d095d638389f7 100644 --- a/awt/java/awt/event/MouseListener.java +++ b/awt/java/awt/event/MouseListener.java @@ -22,6 +22,12 @@ package java.awt.event; import java.util.EventListener; +/** + * This class is not supported in Android 1.0. It is merely provided to maintain + * interface compatibility with desktop Java implementations. + * + * @since Android 1.0 + */ public interface MouseListener extends EventListener { public void mouseClicked(MouseEvent e); diff --git a/awt/java/awt/event/MouseMotionAdapter.java b/awt/java/awt/event/MouseMotionAdapter.java index a4bebcc630f79a0ee6bd80cdbbb71d290e1fba50..1ecd0d5ad52de569258c1ffdcddfa65e4bcb745d 100644 --- a/awt/java/awt/event/MouseMotionAdapter.java +++ b/awt/java/awt/event/MouseMotionAdapter.java @@ -20,6 +20,12 @@ */ package java.awt.event; +/** + * This class is not supported in Android 1.0. It is merely provided to maintain + * interface compatibility with desktop Java implementations. + * + * @since Android 1.0 + */ public abstract class MouseMotionAdapter implements MouseMotionListener { public MouseMotionAdapter() { diff --git a/awt/java/awt/event/MouseMotionListener.java b/awt/java/awt/event/MouseMotionListener.java index a5c11da6328bb87d77f6dc9ab09c4ddb7a1dd7de..e1313c340b7a50a1ee0565787027526baa6ce687 100644 --- a/awt/java/awt/event/MouseMotionListener.java +++ b/awt/java/awt/event/MouseMotionListener.java @@ -22,6 +22,12 @@ package java.awt.event; import java.util.EventListener; +/** + * This class is not supported in Android 1.0. It is merely provided to maintain + * interface compatibility with desktop Java implementations. + * + * @since Android 1.0 + */ public interface MouseMotionListener extends EventListener { public void mouseDragged(MouseEvent e); diff --git a/awt/java/awt/event/MouseWheelEvent.java b/awt/java/awt/event/MouseWheelEvent.java index d3ac9d8c8815cc09ad2853b28367872cde82beff..a3ed42436898e26b7148a7e1625caeba1fc736a6 100644 --- a/awt/java/awt/event/MouseWheelEvent.java +++ b/awt/java/awt/event/MouseWheelEvent.java @@ -22,6 +22,12 @@ package java.awt.event; import java.awt.Component; +/** + * This class is not supported in Android 1.0. It is merely provided to maintain + * interface compatibility with desktop Java implementations. + * + * @since Android 1.0 + */ public class MouseWheelEvent extends MouseEvent { private static final long serialVersionUID = -9187413581993563929L; diff --git a/awt/java/awt/event/MouseWheelListener.java b/awt/java/awt/event/MouseWheelListener.java index 8ca1c8b8f790ff52f38dded922935162ab6dfc30..2d6a98236b2a9e1be18174adb8808e494744961f 100644 --- a/awt/java/awt/event/MouseWheelListener.java +++ b/awt/java/awt/event/MouseWheelListener.java @@ -22,6 +22,12 @@ package java.awt.event; import java.util.EventListener; +/** + * This class is not supported in Android 1.0. It is merely provided to maintain + * interface compatibility with desktop Java implementations. + * + * @since Android 1.0 + */ public interface MouseWheelListener extends EventListener { public void mouseWheelMoved(MouseWheelEvent e); diff --git a/awt/java/awt/event/PaintEvent.java b/awt/java/awt/event/PaintEvent.java index d0573e16e21fc401f3ef8cfc6813410b7afd13f0..22ac0908df17c84ccea95e438edf77d830d5fbc4 100644 --- a/awt/java/awt/event/PaintEvent.java +++ b/awt/java/awt/event/PaintEvent.java @@ -23,6 +23,12 @@ package java.awt.event; import java.awt.Component; import java.awt.Rectangle; +/** + * This class is not supported in Android 1.0. It is merely provided to maintain + * interface compatibility with desktop Java implementations. + * + * @since Android 1.0 + */ public class PaintEvent extends ComponentEvent { private static final long serialVersionUID = 1267492026433337593L; diff --git a/awt/java/awt/event/TextEvent.java b/awt/java/awt/event/TextEvent.java index e2bfd96a9339e97e60abc70c1e9a2bd8fae0795f..2a690ad50d31938aefb286d6a35c29c656c43564 100644 --- a/awt/java/awt/event/TextEvent.java +++ b/awt/java/awt/event/TextEvent.java @@ -22,6 +22,12 @@ package java.awt.event; import java.awt.AWTEvent; +/** + * This class is not supported in Android 1.0. It is merely provided to maintain + * interface compatibility with desktop Java implementations. + * + * @since Android 1.0 + */ public class TextEvent extends AWTEvent { private static final long serialVersionUID = 6269902291250941179L; diff --git a/awt/java/awt/event/TextListener.java b/awt/java/awt/event/TextListener.java index 6c5a671d2b6c24561287901acb0b6701b039cfe2..05757c42ac41572749f3ce691dc1b9995015ac01 100644 --- a/awt/java/awt/event/TextListener.java +++ b/awt/java/awt/event/TextListener.java @@ -22,6 +22,12 @@ package java.awt.event; import java.util.EventListener; +/** + * This class is not supported in Android 1.0. It is merely provided to maintain + * interface compatibility with desktop Java implementations. + * + * @since Android 1.0 + */ public interface TextListener extends EventListener { public void textValueChanged(TextEvent e); diff --git a/awt/java/awt/event/WindowAdapter.java b/awt/java/awt/event/WindowAdapter.java index 9d4b37784ae17af938e0175ac64322f210ba5842..970aa8de45a5b039ace12012558aad12f42aa8df 100644 --- a/awt/java/awt/event/WindowAdapter.java +++ b/awt/java/awt/event/WindowAdapter.java @@ -20,6 +20,12 @@ */ package java.awt.event; +/** + * This class is not supported in Android 1.0. It is merely provided to maintain + * interface compatibility with desktop Java implementations. + * + * @since Android 1.0 + */ public abstract class WindowAdapter implements WindowListener, WindowStateListener, WindowFocusListener { public WindowAdapter() { diff --git a/awt/java/awt/event/WindowEvent.java b/awt/java/awt/event/WindowEvent.java index 65a30e4a36cfb78ea4a673234482d1aea27cff19..474d2ac82bd8a5ec12f0821203a3f465865a7d46 100644 --- a/awt/java/awt/event/WindowEvent.java +++ b/awt/java/awt/event/WindowEvent.java @@ -25,6 +25,12 @@ package java.awt.event; //import java.awt.Window; //import java.awt.Frame; +/** + * This class is not supported in Android 1.0. It is merely provided to maintain + * interface compatibility with desktop Java implementations. + * + * @since Android 1.0 + */ public class WindowEvent extends ComponentEvent { private static final long serialVersionUID = -1567959133147912127L; diff --git a/awt/java/awt/event/WindowFocusListener.java b/awt/java/awt/event/WindowFocusListener.java index e0200f282665dd2981439f3cf669c7746d79eb87..528459f3b510dafa0ef8787aac2d711807aede1d 100644 --- a/awt/java/awt/event/WindowFocusListener.java +++ b/awt/java/awt/event/WindowFocusListener.java @@ -22,6 +22,12 @@ package java.awt.event; import java.util.EventListener; +/** + * This class is not supported in Android 1.0. It is merely provided to maintain + * interface compatibility with desktop Java implementations. + * + * @since Android 1.0 + */ public interface WindowFocusListener extends EventListener { public void windowGainedFocus(WindowEvent e); diff --git a/awt/java/awt/event/WindowListener.java b/awt/java/awt/event/WindowListener.java index 20a2b08800783eea022babe4fe5d632eb71c76ca..31bd547bd385e454f1dec4a73a05d3efd5b88829 100644 --- a/awt/java/awt/event/WindowListener.java +++ b/awt/java/awt/event/WindowListener.java @@ -22,6 +22,12 @@ package java.awt.event; import java.util.EventListener; +/** + * This class is not supported in Android 1.0. It is merely provided to maintain + * interface compatibility with desktop Java implementations. + * + * @since Android 1.0 + */ public interface WindowListener extends EventListener { public void windowActivated(WindowEvent e); diff --git a/awt/java/awt/event/WindowStateListener.java b/awt/java/awt/event/WindowStateListener.java index 12dbc2085e90f6429527801e6f5eb82f7b0ca030..ba14d9ee8d65e07d501516baedb9a772c4a70afe 100644 --- a/awt/java/awt/event/WindowStateListener.java +++ b/awt/java/awt/event/WindowStateListener.java @@ -22,6 +22,12 @@ package java.awt.event; import java.util.EventListener; +/** + * This class is not supported in Android 1.0. It is merely provided to maintain + * interface compatibility with desktop Java implementations. + * + * @since Android 1.0 + */ public interface WindowStateListener extends EventListener { public void windowStateChanged(WindowEvent e); diff --git a/awt/java/awt/font/FontRenderContext.java b/awt/java/awt/font/FontRenderContext.java index 766300d7d00d5dc2a9494035cf30771200deacb0..d7de00f2090d6b52188f1affdc070239dfe6724d 100644 --- a/awt/java/awt/font/FontRenderContext.java +++ b/awt/java/awt/font/FontRenderContext.java @@ -23,23 +23,30 @@ package java.awt.font; import java.awt.geom.AffineTransform; /** - * The FontRenderContext class contains the information - * about text measurement. Anti-aliasing and fractional-metrics - * modes are defined by an application and affect the size of - * a character. + * The FontRenderContext class contains the information about text measurement. + * Anti-aliasing and fractional-metrics modes are defined by an application and + * affect the size of a character. + * + * @since Android 1.0 */ public class FontRenderContext { // Affine transform of this mode - /** The transform. */ + /** + * The transform. + */ private AffineTransform transform; // Is the anti-aliased mode used - /** The anti aliased. */ + /** + * The anti aliased. + */ private boolean fAntiAliased; // Is the fractional metrics used - /** The fractional metrics. */ + /** + * The fractional metrics. + */ private boolean fFractionalMetrics; @@ -47,9 +54,12 @@ public class FontRenderContext { * Instantiates a new FontRenderContext object with the specified * AffineTransform, anti-aliasing and fractional metrics flags. * - * @param trans the AffineTransform. - * @param antiAliased the anti-aliasing flag. - * @param usesFractionalMetrics the fractional metrics flag. + * @param trans + * the AffineTransform. + * @param antiAliased + * the anti-aliasing flag. + * @param usesFractionalMetrics + * the fractional metrics flag. */ public FontRenderContext(AffineTransform trans, boolean antiAliased, boolean usesFractionalMetrics) { @@ -67,12 +77,12 @@ public class FontRenderContext { } /** - * Compares the specified Object with current FontRenderContext object. - * - * @param obj the Object to be compared. + * Compares the specified Object with current FontRenderContext object. * + * @param obj + * the Object to be compared. * @return true, if the specified Object is equal to current - * FontRenderContext object. + * FontRenderContext object. */ @Override public boolean equals(Object obj) { @@ -92,11 +102,11 @@ public class FontRenderContext { } /** - * Gets the transform which is used for scaling typographical points - * to pixels in this FontRenderContext. + * Gets the transform which is used for scaling typographical points to + * pixels in this FontRenderContext. * - * @return the AffineTransform which is used for scaling typographical - * points to pixels in this FontRenderContext. + * @return the AffineTransform which is used for scaling typographical + * points to pixels in this FontRenderContext. */ public AffineTransform getTransform() { if (transform != null){ @@ -106,13 +116,13 @@ public class FontRenderContext { } /** - * Compares the specified FontRenderContext object with current + * Compares the specified FontRenderContext object with current * FontRenderContext. * - * @param frc the FontRenderContext object to be compared. - * - * @return true, if the specified FontRenderContext object is - * equal to current FontRenderContext. + * @param frc + * the FontRenderContext object to be compared. + * @return true, if the specified FontRenderContext object is equal to + * current FontRenderContext. */ public boolean equals(FontRenderContext frc) { if (this == frc){ @@ -132,11 +142,11 @@ public class FontRenderContext { } /** - * Returns true if the text fractional metrics are used in - * this FontRenderContext. + * Returns true if the text fractional metrics are used in this + * FontRenderContext. * - * @return true, if the text fractional metrics are used in - * this FontRenderContext, false otherwise. + * @return true, if the text fractional metrics are used in this + * FontRenderContext, false otherwise. */ public boolean usesFractionalMetrics() { return this.fFractionalMetrics; @@ -146,7 +156,7 @@ public class FontRenderContext { * Returns true if anti-aliasing is used in this FontRenderContext. * * @return true, if is anti-aliasing is used in this FontRenderContext, - * false otherwise. + * false otherwise. */ public boolean isAntiAliased() { return this.fAntiAliased; diff --git a/awt/java/awt/font/GlyphJustificationInfo.java b/awt/java/awt/font/GlyphJustificationInfo.java index 4c3e02ea7dec0133990b9fe7a49e6bd3ea1672a1..b03de0aa15e4d6980a4c48f4bbf0a38da2bffb04 100644 --- a/awt/java/awt/font/GlyphJustificationInfo.java +++ b/awt/java/awt/font/GlyphJustificationInfo.java @@ -18,124 +18,134 @@ * @author Ilya S. Okomin * @version $Revision$ */ + package java.awt.font; import org.apache.harmony.awt.internal.nls.Messages; /** - * The GlyphJustificationInfo class provides information about - * the glyph's justification properties. There are four justification - * properties: weight, priority, absorb, and limit. + * The GlyphJustificationInfo class provides information about the glyph's + * justification properties. There are four justification properties: weight, + * priority, absorb, and limit. *

    - * There are two sets of metrics: growing and shrinking. - * Growing metrics are used when the glyphs are to be spread apart - * to fit a larger width. Shrinking metrics are used when the glyphs - * are to be moved together to fit a smaller width. + * There are two sets of metrics: growing and shrinking. Growing metrics are + * used when the glyphs are to be spread apart to fit a larger width. Shrinking + * metrics are used when the glyphs are to be moved together to fit a smaller + * width. + *

    + * + * @since Android 1.0 */ public final class GlyphJustificationInfo { - /** - * The Constant PRIORITY_KASHIDA indicates the highest - * justification priority. + /** + * The Constant PRIORITY_KASHIDA indicates the highest justification + * priority. */ public static final int PRIORITY_KASHIDA = 0; /** - * The Constant PRIORITY_WHITESPACE indicates the second highest - * justification priority. + * The Constant PRIORITY_WHITESPACE indicates the second highest + * justification priority. */ public static final int PRIORITY_WHITESPACE = 1; - /** - * The Constant PRIORITY_INTERCHAR indicates the second lowest - * justification priority. + /** + * The Constant PRIORITY_INTERCHAR indicates the second lowest justification + * priority. */ public static final int PRIORITY_INTERCHAR = 2; /** - * The Constant PRIORITY_NONE indicates the lowest justification - * priority. + * The Constant PRIORITY_NONE indicates the lowest justification priority. */ public static final int PRIORITY_NONE = 3; - /** - * The grow absorb flag indicates if this glyph absorbs all extra - * space at this and lower priority levels when it grows. + /** + * The grow absorb flag indicates if this glyph absorbs all extra space at + * this and lower priority levels when it grows. */ public final boolean growAbsorb; - /** - * The grow left limit value represents the maximum value by which - * the left side of this glyph grows. + /** + * The grow left limit value represents the maximum value by which the left + * side of this glyph grows. */ public final float growLeftLimit; - /** - * The grow right limit value repesents the maximum value by which - * the right side of this glyph grows. + /** + * The grow right limit value repesents the maximum value by which the right + * side of this glyph grows. */ public final float growRightLimit; - /** - * The grow priority value represents the priority level of this - * glyph as it is growing. + /** + * The grow priority value represents the priority level of this glyph as it + * is growing. */ public final int growPriority; - /** - * The shrink absorb fleg indicates this glyph absorbs all remaining - * shrinkage at this and lower priority levels as it shrinks. + /** + * The shrink absorb fleg indicates this glyph absorbs all remaining + * shrinkage at this and lower priority levels as it shrinks. */ public final boolean shrinkAbsorb; - /** - * The shrink left limit value represents the maximum value by which - * the left side of this glyph shrinks. + /** + * The shrink left limit value represents the maximum value by which the + * left side of this glyph shrinks. */ public final float shrinkLeftLimit; - /** - * The shrink right limit value represents the maximum value by which - * the right side of this glyph shrinks. + /** + * The shrink right limit value represents the maximum value by which the + * right side of this glyph shrinks. */ public final float shrinkRightLimit; /** - * The shrink priority represents the glyth's priority level - * as it is shrinking. + * The shrink priority represents the glyth's priority level as it is + * shrinking. */ public final int shrinkPriority; - /** - * The weight of the glyph. + /** + * The weight of the glyph. */ public final float weight; /** - * Instantiates a new GlyphJustificationInfo object which contains - * glyph's justification properties. + * Instantiates a new GlyphJustificationInfo object which contains glyph's + * justification properties. * - * @param weight the weight of glyph. - * @param growAbsorb indicates if this glyph contais all space - * at this priority and lower priority levels when it grows. - * @param growPriority indicates the priority level of this glyph - * when it grows. - * @param growLeftLimit indicates the maximum value of which the - * left side of this glyph can grow. - * @param growRightLimit the maximum value of which the right side of - * this glyph can grow. - * @param shrinkAbsorb indicates if this glyph contains all remaining - * shrinkage at this and lower priority levels when it shrinks. - * @param shrinkPriority indicates the glyph's priority level when - * it shrinks. - * @param shrinkLeftLimit indicates the maximum value of which - * the left side of this glyph can shrink. - * @param shrinkRightLimit indicates the maximum amount by which - * the right side of this glyph can shrink. + * @param weight + * the weight of glyph. + * @param growAbsorb + * indicates if this glyph contais all space at this priority and + * lower priority levels when it grows. + * @param growPriority + * indicates the priority level of this glyph when it grows. + * @param growLeftLimit + * indicates the maximum value of which the left side of this + * glyph can grow. + * @param growRightLimit + * the maximum value of which the right side of this glyph can + * grow. + * @param shrinkAbsorb + * indicates if this glyph contains all remaining shrinkage at + * this and lower priority levels when it shrinks. + * @param shrinkPriority + * indicates the glyph's priority level when it shrinks. + * @param shrinkLeftLimit + * indicates the maximum value of which the left side of this + * glyph can shrink. + * @param shrinkRightLimit + * indicates the maximum amount by which the right side of this + * glyph can shrink. */ public GlyphJustificationInfo(float weight, boolean growAbsorb, int growPriority, - float growLeftLimit, float growRightLimit, boolean shrinkAbsorb, - int shrinkPriority, float shrinkLeftLimit, float shrinkRightLimit) { + float growLeftLimit, float growRightLimit, boolean shrinkAbsorb, int shrinkPriority, + float shrinkLeftLimit, float shrinkRightLimit) { if (weight < 0) { // awt.19C=weight must be a positive number @@ -156,13 +166,15 @@ public final class GlyphJustificationInfo { this.growRightLimit = growRightLimit; if ((shrinkPriority < 0) || (shrinkPriority > PRIORITY_NONE)) { - // awt.19F=incorrect value for shrinkPriority, more than PRIORITY_NONE or less than PRIORITY_KASHIDA value + // awt.19F=incorrect value for shrinkPriority, more than + // PRIORITY_NONE or less than PRIORITY_KASHIDA value throw new IllegalArgumentException(Messages.getString("awt.19F")); //$NON-NLS-1$ } this.shrinkPriority = shrinkPriority; if ((growPriority < 0) || (growPriority > PRIORITY_NONE)) { - // awt.200=incorrect value for growPriority, more than PRIORITY_NONE or less than PRIORITY_KASHIDA value + // awt.200=incorrect value for growPriority, more than PRIORITY_NONE + // or less than PRIORITY_KASHIDA value throw new IllegalArgumentException(Messages.getString("awt.200")); //$NON-NLS-1$ } this.growPriority = growPriority; diff --git a/awt/java/awt/font/GlyphMetrics.java b/awt/java/awt/font/GlyphMetrics.java index d96ef1815756dcf8fabc65904ebb43eff07eb89d..287172231be492050b4ecaaa9b99ff4027c323c3 100644 --- a/awt/java/awt/font/GlyphMetrics.java +++ b/awt/java/awt/font/GlyphMetrics.java @@ -18,82 +18,98 @@ * @author Ilya S. Okomin * @version $Revision$ */ + package java.awt.font; import java.awt.geom.Rectangle2D; /** - * The GlyphMetrics class provides information about the size and shape - * of a single glyph. - * Each glyph has information to specify whether its baseline is horizontal - * or vertical as well as information on how it interacts with - * other characters in a text, given as one of the - * following types: STANDARD, LIGATURE, COMBINING, or COMPONENT. + * The GlyphMetrics class provides information about the size and shape of a + * single glyph. Each glyph has information to specify whether its baseline is + * horizontal or vertical as well as information on how it interacts with other + * characters in a text, given as one of the following types: STANDARD, + * LIGATURE, COMBINING, or COMPONENT. + * + * @since Android 1.0 */ public final class GlyphMetrics { // advance width of the glyph character cell - /** The advance x. */ + /** + * The advance x. + */ private float advanceX; - + // advance height of the glyph character cell - /** The advance y. */ + /** + * The advance y. + */ private float advanceY; // flag if the glyph horizontal - /** The horizontal. */ + /** + * The horizontal. + */ private boolean horizontal; - // glyph type code - /** The glyph type. */ + // glyph type code + /** + * The glyph type. + */ private byte glyphType; - + // bounding box for outline of the glyph - /** The bounds. */ + /** + * The bounds. + */ private Rectangle2D.Float bounds; - /** - * The Constant STANDARD indicates a glyph that represents a single - * character. + /** + * The Constant STANDARD indicates a glyph that represents a single + * character. */ public static final byte STANDARD = 0; - /** - * The Constant LIGATURE indicates a glyph that represents multiple - * characters as a ligature. + /** + * The Constant LIGATURE indicates a glyph that represents multiple + * characters as a ligature. */ public static final byte LIGATURE = 1; - /** - * The Constant COMBINING indicates a glyph which has no caret position + /** + * The Constant COMBINING indicates a glyph which has no caret position * between glyphs (for example umlaut). */ public static final byte COMBINING = 2; - /** - * The Constant COMPONENT indicates a glyph with no corresponding character + /** + * The Constant COMPONENT indicates a glyph with no corresponding character * in the backing store. */ public static final byte COMPONENT = 3; - /** - * The Constant WHITESPACE indicates a glyph without visual - * representation. + /** + * The Constant WHITESPACE indicates a glyph without visual representation. */ public static final byte WHITESPACE = 4; /** * Instantiates a new GlyphMetrics object with the specified parameters. * - * @param horizontal specifies if metrics are for a horizontal baseline - * (true value), or a vertical baseline (false value). - * @param advanceX the X component of the glyph's advance. - * @param advanceY the Y component of the glyph's advance. - * @param bounds the glyph's bounds. - * @param glyphType the glyph's type. - */ - public GlyphMetrics(boolean horizontal, float advanceX, float advanceY, - Rectangle2D bounds, byte glyphType) { + * @param horizontal + * specifies if metrics are for a horizontal baseline (true + * value), or a vertical baseline (false value). + * @param advanceX + * the X component of the glyph's advance. + * @param advanceY + * the Y component of the glyph's advance. + * @param bounds + * the glyph's bounds. + * @param glyphType + * the glyph's type. + */ + public GlyphMetrics(boolean horizontal, float advanceX, float advanceY, Rectangle2D bounds, + byte glyphType) { this.horizontal = horizontal; this.advanceX = advanceX; this.advanceY = advanceY; @@ -107,9 +123,12 @@ public final class GlyphMetrics { /** * Instantiates a new horizontal GlyphMetrics with the specified parameters. * - * @param advanceX the X component of the glyph's advance. - * @param bounds the glyph's bounds. - * @param glyphType the glyph's type. + * @param advanceX + * the X component of the glyph's advance. + * @param bounds + * the glyph's bounds. + * @param glyphType + * the glyph's type. */ public GlyphMetrics(float advanceX, Rectangle2D bounds, byte glyphType) { this.advanceX = advanceX; @@ -129,7 +148,7 @@ public final class GlyphMetrics { * @return glyph's bounds. */ public Rectangle2D getBounds2D() { - return (Rectangle2D.Float) this.bounds.clone(); + return (Rectangle2D.Float)this.bounds.clone(); } /** @@ -187,11 +206,11 @@ public final class GlyphMetrics { } /** - * Gets the distance from the right (for horizontal) or - * bottom (for vertical) of the glyph bounds to the advance. + * Gets the distance from the right (for horizontal) or bottom (for + * vertical) of the glyph bounds to the advance. * - * @return the distance from the right (for horizontal) or - * bottom (for vertical) of the glyph bounds to the advance. + * @return the distance from the right (for horizontal) or bottom (for + * vertical) of the glyph bounds to the advance. */ public float getRSB() { if (this.horizontal) { @@ -201,11 +220,11 @@ public final class GlyphMetrics { } /** - * Gets the distance from 0, 0 to the left (for horizontal) - * or top (for vertical) of the glyph bounds. + * Gets the distance from 0, 0 to the left (for horizontal) or top (for + * vertical) of the glyph bounds. * - * @return the distance from 0, 0 to the left (for horizontal) - * or top (for vertical) of the glyph bounds. + * @return the distance from 0, 0 to the left (for horizontal) or top (for + * vertical) of the glyph bounds. */ public float getLSB() { if (this.horizontal) { @@ -245,4 +264,3 @@ public final class GlyphMetrics { } } - diff --git a/awt/java/awt/font/GlyphVector.java b/awt/java/awt/font/GlyphVector.java index b3c9406a9b1b71526c2e9d89df84d29388783b5f..a72b774bfad252143f09b7a59234bc797caecaeb 100644 --- a/awt/java/awt/font/GlyphVector.java +++ b/awt/java/awt/font/GlyphVector.java @@ -18,6 +18,7 @@ * @author Ilya S. Okomin * @version $Revision$ */ + package java.awt.font; import java.awt.Font; @@ -32,45 +33,47 @@ import java.awt.geom.Point2D; import java.awt.geom.Rectangle2D; /** - * The GlyphVector class contains a collection of glyphs with geometric - * information and each glyph's location. Each GlyphVector can be associated - * with only one Font. GlyphVector contains the following properties for - * each glyph: + * The GlyphVector class contains a collection of glyphs with geometric + * information and each glyph's location. Each GlyphVector can be associated + * with only one Font. GlyphVector contains the following properties for each + * glyph: *
      *
    • the glyph position;
    • *
    • the transform of the glyph;
    • *
    • the metrics of the glyph in the context of the GlyphVector.
    • *
    + * + * @since Android 1.0 */ public abstract class GlyphVector implements Cloneable { - /** - * The Constant FLAG_HAS_TRANSFORMS indicates that this GlyphVector - * has per-glyph transforms. + /** + * The Constant FLAG_HAS_TRANSFORMS indicates that this GlyphVector has + * per-glyph transforms. */ public static final int FLAG_HAS_TRANSFORMS = 1; - /** - * The Constant FLAG_HAS_POSITION_ADJUSTMENTS indicates that - * the GlyphVector has per-glyph position adjustments. + /** + * The Constant FLAG_HAS_POSITION_ADJUSTMENTS indicates that the GlyphVector + * has per-glyph position adjustments. */ public static final int FLAG_HAS_POSITION_ADJUSTMENTS = 2; - /** - * The Constant FLAG_RUN_RTL indicates that this GlyphVector has a - * right to left run direction. + /** + * The Constant FLAG_RUN_RTL indicates that this GlyphVector has a right to + * left run direction. */ public static final int FLAG_RUN_RTL = 4; - /** - * The Constant FLAG_COMPLEX_GLYPHS indicates that this GlyphVector - * has a complex glyph to char mapping. + /** + * The Constant FLAG_COMPLEX_GLYPHS indicates that this GlyphVector has a + * complex glyph to char mapping. */ public static final int FLAG_COMPLEX_GLYPHS = 8; - /** - * The Constant FLAG_MASK indicates a mask for supported flags - * from getLayoutFlags. + /** + * The Constant FLAG_MASK indicates a mask for supported flags from + * getLayoutFlags. */ public static final int FLAG_MASK = 15; // (|) mask of other flags @@ -81,17 +84,19 @@ public abstract class GlyphVector implements Cloneable { } /** - * Gets the pixel bounds of the GlyphVector when rendered - * at the specified location with the specified FontRenderContext. - * - * @param frc the FontRenderContext. - * @param x the X coordinate of the GlyphVector's location. - * @param y the Y coordinate of the GlyphVector's location. - * + * Gets the pixel bounds of the GlyphVector when rendered at the specified + * location with the specified FontRenderContext. + * + * @param frc + * the FontRenderContext. + * @param x + * the X coordinate of the GlyphVector's location. + * @param y + * the Y coordinate of the GlyphVector's location. * @return the pixel bounds */ public Rectangle getPixelBounds(FontRenderContext frc, float x, float y) { - // default implementation - integer Rectangle, that encloses visual + // default implementation - integer Rectangle, that encloses visual // bounds rectangle Rectangle2D visualRect = getVisualBounds(); @@ -104,19 +109,21 @@ public abstract class GlyphVector implements Cloneable { } /** - * Gets the pixel bounds of the glyph with the specified index in - * this GlyphVector which is rendered with the specified - * FontRenderContext at the specified location. - * - * @param index the glyph index in this GlyphVector. - * @param frc the FontRenderContext. - * @param x the X coordinate of the GlyphVector's location. - * @param y the Y coordinate of the GlyphVector's location. - * + * Gets the pixel bounds of the glyph with the specified index in this + * GlyphVector which is rendered with the specified FontRenderContext at the + * specified location. + * + * @param index + * the glyph index in this GlyphVector. + * @param frc + * the FontRenderContext. + * @param x + * the X coordinate of the GlyphVector's location. + * @param y + * the Y coordinate of the GlyphVector's location. * @return a Rectangle bounds. */ - public Rectangle getGlyphPixelBounds(int index, FontRenderContext frc, - float x, float y) { + public Rectangle getGlyphPixelBounds(int index, FontRenderContext frc, float x, float y) { Rectangle2D visualRect = getGlyphVisualBounds(index).getBounds2D(); int minX = (int)Math.floor(visualRect.getMinX() + x); @@ -128,14 +135,14 @@ public abstract class GlyphVector implements Cloneable { } /** - * Gets the visual bounds of the GlyphVector. + * Gets the visual bounds of the GlyphVector. * * @return the visual bounds of the GlyphVector. */ public abstract Rectangle2D getVisualBounds(); /** - * Gets the logical bounds of the GlyphVector. + * Gets the logical bounds of the GlyphVector. * * @return the logical bounds of the GlyphVector. */ @@ -144,36 +151,38 @@ public abstract class GlyphVector implements Cloneable { /** * Sets the position of the specified glyph in this GlyphVector. * - * @param glyphIndex the glyph index in this GlyphVector. - * @param newPos the new position of the glyph at the specified glyphIndex. + * @param glyphIndex + * the glyph index in this GlyphVector. + * @param newPos + * the new position of the glyph at the specified glyphIndex. */ public abstract void setGlyphPosition(int glyphIndex, Point2D newPos); /** * Gets the position of the specified glyph in this GlyphVector. * - * @param glyphIndex the glyph index in this GlyphVector. - * + * @param glyphIndex + * the glyph index in this GlyphVector. * @return the position of the specified glyph in this GlyphVector. */ public abstract Point2D getGlyphPosition(int glyphIndex); /** - * Sets the affine transform to a glyph with the specified index - * in this GlyphVector. + * Sets the affine transform to a glyph with the specified index in this + * GlyphVector. * - * @param glyphIndex the glyth index in this GlyphVector. - * @param trans the AffineTransform to be assigned to the - * specified glyph. + * @param glyphIndex + * the glyth index in this GlyphVector. + * @param trans + * the AffineTransform to be assigned to the specified glyph. */ - public abstract void setGlyphTransform(int glyphIndex, - AffineTransform trans); + public abstract void setGlyphTransform(int glyphIndex, AffineTransform trans); /** * Gets the transform of the specified glyph in this GlyphVector. * - * @param glyphIndex the glyph index in this GlyphVector. - * + * @param glyphIndex + * the glyph index in this GlyphVector. * @return the new transform of the glyph. */ public abstract AffineTransform getGlyphTransform(int glyphIndex); @@ -181,34 +190,32 @@ public abstract class GlyphVector implements Cloneable { /** * Compares this GlyphVector with the specified GlyphVector objects. * - * @param glyphVector the GlyphVector object to be compared. - * + * @param glyphVector + * the GlyphVector object to be compared. * @return true, if this GlyphVector is equal to the specified GlyphVector - * object, false otherwise. + * object, false otherwise. */ public abstract boolean equals(GlyphVector glyphVector); /** - * Gets the metrics of the glyph with the specified index - * in this GlyphVector. - * - * @param glyphIndex index in this GlyphVector. + * Gets the metrics of the glyph with the specified index in this + * GlyphVector. * - * @return the metrics of the glyph with the specified index - * in this GlyphVector. + * @param glyphIndex + * index in this GlyphVector. + * @return the metrics of the glyph with the specified index in this + * GlyphVector. */ public abstract GlyphMetrics getGlyphMetrics(int glyphIndex); /** - * Gets the justification information of the glyph - * whose index is specified. + * Gets the justification information of the glyph whose index is specified. * - * @param glyphIndex the glyph index. - * - * @return the GlyphJustificationInfo for the specified glyph. + * @param glyphIndex + * the glyph index. + * @return the GlyphJustificationInfo for the specified glyph. */ - public abstract GlyphJustificationInfo getGlyphJustificationInfo( - int glyphIndex); + public abstract GlyphJustificationInfo getGlyphJustificationInfo(int glyphIndex); /** * Gets the FontRenderContext of this GlyphVector. @@ -218,18 +225,20 @@ public abstract class GlyphVector implements Cloneable { public abstract FontRenderContext getFontRenderContext(); /** - * Gets a Shape object which defines the visual representation - * of the specified glyph in this GlyphVector, translated a - * distance of x in the X direction and y in the Y direction. - * - * @param glyphIndex the glyth index in this GlyphVector. - * @param x the distance in the X direction to translate the - * shape object before returning it. - * @param y the distance in the Y direction to translate the - * shape object before returning it. - * - * @return a Shape object which represents the visual representation - * of the specified glyph in this GlyphVector - glyph outline. + * Gets a Shape object which defines the visual representation of the + * specified glyph in this GlyphVector, translated a distance of x in the X + * direction and y in the Y direction. + * + * @param glyphIndex + * the glyth index in this GlyphVector. + * @param x + * the distance in the X direction to translate the shape object + * before returning it. + * @param y + * the distance in the Y direction to translate the shape object + * before returning it. + * @return a Shape object which represents the visual representation of the + * specified glyph in this GlyphVector - glyph outline. */ public Shape getGlyphOutline(int glyphIndex, float x, float y) { Shape initialShape = getGlyphOutline(glyphIndex); @@ -240,43 +249,42 @@ public abstract class GlyphVector implements Cloneable { /** * Gets the visual bounds of the specified glyph in the GlyphVector. * - * @param glyphIndex the glyph index in this GlyphVector. - * - * @return the glyph visual bounds of the glyph with the specified - * index in the GlyphVector. + * @param glyphIndex + * the glyph index in this GlyphVector. + * @return the glyph visual bounds of the glyph with the specified index in + * the GlyphVector. */ public abstract Shape getGlyphVisualBounds(int glyphIndex); /** - * Gets a Shape object which defines the visual representation - * of the specified glyph in this GlyphVector. - * - * @param glyphIndex the glyth index in this GlyphVector. + * Gets a Shape object which defines the visual representation of the + * specified glyph in this GlyphVector. * - * @return a Shape object which represents the visual representation - * of the specified glyph in this GlyphVector - glyph outline. + * @param glyphIndex + * the glyth index in this GlyphVector. + * @return a Shape object which represents the visual representation of the + * specified glyph in this GlyphVector - glyph outline. */ public abstract Shape getGlyphOutline(int glyphIndex); /** - * Gets the logical bounds of the specified glyph in - * the GlyphVector. + * Gets the logical bounds of the specified glyph in the GlyphVector. * - * @param glyphIndex the index in this GlyphVector of the glyph from which - * to retrieve its logical bounds - * - * @return the logical bounds of the specified glyph in - * the GlyphVector. + * @param glyphIndex + * the index in this GlyphVector of the glyph from which to + * retrieve its logical bounds + * @return the logical bounds of the specified glyph in the GlyphVector. */ public abstract Shape getGlyphLogicalBounds(int glyphIndex); /** - * Gets the visual representation of this GlyphVector rendered in - * x, y location as a Shape object. - * - * @param x the x coordinate of the GlyphVector. - * @param y the y coordinate of the GlyphVector. + * Gets the visual representation of this GlyphVector rendered in x, y + * location as a Shape object. * + * @param x + * the x coordinate of the GlyphVector. + * @param y + * the y coordinate of the GlyphVector. * @return the visual representation of this GlyphVector as a Shape object. */ public abstract Shape getOutline(float x, float y); @@ -298,77 +306,79 @@ public abstract class GlyphVector implements Cloneable { /** * Gets an array of the glyph codes of the specified glyphs. * - * @param beginGlyphIndex the index into this GlyphVector at which - * to start retrieving glyph codes. - * @param numEntries the number of glyph codes. - * @param codeReturn the array into which the resulting - * glyphcodes will be written. - * + * @param beginGlyphIndex + * the index into this GlyphVector at which to start retrieving + * glyph codes. + * @param numEntries + * the number of glyph codes. + * @param codeReturn + * the array into which the resulting glyphcodes will be written. * @return the array of the glyph codes. */ - public abstract int[] getGlyphCodes(int beginGlyphIndex, int numEntries, - int[] codeReturn); + public abstract int[] getGlyphCodes(int beginGlyphIndex, int numEntries, int[] codeReturn); /** - * Gets an array of the character indices of - * the specified glyphs. - * - * @param beginGlyphIndex the index of the first glyph to return information for. - * @param numEntries the number of glyph indices to return. - * @param codeReturn the array into which the resulting character - * indices will be written. - * + * Gets an array of the character indices of the specified glyphs. + * + * @param beginGlyphIndex + * the index of the first glyph to return information for. + * @param numEntries + * the number of glyph indices to return. + * @param codeReturn + * the array into which the resulting character indices will be + * written. * @return an array of character indices for the specifies glyphs. */ - public int[] getGlyphCharIndices(int beginGlyphIndex, int numEntries, - int[] codeReturn) { + public int[] getGlyphCharIndices(int beginGlyphIndex, int numEntries, int[] codeReturn) { if (codeReturn == null) { codeReturn = new int[numEntries]; } - for (int i = 0; i < numEntries; i++){ - codeReturn[i] = getGlyphCharIndex(i+beginGlyphIndex); + for (int i = 0; i < numEntries; i++) { + codeReturn[i] = getGlyphCharIndex(i + beginGlyphIndex); } return codeReturn; } /** - * Gets an array of the positions of the specified glyphs in - * this GlyphVector. - * - * @param beginGlyphIndex the index of the first glyph to return information for. - * @param numEntries the number of glyphs to return information for. - * @param positionReturn the array where the result will be stored. - * + * Gets an array of the positions of the specified glyphs in this + * GlyphVector. + * + * @param beginGlyphIndex + * the index of the first glyph to return information for. + * @param numEntries + * the number of glyphs to return information for. + * @param positionReturn + * the array where the result will be stored. * @return an array of glyph positions. */ - public abstract float[] getGlyphPositions(int beginGlyphIndex, - int numEntries, float[] positionReturn); + public abstract float[] getGlyphPositions(int beginGlyphIndex, int numEntries, + float[] positionReturn); /** * Gets the glyph code of the specified glyph. * - * @param glyphIndex the index in this GlyphVector which corresponds - * to the glyph from which to retrieve the glyphcode. - * + * @param glyphIndex + * the index in this GlyphVector which corresponds to the glyph + * from which to retrieve the glyphcode. * @return the glyphcode of the specified glyph. */ public abstract int getGlyphCode(int glyphIndex); /** - * Gets the first logical character's index of the specified glyph. - * - * @param glyphIndex the glyph index. + * Gets the first logical character's index of the specified glyph. * + * @param glyphIndex + * the glyph index. * @return the the first logical character's index. */ - public int getGlyphCharIndex(int glyphIndex){ + public int getGlyphCharIndex(int glyphIndex) { // default implemetation one-to-one return glyphIndex; } /** - * Sets default layout to this GlyphVector. + * Sets default layout to this GlyphVector. */ public abstract void performDefaultLayout(); @@ -380,15 +390,14 @@ public abstract class GlyphVector implements Cloneable { public abstract int getNumGlyphs(); /** - * Gets flags which describe the global state of the GlyphVector. - * The default implementation returns 0. + * Gets flags which describe the global state of the GlyphVector. The + * default implementation returns 0. * * @return the layout flags */ - public int getLayoutFlags(){ + public int getLayoutFlags() { // default implementation - returned value is 0 return 0; } } - diff --git a/awt/java/awt/font/GraphicAttribute.java b/awt/java/awt/font/GraphicAttribute.java index 2f41951c65968f3eeeb0446f428714cb0d687a3b..8480e0f6a1b27f29b76ebbbed66805874b70ab55 100644 --- a/awt/java/awt/font/GraphicAttribute.java +++ b/awt/java/awt/font/GraphicAttribute.java @@ -18,6 +18,7 @@ * @author Ilya S. Okomin * @version $Revision$ */ + package java.awt.font; import java.awt.Graphics2D; @@ -26,49 +27,54 @@ import java.awt.geom.Rectangle2D; import org.apache.harmony.awt.internal.nls.Messages; /** - * The GraphicAttribute abstract class provides an opportunity to - * insert graphical elements in printed text. + * The GraphicAttribute abstract class provides an opportunity to insert + * graphical elements in printed text. + * + * @since Android 1.0 */ public abstract class GraphicAttribute { - /** - * The Constant TOP_ALIGNMENT indicates using the top line to - * calculate placement of graphics. + /** + * The Constant TOP_ALIGNMENT indicates using the top line to calculate + * placement of graphics. */ public static final int TOP_ALIGNMENT = -1; - /** - * The Constant BOTTOM_ALIGNMENT indicates using the bottom line to - * calculate placement of graphics. + /** + * The Constant BOTTOM_ALIGNMENT indicates using the bottom line to + * calculate placement of graphics. */ public static final int BOTTOM_ALIGNMENT = -2; - /** - * The Constant ROMAN_BASELINE indicates the placement of the roman - * baseline with respect to the graphics origin. + /** + * The Constant ROMAN_BASELINE indicates the placement of the roman baseline + * with respect to the graphics origin. */ public static final int ROMAN_BASELINE = 0; - /** - * The Constant CENTER_BASELINE indicates the placement of the center + /** + * The Constant CENTER_BASELINE indicates the placement of the center * baseline with respect to the graphics origin. */ public static final int CENTER_BASELINE = 1; - /** - * The Constant HANGING_BASELINE indicates the placement of the hanging - * baseline with respect to the graphics origin. + /** + * The Constant HANGING_BASELINE indicates the placement of the hanging + * baseline with respect to the graphics origin. */ public static final int HANGING_BASELINE = 2; // the alignment of this GraphicAttribute - /** The alignment. */ + /** + * The alignment. + */ private int alignment; /** * Instantiates a new graphic attribute with the specified alignment. * - * @param align the specified alignment. + * @param align + * the specified alignment. */ protected GraphicAttribute(int align) { if ((align < BOTTOM_ALIGNMENT) || (align > HANGING_BASELINE)) { @@ -81,16 +87,19 @@ public abstract class GraphicAttribute { /** * Draws the GraphicAttribute at the specified location. * - * @param graphics the Graphics. - * @param x the X coordinate of GraphicAttribute location. - * @param y the Y coordinate of GraphicAttribute location. + * @param graphics + * the Graphics. + * @param x + * the X coordinate of GraphicAttribute location. + * @param y + * the Y coordinate of GraphicAttribute location. */ public abstract void draw(Graphics2D graphics, float x, float y); /** - * Gets the GraphicAttribute's advance. It's the distance from the point - * at which the graphic is rendered and the point where the next character - * or graphic is rendered. + * Gets the GraphicAttribute's advance. It's the distance from the point at + * which the graphic is rendered and the point where the next character or + * graphic is rendered. * * @return the GraphicAttribute's advance. */ @@ -139,58 +148,32 @@ public abstract class GraphicAttribute { * @return the GlyphJustificationInfo of this GraphicAttribute. */ public GlyphJustificationInfo getJustificationInfo() { - - /* Default implementation. - * Since documentation doesn't describe default values, - * they were calculated based on 1.5 release - * behavior and can be obtained using next test sample: - * - * // Create GraphicAttribute class implementation - * public class MyGraphicAttribute extends GraphicAttribute { - * protected MyGraphicAttribute(int align) { - * super(align); - * } - * - * public float getDescent() { - * return 0; - * } - * - * public float getAdvance() { - * return 1; - * } - * - * public void draw(Graphics2D g2, float x, float y) { - * } - * - * public float getAscent() { - * return 0; - * } - * } - * - * MyGraphicAttribute myGA = gat.new MyGraphicAttribute(0); - * // print justification parameters - * System.out.println(myGA.getJustificationInfo().growAbsorb); - * System.out.println(myGA.getJustificationInfo().shrinkAbsorb); - * System.out.println(myGA.getJustificationInfo().growLeftLimit); - * System.out.println(myGA.getJustificationInfo().growPriority); - * System.out.println(myGA.getJustificationInfo().growRightLimit); - * System.out.println(myGA.getJustificationInfo().shrinkLeftLimit); - * System.out.println(myGA.getJustificationInfo().shrinkPriority); - * System.out.println(myGA.getJustificationInfo().shrinkRightLimit); - * System.out.println(myGA.getJustificationInfo().weight); + + /* + * Default implementation. Since documentation doesn't describe default + * values, they were calculated based on 1.5 release behavior and can be + * obtained using next test sample: // Create GraphicAttribute class + * implementation public class MyGraphicAttribute extends + * GraphicAttribute { protected MyGraphicAttribute(int align) { + * super(align); } public float getDescent() { return 0; } public float + * getAdvance() { return 1; } public void draw(Graphics2D g2, float x, + * float y) { } public float getAscent() { return 0; } } + * MyGraphicAttribute myGA = gat.new MyGraphicAttribute(0); // print + * justification parameters + * System.out.println(myGA.getJustificationInfo().growAbsorb); + * System.out.println(myGA.getJustificationInfo().shrinkAbsorb); + * System.out.println(myGA.getJustificationInfo().growLeftLimit); + * System.out.println(myGA.getJustificationInfo().growPriority); + * System.out.println(myGA.getJustificationInfo().growRightLimit); + * System.out.println(myGA.getJustificationInfo().shrinkLeftLimit); + * System.out.println(myGA.getJustificationInfo().shrinkPriority); + * System.out.println(myGA.getJustificationInfo().shrinkRightLimit); + * System.out.println(myGA.getJustificationInfo().weight); */ float advance = getAdvance(); - return new GlyphJustificationInfo( - advance, - false, - GlyphJustificationInfo.PRIORITY_INTERCHAR, - advance / 3, - advance / 3, - false, - GlyphJustificationInfo.PRIORITY_WHITESPACE, - 0, - 0); + return new GlyphJustificationInfo(advance, false, + GlyphJustificationInfo.PRIORITY_INTERCHAR, advance / 3, advance / 3, false, + GlyphJustificationInfo.PRIORITY_WHITESPACE, 0, 0); } } - diff --git a/awt/java/awt/font/ImageGraphicAttribute.java b/awt/java/awt/font/ImageGraphicAttribute.java index 41f90b8e818222e7372b0c155e5119d822ef93ac..d6d4758d355e92b2d2d46248fd8ca723be9c0ecd 100644 --- a/awt/java/awt/font/ImageGraphicAttribute.java +++ b/awt/java/awt/font/ImageGraphicAttribute.java @@ -18,6 +18,7 @@ * @author Ilya S. Okomin * @version $Revision$ */ + package java.awt.font; import java.awt.Graphics2D; @@ -27,44 +28,57 @@ import java.awt.geom.Rectangle2D; import org.apache.harmony.misc.HashCode; /** - * The ImageGraphicAttribute class provides an opportunity to insert - * images to a text. + * The ImageGraphicAttribute class provides an opportunity to insert images to a + * text. + * + * @since Android 1.0 */ public final class ImageGraphicAttribute extends GraphicAttribute { // Image object rendered by this ImageGraphicAttribute - /** The image. */ + /** + * The image. + */ private Image fImage; // X coordinate of the origin point - /** The origin x. */ + /** + * The origin x. + */ private float fOriginX; // Y coordinate of the origin point - /** The origin y. */ + /** + * The origin y. + */ private float fOriginY; // the width of the image object - /** The img width. */ + /** + * The img width. + */ private float fImgWidth; // the height of the image object - /** The img height. */ + /** + * The img height. + */ private float fImgHeight; /** * Instantiates a new ImageGraphicAttribute with the specified image, * alignment and origins. * - * @param image the Image to be rendered by ImageGraphicAttribute. - * @param alignment the alignment of the ImageGraphicAttribute. - * @param originX the origin X coordinate in the image of - * ImageGraphicAttribute. - * @param originY the origin Y coordinate in the image of - * ImageGraphicAttribute. + * @param image + * the Image to be rendered by ImageGraphicAttribute. + * @param alignment + * the alignment of the ImageGraphicAttribute. + * @param originX + * the origin X coordinate in the image of ImageGraphicAttribute. + * @param originY + * the origin Y coordinate in the image of ImageGraphicAttribute. */ - public ImageGraphicAttribute(Image image, int alignment, float originX, - float originY) { + public ImageGraphicAttribute(Image image, int alignment, float originX, float originY) { super(alignment); this.fImage = image; @@ -80,8 +94,10 @@ public final class ImageGraphicAttribute extends GraphicAttribute { * Instantiates a new ImageGraphicAttribute with the specified image and * alignment. * - * @param image the Image to be rendered by ImageGraphicAttribute. - * @param alignment the alignment of the ImageGraphicAttribute. + * @param image + * the Image to be rendered by ImageGraphicAttribute. + * @param alignment + * the alignment of the ImageGraphicAttribute. */ public ImageGraphicAttribute(Image image, int alignment) { this(image, alignment, 0, 0); @@ -105,10 +121,10 @@ public final class ImageGraphicAttribute extends GraphicAttribute { * Compares the specified ImageGraphicAttribute object with this * ImageGraphicAttribute object. * - * @param iga the ImageGraphicAttribute object to be compared. - * + * @param iga + * the ImageGraphicAttribute object to be compared. * @return true, if the specified ImageGraphicAttribute object is equal to - * this ImageGraphicAttribute object, false otherwise. + * this ImageGraphicAttribute object, false otherwise. */ public boolean equals(ImageGraphicAttribute iga) { if (iga == null) { @@ -119,26 +135,23 @@ public final class ImageGraphicAttribute extends GraphicAttribute { return true; } - return (fOriginX == iga.fOriginX && - fOriginY == iga.fOriginY && - getAlignment() == iga.getAlignment() && - fImage.equals(iga.fImage)); + return (fOriginX == iga.fOriginX && fOriginY == iga.fOriginY + && getAlignment() == iga.getAlignment() && fImage.equals(iga.fImage)); } /** * Compares the specified Object with this ImageGraphicAttribute object. - * - * @param obj the Object to be compared. * + * @param obj + * the Object to be compared. * @return true, if the specified Object is equal to this - * ImageGraphicAttribute object, false otherwise. + * ImageGraphicAttribute object, false otherwise. */ @Override public boolean equals(Object obj) { try { - return equals((ImageGraphicAttribute) obj); - } - catch(ClassCastException e) { + return equals((ImageGraphicAttribute)obj); + } catch (ClassCastException e) { return false; } @@ -149,9 +162,6 @@ public final class ImageGraphicAttribute extends GraphicAttribute { g2.drawImage(fImage, (int)(x - fOriginX), (int)(y - fOriginY), null); } - /** - * @see java.awt.font.GraphicAttribute#getAdvance() - */ @Override public float getAdvance() { return Math.max(0, fImgWidth - fOriginX); @@ -167,13 +177,9 @@ public final class ImageGraphicAttribute extends GraphicAttribute { return new Rectangle2D.Float(-fOriginX, -fOriginY, fImgWidth, fImgHeight); } - /** - * @see java.awt.font.GraphicAttribute#getDescent() - */ @Override public float getDescent() { return Math.max(0, fImgHeight - fOriginY); } } - diff --git a/awt/java/awt/font/LineBreakMeasurer.java b/awt/java/awt/font/LineBreakMeasurer.java index efce615944cfa5392662ed0a121454f47830db83..4800093f63782757e902257a1e5f1f84e07c6045 100644 --- a/awt/java/awt/font/LineBreakMeasurer.java +++ b/awt/java/awt/font/LineBreakMeasurer.java @@ -21,64 +21,69 @@ package java.awt.font; -import java.text.AttributedCharacterIterator; -//???AWT: import java.text.BreakIterator; +import java.text.AttributedCharacterIterator; //???AWT: import java.text.BreakIterator; import org.apache.harmony.awt.internal.nls.Messages; /** - * The class LineBreakMeasurer provides methods to measure the graphical - * representation of a text in order to determine where to add line - * breaks so the resulting line of text fits its wrapping width. - * The wrapping width defines the visual width of the paragraph. + * The class LineBreakMeasurer provides methods to measure the graphical + * representation of a text in order to determine where to add line breaks so + * the resulting line of text fits its wrapping width. The wrapping width + * defines the visual width of the paragraph. + * + * @since Android 1.0 */ public final class LineBreakMeasurer { - - /** The tm. */ + + /** + * The tm. + */ private TextMeasurer tm = null; - //???AWT private BreakIterator bi = null; - /** The position. */ + + // ???AWT private BreakIterator bi = null; + /** + * The position. + */ private int position = 0; - - /** The maxpos. */ + + /** + * The maxpos. + */ int maxpos = 0; /** * Instantiates a new LineBreakMeasurer object for the specified text. * - * @param text the AttributedCharacterIterator object which contains - * text with at least one character. - * @param frc the FontRenderContext represented information - * about graphic device. + * @param text + * the AttributedCharacterIterator object which contains text + * with at least one character. + * @param frc + * the FontRenderContext represented information about graphic + * device. */ public LineBreakMeasurer(AttributedCharacterIterator text, FontRenderContext frc) { - //???AWT: this(text, BreakIterator.getLineInstance(), frc); + // ???AWT: this(text, BreakIterator.getLineInstance(), frc); } - /* ???AWT - public LineBreakMeasurer( - AttributedCharacterIterator text, - BreakIterator bi, - FontRenderContext frc - ) { - tm = new TextMeasurer(text, frc); - this.bi = bi; - this.bi.setText(text); - position = text.getBeginIndex(); - maxpos = tm.aci.getEndIndex(); - } - */ + /* + * ???AWT public LineBreakMeasurer( AttributedCharacterIterator text, + * BreakIterator bi, FontRenderContext frc ) { tm = new TextMeasurer(text, + * frc); this.bi = bi; this.bi.setText(text); position = + * text.getBeginIndex(); maxpos = tm.aci.getEndIndex(); } + */ /** - * Deletes a character from the specified position of the text, - * updates this LineBreakMeasurer object. + * Deletes a character from the specified position of the text, updates this + * LineBreakMeasurer object. * - * @param newText the new text. - * @param pos the posion of the character which is deleted. + * @param newText + * the new text. + * @param pos + * the position of the character which is deleted. */ public void deleteChar(AttributedCharacterIterator newText, int pos) { tm.deleteChar(newText, pos); - //???AWT: bi.setText(newText); + // ???AWT: bi.setText(newText); position = newText.getBeginIndex(); @@ -88,22 +93,24 @@ public final class LineBreakMeasurer { /** * Gets current position of this LineBreakMeasurer. * - * @return current position of this LineBreakMeasurer + * @return the current position of this LineBreakMeasurer */ public int getPosition() { return position; } /** - * Insertes a character at the specified position in the text, - * updates this LineBreakMeasurer object. + * Inserts a character at the specified position in the text, updates this + * LineBreakMeasurer object. * - * @param newText the new text. - * @param pos the posion of the character which is inserted. + * @param newText + * the new text. + * @param pos + * the position of the character which is inserted. */ public void insertChar(AttributedCharacterIterator newText, int pos) { tm.insertChar(newText, pos); -// ???AWT: bi.setText(newText); + // ???AWT: bi.setText(newText); position = newText.getBeginIndex(); @@ -111,21 +118,23 @@ public final class LineBreakMeasurer { } /** - * Returns the next line of text, updates current position in this + * Returns the next line of text, updates current position in this * LineBreakMeasurer. * - * @param wrappingWidth the maximum visible line width. - * @param offsetLimit the limit point withing the text indicating - * that no further text should be included on the line; the paragraph break. - * @param requireNextWord if true, null is returned (the entire word at the current - * position does not fit within the wrapping width); - * if false, a valid layout is returned that includes at least the - * character at the current position. - * - * @return the next TextLayout which begins at the current position and - * represents the next line of text with width wrappingWidth, null is - * returned if the entire word at the current position does not fit within - * the wrapping width. + * @param wrappingWidth + * the maximum visible line width. + * @param offsetLimit + * the limit point within the text indicating that no further + * text should be included on the line; the paragraph break. + * @param requireNextWord + * if true, null is returned (the entire word at the current + * position does not fit within the wrapping width); if false, a + * valid layout is returned that includes at least the character + * at the current position. + * @return the next TextLayout which begins at the current position and + * represents the next line of text with width wrappingWidth, null + * is returned if the entire word at the current position does not + * fit within the wrapping width. */ public TextLayout nextLayout(float wrappingWidth, int offsetLimit, boolean requireNextWord) { if (position == maxpos) { @@ -145,8 +154,8 @@ public final class LineBreakMeasurer { /** * Returns the next line of text. * - * @param wrappingWidth the maximum visible line width. - * + * @param wrappingWidth + * the maximum visible line width. * @return the next line of text. */ public TextLayout nextLayout(float wrappingWidth) { @@ -156,8 +165,8 @@ public final class LineBreakMeasurer { /** * Returns the end position of the next line of text. * - * @param wrappingWidth the maximum visible line width. - * + * @param wrappingWidth + * the maximum visible line width. * @return the end position of the next line of text. */ public int nextOffset(float wrappingWidth) { @@ -167,22 +176,22 @@ public final class LineBreakMeasurer { /** * Returns the end position of the next line of text. * - * @param wrappingWidth the maximum visible line width. - * @param offsetLimit the limit point withing the text indicating - * that no further text should be included on the line; the paragraph break. - * @param requireNextWord if true, the current position is returned - * if the entire next word does not fit within wrappingWidth; - * if false, the offset returned is at least one greater than the current - * position. - * + * @param wrappingWidth + * the maximum visible line width. + * @param offsetLimit + * the limit point withing the text indicating that no further + * text should be included on the line; the paragraph break. + * @param requireNextWord + * if true, the current position is returned if the entire next + * word does not fit within wrappingWidth; if false, the offset + * returned is at least one greater than the current position. * @return the end position of the next line of text. - * - * @throws IllegalArgumentException if the offsetLimit is less than - * the current position. + * @throws IllegalArgumentException + * if the offsetLimit is less than the current position. */ public int nextOffset(float wrappingWidth, int offsetLimit, boolean requireNextWord) { if (offsetLimit <= position) { - // awt.203=Offset limit should be greater than current position. + // awt.203=Offset limit should be greater than current position. throw new IllegalArgumentException(Messages.getString("awt.203")); //$NON-NLS-1$ } @@ -193,22 +202,20 @@ public final class LineBreakMeasurer { int breakPos = tm.getLineBreakIndex(position, wrappingWidth); int correctedPos = breakPos; - // This check is required because bi.preceding(maxpos) throws an exception - /* ???AWT - if (breakPos == maxpos) { - correctedPos = maxpos; - } else if (Character.isWhitespace(bi.getText().setIndex(breakPos))) { - correctedPos = bi.following(breakPos); - } else { - correctedPos = bi.preceding(breakPos); - } - */ - + // This check is required because bi.preceding(maxpos) throws an + // exception + /* + * ???AWT if (breakPos == maxpos) { correctedPos = maxpos; } else if + * (Character.isWhitespace(bi.getText().setIndex(breakPos))) { + * correctedPos = bi.following(breakPos); } else { correctedPos = + * bi.preceding(breakPos); } + */ + if (position >= correctedPos) { if (requireNextWord) { correctedPos = position; } else { - correctedPos = Math.max(position+1, breakPos); + correctedPos = Math.max(position + 1, breakPos); } } @@ -218,7 +225,8 @@ public final class LineBreakMeasurer { /** * Sets the new position of this LineBreakMeasurer. * - * @param pos the new position of this LineBreakMeasurer. + * @param pos + * the new position of this LineBreakMeasurer. */ public void setPosition(int pos) { if (tm.aci.getBeginIndex() > pos || maxpos < pos) { @@ -228,4 +236,3 @@ public final class LineBreakMeasurer { position = pos; } } - diff --git a/awt/java/awt/font/LineMetrics.java b/awt/java/awt/font/LineMetrics.java index 28571871046dbebdd10ab37f8dd5720bfbe6e4ef..4b03e5db2b0e23171a7d19b66206b2de31a943e8 100644 --- a/awt/java/awt/font/LineMetrics.java +++ b/awt/java/awt/font/LineMetrics.java @@ -18,22 +18,24 @@ * @author Ilya S. Okomin * @version $Revision$ */ + package java.awt.font; /** - * The LineMetrics class provides information such as concerning how the text - * is positioned with respect to the base line, such as ascent, descent, - * and leading. + * The LineMetrics class provides information such as concerning how the text is + * positioned with respect to the base line, such as ascent, descent, and + * leading. * + * @since Android 1.0 */ public abstract class LineMetrics { /** - * Gets the baseline offsets of the text according to the - * the baseline of this text. + * Gets the baseline offsets of the text according to the the baseline of + * this text. * - * @return the baseline offsets of the text according to the - * the baseline of this text. + * @return the baseline offsets of the text according to the the baseline of + * this text. */ public abstract float[] getBaselineOffsets(); @@ -45,11 +47,11 @@ public abstract class LineMetrics { public abstract int getNumChars(); /** - * Gets the baseline index, returns one of the following - * index: ROMAN_BASELINE, CENTER_BASELINE, HANGING_BASELINE. + * Gets the baseline index, returns one of the following index: + * ROMAN_BASELINE, CENTER_BASELINE, HANGING_BASELINE. * - * @return the baseline index: ROMAN_BASELINE, CENTER_BASELINE - * or HANGING_BASELINE. + * @return the baseline index: ROMAN_BASELINE, CENTER_BASELINE or + * HANGING_BASELINE. */ public abstract int getBaselineIndex(); @@ -89,11 +91,11 @@ public abstract class LineMetrics { public abstract float getLeading(); /** - * Gets the height of the text as a sum of the ascent, the descent - * and the leading. + * Gets the height of the text as a sum of the ascent, the descent and the + * leading. * - * @return the height of the text as a sum of the ascent, the descent - * and the leading. + * @return the height of the text as a sum of the ascent, the descent and + * the leading. */ public abstract float getHeight(); @@ -112,4 +114,3 @@ public abstract class LineMetrics { public abstract float getAscent(); } - diff --git a/awt/java/awt/font/MultipleMaster.java b/awt/java/awt/font/MultipleMaster.java index 773bfcfbf3946f982bc57577cc9996601bfb5f55..d264f24833f4486e1429459400c70d1b7d3403fa 100644 --- a/awt/java/awt/font/MultipleMaster.java +++ b/awt/java/awt/font/MultipleMaster.java @@ -18,38 +18,44 @@ * @author Ilya S. Okomin * @version $Revision$ */ + package java.awt.font; import java.awt.Font; /** - * The MultipleMaster interface provides methods to manipulate MultipleMaster + * The MultipleMaster interface provides methods to manipulate MultipleMaster * type fonts and retrieve graphical and design data from them. + * + * @since Android 1.0 */ public interface MultipleMaster { /** - * Derives a new multiple master font based on the specified - * parameters. - * - * @param glyphWidths float array which represents width of each glyph - * in font space. - * @param avgStemWidth the average stem width in font space. - * @param typicalCapHeight the typical upper case char height. - * @param typicalXHeight the typical lower case char height. - * @param italicAngle the slope angle for italics. + * Derives a new multiple master font based on the specified parameters. * + * @param glyphWidths + * float array which represents width of each glyph in font + * space. + * @param avgStemWidth + * the average stem width in font space. + * @param typicalCapHeight + * the typical upper case char height. + * @param typicalXHeight + * the typical lower case char height. + * @param italicAngle + * the slope angle for italics. * @return a MultipleMaster font. */ - public Font deriveMMFont(float[] glyphWidths, float avgStemWidth, - float typicalCapHeight, float typicalXHeight, float italicAngle); + public Font deriveMMFont(float[] glyphWidths, float avgStemWidth, float typicalCapHeight, + float typicalXHeight, float italicAngle); /** - * Derives a new multiple master font based on the design axis values - * contained in the specified array. - * - * @param axes an float array which contains axis values. + * Derives a new multiple master font based on the design axis values + * contained in the specified array. * + * @param axes + * an float array which contains axis values. * @return a MultipleMaster font. */ public Font deriveMMFont(float[] axes); @@ -62,25 +68,24 @@ public interface MultipleMaster { public float[] getDesignAxisDefaults(); /** - * Gets the array of design axis names. + * Gets the array of design axis names. * - * @return the array of design axis names. + * @return the array of design axis names. */ public String[] getDesignAxisNames(); /** - * Gets the array of design axis ranges. + * Gets the array of design axis ranges. * * @return the array of design axis ranges. */ public float[] getDesignAxisRanges(); /** - * Gets the number of multiple master design controls. + * Gets the number of multiple master design controls. * * @return the number of multiple master design controls. */ public int getNumDesignAxes(); } - diff --git a/awt/java/awt/font/OpenType.java b/awt/java/awt/font/OpenType.java index 53cb6c0d550eb6ffee27e000bf2f99981cbdfa94..db66911c49c1ed7a9a0466bafc81fd5f8770ef57 100644 --- a/awt/java/awt/font/OpenType.java +++ b/awt/java/awt/font/OpenType.java @@ -18,318 +18,323 @@ * @author Ilya S. Okomin * @version $Revision$ */ + package java.awt.font; /** - * The OpenType interface provides constants and methods for getting - * instance data for fonts of type OpenType and TrueType. For more information, - * see the OpenType specification. + * The OpenType interface provides constants and methods for getting instance + * data for fonts of type OpenType and TrueType. For more information, see the + * + * OpenType specification. + * + * @since Android 1.0 */ public interface OpenType { - /** - * The Constant TAG_ACNT indicates corresponding table tag - * in the Open Type Specification. + /** + * The Constant TAG_ACNT indicates corresponding table tag in the Open Type + * Specification. */ public static final int TAG_ACNT = 1633906292; - /** - * The Constant TAG_AVAR indicates corresponding table tag - * in the Open Type Specification. + /** + * The Constant TAG_AVAR indicates corresponding table tag in the Open Type + * Specification. */ public static final int TAG_AVAR = 1635148146; - /** - * The Constant TAG_BASE indicates corresponding table tag - * in the Open Type Specification. + /** + * The Constant TAG_BASE indicates corresponding table tag in the Open Type + * Specification. */ public static final int TAG_BASE = 1111577413; - /** - * The Constant TAG_BDAT indicates corresponding table tag - * in the Open Type Specification. + /** + * The Constant TAG_BDAT indicates corresponding table tag in the Open Type + * Specification. */ public static final int TAG_BDAT = 1650745716; - /** - * The Constant TAG_BLOC indicates corresponding table tag - * in the Open Type Specification. + /** + * The Constant TAG_BLOC indicates corresponding table tag in the Open Type + * Specification. */ public static final int TAG_BLOC = 1651273571; - /** - * The Constant TAG_BSLN indicates corresponding table tag - * in the Open Type Specification. + /** + * The Constant TAG_BSLN indicates corresponding table tag in the Open Type + * Specification. */ public static final int TAG_BSLN = 1651731566; - /** - * The Constant TAG_CFF indicates corresponding table tag - * in the Open Type Specification. + /** + * The Constant TAG_CFF indicates corresponding table tag in the Open Type + * Specification. */ public static final int TAG_CFF = 1128678944; - /** - * The Constant TAG_CMAP indicates corresponding table tag - * in the Open Type Specification. + /** + * The Constant TAG_CMAP indicates corresponding table tag in the Open Type + * Specification. */ public static final int TAG_CMAP = 1668112752; - /** - * The Constant TAG_CVAR indicates corresponding table tag - * in the Open Type Specification. + /** + * The Constant TAG_CVAR indicates corresponding table tag in the Open Type + * Specification. */ public static final int TAG_CVAR = 1668702578; - /** - * The Constant TAG_CVT indicates corresponding table tag - * in the Open Type Specification. + /** + * The Constant TAG_CVT indicates corresponding table tag in the Open Type + * Specification. */ public static final int TAG_CVT = 1668707360; - /** - * The Constant TAG_DSIG indicates corresponding table tag - * in the Open Type Specification. + /** + * The Constant TAG_DSIG indicates corresponding table tag in the Open Type + * Specification. */ public static final int TAG_DSIG = 1146308935; - /** - * The Constant TAG_EBDT indicates corresponding table tag - * in the Open Type Specification. + /** + * The Constant TAG_EBDT indicates corresponding table tag in the Open Type + * Specification. */ public static final int TAG_EBDT = 1161970772; - /** - * The Constant TAG_EBLC indicates corresponding table tag - * in the Open Type Specification. + /** + * The Constant TAG_EBLC indicates corresponding table tag in the Open Type + * Specification. */ public static final int TAG_EBLC = 1161972803; - /** - * The Constant TAG_EBSC indicates corresponding table tag - * in the Open Type Specification. + /** + * The Constant TAG_EBSC indicates corresponding table tag in the Open Type + * Specification. */ public static final int TAG_EBSC = 1161974595; - /** - * The Constant TAG_FDSC indicates corresponding table tag - * in the Open Type Specification. + /** + * The Constant TAG_FDSC indicates corresponding table tag in the Open Type + * Specification. */ public static final int TAG_FDSC = 1717859171; - /** - * The Constant TAG_FEAT indicates corresponding table tag - * in the Open Type Specification. + /** + * The Constant TAG_FEAT indicates corresponding table tag in the Open Type + * Specification. */ public static final int TAG_FEAT = 1717920116; - /** - * The Constant TAG_FMTX indicates corresponding table tag - * in the Open Type Specification. + /** + * The Constant TAG_FMTX indicates corresponding table tag in the Open Type + * Specification. */ public static final int TAG_FMTX = 1718449272; - /** - * The Constant TAG_FPGM indicates corresponding table tag - * in the Open Type Specification. + /** + * The Constant TAG_FPGM indicates corresponding table tag in the Open Type + * Specification. */ public static final int TAG_FPGM = 1718642541; - /** - * The Constant TAG_FVAR indicates corresponding table tag - * in the Open Type Specification. + /** + * The Constant TAG_FVAR indicates corresponding table tag in the Open Type + * Specification. */ public static final int TAG_FVAR = 1719034226; - /** - * The Constant TAG_GASP indicates corresponding table tag - * in the Open Type Specification. + /** + * The Constant TAG_GASP indicates corresponding table tag in the Open Type + * Specification. */ public static final int TAG_GASP = 1734439792; - /** - * The Constant TAG_GDEF indicates corresponding table tag - * in the Open Type Specification. + /** + * The Constant TAG_GDEF indicates corresponding table tag in the Open Type + * Specification. */ public static final int TAG_GDEF = 1195656518; - /** - * The Constant TAG_GLYF indicates corresponding table tag - * in the Open Type Specification. + /** + * The Constant TAG_GLYF indicates corresponding table tag in the Open Type + * Specification. */ public static final int TAG_GLYF = 1735162214; - /** - * The Constant TAG_GPOS indicates corresponding table tag - * in the Open Type Specification. + /** + * The Constant TAG_GPOS indicates corresponding table tag in the Open Type + * Specification. */ public static final int TAG_GPOS = 1196445523; - /** - * The Constant TAG_GSUB indicates corresponding table tag - * in the Open Type Specification. + /** + * The Constant TAG_GSUB indicates corresponding table tag in the Open Type + * Specification. */ public static final int TAG_GSUB = 1196643650; - /** - * The Constant TAG_GVAR indicates corresponding table tag - * in the Open Type Specification. + /** + * The Constant TAG_GVAR indicates corresponding table tag in the Open Type + * Specification. */ public static final int TAG_GVAR = 1735811442; - /** - * The Constant TAG_HDMX indicates corresponding table tag - * in the Open Type Specification. + /** + * The Constant TAG_HDMX indicates corresponding table tag in the Open Type + * Specification. */ public static final int TAG_HDMX = 1751412088; - /** - * The Constant TAG_HEAD indicates corresponding table tag - * in the Open Type Specification. + /** + * The Constant TAG_HEAD indicates corresponding table tag in the Open Type + * Specification. */ public static final int TAG_HEAD = 1751474532; - /** - * The Constant TAG_HHEA indicates corresponding table tag - * in the Open Type Specification. + /** + * The Constant TAG_HHEA indicates corresponding table tag in the Open Type + * Specification. */ public static final int TAG_HHEA = 1751672161; - /** - * The Constant TAG_HMTX indicates corresponding table tag - * in the Open Type Specification. + /** + * The Constant TAG_HMTX indicates corresponding table tag in the Open Type + * Specification. */ public static final int TAG_HMTX = 1752003704; - /** - * The Constant TAG_JSTF indicates corresponding table tag - * in the Open Type Specification. + /** + * The Constant TAG_JSTF indicates corresponding table tag in the Open Type + * Specification. */ public static final int TAG_JSTF = 1246975046; - /** - * The Constant TAG_JUST indicates corresponding table tag - * in the Open Type Specification. + /** + * The Constant TAG_JUST indicates corresponding table tag in the Open Type + * Specification. */ public static final int TAG_JUST = 1786082164; - /** - * The Constant TAG_KERN indicates corresponding table tag - * in the Open Type Specification. + /** + * The Constant TAG_KERN indicates corresponding table tag in the Open Type + * Specification. */ public static final int TAG_KERN = 1801810542; - /** - * The Constant TAG_LCAR indicates corresponding table tag - * in the Open Type Specification. + /** + * The Constant TAG_LCAR indicates corresponding table tag in the Open Type + * Specification. */ public static final int TAG_LCAR = 1818452338; - /** - * The Constant TAG_LOCA indicates corresponding table tag - * in the Open Type Specification. + /** + * The Constant TAG_LOCA indicates corresponding table tag in the Open Type + * Specification. */ public static final int TAG_LOCA = 1819239265; - /** - * The Constant TAG_LTSH indicates corresponding table tag - * in the Open Type Specification. + /** + * The Constant TAG_LTSH indicates corresponding table tag in the Open Type + * Specification. */ public static final int TAG_LTSH = 1280594760; - /** - * The Constant TAG_MAXP indicates corresponding table tag - * in the Open Type Specification. + /** + * The Constant TAG_MAXP indicates corresponding table tag in the Open Type + * Specification. */ public static final int TAG_MAXP = 1835104368; - /** - * The Constant TAG_MMFX indicates corresponding table tag - * in the Open Type Specification. + /** + * The Constant TAG_MMFX indicates corresponding table tag in the Open Type + * Specification. */ public static final int TAG_MMFX = 1296909912; - /** - * The Constant TAG_MMSD indicates corresponding table tag - * in the Open Type Specification. + /** + * The Constant TAG_MMSD indicates corresponding table tag in the Open Type + * Specification. */ public static final int TAG_MMSD = 1296913220; - /** - * The Constant TAG_MORT indicates corresponding table tag - * in the Open Type Specification. + /** + * The Constant TAG_MORT indicates corresponding table tag in the Open Type + * Specification. */ public static final int TAG_MORT = 1836020340; - /** - * The Constant TAG_NAME indicates corresponding table tag - * in the Open Type Specification. + /** + * The Constant TAG_NAME indicates corresponding table tag in the Open Type + * Specification. */ public static final int TAG_NAME = 1851878757; - /** - * The Constant TAG_OPBD indicates corresponding table tag - * in the Open Type Specification. + /** + * The Constant TAG_OPBD indicates corresponding table tag in the Open Type + * Specification. */ public static final int TAG_OPBD = 1836020340; - /** - * The Constant TAG_OS2 indicates corresponding table tag - * in the Open Type Specification. + /** + * The Constant TAG_OS2 indicates corresponding table tag in the Open Type + * Specification. */ public static final int TAG_OS2 = 1330851634; - /** - * The Constant TAG_PCLT indicates corresponding table tag - * in the Open Type Specification. + /** + * The Constant TAG_PCLT indicates corresponding table tag in the Open Type + * Specification. */ public static final int TAG_PCLT = 1346587732; - /** - * The Constant TAG_POST indicates corresponding table tag - * in the Open Type Specification. + /** + * The Constant TAG_POST indicates corresponding table tag in the Open Type + * Specification. */ public static final int TAG_POST = 1886352244; - /** - * The Constant TAG_PREP indicates corresponding table tag - * in the Open Type Specification. + /** + * The Constant TAG_PREP indicates corresponding table tag in the Open Type + * Specification. */ public static final int TAG_PREP = 1886545264; - /** - * The Constant TAG_PROP indicates corresponding table tag - * in the Open Type Specification. + /** + * The Constant TAG_PROP indicates corresponding table tag in the Open Type + * Specification. */ public static final int TAG_PROP = 1886547824; - /** - * The Constant TAG_TRAK indicates corresponding table tag - * in the Open Type Specification. + /** + * The Constant TAG_TRAK indicates corresponding table tag in the Open Type + * Specification. */ public static final int TAG_TRAK = 1953653099; - /** - * The Constant TAG_TYP1 indicates corresponding table tag - * in the Open Type Specification. + /** + * The Constant TAG_TYP1 indicates corresponding table tag in the Open Type + * Specification. */ public static final int TAG_TYP1 = 1954115633; - /** - * The Constant TAG_VDMX indicates corresponding table tag - * in the Open Type Specification. + /** + * The Constant TAG_VDMX indicates corresponding table tag in the Open Type + * Specification. */ public static final int TAG_VDMX = 1447316824; - /** - * The Constant TAG_VHEA indicates corresponding table tag - * in the Open Type Specification. + /** + * The Constant TAG_VHEA indicates corresponding table tag in the Open Type + * Specification. */ public static final int TAG_VHEA = 1986553185; - /** - * The Constant TAG_VMTX indicates corresponding table tag - * in the Open Type Specification. + /** + * The Constant TAG_VMTX indicates corresponding table tag in the Open Type + * Specification. */ public static final int TAG_VMTX = 1986884728; @@ -341,70 +346,73 @@ public interface OpenType { public int getVersion(); /** - * Gets the table for a specified tag. - * Sfnt tables include cmap, name and head items. - * - * @param sfntTag the sfnt tag. + * Gets the table for a specified tag. Sfnt tables include cmap, name and + * head items. * - * @return a byte array contains the font data corresponding - * to the specified tag. + * @param sfntTag + * the sfnt tag. + * @return a byte array contains the font data corresponding to the + * specified tag. */ public byte[] getFontTable(int sfntTag); /** - * Gets the table for a specified tag. - * Sfnt tables include cmap, name and head items. - * - * @param sfntTag the sfnt tag. - * @param offset the offset of the returned table. - * @param count the number of returned table. + * Gets the table for a specified tag. Sfnt tables include cmap, name and + * head items. * - * @return the table corresponding to sfntTag and containing - * the bytes starting at offset byte and including count bytes. + * @param sfntTag + * the sfnt tag. + * @param offset + * the offset of the returned table. + * @param count + * the number of returned table. + * @return the table corresponding to sfntTag and containing the bytes + * starting at offset byte and including count bytes. */ public byte[] getFontTable(int sfntTag, int offset, int count); /** - * Gets the table for a specified tag. - * Sfnt tables include cmap, name and head items. - * - * @param strSfntTag the str sfnt tag as a String. + * Gets the table for a specified tag. Sfnt tables include cmap, name and + * head items. * - * @return a byte array contains the font data corresponding - * to the specified tag. + * @param strSfntTag + * the str sfnt tag as a String. + * @return a byte array contains the font data corresponding to the + * specified tag. */ public byte[] getFontTable(String strSfntTag); /** - * Gets the table for a specified tag. - * Sfnt tables include cmap, name and head items. - * - * @param strSfntTag the sfnt tag as a String. - * @param offset the offset of the returned table. - * @param count the number of returned table. + * Gets the table for a specified tag. Sfnt tables include cmap, name and + * head items. * - * @return the table corresponding to sfntTag and containing - * the bytes starting at offset byte and including count bytes. + * @param strSfntTag + * the sfnt tag as a String. + * @param offset + * the offset of the returned table. + * @param count + * the number of returned table. + * @return the table corresponding to sfntTag and containing the bytes + * starting at offset byte and including count bytes. */ public byte[] getFontTable(String strSfntTag, int offset, int count); /** - * Gets the table size for a specified tag. - * - * @param strSfntTag the sfnt tag as a String. + * Gets the table size for a specified tag. * + * @param strSfntTag + * the sfnt tag as a String. * @return the table size for a specified tag. */ public int getFontTableSize(String strSfntTag); /** - * Gets the table size for a specified tag. - * - * @param sfntTag the sfnt tag. + * Gets the table size for a specified tag. * + * @param sfntTag + * the sfnt tag. * @return the table size for a specified tag. */ public int getFontTableSize(int sfntTag); } - diff --git a/awt/java/awt/font/ShapeGraphicAttribute.java b/awt/java/awt/font/ShapeGraphicAttribute.java index 45199fd3f39bcf1dadc4ed15770e6f529f8df9c7..182bffddc2e194be82b4cd7f5b2346819e378bac 100644 --- a/awt/java/awt/font/ShapeGraphicAttribute.java +++ b/awt/java/awt/font/ShapeGraphicAttribute.java @@ -18,6 +18,7 @@ * @author Ilya S. Okomin * @version $Revision$ */ + package java.awt.font; import java.awt.BasicStroke; @@ -29,61 +30,75 @@ import java.awt.geom.Rectangle2D; import org.apache.harmony.misc.HashCode; - /** - * The ShapeGraphicAttribute class provides an opportunity to insert - * shapes to a text. + * The ShapeGraphicAttribute class provides an opportunity to insert shapes to a + * text. + * + * @since Android 1.0 */ public final class ShapeGraphicAttribute extends GraphicAttribute { // shape to render - /** The shape. */ + /** + * The shape. + */ private Shape fShape; - + // flag, if the shape should be stroked (true) or filled (false) - /** The stroke. */ + /** + * The stroke. + */ private boolean fStroke; // bounds of the shape - /** The bounds. */ + /** + * The bounds. + */ private Rectangle2D fBounds; - + // X coordinate of the origin point - /** The origin x. */ + /** + * The origin x. + */ private float fOriginX; - + // Y coordinate of the origin point - /** The origin y. */ + /** + * The origin y. + */ private float fOriginY; // width of the shape - /** The shape width. */ + /** + * The shape width. + */ private float fShapeWidth; - + // height of the shape - /** The shape height. */ + /** + * The shape height. + */ private float fShapeHeight; - /** - * The Constant STROKE indicates whether the Shape is stroked - * or not. + /** + * The Constant STROKE indicates whether the Shape is stroked or not. */ public static final boolean STROKE = true; - /** - * The Constant FILL indicates whether the Shape is filled - * or not. */ + /** + * The Constant FILL indicates whether the Shape is filled or not. + */ public static final boolean FILL = false; /** - * Instantiates a new ShapeGraphicAttribute object for the specified - * Shape. + * Instantiates a new ShapeGraphicAttribute object for the specified Shape. * - * @param shape the shape to be rendered by this - * ShapeGraphicAttribute. - * @param alignment the alignment of this ShapeGraphicAttribute. - * @param stroke true if the Shape is stroked, - * false if the Shape is filled. + * @param shape + * the shape to be rendered by this ShapeGraphicAttribute. + * @param alignment + * the alignment of this ShapeGraphicAttribute. + * @param stroke + * true if the Shape is stroked, false if the Shape is filled. */ public ShapeGraphicAttribute(Shape shape, int alignment, boolean stroke) { super(alignment); @@ -91,7 +106,7 @@ public final class ShapeGraphicAttribute extends GraphicAttribute { this.fShape = shape; this.fStroke = stroke; - this.fBounds = fShape.getBounds2D(); + this.fBounds = fShape.getBounds2D(); this.fOriginX = (float)fBounds.getMinX(); this.fOriginY = (float)fBounds.getMinY(); @@ -118,10 +133,10 @@ public final class ShapeGraphicAttribute extends GraphicAttribute { * Compares this ShapeGraphicAttribute object to the specified * ShapeGraphicAttribute object. * - * @param sga the ShapeGraphicAttribute object to be compared. - * - * @return true, if this ShapeGraphicAttribute object is equal - * to the specified ShapeGraphicAttribute object, false otherwise. + * @param sga + * the ShapeGraphicAttribute object to be compared. + * @return true, if this ShapeGraphicAttribute object is equal to the + * specified ShapeGraphicAttribute object, false otherwise. */ public boolean equals(ShapeGraphicAttribute sga) { if (sga == null) { @@ -132,27 +147,24 @@ public final class ShapeGraphicAttribute extends GraphicAttribute { return true; } - return ( fStroke == sga.fStroke && - getAlignment() == sga.getAlignment() && - fShape.equals(sga.fShape)); + return (fStroke == sga.fStroke && getAlignment() == sga.getAlignment() && fShape + .equals(sga.fShape)); } /** - * Compares this ShapeGraphicAttribute object to the specified - * Object. + * Compares this ShapeGraphicAttribute object to the specified Object. * - * @param obj the Object to be compared. - * - * @return true, if this ShapeGraphicAttribute object is equal - * to the specified Object, false otherwise. + * @param obj + * the Object to be compared. + * @return true, if this ShapeGraphicAttribute object is equal to the + * specified Object, false otherwise. */ @Override public boolean equals(Object obj) { try { - return equals((ShapeGraphicAttribute) obj); - } - catch(ClassCastException e) { + return equals((ShapeGraphicAttribute)obj); + } catch (ClassCastException e) { return false; } } @@ -160,7 +172,7 @@ public final class ShapeGraphicAttribute extends GraphicAttribute { @Override public void draw(Graphics2D g2, float x, float y) { AffineTransform at = AffineTransform.getTranslateInstance(x, y); - if (fStroke == STROKE){ + if (fStroke == STROKE) { Stroke oldStroke = g2.getStroke(); g2.setStroke(new BasicStroke()); g2.draw(at.createTransformedShape(fShape)); @@ -192,4 +204,3 @@ public final class ShapeGraphicAttribute extends GraphicAttribute { } } - diff --git a/awt/java/awt/font/TextHitInfo.java b/awt/java/awt/font/TextHitInfo.java index 17bbf717cef1c8f87c62f8d2a0dfac4372f786b3..6460ebacee79a06dd936b28e330749f7f02a7e59 100644 --- a/awt/java/awt/font/TextHitInfo.java +++ b/awt/java/awt/font/TextHitInfo.java @@ -23,29 +23,36 @@ package java.awt.font; import org.apache.harmony.misc.HashCode; - /** - * The TextHitInfo class provides information about a caret position - * in a text model for insertion or deletion of a character in a text. - * The TextHitInfo defines two biases of the character: leading or trailing. - * Leading position means the left edge of the specified character - * (TextHitInfo.leading(2) method for "text" returns the left side of "x"). - * Trailing position means the right edge of the specified character - * (TextHitInfo.trailing(2) method for "text" returns the right side of "x"). + * The TextHitInfo class provides information about a caret position in a text + * model for insertion or deletion of a character in a text. The TextHitInfo + * defines two biases of the character: leading or trailing. Leading position + * means the left edge of the specified character (TextHitInfo.leading(2) method + * for "text" returns the left side of "x"). Trailing position means the right + * edge of the specified character (TextHitInfo.trailing(2) method for "text" + * returns the right side of "x"). + * + * @since Android 1.0 */ public final class TextHitInfo { - - /** The char idx. */ + + /** + * The char idx. + */ private int charIdx; // Represents character index in the line - - /** The is trailing. */ + + /** + * The is trailing. + */ private boolean isTrailing; /** * Instantiates a new text hit info. * - * @param idx the idx - * @param isTrailing the is trailing + * @param idx + * the idx. + * @param isTrailing + * the is trailing. */ private TextHitInfo(int idx, boolean isTrailing) { charIdx = idx; @@ -53,90 +60,82 @@ public final class TextHitInfo { } /** - * To string. + * Returns the textual string representation of this TextHitInfo instance. * - * @return the string + * @return the string representation. */ @Override public String toString() { - return new String( - "TextHitInfo[" + charIdx + ", " + //$NON-NLS-1$ //$NON-NLS-2$ - (isTrailing?"Trailing":"Leading") + "]" //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + return new String("TextHitInfo[" + charIdx + ", " + //$NON-NLS-1$ //$NON-NLS-2$ + (isTrailing ? "Trailing" : "Leading") + "]" //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ ); } /** * Compares this TextHitInfo object with the specified object. * - * @param obj the Object to be compared. - * - * @return true, if the specified object is a TextHitInfo object - * with the same data values as this TextHitInfo, false otherwise. + * @param obj + * the Object to be compared. + * @return true, if the specified object is a TextHitInfo object with the + * same data values as this TextHitInfo, false otherwise. */ @Override public boolean equals(Object obj) { if (obj instanceof TextHitInfo) { - return equals((TextHitInfo) obj); + return equals((TextHitInfo)obj); } return false; } /** - * Compares this TextHitInfo object with the specified TextHitInfo - * object. - * - * @param thi the TextHitInfo object to be compared. + * Compares this TextHitInfo object with the specified TextHitInfo object. * + * @param thi + * the TextHitInfo object to be compared. * @return true, if this TextHitInfo object has the same data values as the - * specified TextHitInfo object, false otherwise. + * specified TextHitInfo object, false otherwise. */ public boolean equals(TextHitInfo thi) { - return - thi != null && - thi.charIdx == charIdx && - thi.isTrailing == isTrailing; + return thi != null && thi.charIdx == charIdx && thi.isTrailing == isTrailing; } /** - * Gets a TextHitInfo object with its character index - * at the specified offset from the character index of - * this TextHitInfo. + * Gets a TextHitInfo object with its character index at the specified + * offset from the character index of this TextHitInfo. * - * @param offset the offset. - * - * @return the TextHitInfo. + * @param offset + * the offset. + * @return the TextHitInfo. */ public TextHitInfo getOffsetHit(int offset) { return new TextHitInfo(charIdx + offset, isTrailing); } /** - * Gets a TextHitInfo associated with the other side of - * the insertion point. - * + * Gets a TextHitInfo associated with the other side of the insertion point. + * * @return the other hit. */ public TextHitInfo getOtherHit() { - return isTrailing ? - new TextHitInfo(charIdx+1, false) : - new TextHitInfo(charIdx-1, true); + return isTrailing ? new TextHitInfo(charIdx + 1, false) + : new TextHitInfo(charIdx - 1, true); } /** - * Returns true if the leading edge of the character is hit, - * false if the trailing edge of the character is hit. + * Returns true if the leading edge of the character is hit, false if the + * trailing edge of the character is hit. * - * @return true if the leading edge of the character is hit, - * false if the trailing edge of the character is hit. + * @return true if the leading edge of the character is hit, false if the + * trailing edge of the character is hit. */ public boolean isLeadingEdge() { return !isTrailing; } /** - * Hash code. + * Returns the hash code value of this TextHitInfo instance. * - * @return the int + * @return the hash code value. */ @Override public int hashCode() { @@ -146,11 +145,11 @@ public final class TextHitInfo { /** * Gets the insertion index. * - * @return the insertion index: character index if the leading edge - * is hit, or character index + 1 if the trailing edge is hit. + * @return the insertion index: character index if the leading edge is hit, + * or character index + 1 if the trailing edge is hit. */ public int getInsertionIndex() { - return isTrailing ? charIdx+1 : charIdx; + return isTrailing ? charIdx + 1 : charIdx; } /** @@ -163,52 +162,52 @@ public final class TextHitInfo { } /** - * Returns a TextHitInfo associated with the trailing edge of - * the character at the specified char index. + * Returns a TextHitInfo associated with the trailing edge of the character + * at the specified char index. * - * @param charIndex the char index. - * - * @return the TextHitInfo associated with the trailing edge of - * the character at the specified char index. + * @param charIndex + * the char index. + * @return the TextHitInfo associated with the trailing edge of the + * character at the specified char index. */ public static TextHitInfo trailing(int charIndex) { return new TextHitInfo(charIndex, true); } /** - * Returns a TextHitInfo object associated with the leading edge - * of the character at the specified char index. - * - * @param charIndex the char index. + * Returns a TextHitInfo object associated with the leading edge of the + * character at the specified char index. * - * @return the TextHitInfo object associated with the leading edge - * of the character at the specified char index. + * @param charIndex + * the char index. + * @return the TextHitInfo object associated with the leading edge of the + * character at the specified char index. */ public static TextHitInfo leading(int charIndex) { return new TextHitInfo(charIndex, false); } /** - * Returns a (trailing) TextHitInfo object associated with the character + * Returns a (trailing) TextHitInfo object associated with the character * before the specified offset. * - * @param offset the offset. - * - * @return the TextHitInfo object associated with the character - * before the specified offset. + * @param offset + * the offset. + * @return the TextHitInfo object associated with the character before the + * specified offset. */ public static TextHitInfo beforeOffset(int offset) { - return new TextHitInfo(offset-1, true); + return new TextHitInfo(offset - 1, true); } /** - * Returns a (leading) TextHitInfo object associated with the character + * Returns a (leading) TextHitInfo object associated with the character * after the specified offset. * - * @param offset the offset. - * - * @return the TextHitInfo object associated with the character - * after the specified offset. + * @param offset + * the offset. + * @return the TextHitInfo object associated with the character after the + * specified offset. */ public static TextHitInfo afterOffset(int offset) { return new TextHitInfo(offset, false); diff --git a/awt/java/awt/font/TextLayout.java b/awt/java/awt/font/TextLayout.java index e80afd091e0e923f2b72ef35de9a8f2b8a6ec973..cc6f0ba3af61dbf8539bb01b529e0ab80bbf6e0e 100644 --- a/awt/java/awt/font/TextLayout.java +++ b/awt/java/awt/font/TextLayout.java @@ -39,18 +39,19 @@ import org.apache.harmony.awt.internal.nls.Messages; /** * The TextLayout class defines the graphical representation of character data. - * This class provides method for obtaining information about cursor - * positioning and movement, split cursors for text with different directions, - * logical and visual highlighting, multiple baselines, hits, justification, - * ascent, descent, and advance, and rendering. A TextLayout object can be - * rendered using Graphics context. + * This class provides method for obtaining information about cursor positioning + * and movement, split cursors for text with different directions, logical and + * visual highlighting, multiple baselines, hits, justification, ascent, + * descent, and advance, and rendering. A TextLayout object can be rendered + * using Graphics context. + * + * @since Android 1.0 */ public final class TextLayout implements Cloneable { /** - * The CaretPolicy class provides a policy for obtaining the - * caret location. The single getStrongCaret method specifies - * the policy. + * The CaretPolicy class provides a policy for obtaining the caret location. + * The single getStrongCaret method specifies the policy. */ public static class CaretPolicy { @@ -62,14 +63,15 @@ public final class TextLayout implements Cloneable { } /** - * Returns whichever of the two specified TextHitInfo objects - * has the stronger caret (higher character level) in the - * specified TextLayout. - * - * @param hit1 the first TextHitInfo of the specified TextLayout. - * @param hit2 the second TextHitInfo of the specified TextLayout. - * @param layout the TextLayout. + * Returns whichever of the two specified TextHitInfo objects has the + * stronger caret (higher character level) in the specified TextLayout. * + * @param hit1 + * the first TextHitInfo of the specified TextLayout. + * @param hit2 + * the second TextHitInfo of the specified TextLayout. + * @param layout + * the TextLayout. * @return the TextHitInfo with the stronger caret. */ public TextHitInfo getStrongCaret(TextHitInfo hit1, TextHitInfo hit2, TextLayout layout) { @@ -87,50 +89,64 @@ public final class TextLayout implements Cloneable { } - /** + /** * The Constant DEFAULT_CARET_POLICY indicates the default caret policy. */ public static final TextLayout.CaretPolicy DEFAULT_CARET_POLICY = new CaretPolicy(); - /** The breaker. */ + /** + * The breaker. + */ private TextRunBreaker breaker; - - /** The metrics valid. */ + + /** + * The metrics valid. + */ private boolean metricsValid = false; - - /** The tmc. */ + + /** + * The tmc. + */ private TextMetricsCalculator tmc; - - /** The metrics. */ + + /** + * The metrics. + */ private BasicMetrics metrics; - - /** The caret manager. */ + + /** + * The caret manager. + */ private CaretManager caretManager; - - /** The justification width. */ + + /** + * The justification width. + */ float justificationWidth = -1; /** - * Instantiates a new TextLayout object from the specified string - * and Font. + * Instantiates a new TextLayout object from the specified string and Font. * - * @param string the string to be displayed. - * @param font the font of the text. - * @param frc the FontRenderContext object for obtaining - * information about a graphics device. + * @param string + * the string to be displayed. + * @param font + * the font of the text. + * @param frc + * the FontRenderContext object for obtaining information about a + * graphics device. */ public TextLayout(String string, Font font, FontRenderContext frc) { - if (string == null){ + if (string == null) { // awt.01='{0}' parameter is null throw new IllegalArgumentException(Messages.getString("awt.01", "string")); //$NON-NLS-1$ //$NON-NLS-2$ } - - if (font == null){ + + if (font == null) { // awt.01='{0}' parameter is null throw new IllegalArgumentException(Messages.getString("awt.01", "font")); //$NON-NLS-1$ //$NON-NLS-2$ } - if (string.length() == 0){ + if (string.length() == 0) { // awt.02='{0}' parameter has zero length throw new IllegalArgumentException(Messages.getString("awt.02", "string")); //$NON-NLS-1$ //$NON-NLS-2$ } @@ -142,35 +158,35 @@ public final class TextLayout implements Cloneable { } /** - * Instantiates a new TextLayout from the specified text and - * a map of attributes. + * Instantiates a new TextLayout from the specified text and a map of + * attributes. * - * @param string the string to be displayed. - * @param attributes the attributes to be used for obtaining the text - * style. - * @param frc the FontRenderContext object for obtaining - * information about a graphics device. + * @param string + * the string to be displayed. + * @param attributes + * the attributes to be used for obtaining the text style. + * @param frc + * the FontRenderContext object for obtaining information about a + * graphics device. */ - public TextLayout( - String string, + public TextLayout(String string, Map attributes, - FontRenderContext frc ) { - if (string == null){ + FontRenderContext frc) { + if (string == null) { // awt.01='{0}' parameter is null throw new IllegalArgumentException(Messages.getString("awt.01", "string")); //$NON-NLS-1$ //$NON-NLS-2$ } - - if (attributes == null){ + + if (attributes == null) { // awt.01='{0}' parameter is null throw new IllegalArgumentException(Messages.getString("awt.01", "attributes")); //$NON-NLS-1$ //$NON-NLS-2$ } - - if (string.length() == 0){ + + if (string.length() == 0) { // awt.02='{0}' parameter has zero length throw new IllegalArgumentException(Messages.getString("awt.02", "string")); //$NON-NLS-1$ //$NON-NLS-2$ } - - + AttributedString as = new AttributedString(string); as.addAttributes(attributes, 0, string.length()); this.breaker = new TextRunBreaker(as.getIterator(), frc); @@ -180,17 +196,19 @@ public final class TextLayout implements Cloneable { /** * Instantiates a new TextLayout from the AttributedCharacterIterator. * - * @param text the AttributedCharacterIterator. - * @param frc the FontRenderContext object for obtaining - * information about a graphics device. + * @param text + * the AttributedCharacterIterator. + * @param frc + * the FontRenderContext object for obtaining information about a + * graphics device. */ public TextLayout(AttributedCharacterIterator text, FontRenderContext frc) { - if (text == null){ + if (text == null) { // awt.03='{0}' iterator parameter is null throw new IllegalArgumentException(Messages.getString("awt.03", "text")); //$NON-NLS-1$ //$NON-NLS-2$ } - - if (text.getBeginIndex() == text.getEndIndex()){ + + if (text.getBeginIndex() == text.getEndIndex()) { // awt.04='{0}' iterator parameter has zero length throw new IllegalArgumentException(Messages.getString("awt.04", "text")); //$NON-NLS-1$ //$NON-NLS-2$ } @@ -202,7 +220,8 @@ public final class TextLayout implements Cloneable { /** * Instantiates a new text layout. * - * @param breaker the breaker + * @param breaker + * the breaker. */ TextLayout(TextRunBreaker breaker) { this.breaker = breaker; @@ -226,7 +245,7 @@ public final class TextLayout implements Cloneable { */ @Override protected Object clone() { - TextLayout res = new TextLayout((TextRunBreaker) breaker.clone()); + TextLayout res = new TextLayout((TextRunBreaker)breaker.clone()); if (justificationWidth >= 0) { res.handleJustify(justificationWidth); @@ -238,10 +257,10 @@ public final class TextLayout implements Cloneable { /** * Compares this TextLayout object to the specified TextLayout object. * - * @param layout the TextLayout object to be compared. - * - * @return true, if this TextLayout object is equal to - * the specified TextLayout object, false otherwise. + * @param layout + * the TextLayout object to be compared. + * @return true, if this TextLayout object is equal to the specified + * TextLayout object, false otherwise. */ public boolean equals(TextLayout layout) { if (layout == null) { @@ -253,14 +272,14 @@ public final class TextLayout implements Cloneable { /** * Compares this TextLayout object to the specified Object. * - * @param obj the Object to be compared. - * - * @return true, if this TextLayout object is equal to - * the specified Object, false otherwise. + * @param obj + * the Object to be compared. + * @return true, if this TextLayout object is equal to the specified Object, + * false otherwise. */ @Override public boolean equals(Object obj) { - return obj instanceof TextLayout ? equals((TextLayout) obj) : false; + return obj instanceof TextLayout ? equals((TextLayout)obj) : false; } /** @@ -274,16 +293,19 @@ public final class TextLayout implements Cloneable { } /** - * Draws this TextLayout at the specified location with the - * specified Graphics2D context. + * Draws this TextLayout at the specified location with the specified + * Graphics2D context. * - * @param g2d the Graphics2D object which renders this TextLayout. - * @param x the X coordinate of the TextLayout origin. - * @param y the Y coordinate of the TextLayout origin. + * @param g2d + * the Graphics2D object which renders this TextLayout. + * @param x + * the X coordinate of the TextLayout origin. + * @param y + * the Y coordinate of the TextLayout origin. */ public void draw(Graphics2D g2d, float x, float y) { updateMetrics(); - breaker.drawSegments(g2d, x ,y); + breaker.drawSegments(g2d, x, y); } /** @@ -325,15 +347,15 @@ public final class TextLayout implements Cloneable { */ public byte getBaseline() { updateMetrics(); - return (byte) metrics.getBaseLineIndex(); + return (byte)metrics.getBaseLineIndex(); } /** - * Gets the float array of offsets for the baselines which - * are used in this TextLayout. + * Gets the float array of offsets for the baselines which are used in this + * TextLayout. * - * @return the float array of offsets for the baselines which - * are used in this TextLayout. + * @return the float array of offsets for the baselines which are used in + * this TextLayout. */ public float[] getBaselineOffsets() { updateMetrics(); @@ -341,14 +363,15 @@ public final class TextLayout implements Cloneable { } /** - * Gets the black box bounds of the characters in the specified area. - * The black box bounds is an Shape which contains all - * bounding boxes of all the glyphs of the characters - * between firstEndpoint and secondEndpoint parameters values. - * - * @param firstEndpoint the first point of the area. - * @param secondEndpoint the second point of the area. + * Gets the black box bounds of the characters in the specified area. The + * black box bounds is an Shape which contains all bounding boxes of all the + * glyphs of the characters between firstEndpoint and secondEndpoint + * parameters values. * + * @param firstEndpoint + * the first point of the area. + * @param secondEndpoint + * the second point of the area. * @return the Shape which contains black box bounds. */ public Shape getBlackBoxBounds(int firstEndpoint, int secondEndpoint) { @@ -372,8 +395,8 @@ public final class TextLayout implements Cloneable { /** * Gets information about the caret of the specified TextHitInfo. * - * @param hitInfo the TextHitInfo. - * + * @param hitInfo + * the TextHitInfo. * @return the information about the caret of the specified TextHitInfo. */ public float[] getCaretInfo(TextHitInfo hitInfo) { @@ -382,12 +405,13 @@ public final class TextLayout implements Cloneable { } /** - * Gets information about the caret of the specified TextHitInfo - * of a character in this TextLayout. - * - * @param hitInfo the TextHitInfo of a character in this TextLayout. - * @param bounds the bounds to which the caret info is constructed. + * Gets information about the caret of the specified TextHitInfo of a + * character in this TextLayout. * + * @param hitInfo + * the TextHitInfo of a character in this TextLayout. + * @param bounds + * the bounds to which the caret info is constructed. * @return the caret of the specified TextHitInfo. */ public float[] getCaretInfo(TextHitInfo hitInfo, Rectangle2D bounds) { @@ -396,12 +420,13 @@ public final class TextLayout implements Cloneable { } /** - * Gets a Shape which represents the caret of the specified TextHitInfo - * in the bounds of this TextLayout. - * - * @param hitInfo the TextHitInfo. - * @param bounds the bounds to which the caret info is constructed. + * Gets a Shape which represents the caret of the specified TextHitInfo in + * the bounds of this TextLayout. * + * @param hitInfo + * the TextHitInfo. + * @param bounds + * the bounds to which the caret info is constructed. * @return the Shape which represents the caret. */ public Shape getCaretShape(TextHitInfo hitInfo, Rectangle2D bounds) { @@ -410,11 +435,11 @@ public final class TextLayout implements Cloneable { } /** - * Gets a Shape which represents the caret of the specified TextHitInfo - * in the bounds of this TextLayout. - * - * @param hitInfo the TextHitInfo. + * Gets a Shape which represents the caret of the specified TextHitInfo in + * the bounds of this TextLayout. * + * @param hitInfo + * the TextHitInfo. * @return the Shape which represents the caret. */ public Shape getCaretShape(TextHitInfo hitInfo) { @@ -423,45 +448,47 @@ public final class TextLayout implements Cloneable { } /** - * Gets two Shapes for the strong and weak carets with - * default caret policy and null bounds: the first element - * is the strong caret, the second is the weak caret or null. + * Gets two Shapes for the strong and weak carets with default caret policy + * and null bounds: the first element is the strong caret, the second is the + * weak caret or null. * - * @param offset an offset in the TextLayout. - * - * @return an array of two Shapes corresponded to the strong - * and weak carets. + * @param offset + * an offset in the TextLayout. + * @return an array of two Shapes corresponded to the strong and weak + * carets. */ public Shape[] getCaretShapes(int offset) { return getCaretShapes(offset, null, TextLayout.DEFAULT_CARET_POLICY); } /** - * Gets two Shapes for the strong and weak carets with - * the default caret policy: the first element is the strong - * caret, the second is the weak caret or null. - * - * @param offset an offset in the TextLayout. - * @param bounds the bounds to which to extend the carets. + * Gets two Shapes for the strong and weak carets with the default caret + * policy: the first element is the strong caret, the second is the weak + * caret or null. * - * @return an array of two Shapes corresponded to the strong - * and weak carets. + * @param offset + * an offset in the TextLayout. + * @param bounds + * the bounds to which to extend the carets. + * @return an array of two Shapes corresponded to the strong and weak + * carets. */ public Shape[] getCaretShapes(int offset, Rectangle2D bounds) { return getCaretShapes(offset, bounds, TextLayout.DEFAULT_CARET_POLICY); } /** - * Gets two Shapes for the strong and weak carets: the first - * element is the strong caret, the second is the weak caret - * or null. - * - * @param offset an offset in the TextLayout. - * @param bounds the bounds to which to extend the carets. - * @param policy the specified CaretPolicy. + * Gets two Shapes for the strong and weak carets: the first element is the + * strong caret, the second is the weak caret or null. * - * @return an array of two Shapes corresponded to the strong - * and weak carets. + * @param offset + * an offset in the TextLayout. + * @param bounds + * the bounds to which to extend the carets. + * @param policy + * the specified CaretPolicy. + * @return an array of two Shapes corresponded to the strong and weak + * carets. */ public Shape[] getCaretShapes(int offset, Rectangle2D bounds, TextLayout.CaretPolicy policy) { if (offset < 0 || offset > breaker.getCharCount()) { @@ -483,15 +510,15 @@ public final class TextLayout implements Cloneable { } /** - * Gets the level of the character with the specified index. - * - * @param index the specified index of the character. + * Gets the level of the character with the specified index. * + * @param index + * the specified index of the character. * @return the level of the character. */ public byte getCharacterLevel(int index) { if (index == -1 || index == getCharacterCount()) { - return (byte) breaker.getBaseLevel(); + return (byte)breaker.getBaseLevel(); } return breaker.getLevel(index); } @@ -507,16 +534,15 @@ public final class TextLayout implements Cloneable { } /** - * Gets the TextLayout wich is justified with the specified - * width related to this TextLayout. - * - * @param justificationWidth the width which is used - * for justification. + * Gets the TextLayout wich is justified with the specified width related to + * this TextLayout. * + * @param justificationWidth + * the width which is used for justification. * @return a TextLayout justified to the specified width. - * - * @throws Error the error occures if this TextLayout has been - * already justified. + * @throws Error + * the error occures if this TextLayout has been already + * justified. */ public TextLayout getJustifiedLayout(float justificationWidth) throws Error { float justification = breaker.getJustification(); @@ -528,7 +554,7 @@ public final class TextLayout implements Cloneable { return this; } - TextLayout justifiedLayout = new TextLayout((TextRunBreaker) breaker.clone()); + TextLayout justifiedLayout = new TextLayout((TextRunBreaker)breaker.clone()); justifiedLayout.handleJustify(justificationWidth); return justifiedLayout; } @@ -544,15 +570,15 @@ public final class TextLayout implements Cloneable { } /** - * Gets a Shape representing the logical selection betweeen - * the specified endpoints and extended to the natural - * bounds of this TextLayout. - * - * @param firstEndpoint the first selected endpoint within the area of characters - * @param secondEndpoint the second selected endpoint within the area of characters + * Gets a Shape representing the logical selection betweeen the specified + * endpoints and extended to the natural bounds of this TextLayout. * - * @return a Shape represented the logical selection betweeen - * the specified endpoints. + * @param firstEndpoint + * the first selected endpoint within the area of characters + * @param secondEndpoint + * the second selected endpoint within the area of characters + * @return a Shape represented the logical selection betweeen the specified + * endpoints. */ public Shape getLogicalHighlightShape(int firstEndpoint, int secondEndpoint) { updateMetrics(); @@ -560,22 +586,19 @@ public final class TextLayout implements Cloneable { } /** - * Gets a Shape representing the logical selection betweeen - * the specified endpoints and extended to the specified - * bounds of this TextLayout. + * Gets a Shape representing the logical selection betweeen the specified + * endpoints and extended to the specified bounds of this TextLayout. * - * @param firstEndpoint the first selected endpoint within the area of characters - * @param secondEndpoint the second selected endpoint within the area of characters - * @param bounds the specified bounds of this TextLayout. - * - * @return a Shape represented the logical selection betweeen - * the specified endpoints. + * @param firstEndpoint + * the first selected endpoint within the area of characters + * @param secondEndpoint + * the second selected endpoint within the area of characters + * @param bounds + * the specified bounds of this TextLayout. + * @return a Shape represented the logical selection betweeen the specified + * endpoints. */ - public Shape getLogicalHighlightShape( - int firstEndpoint, - int secondEndpoint, - Rectangle2D bounds - ) { + public Shape getLogicalHighlightShape(int firstEndpoint, int secondEndpoint, Rectangle2D bounds) { updateMetrics(); if (firstEndpoint > secondEndpoint) { @@ -583,62 +606,51 @@ public final class TextLayout implements Cloneable { // awt.197=Endpoints are out of range throw new IllegalArgumentException(Messages.getString("awt.197")); //$NON-NLS-1$ } - return caretManager.getLogicalHighlightShape( - secondEndpoint, - firstEndpoint, - bounds, - this - ); + return caretManager.getLogicalHighlightShape(secondEndpoint, firstEndpoint, bounds, + this); } if (firstEndpoint < 0 || secondEndpoint > breaker.getCharCount()) { // awt.197=Endpoints are out of range throw new IllegalArgumentException(Messages.getString("awt.197")); //$NON-NLS-1$ } - return caretManager.getLogicalHighlightShape( - firstEndpoint, - secondEndpoint, - bounds, - this - ); + return caretManager.getLogicalHighlightShape(firstEndpoint, secondEndpoint, bounds, this); } /** - * Gets the logical ranges of text which corresponds to a visual - * selection. - * - * @param hit1 the first endpoint of the visual range. - * @param hit2 the second endpoint of the visual range. + * Gets the logical ranges of text which corresponds to a visual selection. * - * @return the logical ranges of text which corresponds to a visual - * selection. + * @param hit1 + * the first endpoint of the visual range. + * @param hit2 + * the second endpoint of the visual range. + * @return the logical ranges of text which corresponds to a visual + * selection. */ public int[] getLogicalRangesForVisualSelection(TextHitInfo hit1, TextHitInfo hit2) { return caretManager.getLogicalRangesForVisualSelection(hit1, hit2); } /** - * Gets the TextHitInfo for the next caret to the left (or - * up at the end of the line) of the specified offset. - * - * @param offset the offset in this TextLayout. + * Gets the TextHitInfo for the next caret to the left (or up at the end of + * the line) of the specified offset. * - * @return the TextHitInfo for the next caret to the left (or - * up at the end of the line) of the specified hit, or null - * if there is no hit. + * @param offset + * the offset in this TextLayout. + * @return the TextHitInfo for the next caret to the left (or up at the end + * of the line) of the specified hit, or null if there is no hit. */ public TextHitInfo getNextLeftHit(int offset) { return getNextLeftHit(offset, DEFAULT_CARET_POLICY); } /** - * Gets the TextHitInfo for the next caret to the left (or - * up at the end of the line) of the specified hit. + * Gets the TextHitInfo for the next caret to the left (or up at the end of + * the line) of the specified hit. * - * @param hitInfo the initial hit. - * - * @return the TextHitInfo for the next caret to the left (or - * up at the end of the line) of the specified hit, or null - * if there is no hit. + * @param hitInfo + * the initial hit. + * @return the TextHitInfo for the next caret to the left (or up at the end + * of the line) of the specified hit, or null if there is no hit. */ public TextHitInfo getNextLeftHit(TextHitInfo hitInfo) { breaker.createAllSegments(); @@ -646,15 +658,15 @@ public final class TextLayout implements Cloneable { } /** - * Gets the TextHitInfo for the next caret to the left (or - * up at the end of the line) of the specified offset, given the - * specified caret policy. - * - * @param offset the offset in this TextLayout. - * @param policy the policy to be used for obtaining the strong caret. + * Gets the TextHitInfo for the next caret to the left (or up at the end of + * the line) of the specified offset, given the specified caret policy. * - * @return the TextHitInfo for the next caret to the left of the - * specified offset, or null if there is no hit. + * @param offset + * the offset in this TextLayout. + * @param policy + * the policy to be used for obtaining the strong caret. + * @return the TextHitInfo for the next caret to the left of the specified + * offset, or null if there is no hit. */ public TextHitInfo getNextLeftHit(int offset, TextLayout.CaretPolicy policy) { if (offset < 0 || offset > breaker.getCharCount()) { @@ -673,14 +685,14 @@ public final class TextLayout implements Cloneable { } /** - * Gets the TextHitInfo for the next caret to the right (or - * down at the end of the line) of the specified hit. - * - * @param hitInfo the initial hit. + * Gets the TextHitInfo for the next caret to the right (or down at the end + * of the line) of the specified hit. * - * @return the TextHitInfo for the next caret to the right (or - * down at the end of the line) of the specified hit, or null - * if there is no hit. + * @param hitInfo + * the initial hit. + * @return the TextHitInfo for the next caret to the right (or down at the + * end of the line) of the specified hit, or null if there is no + * hit. */ public TextHitInfo getNextRightHit(TextHitInfo hitInfo) { breaker.createAllSegments(); @@ -688,28 +700,28 @@ public final class TextLayout implements Cloneable { } /** - * Gets the TextHitInfo for the next caret to the right (or - * down at the end of the line) of the specified offset. + * Gets the TextHitInfo for the next caret to the right (or down at the end + * of the line) of the specified offset. * - * @param offset the offset in this TextLayout. - * - * @return the TextHitInfo for the next caret to the right of the - * specified offset, or null if there is no hit. + * @param offset + * the offset in this TextLayout. + * @return the TextHitInfo for the next caret to the right of the specified + * offset, or null if there is no hit. */ public TextHitInfo getNextRightHit(int offset) { return getNextRightHit(offset, DEFAULT_CARET_POLICY); } /** - * Gets the TextHitInfo for the next caret to the right (or - * down at the end of the line) of the specified offset, given the - * specified caret policy. - * - * @param offset the offset in this TextLayout. - * @param policy the policy to be used for obtaining the strong caret. + * Gets the TextHitInfo for the next caret to the right (or down at the end + * of the line) of the specified offset, given the specified caret policy. * - * @return the TextHitInfo for the next caret to the right of the - * specified offset, or null if there is no hit. + * @param offset + * the offset in this TextLayout. + * @param policy + * the policy to be used for obtaining the strong caret. + * @return the TextHitInfo for the next caret to the right of the specified + * offset, or null if there is no hit. */ public TextHitInfo getNextRightHit(int offset, TextLayout.CaretPolicy policy) { if (offset < 0 || offset > breaker.getCharCount()) { @@ -730,10 +742,9 @@ public final class TextLayout implements Cloneable { /** * Gets the outline of this TextLayout as a Shape. * - * @param xform the AffineTransform to be used to transform - * the outline before returning it, or null if no transformation - * is desired. - * + * @param xform + * the AffineTransform to be used to transform the outline before + * returning it, or null if no transformation is desired. * @return the outline of this TextLayout as a Shape. */ public Shape getOutline(AffineTransform xform) { @@ -749,8 +760,8 @@ public final class TextLayout implements Cloneable { } /** - * Gets the visible advance of this TextLayout which is defined as - * diffence between leading (advance) and trailing whitespace. + * Gets the visible advance of this TextLayout which is defined as diffence + * between leading (advance) and trailing whitespace. * * @return the visible advance of this TextLayout. */ @@ -764,15 +775,13 @@ public final class TextLayout implements Cloneable { if (lastNonWhitespace < 0) { return 0; - } else if (lastNonWhitespace == getCharacterCount()-1) { + } else if (lastNonWhitespace == getCharacterCount() - 1) { return getAdvance(); } else if (justificationWidth >= 0) { // Layout is justified return justificationWidth; } else { - breaker.pushSegments( - breaker.getACI().getBeginIndex(), - lastNonWhitespace + breaker.getACI().getBeginIndex() + 1 - ); + breaker.pushSegments(breaker.getACI().getBeginIndex(), lastNonWhitespace + + breaker.getACI().getBeginIndex() + 1); breaker.createAllSegments(); @@ -784,14 +793,16 @@ public final class TextLayout implements Cloneable { } /** - * Gets a Shape which corresponds to the highlighted (selected) area - * based on two hit locations within the text and extends to the bounds. - * - * @param hit1 the first text hit location. - * @param hit2 the second text hit location. - * @param bounds the rectangle that the highlighted area should be - * extended or restricted to. + * Gets a Shape which corresponds to the highlighted (selected) area based + * on two hit locations within the text and extends to the bounds. * + * @param hit1 + * the first text hit location. + * @param hit2 + * the second text hit location. + * @param bounds + * the rectangle that the highlighted area should be extended or + * restricted to. * @return a Shape which corresponds to the highlighted (selected) area. */ public Shape getVisualHighlightShape(TextHitInfo hit1, TextHitInfo hit2, Rectangle2D bounds) { @@ -799,12 +810,13 @@ public final class TextLayout implements Cloneable { } /** - * Gets a Shape which corresponds to the highlighted (selected) area - * based on two hit locations within the text. - * - * @param hit1 the first text hit location. - * @param hit2 the second text hit location. + * Gets a Shape which corresponds to the highlighted (selected) area based + * on two hit locations within the text. * + * @param hit1 + * the first text hit location. + * @param hit2 + * the second text hit location. * @return a Shape which corresponds to the highlighted (selected) area. */ public Shape getVisualHighlightShape(TextHitInfo hit1, TextHitInfo hit2) { @@ -813,23 +825,23 @@ public final class TextLayout implements Cloneable { } /** - * Gets the TextHitInfo for a hit on the opposite side of the - * specified hit's caret. - * - * @param hitInfo the specified TextHitInfo. + * Gets the TextHitInfo for a hit on the opposite side of the specified + * hit's caret. * - * @return the TextHitInfo for a hit on the opposite side of the - * specified hit's caret. + * @param hitInfo + * the specified TextHitInfo. + * @return the TextHitInfo for a hit on the opposite side of the specified + * hit's caret. */ public TextHitInfo getVisualOtherHit(TextHitInfo hitInfo) { return caretManager.getVisualOtherHit(hitInfo); } /** - * Justifies the text; this method should be overridden - * by subclasses. + * Justifies the text; this method should be overridden by subclasses. * - * @param justificationWidth the width for justification. + * @param justificationWidth + * the width for justification. */ protected void handleJustify(float justificationWidth) { float justification = breaker.getJustification(); @@ -851,54 +863,54 @@ public final class TextLayout implements Cloneable { } /** - * Returns a TextHitInfo object that gives information on which - * division point (between two characters) is corresponds to a - * hit (such as a mouse click) at the specified coordinates. + * Returns a TextHitInfo object that gives information on which division + * point (between two characters) is corresponds to a hit (such as a mouse + * click) at the specified coordinates. * - * @param x the X coordinate in this TextLayout. - * @param y the Y coordinate in this TextLayout. - * - * TextHitInfo object cooresponding to the given coordinates - * within the text. + * @param x + * the X coordinate in this TextLayout. + * @param y + * the Y coordinate in this TextLayout. TextHitInfo object + * corresponding to the given coordinates within the text. + * @return the information about the character at the specified position. */ public TextHitInfo hitTestChar(float x, float y) { return hitTestChar(x, y, getBounds()); } /** - * Returns a TextHitInfo object that gives information on which - * division point (between two characters) is corresponds to a - * hit (such as a mouse click) at the specified coordinates within - * the specified text rectangle. - * - * @param x the X coordinate in this TextLayout. - * @param y the Y coordinate in this TextLayout. - * @param bounds the bounds of the text area. + * Returns a TextHitInfo object that gives information on which division + * point (between two characters) is corresponds to a hit (such as a mouse + * click) at the specified coordinates within the specified text rectangle. * - * TextHitInfo object cooresponding to the given coordinates - * within the text. + * @param x + * the X coordinate in this TextLayout. + * @param y + * the Y coordinate in this TextLayout. + * @param bounds + * the bounds of the text area. TextHitInfo object corresponding + * to the given coordinates within the text. + * @return the information about the character at the specified position. */ public TextHitInfo hitTestChar(float x, float y, Rectangle2D bounds) { if (x > bounds.getMaxX()) { - return breaker.isLTR() ? - TextHitInfo.trailing(breaker.getCharCount() - 1) : TextHitInfo.leading(0); + return breaker.isLTR() ? TextHitInfo.trailing(breaker.getCharCount() - 1) : TextHitInfo + .leading(0); } if (x < bounds.getMinX()) { - return breaker.isLTR() ? - TextHitInfo.leading(0) : TextHitInfo.trailing(breaker.getCharCount() - 1); + return breaker.isLTR() ? TextHitInfo.leading(0) : TextHitInfo.trailing(breaker + .getCharCount() - 1); } return breaker.hitTest(x, y); } /** - * Returns true if this TextLayout has a "left to right" - * direction. + * Returns true if this TextLayout has a "left to right" direction. * - * @return true if this TextLayout has a "left to right" - * direction, false if this TextLayout has a "right to left" - * direction. + * @return true if this TextLayout has a "left to right" direction, false if + * this TextLayout has a "right to left" direction. */ public boolean isLeftToRight() { return breaker.isLTR(); @@ -913,4 +925,3 @@ public final class TextLayout implements Cloneable { return false; } } - diff --git a/awt/java/awt/font/TextMeasurer.java b/awt/java/awt/font/TextMeasurer.java index 017f3d9c2ea6af24415e5497388464a7df877577..9741f59c40ec26de423c7a8e4ff4b7c49e20d52e 100644 --- a/awt/java/awt/font/TextMeasurer.java +++ b/awt/java/awt/font/TextMeasurer.java @@ -21,7 +21,6 @@ package java.awt.font; - import java.text.AttributedCharacterIterator; import org.apache.harmony.awt.gl.font.TextMetricsCalculator; @@ -29,26 +28,38 @@ import org.apache.harmony.awt.gl.font.TextRunBreaker; /** * The TextMeasurer class provides utilities for line break operations. + * + * @since Android 1.0 */ public final class TextMeasurer implements Cloneable { - - /** The aci. */ + + /** + * The aci. + */ AttributedCharacterIterator aci; - - /** The frc. */ + + /** + * The frc. + */ FontRenderContext frc; - - /** The breaker. */ + + /** + * The breaker. + */ TextRunBreaker breaker = null; - - /** The tmc. */ + + /** + * The tmc. + */ TextMetricsCalculator tmc = null; /** * Instantiates a new text measurer from the specified text. * - * @param text the source text. - * @param frc the FontRenderContext. + * @param text + * the source text. + * @param frc + * the FontRenderContext. */ public TextMeasurer(AttributedCharacterIterator text, FontRenderContext frc) { this.aci = text; @@ -58,17 +69,19 @@ public final class TextMeasurer implements Cloneable { } /** - * Replaces the current text with the new text, inserting a break - * character at the specified insert position. + * Replaces the current text with the new text, inserting a break character + * at the specified insert position. * - * @param newParagraph the new paragraph text. - * @param insertPos the position in the text where the character is inserted. + * @param newParagraph + * the new paragraph text. + * @param insertPos + * the position in the text where the character is inserted. */ public void insertChar(AttributedCharacterIterator newParagraph, int insertPos) { AttributedCharacterIterator oldAci = aci; aci = newParagraph; - if ((oldAci.getEndIndex() - oldAci.getBeginIndex()) - - (aci.getEndIndex() - aci.getBeginIndex()) != -1) { + if ((oldAci.getEndIndex() - oldAci.getBeginIndex()) + - (aci.getEndIndex() - aci.getBeginIndex()) != -1) { breaker = new TextRunBreaker(aci, this.frc); tmc = new TextMetricsCalculator(breaker); } else { @@ -77,17 +90,19 @@ public final class TextMeasurer implements Cloneable { } /** - * Replaces the current text with the new text and deletes a - * character at the specified position. + * Replaces the current text with the new text and deletes a character at + * the specified position. * - * @param newParagraph the paragraph text after deletion. - * @param deletePos the position in the text where the character is removed. + * @param newParagraph + * the paragraph text after deletion. + * @param deletePos + * the position in the text where the character is removed. */ public void deleteChar(AttributedCharacterIterator newParagraph, int deletePos) { AttributedCharacterIterator oldAci = aci; aci = newParagraph; - if ((oldAci.getEndIndex() - oldAci.getBeginIndex()) - - (aci.getEndIndex() - aci.getBeginIndex()) != 1) { + if ((oldAci.getEndIndex() - oldAci.getBeginIndex()) + - (aci.getEndIndex() - aci.getBeginIndex()) != 1) { breaker = new TextRunBreaker(aci, this.frc); tmc = new TextMetricsCalculator(breaker); } else { @@ -102,39 +117,39 @@ public final class TextMeasurer implements Cloneable { */ @Override protected Object clone() { - return new TextMeasurer((AttributedCharacterIterator) aci.clone(), frc); + return new TextMeasurer((AttributedCharacterIterator)aci.clone(), frc); } /** * Returns a TextLayout of the specified character range. * - * @param start the index of the first character. - * @param limit the index after the last character. - * - * @return a TextLayout for the characters beginning at "start" up - * to "end". + * @param start + * the index of the first character. + * @param limit + * the index after the last character. + * @return a TextLayout for the characters beginning at "start" up to "end". */ public TextLayout getLayout(int start, int limit) { breaker.pushSegments(start - aci.getBeginIndex(), limit - aci.getBeginIndex()); breaker.createAllSegments(); - TextLayout layout = new TextLayout((TextRunBreaker) breaker.clone()); + TextLayout layout = new TextLayout((TextRunBreaker)breaker.clone()); breaker.popSegments(); return layout; } /** - * Returns the graphical width of a line beginning at "start" - * parameter and including characters up to "end" parameter. - * "start" and "end" are absolute indices, not relative to the - * "start" of the paragraph. - * - * @param start the character index at which to start measuring. - * @param end the character index at which to stop measuring. + * Returns the graphical width of a line beginning at "start" parameter and + * including characters up to "end" parameter. "start" and "end" are + * absolute indices, not relative to the "start" of the paragraph. * - * @return the graphical width of a line beginning at "start" - * and including characters up to "end". + * @param start + * the character index at which to start measuring. + * @param end + * the character index at which to stop measuring. + * @return the graphical width of a line beginning at "start" and including + * characters up to "end". */ public float getAdvanceBetween(int start, int end) { breaker.pushSegments(start - aci.getBeginIndex(), end - aci.getBeginIndex()); @@ -147,21 +162,21 @@ public final class TextMeasurer implements Cloneable { } /** - * Returns the index of the first character which is not fit on - * a line beginning at start and possible measuring up to maxAdvance - * in graphical width. - * - * @param start he character index at which to start measuring. - * @param maxAdvance the graphical width in which the line must fit. - * - * @return the index after the last character that is fit on a line - * beginning at start, which is not longer than maxAdvance in graphical + * Returns the index of the first character which is not fit on a line + * beginning at start and possible measuring up to maxAdvance in graphical * width. + * + * @param start + * he character index at which to start measuring. + * @param maxAdvance + * the graphical width in which the line must fit. + * @return the index after the last character that is fit on a line + * beginning at start, which is not longer than maxAdvance in + * graphical width. */ public int getLineBreakIndex(int start, float maxAdvance) { breaker.createAllSegments(); - return breaker.getLineBreakIndex( - start - aci.getBeginIndex(), maxAdvance) + aci.getBeginIndex(); + return breaker.getLineBreakIndex(start - aci.getBeginIndex(), maxAdvance) + + aci.getBeginIndex(); } } - diff --git a/awt/java/awt/font/TransformAttribute.java b/awt/java/awt/font/TransformAttribute.java index 7c9b0bd97a587f5bc44451ff9bbd18aff5f6cbed..ff2caa2511b81da7b5e3c09ac2464d8d27d220c2 100644 --- a/awt/java/awt/font/TransformAttribute.java +++ b/awt/java/awt/font/TransformAttribute.java @@ -18,6 +18,7 @@ * @author Ilya S. Okomin * @version $Revision$ */ + package java.awt.font; import java.awt.geom.AffineTransform; @@ -28,28 +29,34 @@ import org.apache.harmony.awt.internal.nls.Messages; /** * The TransformAttribute class is a wrapper for the AffineTransform class in * order to use it as attribute. + * + * @since Android 1.0 */ public final class TransformAttribute implements Serializable { - - /** The Constant serialVersionUID. */ + + /** + * The Constant serialVersionUID. + */ private static final long serialVersionUID = 3356247357827709530L; // affine transform of this TransformAttribute instance - /** The transform. */ + /** + * The transform. + */ private AffineTransform fTransform; /** - * Instantiates a new TransformAttribute from the specified - * AffineTransform. + * Instantiates a new TransformAttribute from the specified AffineTransform. * - * @param transform the AffineTransform to be wrapped. + * @param transform + * the AffineTransform to be wrapped. */ public TransformAttribute(AffineTransform transform) { if (transform == null) { // awt.94=transform can not be null throw new IllegalArgumentException(Messages.getString("awt.94")); //$NON-NLS-1$ } - if (!transform.isIdentity()){ + if (!transform.isIdentity()) { this.fTransform = new AffineTransform(transform); } } @@ -60,7 +67,7 @@ public final class TransformAttribute implements Serializable { * @return the initial AffineTransform which is wrapped. */ public AffineTransform getTransform() { - if (fTransform != null){ + if (fTransform != null) { return new AffineTransform(fTransform); } return new AffineTransform(); @@ -69,12 +76,11 @@ public final class TransformAttribute implements Serializable { /** * Checks if this transform is an identity transform. * - * @return true, if this transform is an identity transform, - * false otherwise. + * @return true, if this transform is an identity transform, false + * otherwise. */ public boolean isIdentity() { return (fTransform == null); } } - diff --git a/awt/java/awt/font/package.html b/awt/java/awt/font/package.html new file mode 100644 index 0000000000000000000000000000000000000000..788dcc0a05c5fabb2460a3ec978be3d76f77ef1c --- /dev/null +++ b/awt/java/awt/font/package.html @@ -0,0 +1,8 @@ + + +

    + This package contains classes to support the representation of different types of fonts for example TrueType fonts. +

    + @since Android 1.0 + + diff --git a/awt/java/awt/geom/AffineTransform.java b/awt/java/awt/geom/AffineTransform.java index 5fd393430837ab1e67c51ef6270ad2b0a76b24d4..8a6938cf05178767f2f86394297e4ea0936b3692 100644 --- a/awt/java/awt/geom/AffineTransform.java +++ b/awt/java/awt/geom/AffineTransform.java @@ -18,6 +18,7 @@ * @author Denis M. Kishenko * @version $Revision$ */ + package java.awt.geom; import java.awt.Shape; @@ -28,76 +29,118 @@ import org.apache.harmony.awt.internal.nls.Messages; import org.apache.harmony.misc.HashCode; /** - * The Class AffineTransform represents a linear transformation - * (rotation, scaling, or shear) followed by a translation that - * acts on a coordinate space. It preserves colinearity of points - * and ratios of distances between collinear points: so if A, B, - * and C are on a line, then after the space has been transformed - * via the affine transform, the images of the three points will - * still be on a line, and the ratio of the distance from A to B - * with the distance from B to C will be the same as the corresponding - * ratio in the image space. + * The Class AffineTransform represents a linear transformation (rotation, + * scaling, or shear) followed by a translation that acts on a coordinate space. + * It preserves collinearity of points and ratios of distances between collinear + * points: so if A, B, and C are on a line, then after the space has been + * transformed via the affine transform, the images of the three points will + * still be on a line, and the ratio of the distance from A to B with the + * distance from B to C will be the same as the corresponding ratio in the image + * space. + * + * @since Android 1.0 */ public class AffineTransform implements Cloneable, Serializable { - /** The Constant serialVersionUID. */ + /** + * The Constant serialVersionUID. + */ private static final long serialVersionUID = 1330973210523860834L; - /** The Constant TYPE_IDENTITY. */ + /** + * The Constant TYPE_IDENTITY. + */ public static final int TYPE_IDENTITY = 0; - - /** The Constant TYPE_TRANSLATION. */ + + /** + * The Constant TYPE_TRANSLATION. + */ public static final int TYPE_TRANSLATION = 1; - - /** The Constant TYPE_UNIFORM_SCALE. */ + + /** + * The Constant TYPE_UNIFORM_SCALE. + */ public static final int TYPE_UNIFORM_SCALE = 2; - - /** The Constant TYPE_GENERAL_SCALE. */ + + /** + * The Constant TYPE_GENERAL_SCALE. + */ public static final int TYPE_GENERAL_SCALE = 4; - - /** The Constant TYPE_QUADRANT_ROTATION. */ + + /** + * The Constant TYPE_QUADRANT_ROTATION. + */ public static final int TYPE_QUADRANT_ROTATION = 8; - - /** The Constant TYPE_GENERAL_ROTATION. */ + + /** + * The Constant TYPE_GENERAL_ROTATION. + */ public static final int TYPE_GENERAL_ROTATION = 16; - - /** The Constant TYPE_GENERAL_TRANSFORM. */ + + /** + * The Constant TYPE_GENERAL_TRANSFORM. + */ public static final int TYPE_GENERAL_TRANSFORM = 32; - - /** The Constant TYPE_FLIP. */ + + /** + * The Constant TYPE_FLIP. + */ public static final int TYPE_FLIP = 64; - - /** The Constant TYPE_MASK_SCALE. */ + + /** + * The Constant TYPE_MASK_SCALE. + */ public static final int TYPE_MASK_SCALE = TYPE_UNIFORM_SCALE | TYPE_GENERAL_SCALE; - - /** The Constant TYPE_MASK_ROTATION. */ + + /** + * The Constant TYPE_MASK_ROTATION. + */ public static final int TYPE_MASK_ROTATION = TYPE_QUADRANT_ROTATION | TYPE_GENERAL_ROTATION; - /** The TYPE_UNKNOWN is an initial type value. */ + /** + * The TYPE_UNKNOWN is an initial type value. + */ static final int TYPE_UNKNOWN = -1; - - /** The min value equivalent to zero. If absolute value less then ZERO it considered as zero. */ + + /** + * The min value equivalent to zero. If absolute value less then ZERO it + * considered as zero. + */ static final double ZERO = 1E-10; - - /** The values of transformation matrix. */ + + /** + * The values of transformation matrix. + */ double m00; - - /** The m10. */ + + /** + * The m10. + */ double m10; - - /** The m01. */ + + /** + * The m01. + */ double m01; - - /** The m11. */ + + /** + * The m11. + */ double m11; - - /** The m02. */ + + /** + * The m02. + */ double m02; - - /** The m12. */ + + /** + * The m12. + */ double m12; - /** The transformation type. */ + /** + * The transformation type. + */ transient int type; /** @@ -111,10 +154,11 @@ public class AffineTransform implements Cloneable, Serializable { } /** - * Instantiates a new affine transform that has the same data as - * the given AffineTransform. + * Instantiates a new affine transform that has the same data as the given + * AffineTransform. * - * @param t the transform to copy. + * @param t + * the transform to copy. */ public AffineTransform(AffineTransform t) { this.type = t.type; @@ -128,15 +172,21 @@ public class AffineTransform implements Cloneable, Serializable { /** * Instantiates a new affine transform by specifying the values of the 2x3 - * transformation matrix as floats. The type is set to the default - * type: TYPE_UNKNOWN - * - * @param m00 the m00 entry in the transformation matrix. - * @param m10 the m10 entry in the transformation matrix. - * @param m01 the m01 entry in the transformation matrix. - * @param m11 the m11 entry in the transformation matrix. - * @param m02 the m02 entry in the transformation matrix. - * @param m12 the m12 entry in the transformation matrix. + * transformation matrix as floats. The type is set to the default type: + * TYPE_UNKNOWN + * + * @param m00 + * the m00 entry in the transformation matrix. + * @param m10 + * the m10 entry in the transformation matrix. + * @param m01 + * the m01 entry in the transformation matrix. + * @param m11 + * the m11 entry in the transformation matrix. + * @param m02 + * the m02 entry in the transformation matrix. + * @param m12 + * the m12 entry in the transformation matrix. */ public AffineTransform(float m00, float m10, float m01, float m11, float m02, float m12) { this.type = TYPE_UNKNOWN; @@ -150,15 +200,21 @@ public class AffineTransform implements Cloneable, Serializable { /** * Instantiates a new affine transform by specifying the values of the 2x3 - * transformation matrix as doubles. The type is set to the default - * type: TYPE_UNKNOWN - * - * @param m00 the m00 entry in the transformation matrix. - * @param m10 the m10 entry in the transformation matrix. - * @param m01 the m01 entry in the transformation matrix. - * @param m11 the m11 entry in the transformation matrix. - * @param m02 the m02 entry in the transformation matrix. - * @param m12 the m12 entry in the transformation matrix. + * transformation matrix as doubles. The type is set to the default type: + * TYPE_UNKNOWN + * + * @param m00 + * the m00 entry in the transformation matrix. + * @param m10 + * the m10 entry in the transformation matrix. + * @param m01 + * the m01 entry in the transformation matrix. + * @param m11 + * the m11 entry in the transformation matrix. + * @param m02 + * the m02 entry in the transformation matrix. + * @param m12 + * the m12 entry in the transformation matrix. */ public AffineTransform(double m00, double m10, double m01, double m11, double m02, double m12) { this.type = TYPE_UNKNOWN; @@ -171,20 +227,20 @@ public class AffineTransform implements Cloneable, Serializable { } /** - * Instantiates a new affine transform by reading the values of the - * transformation matrix from an array of floats. The mapping from the - * array to the matrix starts with matrix[0] giving the - * top-left entry of the matrix and - * proceeds with the usual left-to-right and top-down ordering. + * Instantiates a new affine transform by reading the values of the + * transformation matrix from an array of floats. The mapping from the array + * to the matrix starts with matrix[0] giving the top-left + * entry of the matrix and proceeds with the usual left-to-right and + * top-down ordering. *

    - * If the array has only four entries, then the two entries of the - * last row of the transformation matrix default to zero. - * - * @param matrix the array of four or six floats giving the values - * of the matrix. - * - * @throws ArrayIndexOutOfBoundsException if the size of the array - * is 0, 1, 2, 3, or 5. + * If the array has only four entries, then the two entries of the last row + * of the transformation matrix default to zero. + * + * @param matrix + * the array of four or six floats giving the values of the + * matrix. + * @throws ArrayIndexOutOfBoundsException + * if the size of the array is 0, 1, 2, 3, or 5. */ public AffineTransform(float[] matrix) { this.type = TYPE_UNKNOWN; @@ -199,20 +255,20 @@ public class AffineTransform implements Cloneable, Serializable { } /** - * Instantiates a new affine transform by reading the values of the + * Instantiates a new affine transform by reading the values of the * transformation matrix from an array of doubles. The mapping from the - * array to the matrix starts with matrix[0] giving the - * top-left entry of the matrix and - * proceeds with the usual left-to-right and top-down ordering. + * array to the matrix starts with matrix[0] giving the + * top-left entry of the matrix and proceeds with the usual left-to-right + * and top-down ordering. *

    - * If the array has only four entries, then the two entries of the - * last row of the transformation matrix default to zero. - * - * @param matrix the array of four or six doubles giving the values - * of the matrix. - * - * @throws ArrayIndexOutOfBoundsException if the size of the array - * is 0, 1, 2, 3, or 5. + * If the array has only four entries, then the two entries of the last row + * of the transformation matrix default to zero. + * + * @param matrix + * the array of four or six doubles giving the values of the + * matrix. + * @throws ArrayIndexOutOfBoundsException + * if the size of the array is 0, 1, 2, 3, or 5. */ public AffineTransform(double[] matrix) { this.type = TYPE_UNKNOWN; @@ -226,27 +282,26 @@ public class AffineTransform implements Cloneable, Serializable { } } - /** * Returns type of the affine transformation. *

    - * The type is computed as follows: Label the entries of the - * transformation matrix as three rows (m00, m01), (m10, m11), and - * (m02, m12). Then if the original basis vectors are (1, 0) and (0, 1), - * the new basis vectors after transformation are given by (m00, m01) - * and (m10, m11), and the translation vector is (m02, m12). + * The type is computed as follows: Label the entries of the transformation + * matrix as three rows (m00, m01), (m10, m11), and (m02, m12). Then if the + * original basis vectors are (1, 0) and (0, 1), the new basis vectors after + * transformation are given by (m00, m01) and (m10, m11), and the + * translation vector is (m02, m12). + *

    + * The types are classified as follows:
    TYPE_IDENTITY - no change
    + * TYPE_TRANSLATION - The translation vector isn't zero
    + * TYPE_UNIFORM_SCALE - The new basis vectors have equal length
    + * TYPE_GENERAL_SCALE - The new basis vectors dont' have equal length
    + * TYPE_FLIP - The new basis vector orientation differs from the original + * one
    TYPE_QUADRANT_ROTATION - The new basis is a rotation of the + * original by 90, 180, 270, or 360 degrees
    TYPE_GENERAL_ROTATION - The + * new basis is a rotation of the original by an arbitrary angle
    + * TYPE_GENERAL_TRANSFORM - The transformation can't be inverted.
    *

    - * The types are classified as follows:
    - * TYPE_IDENTITY - no change
    - * TYPE_TRANSLATION - The translation vector isn't zero
    - * TYPE_UNIFORM_SCALE - The new basis vectors have equal length
    - * TYPE_GENERAL_SCALE - The new basis vectors dont' have equal length
    - * TYPE_FLIP - The new basis vector orientation differs from the original one
    - * TYPE_QUADRANT_ROTATION - The new basis is a rotation of the original by 90, 180, 270, or 360 degrees
    - * TYPE_GENERAL_ROTATION - The new basis is a rotation of the original by an arbitrary angle
    - * TYPE_GENERAL_TRANSFORM - The transformation can't be inverted.
    - *

    - * Note that multiple types are possible, thus the types can be combined + * Note that multiple types are possible, thus the types can be combined * using bitwise combinations. * * @return the type of the Affine Transform. @@ -265,11 +320,10 @@ public class AffineTransform implements Cloneable, Serializable { if (m02 != 0.0 || m12 != 0.0) { type |= TYPE_TRANSLATION; - } else - if (m00 == 1.0 && m11 == 1.0 && m01 == 0.0 && m10 == 0.0) { - type = TYPE_IDENTITY; - return type; - } + } else if (m00 == 1.0 && m11 == 1.0 && m01 == 0.0 && m10 == 0.0) { + type = TYPE_IDENTITY; + return type; + } if (m00 * m11 - m01 * m10 < 0.0) { type |= TYPE_FLIP; @@ -279,26 +333,22 @@ public class AffineTransform implements Cloneable, Serializable { double dy = m01 * m01 + m11 * m11; if (dx != dy) { type |= TYPE_GENERAL_SCALE; - } else - if (dx != 1.0) { - type |= TYPE_UNIFORM_SCALE; - } + } else if (dx != 1.0) { + type |= TYPE_UNIFORM_SCALE; + } - if ((m00 == 0.0 && m11 == 0.0) || - (m10 == 0.0 && m01 == 0.0 && (m00 < 0.0 || m11 < 0.0))) - { + if ((m00 == 0.0 && m11 == 0.0) || (m10 == 0.0 && m01 == 0.0 && (m00 < 0.0 || m11 < 0.0))) { type |= TYPE_QUADRANT_ROTATION; - } else - if (m01 != 0.0 || m10 != 0.0) { - type |= TYPE_GENERAL_ROTATION; - } + } else if (m01 != 0.0 || m10 != 0.0) { + type |= TYPE_GENERAL_ROTATION; + } return type; } /** - * Gets the scale x entry of the transformation matrix - * (the upper left matrix entry). + * Gets the scale x entry of the transformation matrix (the upper left + * matrix entry). * * @return the scale x value. */ @@ -307,8 +357,8 @@ public class AffineTransform implements Cloneable, Serializable { } /** - * Gets the scale y entry of the transformation matrix - * (the lower right entry of the linear transformation). + * Gets the scale y entry of the transformation matrix (the lower right + * entry of the linear transformation). * * @return the scale y value. */ @@ -317,8 +367,8 @@ public class AffineTransform implements Cloneable, Serializable { } /** - * Gets the shear x entry of the transformation matrix - * (the upper right entry of the linear transformation). + * Gets the shear x entry of the transformation matrix (the upper right + * entry of the linear transformation). * * @return the shear x value. */ @@ -327,8 +377,8 @@ public class AffineTransform implements Cloneable, Serializable { } /** - * Gets the shear y entry of the transformation matrix - * (the lower left entry of the linear transformation). + * Gets the shear y entry of the transformation matrix (the lower left entry + * of the linear transformation). * * @return the shear y value. */ @@ -364,15 +414,15 @@ public class AffineTransform implements Cloneable, Serializable { } /** - * Writes the values of the transformation matrix into the given - * array of doubles. If the array has length 4, only the linear - * transformation part will be written into it. If it has length - * greater than 4, the translation vector will be included as well. - * - * @param matrix the array to fill with the values of the matrix. - * - * @throws ArrayIndexOutOfBoundsException if the size of the array - * is 0, 1, 2, 3, or 5. + * Writes the values of the transformation matrix into the given array of + * doubles. If the array has length 4, only the linear transformation part + * will be written into it. If it has length greater than 4, the translation + * vector will be included as well. + * + * @param matrix + * the array to fill with the values of the matrix. + * @throws ArrayIndexOutOfBoundsException + * if the size of the array is 0, 1, 2, 3, or 5. */ public void getMatrix(double[] matrix) { matrix[0] = m00; @@ -397,12 +447,18 @@ public class AffineTransform implements Cloneable, Serializable { /** * Sets the transform in terms of a list of double values. * - * @param m00 the m00 coordinate of the transformation matrix. - * @param m10 the m10 coordinate of the transformation matrix. - * @param m01 the m01 coordinate of the transformation matrix. - * @param m11 the m11 coordinate of the transformation matrix. - * @param m02 the m02 coordinate of the transformation matrix. - * @param m12 the m12 coordinate of the transformation matrix. + * @param m00 + * the m00 coordinate of the transformation matrix. + * @param m10 + * the m10 coordinate of the transformation matrix. + * @param m01 + * the m01 coordinate of the transformation matrix. + * @param m11 + * the m11 coordinate of the transformation matrix. + * @param m02 + * the m02 coordinate of the transformation matrix. + * @param m12 + * the m12 coordinate of the transformation matrix. */ public void setTransform(double m00, double m10, double m01, double m11, double m02, double m12) { this.type = TYPE_UNKNOWN; @@ -415,10 +471,11 @@ public class AffineTransform implements Cloneable, Serializable { } /** - * Sets the transform's data to match the data of the transform - * sent as a parameter. + * Sets the transform's data to match the data of the transform sent as a + * parameter. * - * @param t the transform that gives the new values. + * @param t + * the transform that gives the new values. */ public void setTransform(AffineTransform t) { type = t.type; @@ -435,15 +492,16 @@ public class AffineTransform implements Cloneable, Serializable { } /** - * Sets the transformation to a translation alone. - * Sets the linear part of the transformation to identity - * and the translation vector to the values sent as parameters. - * Sets the type to TYPE_IDENTITY - * if the resulting AffineTransformation is the identity - * transformation, otherwise sets it to TYPE_TRANSLATION. - * - * @param mx the distance to translate in the x direction. - * @param my the distance to translate in the y direction. + * Sets the transformation to a translation alone. Sets the linear part of + * the transformation to identity and the translation vector to the values + * sent as parameters. Sets the type to TYPE_IDENTITY if the + * resulting AffineTransformation is the identity transformation, otherwise + * sets it to TYPE_TRANSLATION. + * + * @param mx + * the distance to translate in the x direction. + * @param my + * the distance to translate in the y direction. */ public void setToTranslation(double mx, double my) { m00 = m11 = 1.0; @@ -458,14 +516,15 @@ public class AffineTransform implements Cloneable, Serializable { } /** - * Sets the transformation to being a scale alone, eliminating - * rotation, shear, and translation elements. - * Sets the type to TYPE_IDENTITY - * if the resulting AffineTransformation is the identity - * transformation, otherwise sets it to TYPE_UNKNOWN. - * - * @param scx the scaling factor in the x direction. - * @param scy the scaling factor in the y direction. + * Sets the transformation to being a scale alone, eliminating rotation, + * shear, and translation elements. Sets the type to + * TYPE_IDENTITY if the resulting AffineTransformation is the + * identity transformation, otherwise sets it to TYPE_UNKNOWN. + * + * @param scx + * the scaling factor in the x direction. + * @param scy + * the scaling factor in the y direction. */ public void setToScale(double scx, double scy) { m00 = scx; @@ -479,14 +538,15 @@ public class AffineTransform implements Cloneable, Serializable { } /** - * Sets the transformation to being a shear alone, eliminating - * rotation, scaling, and translation elements. - * Sets the type to TYPE_IDENTITY - * if the resulting AffineTransformation is the identity - * transformation, otherwise sets it to TYPE_UNKNOWN. - * - * @param shx the shearing factor in the x direction. - * @param shy the shearing factor in the y direction. + * Sets the transformation to being a shear alone, eliminating rotation, + * scaling, and translation elements. Sets the type to + * TYPE_IDENTITY if the resulting AffineTransformation is the + * identity transformation, otherwise sets it to TYPE_UNKNOWN. + * + * @param shx + * the shearing factor in the x direction. + * @param shy + * the shearing factor in the y direction. */ public void setToShear(double shx, double shy) { m00 = m11 = 1.0; @@ -501,13 +561,13 @@ public class AffineTransform implements Cloneable, Serializable { } /** - * Sets the transformation to being a rotation alone, eliminating - * shearing, scaling, and translation elements. - * Sets the type to TYPE_IDENTITY - * if the resulting AffineTransformation is the identity - * transformation, otherwise sets it to TYPE_UNKNOWN. + * Sets the transformation to being a rotation alone, eliminating shearing, + * scaling, and translation elements. Sets the type to + * TYPE_IDENTITY if the resulting AffineTransformation is the + * identity transformation, otherwise sets it to TYPE_UNKNOWN. * - * @param angle the angle of rotation in radians. + * @param angle + * the angle of rotation in radians. */ public void setToRotation(double angle) { double sin = Math.sin(angle); @@ -515,11 +575,10 @@ public class AffineTransform implements Cloneable, Serializable { if (Math.abs(cos) < ZERO) { cos = 0.0; sin = sin > 0.0 ? 1.0 : -1.0; - } else - if (Math.abs(sin) < ZERO) { - sin = 0.0; - cos = cos > 0.0 ? 1.0 : -1.0; - } + } else if (Math.abs(sin) < ZERO) { + sin = 0.0; + cos = cos > 0.0 ? 1.0 : -1.0; + } m00 = m11 = cos; m01 = -sin; m10 = sin; @@ -528,13 +587,15 @@ public class AffineTransform implements Cloneable, Serializable { } /** - * Sets the transformation to being a rotation followed by a - * translation. + * Sets the transformation to being a rotation followed by a translation. * Sets the type to TYPE_UNKNOWN. * - * @param angle the angle of rotation in radians. - * @param px the distance to translate in the x direction. - * @param py the distance to translate in the y direction. + * @param angle + * the angle of rotation in radians. + * @param px + * the distance to translate in the x direction. + * @param py + * the distance to translate in the y direction. */ public void setToRotation(double angle, double px, double py) { setToRotation(angle); @@ -544,15 +605,16 @@ public class AffineTransform implements Cloneable, Serializable { } /** - * Creates a new AffineTransformation that is a translation alone - * with the translation vector given by the values sent as parameters. - * The new transformation's type is TYPE_IDENTITY - * if the AffineTransformation is the identity - * transformation, otherwise it's TYPE_TRANSLATION. - * - * @param mx the distance to translate in the x direction. - * @param my the distance to translate in the y direction. - + * Creates a new AffineTransformation that is a translation alone with the + * translation vector given by the values sent as parameters. The new + * transformation's type is TYPE_IDENTITY if the + * AffineTransformation is the identity transformation, otherwise it's + * TYPE_TRANSLATION. + * + * @param mx + * the distance to translate in the x direction. + * @param my + * the distance to translate in the y direction. * @return the new AffineTransformation. */ public static AffineTransform getTranslateInstance(double mx, double my) { @@ -562,14 +624,15 @@ public class AffineTransform implements Cloneable, Serializable { } /** - * Creates a new AffineTransformation that is a scale alone. - * The new transformation's type is TYPE_IDENTITY - * if the AffineTransformation is the identity - * transformation, otherwise it's TYPE_UNKNOWN. - * - * @param scx the scaling factor in the x direction. - * @param scY the scaling factor in the y direction. - * + * Creates a new AffineTransformation that is a scale alone. The new + * transformation's type is TYPE_IDENTITY if the + * AffineTransformation is the identity transformation, otherwise it's + * TYPE_UNKNOWN. + * + * @param scx + * the scaling factor in the x direction. + * @param scY + * the scaling factor in the y direction. * @return the new AffineTransformation. */ public static AffineTransform getScaleInstance(double scx, double scY) { @@ -579,14 +642,15 @@ public class AffineTransform implements Cloneable, Serializable { } /** - * Creates a new AffineTransformation that is a shear alone. - * The new transformation's type is TYPE_IDENTITY - * if the AffineTransformation is the identity - * transformation, otherwise it's TYPE_UNKNOWN. - * - * @param shx the shearing factor in the x direction. - * @param shy the shearing factor in the y direction. - * + * Creates a new AffineTransformation that is a shear alone. The new + * transformation's type is TYPE_IDENTITY if the + * AffineTransformation is the identity transformation, otherwise it's + * TYPE_UNKNOWN. + * + * @param shx + * the shearing factor in the x direction. + * @param shy + * the shearing factor in the y direction. * @return the new AffineTransformation. */ public static AffineTransform getShearInstance(double shx, double shy) { @@ -596,13 +660,13 @@ public class AffineTransform implements Cloneable, Serializable { } /** - * Creates a new AffineTransformation that is a rotation alone. - * The new transformation's type is TYPE_IDENTITY - * if the AffineTransformation is the identity - * transformation, otherwise it's TYPE_UNKNOWN. - * - * @param angle the angle of rotation in radians. + * Creates a new AffineTransformation that is a rotation alone. The new + * transformation's type is TYPE_IDENTITY if the + * AffineTransformation is the identity transformation, otherwise it's + * TYPE_UNKNOWN. * + * @param angle + * the angle of rotation in radians. * @return the new AffineTransformation. */ public static AffineTransform getRotateInstance(double angle) { @@ -612,14 +676,15 @@ public class AffineTransform implements Cloneable, Serializable { } /** - * Creates a new AffineTransformation that is a rotation followed by a - * translation. - * Sets the type to TYPE_UNKNOWN. - * - * @param angle the angle of rotation in radians. - * @param x the distance to translate in the x direction. - * @param y the distance to translate in the y direction. - * + * Creates a new AffineTransformation that is a rotation followed by a + * translation. Sets the type to TYPE_UNKNOWN. + * + * @param angle + * the angle of rotation in radians. + * @param x + * the distance to translate in the x direction. + * @param y + * the distance to translate in the y direction. * @return the new AffineTransformation. */ public static AffineTransform getRotateInstance(double angle, double x, double y) { @@ -631,8 +696,10 @@ public class AffineTransform implements Cloneable, Serializable { /** * Applies a translation to this AffineTransformation. * - * @param mx the distance to translate in the x direction. - * @param my the distance to translate in the y direction. + * @param mx + * the distance to translate in the x direction. + * @param my + * the distance to translate in the y direction. */ public void translate(double mx, double my) { concatenate(AffineTransform.getTranslateInstance(mx, my)); @@ -641,8 +708,10 @@ public class AffineTransform implements Cloneable, Serializable { /** * Applies a scaling transformation to this AffineTransformation. * - * @param scx the scaling factor in the x direction. - * @param scy the scaling factor in the y direction. + * @param scx + * the scaling factor in the x direction. + * @param scy + * the scaling factor in the y direction. */ public void scale(double scx, double scy) { concatenate(AffineTransform.getScaleInstance(scx, scy)); @@ -651,8 +720,10 @@ public class AffineTransform implements Cloneable, Serializable { /** * Applies a shearing transformation to this AffineTransformation. * - * @param shx the shearing factor in the x direction. - * @param shy the shearing factor in the y direction. + * @param shx + * the shearing factor in the x direction. + * @param shy + * the shearing factor in the y direction. */ public void shear(double shx, double shy) { concatenate(AffineTransform.getShearInstance(shx, shy)); @@ -661,19 +732,23 @@ public class AffineTransform implements Cloneable, Serializable { /** * Applies a rotation transformation to this AffineTransformation. * - * @param angle the angle of rotation in radians. + * @param angle + * the angle of rotation in radians. */ public void rotate(double angle) { concatenate(AffineTransform.getRotateInstance(angle)); } /** - * Applies a rotation and translation transformation to this + * Applies a rotation and translation transformation to this * AffineTransformation. * - * @param angle the angle of rotation in radians. - * @param px the distance to translate in the x direction. - * @param py the distance to translate in the y direction. + * @param angle + * the angle of rotation in radians. + * @param px + * the distance to translate in the x direction. + * @param py + * the distance to translate in the y direction. */ public void rotate(double angle, double px, double py) { concatenate(AffineTransform.getRotateInstance(angle, px, py)); @@ -682,36 +757,40 @@ public class AffineTransform implements Cloneable, Serializable { /** * Multiplies the matrix representations of two AffineTransform objects. * - * @param t1 - the AffineTransform object is a multiplicand - * @param t2 - the AffineTransform object is a multiplier - * - * @return an AffineTransform object that is the result of t1 multiplied by the matrix t2. + * @param t1 + * - the AffineTransform object is a multiplicand + * @param t2 + * - the AffineTransform object is a multiplier + * @return an AffineTransform object that is the result of t1 multiplied by + * the matrix t2. */ AffineTransform multiply(AffineTransform t1, AffineTransform t2) { - return new AffineTransform( - t1.m00 * t2.m00 + t1.m10 * t2.m01, // m00 - t1.m00 * t2.m10 + t1.m10 * t2.m11, // m01 - t1.m01 * t2.m00 + t1.m11 * t2.m01, // m10 - t1.m01 * t2.m10 + t1.m11 * t2.m11, // m11 + return new AffineTransform(t1.m00 * t2.m00 + t1.m10 * t2.m01, // m00 + t1.m00 * t2.m10 + t1.m10 * t2.m11, // m01 + t1.m01 * t2.m00 + t1.m11 * t2.m01, // m10 + t1.m01 * t2.m10 + t1.m11 * t2.m11, // m11 t1.m02 * t2.m00 + t1.m12 * t2.m01 + t2.m02, // m02 t1.m02 * t2.m10 + t1.m12 * t2.m11 + t2.m12);// m12 } /** - * Applies the given AffineTransform to this AffineTransform - * via matrix multiplication. + * Applies the given AffineTransform to this AffineTransform via matrix + * multiplication. * - * @param t the AffineTransform to apply to this AffineTransform. + * @param t + * the AffineTransform to apply to this AffineTransform. */ public void concatenate(AffineTransform t) { setTransform(multiply(t, this)); } /** - * Changes the current AffineTransform the one obtained by - * taking the transform t and applying this AffineTransform to it. + * Changes the current AffineTransform the one obtained by taking the + * transform t and applying this AffineTransform to it. * - * @param t the AffineTransform that this AffineTransform is multiplied by. + * @param t + * the AffineTransform that this AffineTransform is multiplied + * by. */ public void preConcatenate(AffineTransform t) { setTransform(multiply(this, t)); @@ -721,9 +800,9 @@ public class AffineTransform implements Cloneable, Serializable { * Creates an AffineTransform that is the inverse of this transform. * * @return the affine transform that is the inverse of this AffineTransform. - * - * @throws NoninvertibleTransformException if this AffineTransform cannot be - * inverted (the determinant of the linear transformation part is zero). + * @throws NoninvertibleTransformException + * if this AffineTransform cannot be inverted (the determinant + * of the linear transformation part is zero). */ public AffineTransform createInverse() throws NoninvertibleTransformException { double det = getDeterminant(); @@ -731,25 +810,26 @@ public class AffineTransform implements Cloneable, Serializable { // awt.204=Determinant is zero throw new NoninvertibleTransformException(Messages.getString("awt.204")); //$NON-NLS-1$ } - return new AffineTransform( - m11 / det, // m00 + return new AffineTransform(m11 / det, // m00 -m10 / det, // m10 -m01 / det, // m01 - m00 / det, // m11 + m00 / det, // m11 (m01 * m12 - m11 * m02) / det, // m02 - (m10 * m02 - m00 * m12) / det // m12 + (m10 * m02 - m00 * m12) / det // m12 ); } /** * Apply the current AffineTransform to the point. * - * @param src the original point. - * @param dst Point2D object to be filled with the destination - * coordinates (where the original point is sent by this AffineTransform). May be null. - * - * @return the point in the AffineTransform's image space where the - * original point is sent. + * @param src + * the original point. + * @param dst + * Point2D object to be filled with the destination coordinates + * (where the original point is sent by this AffineTransform). + * May be null. + * @return the point in the AffineTransform's image space where the original + * point is sent. */ public Point2D transform(Point2D src, Point2D dst) { if (dst == null) { @@ -770,25 +850,29 @@ public class AffineTransform implements Cloneable, Serializable { /** * Applies this AffineTransform to an array of points. * - * @param src the array of points to be transformed. - * @param srcOff the offset in the source point array of the first point - * to be transformed. - * @param dst the point array where the images of the points (after - * applying the AffineTransformation) should be placed. - * @param dstOff the offset in the destination array where the new - * values should be written. - * @param length the number of points to transform. - * - * @throws ArrayIndexOutOfBoundsException if - * srcOff + length > src.length or - * dstOff + length > dst.length. + * @param src + * the array of points to be transformed. + * @param srcOff + * the offset in the source point array of the first point to be + * transformed. + * @param dst + * the point array where the images of the points (after applying + * the AffineTransformation) should be placed. + * @param dstOff + * the offset in the destination array where the new values + * should be written. + * @param length + * the number of points to transform. + * @throws ArrayIndexOutOfBoundsException + * if srcOff + length > src.length or + * dstOff + length > dst.length. */ public void transform(Point2D[] src, int srcOff, Point2D[] dst, int dstOff, int length) { while (--length >= 0) { - Point2D srcPoint = src[srcOff++]; + Point2D srcPoint = src[srcOff++]; double x = srcPoint.getX(); double y = srcPoint.getY(); - Point2D dstPoint = dst[dstOff]; + Point2D dstPoint = dst[dstOff]; if (dstPoint == null) { if (srcPoint instanceof Point2D.Double) { dstPoint = new Point2D.Double(); @@ -800,27 +884,31 @@ public class AffineTransform implements Cloneable, Serializable { dst[dstOff++] = dstPoint; } } - + /** - * Applies this AffineTransform to a set of points given - * as an array of double values where every two values in the array - * give the coordinates of a point; the even-indexed values giving the - * x coordinates and the odd-indexed values giving the y coordinates. - * - * @param src the array of points to be transformed. - * @param srcOff the offset in the source point array of the first point - * to be transformed. - * @param dst the point array where the images of the points (after - * applying the AffineTransformation) should be placed. - * @param dstOff the offset in the destination array where the new - * values should be written. - * @param length the number of points to transform. - * - * @throws ArrayIndexOutOfBoundsException if - * srcOff + length*2 > src.length or - * dstOff + length*2 > dst.length. + * Applies this AffineTransform to a set of points given as an array of + * double values where every two values in the array give the coordinates of + * a point; the even-indexed values giving the x coordinates and the + * odd-indexed values giving the y coordinates. + * + * @param src + * the array of points to be transformed. + * @param srcOff + * the offset in the source point array of the first point to be + * transformed. + * @param dst + * the point array where the images of the points (after applying + * the AffineTransformation) should be placed. + * @param dstOff + * the offset in the destination array where the new values + * should be written. + * @param length + * the number of points to transform. + * @throws ArrayIndexOutOfBoundsException + * if srcOff + length*2 > src.length or + * dstOff + length*2 > dst.length. */ - public void transform(double[] src, int srcOff, double[] dst, int dstOff, int length) { + public void transform(double[] src, int srcOff, double[] dst, int dstOff, int length) { int step = 2; if (src == dst && srcOff < dstOff && dstOff < srcOff + length * 2) { srcOff = srcOff + length * 2 - 2; @@ -838,23 +926,27 @@ public class AffineTransform implements Cloneable, Serializable { } /** - * Applies this AffineTransform to a set of points given - * as an array of float values where every two values in the array - * give the coordinates of a point; the even-indexed values giving the - * x coordinates and the odd-indexed values giving the y coordinates. - * - * @param src the array of points to be transformed. - * @param srcOff the offset in the source point array of the first point - * to be transformed. - * @param dst the point array where the images of the points (after - * applying the AffineTransformation) should be placed. - * @param dstOff the offset in the destination array where the new - * values should be written. - * @param length the number of points to transform. - * - * @throws ArrayIndexOutOfBoundsException if - * srcOff + length*2 > src.length or - * dstOff + length*2 > dst.length. + * Applies this AffineTransform to a set of points given as an array of + * float values where every two values in the array give the coordinates of + * a point; the even-indexed values giving the x coordinates and the + * odd-indexed values giving the y coordinates. + * + * @param src + * the array of points to be transformed. + * @param srcOff + * the offset in the source point array of the first point to be + * transformed. + * @param dst + * the point array where the images of the points (after applying + * the AffineTransformation) should be placed. + * @param dstOff + * the offset in the destination array where the new values + * should be written. + * @param length + * the number of points to transform. + * @throws ArrayIndexOutOfBoundsException + * if srcOff + length*2 > src.length or + * dstOff + length*2 > dst.length. */ public void transform(float[] src, int srcOff, float[] dst, int dstOff, int length) { int step = 2; @@ -872,26 +964,30 @@ public class AffineTransform implements Cloneable, Serializable { dstOff += step; } } - + /** - * Applies this AffineTransform to a set of points given - * as an array of float values where every two values in the array - * give the coordinates of a point; the even-indexed values giving the - * x coordinates and the odd-indexed values giving the y coordinates. - * The destination coordinates are given as values of type double. - * - * @param src the array of points to be transformed. - * @param srcOff the offset in the source point array of the first point - * to be transformed. - * @param dst the point array where the images of the points (after - * applying the AffineTransformation) should be placed. - * @param dstOff the offset in the destination array where the new - * values should be written. - * @param length the number of points to transform. - * - * @throws ArrayIndexOutOfBoundsException if - * srcOff + length*2 > src.length or - * dstOff + length*2 > dst.length. + * Applies this AffineTransform to a set of points given as an array of + * float values where every two values in the array give the coordinates of + * a point; the even-indexed values giving the x coordinates and the + * odd-indexed values giving the y coordinates. The destination coordinates + * are given as values of type double. + * + * @param src + * the array of points to be transformed. + * @param srcOff + * the offset in the source point array of the first point to be + * transformed. + * @param dst + * the point array where the images of the points (after applying + * the AffineTransformation) should be placed. + * @param dstOff + * the offset in the destination array where the new values + * should be written. + * @param length + * the number of points to transform. + * @throws ArrayIndexOutOfBoundsException + * if srcOff + length*2 > src.length or + * dstOff + length*2 > dst.length. */ public void transform(float[] src, int srcOff, double[] dst, int dstOff, int length) { while (--length >= 0) { @@ -903,24 +999,28 @@ public class AffineTransform implements Cloneable, Serializable { } /** - * Applies this AffineTransform to a set of points given - * as an array of double values where every two values in the array - * give the coordinates of a point; the even-indexed values giving the - * x coordinates and the odd-indexed values giving the y coordinates. - * The destination coordinates are given as values of type float. - * - * @param src the array of points to be transformed. - * @param srcOff the offset in the source point array of the first point - * to be transformed. - * @param dst the point array where the images of the points (after - * applying the AffineTransformation) should be placed. - * @param dstOff the offset in the destination array where the new - * values should be written. - * @param length the number of points to transform. - * - * @throws ArrayIndexOutOfBoundsException if - * srcOff + length*2 > src.length or - * dstOff + length*2 > dst.length. + * Applies this AffineTransform to a set of points given as an array of + * double values where every two values in the array give the coordinates of + * a point; the even-indexed values giving the x coordinates and the + * odd-indexed values giving the y coordinates. The destination coordinates + * are given as values of type float. + * + * @param src + * the array of points to be transformed. + * @param srcOff + * the offset in the source point array of the first point to be + * transformed. + * @param dst + * the point array where the images of the points (after applying + * the AffineTransformation) should be placed. + * @param dstOff + * the offset in the destination array where the new values + * should be written. + * @param length + * the number of points to transform. + * @throws ArrayIndexOutOfBoundsException + * if srcOff + length*2 > src.length or + * dstOff + length*2 > dst.length. */ public void transform(double[] src, int srcOff, float[] dst, int dstOff, int length) { while (--length >= 0) { @@ -932,15 +1032,16 @@ public class AffineTransform implements Cloneable, Serializable { } /** - * Transforms the point according to the linear transformation - * part of this AffineTransformation (without applying the translation). - * - * @param src the original point. - * @param dst the point object where the result of the delta transform - * is written. - * - * @return the result of applying the delta transform (linear part - * only) to the original point. + * Transforms the point according to the linear transformation part of this + * AffineTransformation (without applying the translation). + * + * @param src + * the original point. + * @param dst + * the point object where the result of the delta transform is + * written. + * @return the result of applying the delta transform (linear part only) to + * the original point. */ // TODO: is this right? if dst is null, we check what it's an // instance of? Shouldn't it be src instanceof Point2D.Double? @@ -961,24 +1062,28 @@ public class AffineTransform implements Cloneable, Serializable { } /** - * Applies the linear transformation part of this AffineTransform - * (ignoring the translation part) to a set of points given - * as an array of double values where every two values in the array - * give the coordinates of a point; the even-indexed values giving the - * x coordinates and the odd-indexed values giving the y coordinates. - * - * @param src the array of points to be transformed. - * @param srcOff the offset in the source point array of the first point - * to be transformed. - * @param dst the point array where the images of the points (after - * applying the delta transformation) should be placed. - * @param dstOff the offset in the destination array where the new - * values should be written. - * @param length the number of points to transform. - * - * @throws ArrayIndexOutOfBoundsException if - * srcOff + length*2 > src.length or - * dstOff + length*2 > dst.length. + * Applies the linear transformation part of this AffineTransform (ignoring + * the translation part) to a set of points given as an array of double + * values where every two values in the array give the coordinates of a + * point; the even-indexed values giving the x coordinates and the + * odd-indexed values giving the y coordinates. + * + * @param src + * the array of points to be transformed. + * @param srcOff + * the offset in the source point array of the first point to be + * transformed. + * @param dst + * the point array where the images of the points (after applying + * the delta transformation) should be placed. + * @param dstOff + * the offset in the destination array where the new values + * should be written. + * @param length + * the number of points to transform. + * @throws ArrayIndexOutOfBoundsException + * if srcOff + length*2 > src.length or + * dstOff + length*2 > dst.length. */ public void deltaTransform(double[] src, int srcOff, double[] dst, int dstOff, int length) { while (--length >= 0) { @@ -990,19 +1095,21 @@ public class AffineTransform implements Cloneable, Serializable { } /** - * Transforms the point according to the inverse of this AffineTransformation. - * - * @param src the original point. - * @param dst the point object where the result of the inverse transform - * is written (may be null). - * - * @return the result of applying the inverse transform. - * Inverse transform. + * Transforms the point according to the inverse of this + * AffineTransformation. * - * @throws NoninvertibleTransformException if this AffineTransform cannot be - * inverted (the determinant of the linear transformation part is zero). + * @param src + * the original point. + * @param dst + * the point object where the result of the inverse transform is + * written (may be null). + * @return the result of applying the inverse transform. Inverse transform. + * @throws NoninvertibleTransformException + * if this AffineTransform cannot be inverted (the determinant + * of the linear transformation part is zero). */ - public Point2D inverseTransform(Point2D src, Point2D dst) throws NoninvertibleTransformException { + public Point2D inverseTransform(Point2D src, Point2D dst) + throws NoninvertibleTransformException { double det = getDeterminant(); if (Math.abs(det) < ZERO) { // awt.204=Determinant is zero @@ -1025,29 +1132,33 @@ public class AffineTransform implements Cloneable, Serializable { } /** - * Applies the inverse of this AffineTransform to a set of points given - * as an array of double values where every two values in the array - * give the coordinates of a point; the even-indexed values giving the - * x coordinates and the odd-indexed values giving the y coordinates. - * - * @param src the array of points to be transformed. - * @param srcOff the offset in the source point array of the first point - * to be transformed. - * @param dst the point array where the images of the points (after - * applying the inverse of the AffineTransformation) should be placed. - * @param dstOff the offset in the destination array where the new - * values should be written. - * @param length the number of points to transform. - * - * @throws ArrayIndexOutOfBoundsException if - * srcOff + length*2 > src.length or - * dstOff + length*2 > dst.length. - * @throws NoninvertibleTransformException if this AffineTransform cannot be - * inverted (the determinant of the linear transformation part is zero). + * Applies the inverse of this AffineTransform to a set of points given as + * an array of double values where every two values in the array give the + * coordinates of a point; the even-indexed values giving the x coordinates + * and the odd-indexed values giving the y coordinates. + * + * @param src + * the array of points to be transformed. + * @param srcOff + * the offset in the source point array of the first point to be + * transformed. + * @param dst + * the point array where the images of the points (after applying + * the inverse of the AffineTransformation) should be placed. + * @param dstOff + * the offset in the destination array where the new values + * should be written. + * @param length + * the number of points to transform. + * @throws ArrayIndexOutOfBoundsException + * if srcOff + length*2 > src.length or + * dstOff + length*2 > dst.length. + * @throws NoninvertibleTransformException + * if this AffineTransform cannot be inverted (the determinant + * of the linear transformation part is zero). */ public void inverseTransform(double[] src, int srcOff, double[] dst, int dstOff, int length) - throws NoninvertibleTransformException - { + throws NoninvertibleTransformException { double det = getDeterminant(); if (Math.abs(det) < ZERO) { // awt.204=Determinant is zero @@ -1063,13 +1174,13 @@ public class AffineTransform implements Cloneable, Serializable { } /** - * Creates a new shape whose data is given by applying this - * AffineTransform to the specified shape. - * - * @param src the original shape whose data is to be transformed. + * Creates a new shape whose data is given by applying this AffineTransform + * to the specified shape. * - * @return the new shape found by applying this AffineTransform to - * the original shape. + * @param src + * the original shape whose data is to be transformed. + * @return the new shape found by applying this AffineTransform to the + * original shape. */ public Shape createTransformedShape(Shape src) { if (src == null) { @@ -1086,9 +1197,7 @@ public class AffineTransform implements Cloneable, Serializable { @Override public String toString() { - return - getClass().getName() + - "[[" + m00 + ", " + m01 + ", " + m02 + "], [" //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ + return getClass().getName() + "[[" + m00 + ", " + m01 + ", " + m02 + "], [" //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ + m10 + ", " + m11 + ", " + m12 + "]]"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ } @@ -1120,39 +1229,39 @@ public class AffineTransform implements Cloneable, Serializable { } if (obj instanceof AffineTransform) { AffineTransform t = (AffineTransform)obj; - return - m00 == t.m00 && m01 == t.m01 && - m02 == t.m02 && m10 == t.m10 && - m11 == t.m11 && m12 == t.m12; + return m00 == t.m00 && m01 == t.m01 && m02 == t.m02 && m10 == t.m10 && m11 == t.m11 + && m12 == t.m12; } return false; } - /** * Writes the AffineTrassform object to the output steam. * - * @param stream - the output stream - * - * @throws IOException - if there are I/O errors while writing to the output strem + * @param stream + * - the output stream. + * @throws IOException + * - if there are I/O errors while writing to the output stream. */ private void writeObject(java.io.ObjectOutputStream stream) throws IOException { stream.defaultWriteObject(); } - /** * Read the AffineTransform object from the input stream. * - * @param stream - the input steam - * - * @throws IOException - if there are I/O errors while reading from the input strem - * @throws ClassNotFoundException - if class could not be found + * @param stream + * - the input stream. + * @throws IOException + * - if there are I/O errors while reading from the input + * stream. + * @throws ClassNotFoundException + * - if class could not be found. */ - private void readObject(java.io.ObjectInputStream stream) throws IOException, ClassNotFoundException { + private void readObject(java.io.ObjectInputStream stream) throws IOException, + ClassNotFoundException { stream.defaultReadObject(); type = TYPE_UNKNOWN; } } - diff --git a/awt/java/awt/geom/Arc2D.java b/awt/java/awt/geom/Arc2D.java index bc1e95c643e6f568abe9d9d280c9851c50cbb403..56f5cd392d2283917c2889c42eda50438bb68318 100644 --- a/awt/java/awt/geom/Arc2D.java +++ b/awt/java/awt/geom/Arc2D.java @@ -18,6 +18,7 @@ * @author Denis M. Kishenko * @version $Revision$ */ + package java.awt.geom; import java.util.NoSuchElementException; @@ -25,59 +26,77 @@ import java.util.NoSuchElementException; import org.apache.harmony.awt.internal.nls.Messages; /** - * The Class Arc2D represents a segment of a curve inscribed - * in a rectangle. The curve is defined by a start angle and an - * extent angle (the end angle minus the start angle) as - * a pie wedge whose point is in the center of the rectangle. - * The Arc2D as a shape may be either OPEN (including nothing - * but the curved arc segment itself), CHORD (the curved arc - * segment closed by a connecting segment from the end to the - * beginning of the arc, or PIE (the segments from the end - * of the arc to the center of the rectangle and from the - * center of the rectangle back to the arc's start point are - * included). + * The Class Arc2D represents a segment of a curve inscribed in a rectangle. The + * curve is defined by a start angle and an extent angle (the end angle minus + * the start angle) as a pie wedge whose point is in the center of the + * rectangle. The Arc2D as a shape may be either OPEN (including nothing but the + * curved arc segment itself), CHORD (the curved arc segment closed by a + * connecting segment from the end to the beginning of the arc, or PIE (the + * segments from the end of the arc to the center of the rectangle and from the + * center of the rectangle back to the arc's start point are included). + * + * @since Android 1.0 */ public abstract class Arc2D extends RectangularShape { - /** The arc type OPEN indicates that the shape includes only the - * curved arc segment. */ + /** + * The arc type OPEN indicates that the shape includes only the curved arc + * segment. + */ public final static int OPEN = 0; - - /** The arc type CHORD indicates that as a shape the connecting - * segment from the end point of the curved arc to the beginning - * point is included. */ + + /** + * The arc type CHORD indicates that as a shape the connecting segment from + * the end point of the curved arc to the beginning point is included. + */ public final static int CHORD = 1; - - /** The arc type PIE indicates that as a shape the two segments - * from the arc's endpoint to the center of the rectangle and from - * the center of the rectangle to the arc's endpoint are included. */ + + /** + * The arc type PIE indicates that as a shape the two segments from the + * arc's endpoint to the center of the rectangle and from the center of the + * rectangle to the arc's endpoint are included. + */ public final static int PIE = 2; /** - * The Class Float is a subclass of Arc2D in which all of the - * data values are given as floats. + * The Class Float is a subclass of Arc2D in which all of the data values + * are given as floats. + * * @see Arc2D.Double + * @since Android 1.0 */ public static class Float extends Arc2D { - /** The x coordinate of the upper left corner of the rectangle that - * contains the arc. */ + /** + * The x coordinate of the upper left corner of the rectangle that + * contains the arc. + */ public float x; - - /** The y coordinate of the upper left corner of the rectangle that - * contains the arc. */ + + /** + * The y coordinate of the upper left corner of the rectangle that + * contains the arc. + */ public float y; - - /** The width of the rectangle that contains the arc. */ + + /** + * The width of the rectangle that contains the arc. + */ public float width; - - /** The height of the rectangle that contains the arc. */ + + /** + * The height of the rectangle that contains the arc. + */ public float height; - - /** The start angle of the arc in degrees. */ + + /** + * The start angle of the arc in degrees. + */ public float start; - - /** The width angle of the arc in degrees. */ + + /** + * The width angle of the arc in degrees. + */ public float extent; /** @@ -90,8 +109,9 @@ public abstract class Arc2D extends RectangularShape { /** * Instantiates a new Arc2D of the specified type with float values. * - * @param type the type of the new Arc2D, either {@link Arc2D#OPEN}, - * {@link Arc2D#CHORD}, or {@link Arc2D#PIE}. + * @param type + * the type of the new Arc2D, either {@link Arc2D#OPEN}, + * {@link Arc2D#CHORD}, or {@link Arc2D#PIE}. */ public Float(int type) { super(type); @@ -100,20 +120,26 @@ public abstract class Arc2D extends RectangularShape { /** * Instantiates a Arc2D with the specified float-valued data. * - * @param x the x coordinate of the upper left corner of the rectangle that - * contains the arc. - * @param y the y coordinate of the upper left corner of the rectangle that - * contains the arc. - * @param width the width of the rectangle that - * contains the arc. - * @param height the height of the rectangle that - * contains the arc. - * @param start the start angle of the arc in degrees. - * @param extent the width angle of the arc in degrees. - * @param type the type of the new Arc2D, either {@link Arc2D#OPEN}, - * {@link Arc2D#CHORD}, or {@link Arc2D#PIE}. + * @param x + * the x coordinate of the upper left corner of the rectangle + * that contains the arc. + * @param y + * the y coordinate of the upper left corner of the rectangle + * that contains the arc. + * @param width + * the width of the rectangle that contains the arc. + * @param height + * the height of the rectangle that contains the arc. + * @param start + * the start angle of the arc in degrees. + * @param extent + * the width angle of the arc in degrees. + * @param type + * the type of the new Arc2D, either {@link Arc2D#OPEN}, + * {@link Arc2D#CHORD}, or {@link Arc2D#PIE}. */ - public Float(float x, float y, float width, float height, float start, float extent, int type) { + public Float(float x, float y, float width, float height, float start, float extent, + int type) { super(type); this.x = x; this.y = y; @@ -124,14 +150,18 @@ public abstract class Arc2D extends RectangularShape { } /** - * Instantiates a new Angle2D with the specified float-valued data - * and the bounding rectangle given by the parameter bounds. + * Instantiates a new Angle2D with the specified float-valued data and + * the bounding rectangle given by the parameter bounds. * - * @param bounds the bounding rectangle of the Angle2D. - * @param start the start angle of the arc in degrees. - * @param extent the width angle of the arc in degrees. - * @param type the type of the new Arc2D, either {@link Arc2D#OPEN}, - * {@link Arc2D#CHORD}, or {@link Arc2D#PIE}. + * @param bounds + * the bounding rectangle of the Angle2D. + * @param start + * the start angle of the arc in degrees. + * @param extent + * the width angle of the arc in degrees. + * @param type + * the type of the new Arc2D, either {@link Arc2D#OPEN}, + * {@link Arc2D#CHORD}, or {@link Arc2D#PIE}. */ public Float(Rectangle2D bounds, float start, float extent, int type) { super(type); @@ -148,8 +178,8 @@ public abstract class Arc2D extends RectangularShape { return x; } - @Override - public double getY() { + @Override + public double getY() { return y; } @@ -179,9 +209,8 @@ public abstract class Arc2D extends RectangularShape { } @Override - public void setArc(double x, double y, double width, double height, - double start, double extent, int type) - { + public void setArc(double x, double y, double width, double height, double start, + double extent, int type) { this.setArcType(type); this.x = (float)x; this.y = (float)y; @@ -209,30 +238,44 @@ public abstract class Arc2D extends RectangularShape { } /** - * The Class Double is a subclass of Arc2D in which all of the - * data values are given as doubles. + * The Class Double is a subclass of Arc2D in which all of the data values + * are given as doubles. + * * @see Arc2D.Float + * @since Android 1.0 */ public static class Double extends Arc2D { - /** The x coordinate of the upper left corner of the rectangle that - * contains the arc. */ + /** + * The x coordinate of the upper left corner of the rectangle that + * contains the arc. + */ public double x; - - /** The y coordinate of the upper left corner of the rectangle that - * contains the arc. */ + + /** + * The y coordinate of the upper left corner of the rectangle that + * contains the arc. + */ public double y; - - /** The width of the rectangle that contains the arc. */ + + /** + * The width of the rectangle that contains the arc. + */ public double width; - - /** The height of the rectangle that contains the arc. */ + + /** + * The height of the rectangle that contains the arc. + */ public double height; - - /** The start angle of the arc in degrees. */ + + /** + * The start angle of the arc in degrees. + */ public double start; - - /** The width angle of the arc in degrees. */ + + /** + * The width angle of the arc in degrees. + */ public double extent; /** @@ -245,8 +288,9 @@ public abstract class Arc2D extends RectangularShape { /** * Instantiates a new Arc2D of the specified type with double values. * - * @param type the type of the new Arc2D, either {@link Arc2D#OPEN}, - * {@link Arc2D#CHORD}, or {@link Arc2D#PIE}. + * @param type + * the type of the new Arc2D, either {@link Arc2D#OPEN}, + * {@link Arc2D#CHORD}, or {@link Arc2D#PIE}. */ public Double(int type) { super(type); @@ -255,22 +299,26 @@ public abstract class Arc2D extends RectangularShape { /** * Instantiates a Arc2D with the specified double-valued data. * - * @param x the x coordinate of the upper left corner of the rectangle that - * contains the arc. - * @param y the y coordinate of the upper left corner of the rectangle that - * contains the arc. - * @param width the width of the rectangle that - * contains the arc. - * @param height the height of the rectangle that - * contains the arc. - * @param start the start angle of the arc in degrees. - * @param extent the width angle of the arc in degrees. - * @param type the type of the new Arc2D, either {@link Arc2D#OPEN}, - * {@link Arc2D#CHORD}, or {@link Arc2D#PIE}. + * @param x + * the x coordinate of the upper left corner of the rectangle + * that contains the arc. + * @param y + * the y coordinate of the upper left corner of the rectangle + * that contains the arc. + * @param width + * the width of the rectangle that contains the arc. + * @param height + * the height of the rectangle that contains the arc. + * @param start + * the start angle of the arc in degrees. + * @param extent + * the width angle of the arc in degrees. + * @param type + * the type of the new Arc2D, either {@link Arc2D#OPEN}, + * {@link Arc2D#CHORD}, or {@link Arc2D#PIE}. */ - public Double(double x, double y, double width, double height, - double start, double extent, int type) - { + public Double(double x, double y, double width, double height, double start, double extent, + int type) { super(type); this.x = x; this.y = y; @@ -281,14 +329,18 @@ public abstract class Arc2D extends RectangularShape { } /** - * Instantiates a new Angle2D with the specified float-valued data - * and the bounding rectangle given by the parameter bounds. + * Instantiates a new Angle2D with the specified float-valued data and + * the bounding rectangle given by the parameter bounds. * - * @param bounds the bounding rectangle of the Angle2D. - * @param start the start angle of the arc in degrees. - * @param extent the width angle of the arc in degrees. - * @param type the type of the new Arc2D, either {@link Arc2D#OPEN}, - * {@link Arc2D#CHORD}, or {@link Arc2D#PIE}. + * @param bounds + * the bounding rectangle of the Angle2D. + * @param start + * the start angle of the arc in degrees. + * @param extent + * the width angle of the arc in degrees. + * @param type + * the type of the new Arc2D, either {@link Arc2D#OPEN}, + * {@link Arc2D#CHORD}, or {@link Arc2D#PIE}. */ public Double(Rectangle2D bounds, double start, double extent, int type) { super(type); @@ -336,9 +388,8 @@ public abstract class Arc2D extends RectangularShape { } @Override - public void setArc(double x, double y, double width, double height, - double start, double extent, int type) - { + public void setArc(double x, double y, double width, double height, double start, + double extent, int type) { this.setArcType(type); this.x = x; this.y = y; @@ -366,73 +417,116 @@ public abstract class Arc2D extends RectangularShape { } /** - * The Class Iterator is the subclass of PathIterator that is used to + * The Class Iterator is the subclass of PathIterator that is used to * traverse the boundary of a shape of type Arc2D. */ class Iterator implements PathIterator { - /** The x coordinate of the center of the arc's bounding rectangle. */ + /** + * The x coordinate of the center of the arc's bounding rectangle. + */ double x; - /** The y coordinate of the center of the arc's bounding rectangle. */ + /** + * The y coordinate of the center of the arc's bounding rectangle. + */ double y; - /** Half of the width of the arc's bounding rectangle (the radius in the case of a circular arc). */ + /** + * Half of the width of the arc's bounding rectangle (the radius in the + * case of a circular arc). + */ double width; - - /** Half of the height of the arc's bounding rectangle (the radius in the case of a circular arc). */ + + /** + * Half of the height of the arc's bounding rectangle (the radius in the + * case of a circular arc). + */ double height; - - /** The start angle of the arc in degrees. */ + + /** + * The start angle of the arc in degrees. + */ double angle; - - /** The angle extent in degrees. */ + + /** + * The angle extent in degrees. + */ double extent; - - /** The closure type of the arc. */ + + /** + * The closure type of the arc. + */ int type; - - /** The path iterator transformation. */ + + /** + * The path iterator transformation. + */ AffineTransform t; - - /** The current segment index. */ + + /** + * The current segment index. + */ int index; - - /** The number of arc segments the source arc subdivided to be approximated by Bezier curves. Depends on extent value. */ + + /** + * The number of arc segments the source arc subdivided to be + * approximated by Bezier curves. Depends on extent value. + */ int arcCount; - - /** The number of line segments. Depends on closure type. */ + + /** + * The number of line segments. Depends on closure type. + */ int lineCount; - - /** The step to calculate next arc subdivision point. */ + + /** + * The step to calculate next arc subdivision point. + */ double step; - - /** The temporary value of cosinus of the current angle. */ + + /** + * The temporary value of cosinus of the current angle. + */ double cos; - /** The temporary value of sinus of the current angle. */ + /** + * The temporary value of sinus of the current angle. + */ double sin; - + /** The coefficient to calculate control points of Bezier curves. */ double k; - - /** The temporary value of x coordinate of the Bezier curve control vector. */ + + /** + * The temporary value of x coordinate of the Bezier curve control + * vector. + */ double kx; - /** The temporary value of y coordinate of the Bezier curve control vector. */ + /** + * The temporary value of y coordinate of the Bezier curve control + * vector. + */ double ky; - - /** The x coordinate of the first path point (MOVE_TO). */ + + /** + * The x coordinate of the first path point (MOVE_TO). + */ double mx; - - /** The y coordinate of the first path point (MOVE_TO). */ + + /** + * The y coordinate of the first path point (MOVE_TO). + */ double my; /** * Constructs a new Arc2D.Iterator for given line and transformation * - * @param a - the source Arc2D object - * @param t the AffineTransformation. + * @param a + * the source Arc2D object. + * @param t + * the AffineTransformation. */ Iterator(Arc2D a, AffineTransform t) { if (width < 0 || height < 0) { @@ -462,8 +556,7 @@ public abstract class Arc2D extends RectangularShape { } else { arcCount = (int)Math.rint(Math.abs(extent) / 90.0); step = Math.toRadians(extent / arcCount); - k = 4.0 / 3.0 * (1.0 - Math.cos(step / 2.0)) - / Math.sin(step / 2.0); + k = 4.0 / 3.0 * (1.0 - Math.cos(step / 2.0)) / Math.sin(step / 2.0); } lineCount = 0; @@ -578,13 +671,16 @@ public abstract class Arc2D extends RectangularShape { } - /** The closure type of the arc. */ + /** + * The closure type of the arc. + */ private int type; /** * Instantiates a new arc2D. * - * @param type the closure type. + * @param type + * the closure type. */ protected Arc2D(int type) { setArcType(type); @@ -595,11 +691,16 @@ public abstract class Arc2D extends RectangularShape { * object with values either of type float or of type double depending on * whether this Arc2D instance is of type Float or Double. * - * @param x the x coordinate of the upper left corner of the bounding rectangle. - * @param y the y coordinate of the upper left corner of the bounding rectangle. - * @param width the width of the bounding rectangle. - * @param height the height of the bounding rectangle. - * + * @param x + * the x coordinate of the upper left corner of the bounding + * rectangle. + * @param y + * the y coordinate of the upper left corner of the bounding + * rectangle. + * @param width + * the width of the bounding rectangle. + * @param height + * the height of the bounding rectangle. * @return the corresponding Rectangle2D object. */ protected abstract Rectangle2D makeBounds(double x, double y, double width, double height); @@ -621,39 +722,46 @@ public abstract class Arc2D extends RectangularShape { /** * Sets the start angle. * - * @param start the new start angle. + * @param start + * the new start angle. */ public abstract void setAngleStart(double start); /** * Sets the width angle. * - * @param extent the new width angle. + * @param extent + * the new width angle. */ public abstract void setAngleExtent(double extent); /** * Sets the data values that define the arc. * - * @param x the x coordinate of the upper left corner of the rectangle that - * contains the arc. - * @param y the y coordinate of the upper left corner of the rectangle that - * contains the arc. - * @param width the width of the rectangle that - * contains the arc. - * @param height the height of the rectangle that - * contains the arc. - * @param start the start angle of the arc in degrees. - * @param extent the width angle of the arc in degrees. - * @param type the type of the new Arc2D, either {@link Arc2D#OPEN}, - * {@link Arc2D#CHORD}, or {@link Arc2D#PIE}. + * @param x + * the x coordinate of the upper left corner of the rectangle + * that contains the arc. + * @param y + * the y coordinate of the upper left corner of the rectangle + * that contains the arc. + * @param width + * the width of the rectangle that contains the arc. + * @param height + * the height of the rectangle that contains the arc. + * @param start + * the start angle of the arc in degrees. + * @param extent + * the width angle of the arc in degrees. + * @param type + * the type of the new Arc2D, either {@link Arc2D#OPEN}, + * {@link Arc2D#CHORD}, or {@link Arc2D#PIE}. */ - public abstract void setArc(double x, double y, double width, - double height, double start, double extent, int type); + public abstract void setArc(double x, double y, double width, double height, double start, + double extent, int type); /** - * Gets the arc type, either {@link Arc2D#OPEN}, - * {@link Arc2D#CHORD}, or {@link Arc2D#PIE}. + * Gets the arc type, either {@link Arc2D#OPEN}, {@link Arc2D#CHORD}, or + * {@link Arc2D#PIE}. * * @return the arc type. */ @@ -662,10 +770,11 @@ public abstract class Arc2D extends RectangularShape { } /** - * Sets the arc type, either {@link Arc2D#OPEN}, - * {@link Arc2D#CHORD}, or {@link Arc2D#PIE}. + * Sets the arc type, either {@link Arc2D#OPEN}, {@link Arc2D#CHORD}, or + * {@link Arc2D#PIE}. * - * @param type the new arc type. + * @param type + * the new arc type. */ public void setArcType(int type) { if (type != OPEN && type != CHORD && type != PIE) { @@ -682,9 +791,8 @@ public abstract class Arc2D extends RectangularShape { */ public Point2D getStartPoint() { double a = Math.toRadians(getAngleStart()); - return new Point2D.Double( - getX() + (1.0 + Math.cos(a)) * getWidth() / 2.0, - getY() + (1.0 - Math.sin(a)) * getHeight() / 2.0); + return new Point2D.Double(getX() + (1.0 + Math.cos(a)) * getWidth() / 2.0, getY() + + (1.0 - Math.sin(a)) * getHeight() / 2.0); } /** @@ -694,9 +802,8 @@ public abstract class Arc2D extends RectangularShape { */ public Point2D getEndPoint() { double a = Math.toRadians(getAngleStart() + getAngleExtent()); - return new Point2D.Double( - getX() + (1.0 + Math.cos(a)) * getWidth() / 2.0, - getY() + (1.0 - Math.sin(a)) * getHeight() / 2.0); + return new Point2D.Double(getX() + (1.0 + Math.cos(a)) * getWidth() / 2.0, getY() + + (1.0 - Math.sin(a)) * getHeight() / 2.0); } public Rectangle2D getBounds2D() { @@ -712,8 +819,8 @@ public abstract class Arc2D extends RectangularShape { Point2D p2 = getEndPoint(); double bx1 = containsAngle(180.0) ? rx1 : Math.min(p1.getX(), p2.getX()); - double by1 = containsAngle(90.0) ? ry1 : Math.min(p1.getY(), p2.getY()); - double bx2 = containsAngle(0.0) ? rx2 : Math.max(p1.getX(), p2.getX()); + double by1 = containsAngle(90.0) ? ry1 : Math.min(p1.getY(), p2.getY()); + double bx2 = containsAngle(0.0) ? rx2 : Math.max(p1.getX(), p2.getX()); double by2 = containsAngle(270.0) ? ry2 : Math.max(p1.getY(), p2.getY()); if (type == PIE) { @@ -735,12 +842,17 @@ public abstract class Arc2D extends RectangularShape { /** * Sets the data that defines the arc. * - * @param point the upper left corner of the bounding rectangle. - * @param size the size of the bounding rectangle. - * @param start the start angle of the arc in degrees. - * @param extent the angle witdth of the arc in degrees. - * @param type the closure type, either {@link Arc2D#OPEN}, - * {@link Arc2D#CHORD}, or {@link Arc2D#PIE}. + * @param point + * the upper left corner of the bounding rectangle. + * @param size + * the size of the bounding rectangle. + * @param start + * the start angle of the arc in degrees. + * @param extent + * the angle width of the arc in degrees. + * @param type + * the closure type, either {@link Arc2D#OPEN}, + * {@link Arc2D#CHORD}, or {@link Arc2D#PIE}. */ public void setArc(Point2D point, Dimension2D size, double start, double extent, int type) { setArc(point.getX(), point.getY(), size.getWidth(), size.getHeight(), start, extent, type); @@ -749,11 +861,15 @@ public abstract class Arc2D extends RectangularShape { /** * Sets the data that defines the arc. * - * @param rect the arc's bounding rectangle. - * @param start the start angle of the arc in degrees. - * @param extent the angle witdth of the arc in degrees. - * @param type the closure type, either {@link Arc2D#OPEN}, - * {@link Arc2D#CHORD}, or {@link Arc2D#PIE}. + * @param rect + * the arc's bounding rectangle. + * @param start + * the start angle of the arc in degrees. + * @param extent + * the angle width of the arc in degrees. + * @param type + * the closure type, either {@link Arc2D#OPEN}, + * {@link Arc2D#CHORD}, or {@link Arc2D#PIE}. */ public void setArc(Rectangle2D rect, double start, double extent, int type) { setArc(rect.getX(), rect.getY(), rect.getWidth(), rect.getHeight(), start, extent, type); @@ -762,47 +878,60 @@ public abstract class Arc2D extends RectangularShape { /** * Sets the data that defines the arc by copying it from another Arc2D. * - * @param arc the arc whose data is copied into this arc. + * @param arc + * the arc whose data is copied into this arc. */ public void setArc(Arc2D arc) { - setArc(arc.getX(), arc.getY(), arc.getWidth(), arc.getHeight(), arc - .getAngleStart(), arc.getAngleExtent(), arc.getArcType()); + setArc(arc.getX(), arc.getY(), arc.getWidth(), arc.getHeight(), arc.getAngleStart(), arc + .getAngleExtent(), arc.getArcType()); } /** * Sets the data for a circular arc by giving its center and radius. * - * @param x the x coordinate of the center of the circle. - * @param y the y coordinate of the center of the circle. - * @param radius the radius of the circle. - * @param start the start angle of the arc in degrees. - * @param extent the angle witdth of the arc in degrees. - * @param type the closure type, either {@link Arc2D#OPEN}, - * {@link Arc2D#CHORD}, or {@link Arc2D#PIE}. + * @param x + * the x coordinate of the center of the circle. + * @param y + * the y coordinate of the center of the circle. + * @param radius + * the radius of the circle. + * @param start + * the start angle of the arc in degrees. + * @param extent + * the angle width of the arc in degrees. + * @param type + * the closure type, either {@link Arc2D#OPEN}, + * {@link Arc2D#CHORD}, or {@link Arc2D#PIE}. */ - public void setArcByCenter(double x, double y, double radius, double start, double extent, int type) { + public void setArcByCenter(double x, double y, double radius, double start, double extent, + int type) { setArc(x - radius, y - radius, radius * 2.0, radius * 2.0, start, extent, type); } /** - * Sets the arc data for a circular arc based on two tangent lines - * and the radius. The two tangent lines are the lines from p1 - * to p2 and from p2 to p3, which determine a unique circle - * with the given radius. The start and end points of the arc - * are the points where the circle touches the two lines, and - * the arc itself is the shorter of the two circle segments - * determined by the two points (in other words, it is the - * piece of the circle that is closer to the lines' intersection - * point p2 and forms a concave shape with the segments from p1 to p2 - * and from p2 to p3). + * Sets the arc data for a circular arc based on two tangent lines and the + * radius. The two tangent lines are the lines from p1 to p2 and from p2 to + * p3, which determine a unique circle with the given radius. The start and + * end points of the arc are the points where the circle touches the two + * lines, and the arc itself is the shorter of the two circle segments + * determined by the two points (in other words, it is the piece of the + * circle that is closer to the lines' intersection point p2 and forms a + * concave shape with the segments from p1 to p2 and from p2 to p3). * - * @param p1 a point which determines one of the two tanget lines (with p2). - * @param p2 the point of intersection of the two tangent lines. - * @param p3 a point which determines one of the two tanget lines (with p2). - * @param radius the radius of the circular arc. + * @param p1 + * a point which determines one of the two tangent lines (with + * p2). + * @param p2 + * the point of intersection of the two tangent lines. + * @param p3 + * a point which determines one of the two tangent lines (with + * p2). + * @param radius + * the radius of the circular arc. */ public void setArcByTangent(Point2D p1, Point2D p2, Point2D p3, double radius) { - // Used simple geometric calculations of arc center, radius and angles by tangents + // Used simple geometric calculations of arc center, radius and angles + // by tangents double a1 = -Math.atan2(p1.getY() - p2.getY(), p1.getX() - p2.getX()); double a2 = -Math.atan2(p3.getY() - p2.getY(), p3.getX() - p2.getX()); double am = (a1 + a2) / 2.0; @@ -821,10 +950,11 @@ public abstract class Arc2D extends RectangularShape { } /** - * Sets a new start angle to be the angle given by the the vector - * from the current center point to the specified point. + * Sets a new start angle to be the angle given by the the vector from the + * current center point to the specified point. * - * @param point the point that determines the new start angle. + * @param point + * the point that determines the new start angle. */ public void setAngleStart(Point2D point) { double angle = Math.atan2(point.getY() - getCenterY(), point.getX() - getCenterX()); @@ -832,20 +962,23 @@ public abstract class Arc2D extends RectangularShape { } /** - * Sets the angles in terms of vectors from the current arc center - * to the points (x1, y1) and (x2, y2). The start angle is given - * by the vector from the current center to the point (x1, y1) and - * the end angle is given by the vector from the center to the point - * (x2, y2). + * Sets the angles in terms of vectors from the current arc center to the + * points (x1, y1) and (x2, y2). The start angle is given by the vector from + * the current center to the point (x1, y1) and the end angle is given by + * the vector from the center to the point (x2, y2). * - * @param x1 the x coordinate of the point whose vector from the center - * point determines the new start angle of the arc. - * @param y1 the y coordinate of the point whose vector from the center - * point determines the new start angle of the arc. - * @param x2 the x coordinate of the point whose vector from the center - * point determines the new end angle of the arc. - * @param y2 the y coordinate of the point whose vector from the center - * point determines the new end angle of the arc. + * @param x1 + * the x coordinate of the point whose vector from the center + * point determines the new start angle of the arc. + * @param y1 + * the y coordinate of the point whose vector from the center + * point determines the new start angle of the arc. + * @param x2 + * the x coordinate of the point whose vector from the center + * point determines the new end angle of the arc. + * @param y2 + * the y coordinate of the point whose vector from the center + * point determines the new end angle of the arc. */ public void setAngles(double x1, double y1, double x2, double y2) { double cx = getCenterX(); @@ -861,29 +994,30 @@ public abstract class Arc2D extends RectangularShape { } /** - * Sets the angles in terms of vectors from the current arc center - * to the points p1 and p2. The start angle is given - * by the vector from the current center to the point p1 and - * the end angle is given by the vector from the center to the point - * p2. + * Sets the angles in terms of vectors from the current arc center to the + * points p1 and p2. The start angle is given by the vector from the current + * center to the point p1 and the end angle is given by the vector from the + * center to the point p2. * - * @param p1 the point whose vector from the center - * point determines the new start angle of the arc. - * @param p2 the point whose vector from the center - * point determines the new end angle of the arc. + * @param p1 + * the point whose vector from the center point determines the + * new start angle of the arc. + * @param p2 + * the point whose vector from the center point determines the + * new end angle of the arc. */ public void setAngles(Point2D p1, Point2D p2) { setAngles(p1.getX(), p1.getY(), p2.getX(), p2.getY()); } /** - * Normalizes the angle by removing extra winding (past 360 degrees) - * and placing it in the positive degree range. + * Normalizes the angle by removing extra winding (past 360 degrees) and + * placing it in the positive degree range. * - * @param angle - the source angle in degrees - * - * @return an angle between 0 and 360 degrees which corresponds - * to the same direction vector as the source angle. + * @param angle + * the source angle in degrees. + * @return an angle between 0 and 360 degrees which corresponds to the same + * direction vector as the source angle. */ double getNormAngle(double angle) { double n = Math.floor(angle / 360.0); @@ -893,10 +1027,10 @@ public abstract class Arc2D extends RectangularShape { /** * Determines whether the given angle is contained in the span of the arc. * - * @param angle the angle to test in degrees. - * - * @return true, if the given angle is between the start angle and - * the end angle of the arc. + * @param angle + * the angle to test in degrees. + * @return true, if the given angle is between the start angle and the end + * angle of the arc. */ public boolean containsAngle(double angle) { double extent = getAngleExtent(); @@ -912,8 +1046,7 @@ public abstract class Arc2D extends RectangularShape { if (a2 < 0.0) { return angle >= a2 + 360.0 || angle <= a1; } - return extent > 0.0 ? a1 <= angle && angle <= a2 : a2 <= angle - && angle <= a1; + return extent > 0.0 ? a1 <= angle && angle <= a2 : a2 <= angle && angle <= a1; } public boolean contains(double px, double py) { @@ -931,8 +1064,7 @@ public abstract class Arc2D extends RectangularShape { return true; } - boolean containsAngle = containsAngle(Math.toDegrees(-Math - .atan2(ny, nx))); + boolean containsAngle = containsAngle(Math.toDegrees(-Math.atan2(ny, nx))); if (type == PIE) { return containsAngle; } @@ -943,14 +1075,13 @@ public abstract class Arc2D extends RectangularShape { Line2D l = new Line2D.Double(getStartPoint(), getEndPoint()); int ccw1 = l.relativeCCW(px, py); int ccw2 = l.relativeCCW(getCenterX(), getCenterY()); - return ccw1 == 0 || ccw2 == 0 - || ((ccw1 + ccw2) == 0 ^ absExtent > 180.0); + return ccw1 == 0 || ccw2 == 0 || ((ccw1 + ccw2) == 0 ^ absExtent > 180.0); } public boolean contains(double rx, double ry, double rw, double rh) { - if (!(contains(rx, ry) && contains(rx + rw, ry) - && contains(rx + rw, ry + rh) && contains(rx, ry + rh))) { + if (!(contains(rx, ry) && contains(rx + rw, ry) && contains(rx + rw, ry + rh) && contains( + rx, ry + rh))) { return false; } @@ -1003,9 +1134,8 @@ public abstract class Arc2D extends RectangularShape { } if (type == PIE) { - if (r.intersectsLine(p1.getX(), p1.getY(), cx, cy) || - r.intersectsLine(p2.getX(), p2.getY(), cx, cy)) - { + if (r.intersectsLine(p1.getX(), p1.getY(), cx, cy) + || r.intersectsLine(p2.getX(), p2.getY(), cx, cy)) { return true; } } else { @@ -1025,4 +1155,3 @@ public abstract class Arc2D extends RectangularShape { } } - diff --git a/awt/java/awt/geom/Area.java b/awt/java/awt/geom/Area.java index bc27d4e2486884c4ae1d953f393a4237291918b7..e6619e349c7034e9e4e3017e0ba5d09437a7c941 100644 --- a/awt/java/awt/geom/Area.java +++ b/awt/java/awt/geom/Area.java @@ -18,6 +18,7 @@ * @author Denis M. Kishenko * @version $Revision$ */ + package java.awt.geom; import java.awt.Rectangle; @@ -27,13 +28,18 @@ import java.awt.geom.Rectangle2D; import java.util.NoSuchElementException; import org.apache.harmony.awt.internal.nls.Messages; +import org.apache.harmony.luni.util.NotImplementedException; /** * The Class Area provides a minimal implementation for a generic shape. + * + * @since Android 1.0 */ public class Area implements Shape, Cloneable { - /** The source Shape object. */ + /** + * The source Shape object. + */ Shape s; /** @@ -80,7 +86,8 @@ public class Area implements Shape, Cloneable { /** * Instantiates a new area with data given by the specified shape. * - * @param s the shape that gives the data for this Area + * @param s + * the shape that gives the data for this Area. */ public Area(Shape s) { if (s == null) { @@ -114,11 +121,11 @@ public class Area implements Shape, Cloneable { /** * Tests whether the object is equal to this Area. * - * @param obj the object to compare - * - * @return true, if successful - * - * @throws NotImplementedException if this method is not implemented + * @param obj + * the object to compare. + * @return true, if successful. + * @throws NotImplementedException + * if this method is not implemented. */ public boolean equals(Area obj) throws org.apache.harmony.luni.util.NotImplementedException { throw new RuntimeException("Not implemented"); //$NON-NLS-1$ @@ -140,7 +147,7 @@ public class Area implements Shape, Cloneable { } public Rectangle2D getBounds2D() { - return s == null ? new Rectangle2D.Double(): s.getBounds2D(); + return s == null ? new Rectangle2D.Double() : s.getBounds2D(); } public PathIterator getPathIterator(AffineTransform t) { @@ -154,32 +161,34 @@ public class Area implements Shape, Cloneable { /** * Adds the specified area to this area. * - * @param area the area to add to this area - * - * @throws NotImplementedException if this method is not implemented + * @param area + * the area to add to this area. + * @throws NotImplementedException + * if this method is not implemented. */ public void add(Area area) throws org.apache.harmony.luni.util.NotImplementedException { throw new RuntimeException("Not implemented"); //$NON-NLS-1$ } /** - * Performs an exclusive or operation between this shape and the - * specified shape. + * Performs an exclusive or operation between this shape and the specified + * shape. * - * @param area the area to XOR against this area - * - * @throws NotImplementedException if this method is not implemented + * @param area + * the area to XOR against this area. + * @throws NotImplementedException + * if this method is not implemented. */ public void exclusiveOr(Area area) throws org.apache.harmony.luni.util.NotImplementedException { throw new RuntimeException("Not implemented"); //$NON-NLS-1$ } /** - * Extracts a Rectangle2D from the source shape if the underlying shape - * data describes a rectangle. + * Extracts a Rectangle2D from the source shape if the underlying shape data + * describes a rectangle. * - * @return a Rectangle2D object if the source shape is rectangle, - * or null if shape is empty or not rectangle. + * @return a Rectangle2D object if the source shape is rectangle, or null if + * shape is empty or not rectangle. */ Rectangle2D extractRectangle() { if (s == null) { @@ -189,7 +198,7 @@ public class Area implements Shape, Cloneable { int count = 0; PathIterator p = s.getPathIterator(null); float[] coords = new float[6]; - while(!p.isDone()) { + while (!p.isDone()) { int type = p.currentSegment(coords); if (count > 12 || type == PathIterator.SEG_QUADTO || type == PathIterator.SEG_CUBICTO) { return null; @@ -198,21 +207,22 @@ public class Area implements Shape, Cloneable { points[count++] = coords[1]; p.next(); } - if (points[0] == points[6] && points[6] == points[8] && points[2] == points[4] && - points[1] == points[3] && points[3] == points[9] && points[5] == points[7]) - { - return new Rectangle2D.Float(points[0], points[1], points[2] - points[0], points[7] - points[1]); + if (points[0] == points[6] && points[6] == points[8] && points[2] == points[4] + && points[1] == points[3] && points[3] == points[9] && points[5] == points[7]) { + return new Rectangle2D.Float(points[0], points[1], points[2] - points[0], points[7] + - points[1]); } return null; } - + /** - * Reduces the size of this Area by intersecting it with the - * specified Area if they are both rectangles. + * Reduces the size of this Area by intersecting it with the specified Area + * if they are both rectangles. * - * @see java.awt.geom.Rectangle2D#intersect(Rectangle2D, Rectangle2D, Rectangle2D) - * - * @param area the area + * @see java.awt.geom.Rectangle2D#intersect(Rectangle2D, Rectangle2D, + * Rectangle2D) + * @param area + * the area. */ public void intersect(Area area) { Rectangle2D src1 = extractRectangle(); @@ -225,9 +235,10 @@ public class Area implements Shape, Cloneable { /** * Subtract the specified area from this area. * - * @param area the area to subtract - * - * @throws NotImplementedException if this method is not implemented + * @param area + * the area to subtract. + * @throws NotImplementedException + * if this method is not implemented. */ public void subtract(Area area) throws org.apache.harmony.luni.util.NotImplementedException { throw new RuntimeException("Not implemented"); //$NON-NLS-1$ @@ -236,9 +247,9 @@ public class Area implements Shape, Cloneable { /** * Checks if this Area is empty. * - * @return true, if this Area is empty - * - * @throws NotImplementedException if this method is not implemented + * @return true, if this Area is empty. + * @throws NotImplementedException + * if this method is not implemented. */ public boolean isEmpty() throws org.apache.harmony.luni.util.NotImplementedException { throw new RuntimeException("Not implemented"); //$NON-NLS-1$ @@ -247,9 +258,9 @@ public class Area implements Shape, Cloneable { /** * Checks if this Area is polygonal. * - * @return true, if this Area is polygonal - * - * @throws NotImplementedException if this method is not implemented + * @return true, if this Area is polygonal. + * @throws NotImplementedException + * if this method is not implemented. */ public boolean isPolygonal() throws org.apache.harmony.luni.util.NotImplementedException { throw new RuntimeException("Not implemented"); //$NON-NLS-1$ @@ -258,9 +269,9 @@ public class Area implements Shape, Cloneable { /** * Checks if this Area is rectangular. * - * @return true, if this Area is rectangular - * - * @throws NotImplementedException if this method is not implemented + * @return true, if this Area is rectangular. + * @throws NotImplementedException + * if this method is not implemented. */ public boolean isRectangular() throws org.apache.harmony.luni.util.NotImplementedException { throw new RuntimeException("Not implemented"); //$NON-NLS-1$ @@ -269,9 +280,9 @@ public class Area implements Shape, Cloneable { /** * Checks if this Area is singular. * - * @return true, if this Area is singular - * - * @throws NotImplementedException if this method is not implemented + * @return true, if this Area is singular. + * @throws NotImplementedException + * if this method is not implemented. */ public boolean isSingular() throws org.apache.harmony.luni.util.NotImplementedException { throw new RuntimeException("Not implemented"); //$NON-NLS-1$ @@ -280,30 +291,32 @@ public class Area implements Shape, Cloneable { /** * Resets the data of this Area. * - * @throws NotImplementedException if this method is not implemented + * @throws NotImplementedException + * if this method is not implemented. */ public void reset() throws org.apache.harmony.luni.util.NotImplementedException { throw new RuntimeException("Not implemented"); //$NON-NLS-1$ } /** - * Transforms the data of this Area according to the specified + * Transforms the data of this Area according to the specified * AffineTransform. * - * @param t the transform to use to transform the data + * @param t + * the transform to use to transform the data. */ public void transform(AffineTransform t) { s = t.createTransformedShape(s); } /** - * Creates a new Area that is the result of transforming the data - * of this Area according to the specified AffineTransform. - * - * @param t the transform to use to transform the data + * Creates a new Area that is the result of transforming the data of this + * Area according to the specified AffineTransform. * - * @return the new Area that is the result of transforming the data - * of this Area according to the specified AffineTransform. + * @param t + * the transform to use to transform the data. + * @return the new Area that is the result of transforming the data of this + * Area according to the specified AffineTransform. */ public Area createTransformedArea(AffineTransform t) { return s == null ? new Area() : new Area(t.createTransformedShape(s)); diff --git a/awt/java/awt/geom/CubicCurve2D.java b/awt/java/awt/geom/CubicCurve2D.java index 3e440c8b6cd50d9c6b4cc095bb95a74ad9784fbb..1ddedf39a403cf50c2ad283c52caf016f38bb9fa 100644 --- a/awt/java/awt/geom/CubicCurve2D.java +++ b/awt/java/awt/geom/CubicCurve2D.java @@ -18,6 +18,7 @@ * @author Denis M. Kishenko * @version $Revision$ */ + package java.awt.geom; import java.awt.Rectangle; @@ -28,49 +29,69 @@ import org.apache.harmony.awt.gl.Crossing; import org.apache.harmony.awt.internal.nls.Messages; /** - * The Class CubicCurve2D is a Shape that represents a segment of a - * quadratic (Bezier) curve. The curved segment is determined by four points: - * a start point, an end point, and two control points. - * The control points give information about the tangent and next - * derivative at the endpoints according to the standard theory of - * Bezier curves. For more information on Bezier curves, - * see this article. + * The Class CubicCurve2D is a Shape that represents a segment of a quadratic + * (Bezier) curve. The curved segment is determined by four points: a start + * point, an end point, and two control points. The control points give + * information about the tangent and next derivative at the endpoints according + * to the standard theory of Bezier curves. For more information on Bezier + * curves, see this + * article. + * + * @since Android 1.0 */ public abstract class CubicCurve2D implements Shape, Cloneable { /** - * The Class Float is the subclass of CubicCurve2D that has all - * of its data values stored with float-level precision. + * The Class Float is the subclass of CubicCurve2D that has all of its data + * values stored with float-level precision. + * + * @since Android 1.0 */ public static class Float extends CubicCurve2D { - /** The x coordinate of the starting point. */ + /** + * The x coordinate of the starting point. + */ public float x1; - - /** The y coordinate of the starting point. */ + + /** + * The y coordinate of the starting point. + */ public float y1; - - /** The x coordinate of the first control point. */ + + /** + * The x coordinate of the first control point. + */ public float ctrlx1; - - /** The y coordinate of the first control point. */ + + /** + * The y coordinate of the first control point. + */ public float ctrly1; - - /** The x coordinate of the second control point. */ + + /** + * The x coordinate of the second control point. + */ public float ctrlx2; - - /** The y coordinate of the second control point. */ + + /** + * The y coordinate of the second control point. + */ public float ctrly2; - - /** The x coordinate of the end point. */ + + /** + * The x coordinate of the end point. + */ public float x2; - - /** The y coordinate of the end point. */ + + /** + * The y coordinate of the end point. + */ public float y2; /** - * Instantiates a new float-valued CubicCurve2D with all coordinate values - * set to zero. + * Instantiates a new float-valued CubicCurve2D with all coordinate + * values set to zero. */ public Float() { } @@ -79,16 +100,25 @@ public abstract class CubicCurve2D implements Shape, Cloneable { * Instantiates a new float-valued CubicCurve2D with the specified * coordinate values. * - * @param x1 the x coordinate of the starting point - * @param y1 the y coordinate of the starting point - * @param ctrlx1 the x coordinate of the first control point - * @param ctrly1 the y coordinate of the first control point - * @param ctrlx2 the x coordinate of the second control point - * @param ctrly2 the y coordinate of the second control point - * @param x2 the x coordinate of the end point - * @param y2 the y coordinate of the end point + * @param x1 + * the x coordinate of the starting point. + * @param y1 + * the y coordinate of the starting point. + * @param ctrlx1 + * the x coordinate of the first control point. + * @param ctrly1 + * the y coordinate of the first control point. + * @param ctrlx2 + * the x coordinate of the second control point. + * @param ctrly2 + * the y coordinate of the second control point. + * @param x2 + * the x coordinate of the end point. + * @param y2 + * the y coordinate of the end point. */ - public Float(float x1, float y1, float ctrlx1, float ctrly1, float ctrlx2, float ctrly2, float x2, float y2) { + public Float(float x1, float y1, float ctrlx1, float ctrly1, float ctrlx2, float ctrly2, + float x2, float y2) { setCurve(x1, y1, ctrlx1, ctrly1, ctrlx2, ctrly2, x2, y2); } @@ -153,9 +183,8 @@ public abstract class CubicCurve2D implements Shape, Cloneable { } @Override - public void setCurve(double x1, double y1, double ctrlx1, double ctrly1, - double ctrlx2, double ctrly2, double x2, double y2) - { + public void setCurve(double x1, double y1, double ctrlx1, double ctrly1, double ctrlx2, + double ctrly2, double x2, double y2) { this.x1 = (float)x1; this.y1 = (float)y1; this.ctrlx1 = (float)ctrlx1; @@ -169,18 +198,25 @@ public abstract class CubicCurve2D implements Shape, Cloneable { /** * Sets the data values of the curve. * - * @param x1 the x coordinate of the starting point - * @param y1 the y coordinate of the starting point - * @param ctrlx1 the x coordinate of the first control point - * @param ctrly1 the y coordinate of the first control point - * @param ctrlx2 the x coordinate of the second control point - * @param ctrly2 the y coordinate of the second control point - * @param x2 the x coordinate of the end point - * @param y2 the y coordinate of the end point + * @param x1 + * the x coordinate of the starting point. + * @param y1 + * the y coordinate of the starting point. + * @param ctrlx1 + * the x coordinate of the first control point. + * @param ctrly1 + * the y coordinate of the first control point. + * @param ctrlx2 + * the x coordinate of the second control point. + * @param ctrly2 + * the y coordinate of the second control point. + * @param x2 + * the x coordinate of the end point. + * @param y2 + * the y coordinate of the end point. */ - public void setCurve(float x1, float y1, float ctrlx1, float ctrly1, - float ctrlx2, float ctrly2, float x2, float y2) - { + public void setCurve(float x1, float y1, float ctrlx1, float ctrly1, float ctrlx2, + float ctrly2, float x2, float y2) { this.x1 = x1; this.y1 = y1; this.ctrlx1 = ctrlx1; @@ -201,38 +237,56 @@ public abstract class CubicCurve2D implements Shape, Cloneable { } /** - * The Class Double is the subclass of CubicCurve2D that has all - * of its data values stored with double-level precision. + * The Class Double is the subclass of CubicCurve2D that has all of its data + * values stored with double-level precision. + * + * @since Android 1.0 */ public static class Double extends CubicCurve2D { - /** The x coordinate of the starting point. */ + /** + * The x coordinate of the starting point. + */ public double x1; - - /** The y coordinate of the starting point. */ + + /** + * The y coordinate of the starting point. + */ public double y1; - - /** The x coordinate of the first control point. */ + + /** + * The x coordinate of the first control point. + */ public double ctrlx1; - - /** The y coordinate of the first control point. */ + + /** + * The y coordinate of the first control point. + */ public double ctrly1; - - /** The x coordinate of the second control point. */ + + /** + * The x coordinate of the second control point. + */ public double ctrlx2; - - /** The y coordinate of the second control point. */ + + /** + * The y coordinate of the second control point. + */ public double ctrly2; - - /** The x coordinate of the end point. */ + + /** + * The x coordinate of the end point. + */ public double x2; - - /** The y coordinate of the end point. */ + + /** + * The y coordinate of the end point. + */ public double y2; /** - * Instantiates a new double-valued CubicCurve2D with all coordinate values - * set to zero. + * Instantiates a new double-valued CubicCurve2D with all coordinate + * values set to zero. */ public Double() { } @@ -241,17 +295,25 @@ public abstract class CubicCurve2D implements Shape, Cloneable { * Instantiates a new double-valued CubicCurve2D with the specified * coordinate values. * - * @param x1 the x coordinate of the starting point - * @param y1 the y coordinate of the starting point - * @param ctrlx1 the x coordinate of the first control point - * @param ctrly1 the y coordinate of the first control point - * @param ctrlx2 the x coordinate of the second control point - * @param ctrly2 the y coordinate of the second control point - * @param x2 the x coordinate of the end point - * @param y2 the y coordinate of the end point + * @param x1 + * the x coordinate of the starting point. + * @param y1 + * the y coordinate of the starting point. + * @param ctrlx1 + * the x coordinate of the first control point. + * @param ctrly1 + * the y coordinate of the first control point. + * @param ctrlx2 + * the x coordinate of the second control point. + * @param ctrly2 + * the y coordinate of the second control point. + * @param x2 + * the x coordinate of the end point. + * @param y2 + * the y coordinate of the end point. */ - public Double(double x1, double y1, double ctrlx1, double ctrly1, - double ctrlx2, double ctrly2, double x2, double y2) { + public Double(double x1, double y1, double ctrlx1, double ctrly1, double ctrlx2, + double ctrly2, double x2, double y2) { setCurve(x1, y1, ctrlx1, ctrly1, ctrlx2, ctrly2, x2, y2); } @@ -316,9 +378,8 @@ public abstract class CubicCurve2D implements Shape, Cloneable { } @Override - public void setCurve(double x1, double y1, double ctrlx1, double ctrly1, - double ctrlx2, double ctrly2, double x2, double y2) - { + public void setCurve(double x1, double y1, double ctrlx1, double ctrly1, double ctrlx2, + double ctrly2, double x2, double y2) { this.x1 = x1; this.y1 = y1; this.ctrlx1 = ctrlx1; @@ -339,27 +400,36 @@ public abstract class CubicCurve2D implements Shape, Cloneable { } /* - * CubicCurve2D path iterator + * CubicCurve2D path iterator */ /** * The Iterator class for the Shape CubicCurve2D. */ class Iterator implements PathIterator { - /** The source CubicCurve2D object. */ + /** + * The source CubicCurve2D object. + */ CubicCurve2D c; - - /** The path iterator transformation. */ + + /** + * The path iterator transformation. + */ AffineTransform t; - - /** The current segmenet index. */ + + /** + * The current segment index. + */ int index; /** - * Constructs a new CubicCurve2D.Iterator for given line and transformation + * Constructs a new CubicCurve2D.Iterator for given line and + * transformation * - * @param c - the source CubicCurve2D object - * @param t the t + * @param c + * the source CubicCurve2D object. + * @param t + * the affine transformation object. */ Iterator(CubicCurve2D c, AffineTransform t) { this.c = c; @@ -443,42 +513,42 @@ public abstract class CubicCurve2D implements Shape, Cloneable { /** * Gets the x coordinate of the starting point. * - * @return the x coordinate of the starting point + * @return the x coordinate of the starting point. */ public abstract double getX1(); /** * Gets the y coordinate of the starting point. * - * @return the y coordinate of the starting point + * @return the y coordinate of the starting point. */ public abstract double getY1(); /** * Gets the starting point. * - * @return the starting point + * @return the starting point. */ public abstract Point2D getP1(); /** * Gets the x coordinate of the first control point. * - * @return the x coordinate of the first control point + * @return the x coordinate of the first control point. */ public abstract double getCtrlX1(); /** * Gets the y coordinate of the first control point. * - * @return the y coordinate of the first control point + * @return the y coordinate of the first control point. */ public abstract double getCtrlY1(); /** * Gets the second control point. * - * @return the second control point + * @return the second control point. */ public abstract Point2D getCtrlP1(); @@ -499,42 +569,50 @@ public abstract class CubicCurve2D implements Shape, Cloneable { /** * Gets the second control point. * - * @return the second control point + * @return the second control point. */ public abstract Point2D getCtrlP2(); /** * Gets the x coordinate of the end point. * - * @return the x coordinate of the end point + * @return the x coordinate of the end point. */ public abstract double getX2(); /** * Gets the y coordinate of the end point. * - * @return the y coordinate of the end point + * @return the y coordinate of the end point. */ public abstract double getY2(); /** * Gets the end point. * - * @return the end point + * @return the end point. */ public abstract Point2D getP2(); /** * Sets the data of the curve. * - * @param x1 the x coordinate of the starting point - * @param y1 the y coordinate of the starting point - * @param ctrlx1 the x coordinate of the first control point - * @param ctrly1 the y coordinate of the first control point - * @param ctrlx2 the x coordinate of the second control point - * @param ctrly2 the y coordinate of the second control point - * @param x2 the x coordinate of the end point - * @param y2 the y coordinate of the end point + * @param x1 + * the x coordinate of the starting point. + * @param y1 + * the y coordinate of the starting point. + * @param ctrlx1 + * the x coordinate of the first control point. + * @param ctrly1 + * the y coordinate of the first control point. + * @param ctrlx2 + * the x coordinate of the second control point. + * @param ctrly2 + * the y coordinate of the second control point. + * @param x2 + * the x coordinate of the end point. + * @param y2 + * the y coordinate of the end point. */ public abstract void setCurve(double x1, double y1, double ctrlx1, double ctrly1, double ctrlx2, double ctrly2, double x2, double y2); @@ -542,224 +620,238 @@ public abstract class CubicCurve2D implements Shape, Cloneable { /** * Sets the data of the curve as point objects. * - * @param p1 the starting point - * @param cp1 the first control point - * @param cp2 the second control point - * @param p2 the end point - * - * @throws NullPointerException if any of the points is null. + * @param p1 + * the starting point. + * @param cp1 + * the first control point. + * @param cp2 + * the second control point. + * @param p2 + * the end point. + * @throws NullPointerException + * if any of the points is null. */ public void setCurve(Point2D p1, Point2D cp1, Point2D cp2, Point2D p2) { - setCurve( - p1.getX(), p1.getY(), - cp1.getX(), cp1.getY(), - cp2.getX(), cp2.getY(), - p2.getX(), p2.getY()); + setCurve(p1.getX(), p1.getY(), cp1.getX(), cp1.getY(), cp2.getX(), cp2.getY(), p2.getX(), + p2.getY()); } /** - * Sets the data of the curve by reading the data from an array - * of values. The values are read in the same order as the arguments - * of the method {@link CubicCurve2D#setCurve(double, double, double, double, double, double, double, double)}. - * - * @param coords the array of values containing the new coordinates - * @param offset the offset of the data to read within the array + * Sets the data of the curve by reading the data from an array of values. + * The values are read in the same order as the arguments of the method + * {@link CubicCurve2D#setCurve(double, double, double, double, double, double, double, double)} + * . * - * @throws ArrayIndexOutOfBoundsException if coords.length < offset + 8. - * @throws NullPointerException if the coordinate array is null. + * @param coords + * the array of values containing the new coordinates. + * @param offset + * the offset of the data to read within the array. + * @throws ArrayIndexOutOfBoundsException + * if {@code coords.length} < offset + 8. + * @throws NullPointerException + * if the coordinate array is null. */ public void setCurve(double[] coords, int offset) { - setCurve( - coords[offset + 0], coords[offset + 1], - coords[offset + 2], coords[offset + 3], - coords[offset + 4], coords[offset + 5], - coords[offset + 6], coords[offset + 7]); + setCurve(coords[offset + 0], coords[offset + 1], coords[offset + 2], coords[offset + 3], + coords[offset + 4], coords[offset + 5], coords[offset + 6], coords[offset + 7]); } /** - * Sets the data of the curve by reading the data from an array - * of points. The values are read in the same order as the arguments - * of the method {@link CubicCurve2D#setCurve(Point2D, Point2D, Point2D, Point2D)} + * Sets the data of the curve by reading the data from an array of points. + * The values are read in the same order as the arguments of the method + * {@link CubicCurve2D#setCurve(Point2D, Point2D, Point2D, Point2D)} * - * @param points the array of points containing the new coordinates - * @param offset the offset of the data to read within the array - * - * @throws ArrayIndexOutOfBoundsException if points.length < offset + . - * @throws NullPointerException if the point array is null. + * @param points + * the array of points containing the new coordinates. + * @param offset + * the offset of the data to read within the array. + * @throws ArrayIndexOutOfBoundsException + * if {@code points.length} < offset + . + * @throws NullPointerException + * if the point array is null. */ public void setCurve(Point2D[] points, int offset) { - setCurve( - points[offset + 0].getX(), points[offset + 0].getY(), - points[offset + 1].getX(), points[offset + 1].getY(), - points[offset + 2].getX(), points[offset + 2].getY(), + setCurve(points[offset + 0].getX(), points[offset + 0].getY(), points[offset + 1].getX(), + points[offset + 1].getY(), points[offset + 2].getX(), points[offset + 2].getY(), points[offset + 3].getX(), points[offset + 3].getY()); } /** * Sets the data of the curve by copying it from another CubicCurve2D. * - * @param curve the curve to copy the data points from - * - * @throws NullPointerException if the curve is null. + * @param curve + * the curve to copy the data points from. + * @throws NullPointerException + * if the curve is null. */ public void setCurve(CubicCurve2D curve) { - setCurve( - curve.getX1(), curve.getY1(), - curve.getCtrlX1(), curve.getCtrlY1(), - curve.getCtrlX2(), curve.getCtrlY2(), - curve.getX2(), curve.getY2()); + setCurve(curve.getX1(), curve.getY1(), curve.getCtrlX1(), curve.getCtrlY1(), curve + .getCtrlX2(), curve.getCtrlY2(), curve.getX2(), curve.getY2()); } /** - * Gets the square of the flatness of this curve, where the flatness is the - * maximum distance from the curves control points to the - * line segment connecting the two points. + * Gets the square of the flatness of this curve, where the flatness is the + * maximum distance from the curves control points to the line segment + * connecting the two points. * - * @return the square of the flatness + * @return the square of the flatness. */ public double getFlatnessSq() { - return getFlatnessSq( - getX1(), getY1(), - getCtrlX1(), getCtrlY1(), - getCtrlX2(), getCtrlY2(), + return getFlatnessSq(getX1(), getY1(), getCtrlX1(), getCtrlY1(), getCtrlX2(), getCtrlY2(), getX2(), getY2()); } /** - * Gets the square of the flatness of the cubic curve segment - * defined by the specified values. + * Gets the square of the flatness of the cubic curve segment defined by the + * specified values. * - * @param x1 the x coordinate of the starting point - * @param y1 the y coordinate of the starting point - * @param ctrlx1 the x coordinate of the first control point - * @param ctrly1 the y coordinate of the first control point - * @param ctrlx2 the x coordinate of the second control point - * @param ctrly2 the y coordinate of the second control point - * @param x2 the x coordinate of the end point - * @param y2 the y coordinate of the end point - * - * @return the square of the flatness + * @param x1 + * the x coordinate of the starting point. + * @param y1 + * the y coordinate of the starting point. + * @param ctrlx1 + * the x coordinate of the first control point. + * @param ctrly1 + * the y coordinate of the first control point. + * @param ctrlx2 + * the x coordinate of the second control point. + * @param ctrly2 + * the y coordinate of the second control point. + * @param x2 + * the x coordinate of the end point. + * @param y2 + * the y coordinate of the end point. + * @return the square of the flatness. */ public static double getFlatnessSq(double x1, double y1, double ctrlx1, double ctrly1, - double ctrlx2, double ctrly2, double x2, double y2) - { - return Math.max( - Line2D.ptSegDistSq(x1, y1, x2, y2, ctrlx1, ctrly1), - Line2D.ptSegDistSq(x1, y1, x2, y2, ctrlx2, ctrly2)); + double ctrlx2, double ctrly2, double x2, double y2) { + return Math.max(Line2D.ptSegDistSq(x1, y1, x2, y2, ctrlx1, ctrly1), Line2D.ptSegDistSq(x1, + y1, x2, y2, ctrlx2, ctrly2)); } /** - * Gets the square of the flatness of the cubic curve segment - * defined by the specified values. The values are read in the same order as the arguments - * of the method {@link CubicCurve2D#getFlatnessSq(double, double, double, double, double, double, double, double)}. - * - * @param coords the array of points containing the new coordinates - * @param offset the offset of the data to read within the array + * Gets the square of the flatness of the cubic curve segment defined by the + * specified values. The values are read in the same order as the arguments + * of the method + * {@link CubicCurve2D#getFlatnessSq(double, double, double, double, double, double, double, double)} + * . * - * @return the square of the flatness - * - * @throws ArrayIndexOutOfBoundsException if points.length < offset + . - * @throws NullPointerException if the point array is null. + * @param coords + * the array of points containing the new coordinates. + * @param offset + * the offset of the data to read within the array. + * @return the square of the flatness. + * @throws ArrayIndexOutOfBoundsException + * if points.length < offset + . + * @throws NullPointerException + * if the point array is null. */ public static double getFlatnessSq(double coords[], int offset) { - return getFlatnessSq( - coords[offset + 0], coords[offset + 1], - coords[offset + 2], coords[offset + 3], - coords[offset + 4], coords[offset + 5], - coords[offset + 6], coords[offset + 7]); + return getFlatnessSq(coords[offset + 0], coords[offset + 1], coords[offset + 2], + coords[offset + 3], coords[offset + 4], coords[offset + 5], coords[offset + 6], + coords[offset + 7]); } /** - * Gets the flatness of this curve, where the flatness is the - * maximum distance from the curves control points to the - * line segment connecting the two points. + * Gets the flatness of this curve, where the flatness is the maximum + * distance from the curves control points to the line segment connecting + * the two points. * - * @return the flatness of this curve + * @return the flatness of this curve. */ public double getFlatness() { - return getFlatness( - getX1(), getY1(), - getCtrlX1(), getCtrlY1(), - getCtrlX2(), getCtrlY2(), + return getFlatness(getX1(), getY1(), getCtrlX1(), getCtrlY1(), getCtrlX2(), getCtrlY2(), getX2(), getY2()); } /** - * Gets the flatness of the cubic curve segment - * defined by the specified values. - * - * @param x1 the x coordinate of the starting point - * @param y1 the y coordinate of the starting point - * @param ctrlx1 the x coordinate of the first control point - * @param ctrly1 the y coordinate of the first control point - * @param ctrlx2 the x coordinate of the second control point - * @param ctrly2 the y coordinate of the second control point - * @param x2 the x coordinate of the end point - * @param y2 the y coordinate of the end point + * Gets the flatness of the cubic curve segment defined by the specified + * values. * - * @return the flatness + * @param x1 + * the x coordinate of the starting point. + * @param y1 + * the y coordinate of the starting point. + * @param ctrlx1 + * the x coordinate of the first control point. + * @param ctrly1 + * the y coordinate of the first control point. + * @param ctrlx2 + * the x coordinate of the second control point. + * @param ctrly2 + * the y coordinate of the second control point. + * @param x2 + * the x coordinate of the end point. + * @param y2 + * the y coordinate of the end point. + * @return the flatness. */ public static double getFlatness(double x1, double y1, double ctrlx1, double ctrly1, - double ctrlx2, double ctrly2, double x2, double y2) - { + double ctrlx2, double ctrly2, double x2, double y2) { return Math.sqrt(getFlatnessSq(x1, y1, ctrlx1, ctrly1, ctrlx2, ctrly2, x2, y2)); } /** - * Gets the flatness of the cubic curve segment - * defined by the specified values. The values are read in the same order as the arguments - * of the method {@link CubicCurve2D#getFlatness(double, double, double, double, double, double, double, double)}. + * Gets the flatness of the cubic curve segment defined by the specified + * values. The values are read in the same order as the arguments of the + * method + * {@link CubicCurve2D#getFlatness(double, double, double, double, double, double, double, double)} + * . * - * @param coords the array of points containing the new coordinates - * @param offset the offset of the data to read within the array - * - * @return the flatness - * - * @throws ArrayIndexOutOfBoundsException if points.length < offset + . - * @throws NullPointerException if the point array is null. + * @param coords + * the array of points containing the new coordinates. + * @param offset + * the offset of the data to read within the array. + * @return the flatness. + * @throws ArrayIndexOutOfBoundsException + * if points.length < offset + . + * @throws NullPointerException + * if the point array is null. */ public static double getFlatness(double coords[], int offset) { - return getFlatness( - coords[offset + 0], coords[offset + 1], - coords[offset + 2], coords[offset + 3], - coords[offset + 4], coords[offset + 5], - coords[offset + 6], coords[offset + 7]); + return getFlatness(coords[offset + 0], coords[offset + 1], coords[offset + 2], + coords[offset + 3], coords[offset + 4], coords[offset + 5], coords[offset + 6], + coords[offset + 7]); } /** - * Creates the data for two cubic curves by dividing this - * curve in two. The division point is the point on the curve - * that is closest to the average of curve's two control points. - * The two new control points (nearest the new endpoint) are computed - * by averaging the original control points with the new endpoint. - * The data of this curve is left unchanged. - * - * @param left the CubicCurve2D where the left (start) segment's - * data is written - * @param right the CubicCurve2D where the right (end) segment's - * data is written + * Creates the data for two cubic curves by dividing this curve in two. The + * division point is the point on the curve that is closest to the average + * of curve's two control points. The two new control points (nearest the + * new endpoint) are computed by averaging the original control points with + * the new endpoint. The data of this curve is left unchanged. * - * @throws NullPointerException if either curve is null. + * @param left + * the CubicCurve2D where the left (start) segment's data is + * written. + * @param right + * the CubicCurve2D where the right (end) segment's data is + * written. + * @throws NullPointerException + * if either curve is null. */ public void subdivide(CubicCurve2D left, CubicCurve2D right) { subdivide(this, left, right); } /** - * Creates the data for two cubic curves by dividing the specified - * curve in two. The division point is the point on the curve - * that is closest to the average of curve's two control points. - * The two new control points (nearest the new endpoint) are computed - * by averaging the original control points with the new endpoint. - * The data of the source curve is left unchanged. + * Creates the data for two cubic curves by dividing the specified curve in + * two. The division point is the point on the curve that is closest to the + * average of curve's two control points. The two new control points + * (nearest the new endpoint) are computed by averaging the original control + * points with the new endpoint. The data of the source curve is left + * unchanged. * - * @param src the original curve to be divided in two - * @param left the CubicCurve2D where the left (start) segment's - * data is written - * @param right the CubicCurve2D where the right (end) segment's - * data is written - * - * @throws NullPointerException if either curve is null. + * @param src + * the original curve to be divided in two. + * @param left + * the CubicCurve2D where the left (start) segment's data is + * written. + * @param right + * the CubicCurve2D where the right (end) segment's data is + * written. + * @throws NullPointerException + * if either curve is null. */ public static void subdivide(CubicCurve2D src, CubicCurve2D left, CubicCurve2D right) { double x1 = src.getX1(); @@ -791,27 +883,36 @@ public abstract class CubicCurve2D implements Shape, Cloneable { } /** - * Creates the data for two cubic curves by dividing the specified - * curve in two. The division point is the point on the curve - * that is closest to the average of curve's two control points. - * The two new control points (nearest the new endpoint) are computed - * by averaging the original control points with the new endpoint. - * The data of the source curve is left unchanged. The data for the - * three curves is read/written in the usual order: { x1, y1, - * ctrlx1, ctrly1, ctrlx2, crtry2, x2, y3 } - * - * @param src the array that gives the data values for the source curve - * @param srcOff the offset in the src array to read the values from - * @param left the array where the coordinates of the start curve should be written - * @param leftOff the offset in the left array to start writing the values - * @param right the array where the coordinates of the end curve should be written - * @param rightOff the offset in the right array to start writing the values + * Creates the data for two cubic curves by dividing the specified curve in + * two. The division point is the point on the curve that is closest to the + * average of curve's two control points. The two new control points + * (nearest the new endpoint) are computed by averaging the original control + * points with the new endpoint. The data of the source curve is left + * unchanged. The data for the three curves is read/written in the usual + * order: { x1, y1, ctrlx1, ctrly1, ctrlx2, crtry2, x2, y3 } * - * @throws ArrayIndexOutOfBoundsException if src.length < srcoff + 8 - * or if left.length < leftOff + 8 or if right.length < rightOff + 8. - * @throws NullPointerException if one of the arrays is null. + * @param src + * the array that gives the data values for the source curve. + * @param srcOff + * the offset in the src array to read the values from. + * @param left + * the array where the coordinates of the start curve should be + * written. + * @param leftOff + * the offset in the left array to start writing the values. + * @param right + * the array where the coordinates of the end curve should be + * written. + * @param rightOff + * the offset in the right array to start writing the values. + * @throws ArrayIndexOutOfBoundsException + * if src.length < srcoff + 8 or if left.length < leftOff + 8 or + * if right.length < rightOff + 8. + * @throws NullPointerException + * if one of the arrays is null. */ - public static void subdivide(double src[], int srcOff, double left[], int leftOff, double right[], int rightOff) { + public static void subdivide(double src[], int srcOff, double left[], int leftOff, + double right[], int rightOff) { double x1 = src[srcOff + 0]; double y1 = src[srcOff + 1]; double cx1 = src[srcOff + 2]; @@ -855,42 +956,43 @@ public abstract class CubicCurve2D implements Shape, Cloneable { } /** - * Finds the roots of the cubic polynomial. This is - * accomplished by finding the (real) values of x that solve - * the following equation: eqn[3]*x*x*x + eqn[2]*x*x + eqn[1]*x + eqn[0] = 0. - * The solutions are written back into the array eqn starting - * from the index 0 in the array. The return value tells how - * many array elements have been changed by this method call. + * Finds the roots of the cubic polynomial. This is accomplished by finding + * the (real) values of x that solve the following equation: eqn[3]*x*x*x + + * eqn[2]*x*x + eqn[1]*x + eqn[0] = 0. The solutions are written back into + * the array eqn starting from the index 0 in the array. The return value + * tells how many array elements have been changed by this method call. * - * @param eqn an array containing the coefficients of the - * cubic polynomial to solve. - * - * @return the number of roots of the cubic polynomial - * - * @throws ArrayIndexOutOfBoundsException if eqn.length < 4. - * @throws NullPointerException if the array is null. + * @param eqn + * an array containing the coefficients of the cubic polynomial + * to solve. + * @return the number of roots of the cubic polynomial. + * @throws ArrayIndexOutOfBoundsException + * if eqn.length < 4. + * @throws NullPointerException + * if the array is null. */ public static int solveCubic(double eqn[]) { return solveCubic(eqn, eqn); } /** - * Finds the roots of the cubic polynomial. This is - * accomplished by finding the (real) values of x that solve - * the following equation: eqn[3]*x*x*x + eqn[2]*x*x + eqn[1]*x + eqn[0] = 0. - * The solutions are written into the array res starting - * from the index 0 in the array. The return value tells how - * many array elements have been changed by this method call. - * - * @param eqn an array containing the coefficients of the - * cubic polynomial to solve. - * @param res the array that this method writes the results into - * - * @return the number of roots of the cubic polynomial + * Finds the roots of the cubic polynomial. This is accomplished by finding + * the (real) values of x that solve the following equation: eqn[3]*x*x*x + + * eqn[2]*x*x + eqn[1]*x + eqn[0] = 0. The solutions are written into the + * array res starting from the index 0 in the array. The return value tells + * how many array elements have been changed by this method call. * - * @throws ArrayIndexOutOfBoundsException if eqn.length < 4 or - * if res.length is less than the number of roots. - * @throws NullPointerException if either array is null. + * @param eqn + * an array containing the coefficients of the cubic polynomial + * to solve. + * @param res + * the array that this method writes the results into. + * @return the number of roots of the cubic polynomial. + * @throws ArrayIndexOutOfBoundsException + * if eqn.length < 4 or if res.length is less than the number of + * roots. + * @throws NullPointerException + * if either array is null. */ public static int solveCubic(double eqn[], double res[]) { return Crossing.solveCubic(eqn, res); diff --git a/awt/java/awt/geom/Dimension2D.java b/awt/java/awt/geom/Dimension2D.java index eef63e67c34edd4637aa08b51daacce0802405b0..ea081c517c2b499e6128645a03b1b678bcd546c8 100644 --- a/awt/java/awt/geom/Dimension2D.java +++ b/awt/java/awt/geom/Dimension2D.java @@ -18,12 +18,15 @@ * @author Denis M. Kishenko * @version $Revision$ */ + package java.awt.geom; /** - * The Class Dimension2D represents a size (width and height) of a - * geometric object. It stores double-valued data in order to be compatible - * with high-precision geometric operations. + * The Class Dimension2D represents a size (width and height) of a geometric + * object. It stores double-valued data in order to be compatible with + * high-precision geometric operations. + * + * @since Android 1.0 */ public abstract class Dimension2D implements Cloneable { @@ -36,31 +39,34 @@ public abstract class Dimension2D implements Cloneable { /** * Gets the width. * - * @return the width + * @return the width. */ public abstract double getWidth(); /** * Gets the height. * - * @return the height + * @return the height. */ public abstract double getHeight(); /** * Sets the width and height. * - * @param width the width - * @param height the height + * @param width + * the width. + * @param height + * the height. */ public abstract void setSize(double width, double height); /** - * Sets the width and height based on the data of another - * Dimension2D object. + * Sets the width and height based on the data of another Dimension2D + * object. * - * @param d the Dimension2D object providing the data to copy - * into this Dimension2D object + * @param d + * the Dimension2D object providing the data to copy into this + * Dimension2D object. */ public void setSize(Dimension2D d) { setSize(d.getWidth(), d.getHeight()); @@ -75,4 +81,3 @@ public abstract class Dimension2D implements Cloneable { } } } - diff --git a/awt/java/awt/geom/Ellipse2D.java b/awt/java/awt/geom/Ellipse2D.java index 33464afe74c0a36976e69d21c4f499211f44e67a..89fd0d06617da221f1932749f24da9a162b08451 100644 --- a/awt/java/awt/geom/Ellipse2D.java +++ b/awt/java/awt/geom/Ellipse2D.java @@ -18,6 +18,7 @@ * @author Denis M. Kishenko * @version $Revision$ */ + package java.awt.geom; import java.util.NoSuchElementException; @@ -25,29 +26,41 @@ import java.util.NoSuchElementException; import org.apache.harmony.awt.internal.nls.Messages; /** - * The Class Ellipse2D describes an ellipse defined by a rectangular - * area in which it is inscribed. + * The Class Ellipse2D describes an ellipse defined by a rectangular area in + * which it is inscribed. + * + * @since Android 1.0 */ public abstract class Ellipse2D extends RectangularShape { /** - * The Class Float is the subclass of Ellipse2D that has all - * of its data values stored with float-level precision. + * The Class Float is the subclass of Ellipse2D that has all of its data + * values stored with float-level precision. + * + * @since Android 1.0 */ public static class Float extends Ellipse2D { - /** The x coordinate of the upper left corner of the ellipse's - * bounding rectangle. */ + /** + * The x coordinate of the upper left corner of the ellipse's bounding + * rectangle. + */ public float x; - - /** The y coordinate of the upper left corner of the ellipse's - * bounding rectangle. */ + + /** + * The y coordinate of the upper left corner of the ellipse's bounding + * rectangle. + */ public float y; - - /** The width of the ellipse's bounding rectangle. */ + + /** + * The width of the ellipse's bounding rectangle. + */ public float width; - - /** The height of the ellipse's bounding rectangle. */ + + /** + * The height of the ellipse's bounding rectangle. + */ public float height; /** @@ -59,12 +72,16 @@ public abstract class Ellipse2D extends RectangularShape { /** * Instantiates a new float-valued Ellipse2D with the specified data. * - * @param x the x coordinate of the upper left corner of the ellipse's - * bounding rectangle - * @param y the y coordinate of the upper left corner of the ellipse's - * bounding rectangle - * @param width the width of the ellipse's bounding rectangle - * @param height the height of the ellipse's bounding rectangle + * @param x + * the x coordinate of the upper left corner of the ellipse's + * bounding rectangle. + * @param y + * the y coordinate of the upper left corner of the ellipse's + * bounding rectangle. + * @param width + * the width of the ellipse's bounding rectangle. + * @param height + * the height of the ellipse's bounding rectangle. */ public Float(float x, float y, float width, float height) { setFrame(x, y, width, height); @@ -98,12 +115,16 @@ public abstract class Ellipse2D extends RectangularShape { /** * Sets the data of the ellipse's bounding rectangle. * - * @param x the x coordinate of the upper left corner of the ellipse's - * bounding rectangle - * @param y the y coordinate of the upper left corner of the ellipse's - * bounding rectangle - * @param width the width of the ellipse's bounding rectangle - * @param height the height of the ellipse's bounding rectangle + * @param x + * the x coordinate of the upper left corner of the ellipse's + * bounding rectangle. + * @param y + * the y coordinate of the upper left corner of the ellipse's + * bounding rectangle. + * @param width + * the width of the ellipse's bounding rectangle. + * @param height + * the height of the ellipse's bounding rectangle. */ public void setFrame(float x, float y, float width, float height) { this.x = x; @@ -126,23 +147,33 @@ public abstract class Ellipse2D extends RectangularShape { } /** - * The Class Double is the subclass of Ellipse2D that has all - * of its data values stored with double-level precision. + * The Class Double is the subclass of Ellipse2D that has all of its data + * values stored with double-level precision. + * + * @since Android 1.0 */ public static class Double extends Ellipse2D { - /** The x coordinate of the upper left corner of the ellipse's - * bounding rectangle. */ + /** + * The x coordinate of the upper left corner of the ellipse's bounding + * rectangle. + */ public double x; - - /** The y coordinate of the upper left corner of the ellipse's - * bounding rectangle. */ + + /** + * The y coordinate of the upper left corner of the ellipse's bounding + * rectangle. + */ public double y; - - /** The width of the ellipse's bounding rectangle. */ + + /** + * The width of the ellipse's bounding rectangle. + */ public double width; - - /** The height of the ellipse's bounding rectangle. */ + + /** + * The height of the ellipse's bounding rectangle. + */ public double height; /** @@ -152,15 +183,18 @@ public abstract class Ellipse2D extends RectangularShape { } /** - * Instantiates a new double-valued Ellipse2D with the specified - * data. + * Instantiates a new double-valued Ellipse2D with the specified data. * - * @param x the x coordinate of the upper left corner of the ellipse's - * bounding rectangle - * @param y the y coordinate of the upper left corner of the ellipse's - * bounding rectangle - * @param width the width of the ellipse's bounding rectangle - * @param height the height of the ellipse's bounding rectangle + * @param x + * the x coordinate of the upper left corner of the ellipse's + * bounding rectangle. + * @param y + * the y coordinate of the upper left corner of the ellipse's + * bounding rectangle. + * @param width + * the width of the ellipse's bounding rectangle. + * @param height + * the height of the ellipse's bounding rectangle. */ public Double(double x, double y, double width, double height) { setFrame(x, y, width, height); @@ -205,7 +239,7 @@ public abstract class Ellipse2D extends RectangularShape { } /* - * Ellipse2D path iterator + * Ellipse2D path iterator */ /** * The subclass of PathIterator to traverse an Ellipse2D. @@ -213,46 +247,72 @@ public abstract class Ellipse2D extends RectangularShape { class Iterator implements PathIterator { /* - * Ellipse is subdivided into four quarters by x and y axis. Each part approximated by - * cubic Bezier curve. Arc in first quarter is started in (a, 0) and finished in (0, b) points. - * Control points for cubic curve wiil be (a, 0), (a, m), (n, b) and (0, b) where n and m are - * calculated based on requirement Bezier curve in point 0.5 should lay on the arc. + * Ellipse is subdivided into four quarters by x and y axis. Each part + * approximated by cubic Bezier curve. Arc in first quarter is started + * in (a, 0) and finished in (0, b) points. Control points for cubic + * curve wiil be (a, 0), (a, m), (n, b) and (0, b) where n and m are + * calculated based on requirement Bezier curve in point 0.5 should lay + * on the arc. */ - /** The coefficient to calculate control points of Bezier curves. */ + /** + * The coefficient to calculate control points of Bezier curves. + */ final double u = 2.0 / 3.0 * (Math.sqrt(2.0) - 1.0); - /** The points coordinates calculation table. */ + /** + * The points coordinates calculation table. + */ final double points[][] = { - { 1.0, 0.5 + u, 0.5 + u, 1.0, 0.5, 1.0 }, - { 0.5 - u, 1.0, 0.0, 0.5 + u, 0.0, 0.5 }, - { 0.0, 0.5 - u, 0.5 - u, 0.0, 0.5, 0.0 }, - { 0.5 + u, 0.0, 1.0, 0.5 - u, 1.0, 0.5 } + { + 1.0, 0.5 + u, 0.5 + u, 1.0, 0.5, 1.0 + }, { + 0.5 - u, 1.0, 0.0, 0.5 + u, 0.0, 0.5 + }, { + 0.0, 0.5 - u, 0.5 - u, 0.0, 0.5, 0.0 + }, { + 0.5 + u, 0.0, 1.0, 0.5 - u, 1.0, 0.5 + } }; - /** The x coordinate of left-upper corner of the ellipse bounds. */ + /** + * The x coordinate of left-upper corner of the ellipse bounds. + */ double x; - - /** The y coordinate of left-upper corner of the ellipse bounds. */ + + /** + * The y coordinate of left-upper corner of the ellipse bounds. + */ double y; - - /** The width of the ellipse bounds. */ + + /** + * The width of the ellipse bounds. + */ double width; - - /** The height of the ellipse bounds. */ + + /** + * The height of the ellipse bounds. + */ double height; - /** The path iterator transformation. */ + /** + * The path iterator transformation. + */ AffineTransform t; - /** The current segmenet index. */ + /** + * The current segment index. + */ int index; /** - * Constructs a new Ellipse2D.Iterator for given ellipse and transformation + * Constructs a new Ellipse2D.Iterator for given ellipse and + * transformation * - * @param e - the source Ellipse2D object - * @param t the t + * @param e + * the source Ellipse2D object. + * @param t + * the affine transformation object. */ Iterator(Ellipse2D e, AffineTransform t) { this.x = e.getX(); @@ -389,15 +449,10 @@ public abstract class Ellipse2D extends RectangularShape { double rx2 = rx + rw; double ry2 = ry + rh; - return - contains(rx1, ry1) && - contains(rx2, ry1) && - contains(rx2, ry2) && - contains(rx1, ry2); + return contains(rx1, ry1) && contains(rx2, ry1) && contains(rx2, ry2) && contains(rx1, ry2); } public PathIterator getPathIterator(AffineTransform at) { return new Iterator(this, at); } } - diff --git a/awt/java/awt/geom/FlatteningPathIterator.java b/awt/java/awt/geom/FlatteningPathIterator.java index ca5c7c2f9bf4883d36db49307b966c0127b5fb06..8208f39635f8c940d5826007bf7188826fe8003d 100644 --- a/awt/java/awt/geom/FlatteningPathIterator.java +++ b/awt/java/awt/geom/FlatteningPathIterator.java @@ -18,6 +18,7 @@ * @author Denis M. Kishenko * @version $Revision$ */ + package java.awt.geom; import java.util.NoSuchElementException; @@ -25,104 +26,139 @@ import java.util.NoSuchElementException; import org.apache.harmony.awt.internal.nls.Messages; /** - * The Class FlatteningPathIterator takes a PathIterator for traversing - * a curved shape and flattens it by estimating the curve as a series - * of line segments. The flattening factor indicates how far the - * estimating line segments are allowed to be from the actual curve: - * the FlatteningPathIterator will keep dividing each curved segment - * into smaller and smaller flat segments until either the segments - * are withing the flattening factor of the curve or until the buffer - * limit is reached. + * The Class FlatteningPathIterator takes a PathIterator for traversing a curved + * shape and flattens it by estimating the curve as a series of line segments. + * The flattening factor indicates how far the estimating line segments are + * allowed to be from the actual curve: the FlatteningPathIterator will keep + * dividing each curved segment into smaller and smaller flat segments until + * either the segments are within the flattening factor of the curve or until + * the buffer limit is reached. + * + * @since Android 1.0 */ public class FlatteningPathIterator implements PathIterator { - /** The default points buffer size. */ + /** + * The default points buffer size. + */ private static final int BUFFER_SIZE = 16; - - /** The default curve subdivision limit. */ + + /** + * The default curve subdivision limit. + */ private static final int BUFFER_LIMIT = 16; - /** The points buffer capacity. */ + /** + * The points buffer capacity. + */ private static final int BUFFER_CAPACITY = 16; - - /** The type of current segment to be flat. */ + + /** + * The type of current segment to be flat. + */ int bufType; - - /** The curve subdivision limit. */ + + /** + * The curve subdivision limit. + */ int bufLimit; - - /** The current points buffer size. */ + + /** + * The current points buffer size. + */ int bufSize; - - /** The inner cursor position in points buffer. */ + + /** + * The inner cursor position in points buffer. + */ int bufIndex; - - /** The current subdivision count. */ + + /** + * The current subdivision count. + */ int bufSubdiv; - /** The points buffer. */ + /** + * The points buffer. + */ double buf[]; - - /** The indicator of empty points buffer. */ + + /** + * The indicator of empty points buffer. + */ boolean bufEmpty = true; - - /** The source PathIterator. */ + + /** + * The source PathIterator. + */ PathIterator p; - - /** The flatness of new path. */ + + /** + * The flatness of new path. + */ double flatness; - - /** The square of flatness. */ + + /** + * The square of flatness. + */ double flatness2; - - /** The x coordinate of previous path segment. */ + + /** + * The x coordinate of previous path segment. + */ double px; - /** The y coordinate of previous path segment. */ + /** + * The y coordinate of previous path segment. + */ double py; - - /** The tamporary buffer for getting points from PathIterator. */ + + /** + * The temporary buffer for getting points from PathIterator. + */ double coords[] = new double[6]; /** - * Instantiates a new flattening path iterator given the path - * iterator for a (possibly) curved path and a flattening factor - * which indicates how close together the points on the curve - * should be chosen. The buffer limit defaults to 16 which means - * that each curve will be divided into no more than 16 segments - * regardless of the flattening factor. - * - * @param path the path iterator of the original curve - * @param flatness the flattening factor that indicates how far the - * flat path is allowed to be from the actual curve in order to - * decide when to stop dividing the path into smaller and smaller - * segments. + * Instantiates a new flattening path iterator given the path iterator for a + * (possibly) curved path and a flattening factor which indicates how close + * together the points on the curve should be chosen. The buffer limit + * defaults to 16 which means that each curve will be divided into no more + * than 16 segments regardless of the flattening factor. * - * @throws IllegalArgumentException if the flatness is less than zero. - * @throws NullPointerException if the path is null. + * @param path + * the path iterator of the original curve. + * @param flatness + * the flattening factor that indicates how far the flat path is + * allowed to be from the actual curve in order to decide when to + * stop dividing the path into smaller and smaller segments. + * @throws IllegalArgumentException + * if the flatness is less than zero. + * @throws NullPointerException + * if the path is null. */ public FlatteningPathIterator(PathIterator path, double flatness) { this(path, flatness, BUFFER_LIMIT); } /** - * Instantiates a new flattening path iterator given the path - * iterator for a (possibly) curved path and a flattening factor - * and a buffer limit. The FlatteningPathIterator will keep - * dividing each curved segment into smaller and smaller flat segments - * until either the segments are withing the flattening factor of the - * curve or until the buffer limit is reached. + * Instantiates a new flattening path iterator given the path iterator for a + * (possibly) curved path and a flattening factor and a buffer limit. The + * FlatteningPathIterator will keep dividing each curved segment into + * smaller and smaller flat segments until either the segments are within + * the flattening factor of the curve or until the buffer limit is reached. * - * @param path the path iterator of the original curve - * @param flatness the flattening factor that indicates how far the - * flat path is allowed to be from the actual curve in order to - * decide when to stop dividing the path into smaller and smaller - * segments. - * @param limit the maximum number of flat segments to divide each - * curve into - * - * @throws IllegalArgumentException if the flatness or limit is less than zero. - * @throws NullPointerException if the path is null. + * @param path + * the path iterator of the original curve. + * @param flatness + * the flattening factor that indicates how far the flat path is + * allowed to be from the actual curve in order to decide when to + * stop dividing the path into smaller and smaller segments. + * @param limit + * the maximum number of flat segments to divide each curve into. + * @throws IllegalArgumentException + * if the flatness or limit is less than zero. + * @throws NullPointerException + * if the path is null. */ public FlatteningPathIterator(PathIterator path, double flatness, int limit) { if (flatness < 0.0) { @@ -149,7 +185,7 @@ public class FlatteningPathIterator implements PathIterator { /** * Gets the flattening factor. * - * @return the flattening factor + * @return the flattening factor. */ public double getFlatness() { return flatness; @@ -158,7 +194,7 @@ public class FlatteningPathIterator implements PathIterator { /** * Gets the maximum number of subdivisions per curved segment. * - * @return the maximum number of subdivisions per curved segment + * @return the maximum number of subdivisions per curved segment. */ public int getRecursionLimit() { return bufLimit; @@ -173,12 +209,13 @@ public class FlatteningPathIterator implements PathIterator { } /** - * Calculates flat path points for current segment of the source shape. - * - * Line segment is flat by itself. Flatness of quad and cubic curves evaluated by getFlatnessSq() method. - * Curves subdivided until current flatness is bigger than user defined and subdivision limit isn't exhausted. - * Single source segment translated to series of buffer points. The less flatness the bigger serries. - * Every currentSegment() call extract one point from the buffer. When series completed evaluate() takes next source shape segment. + * Calculates flat path points for current segment of the source shape. Line + * segment is flat by itself. Flatness of quad and cubic curves evaluated by + * getFlatnessSq() method. Curves subdivided until current flatness is + * bigger than user defined and subdivision limit isn't exhausted. Single + * source segment translated to series of buffer points. The less flatness + * the bigger series. Every currentSegment() call extract one point from the + * buffer. When series completed evaluate() takes next source shape segment. */ void evaluate() { if (bufEmpty) { @@ -186,99 +223,95 @@ public class FlatteningPathIterator implements PathIterator { } switch (bufType) { - case SEG_MOVETO: - case SEG_LINETO: - px = coords[0]; - py = coords[1]; - break; - case SEG_QUADTO: - if (bufEmpty) { - bufIndex -= 6; - buf[bufIndex + 0] = px; - buf[bufIndex + 1] = py; - System.arraycopy(coords, 0, buf, bufIndex + 2, 4); - bufSubdiv = 0; - } - - while (bufSubdiv < bufLimit) { - if (QuadCurve2D.getFlatnessSq(buf, bufIndex) < flatness2) { - break; + case SEG_MOVETO: + case SEG_LINETO: + px = coords[0]; + py = coords[1]; + break; + case SEG_QUADTO: + if (bufEmpty) { + bufIndex -= 6; + buf[bufIndex + 0] = px; + buf[bufIndex + 1] = py; + System.arraycopy(coords, 0, buf, bufIndex + 2, 4); + bufSubdiv = 0; } - // Realloc buffer - if (bufIndex <= 4) { - double tmp[] = new double[bufSize + BUFFER_CAPACITY]; - System.arraycopy( - buf, bufIndex, - tmp, bufIndex + BUFFER_CAPACITY, - bufSize - bufIndex); - buf = tmp; - bufSize += BUFFER_CAPACITY; - bufIndex += BUFFER_CAPACITY; + while (bufSubdiv < bufLimit) { + if (QuadCurve2D.getFlatnessSq(buf, bufIndex) < flatness2) { + break; + } + + // Realloc buffer + if (bufIndex <= 4) { + double tmp[] = new double[bufSize + BUFFER_CAPACITY]; + System.arraycopy(buf, bufIndex, tmp, bufIndex + BUFFER_CAPACITY, bufSize + - bufIndex); + buf = tmp; + bufSize += BUFFER_CAPACITY; + bufIndex += BUFFER_CAPACITY; + } + + QuadCurve2D.subdivide(buf, bufIndex, buf, bufIndex - 4, buf, bufIndex); + + bufIndex -= 4; + bufSubdiv++; } - QuadCurve2D.subdivide(buf, bufIndex, buf, bufIndex - 4, buf, bufIndex); - - bufIndex -= 4; - bufSubdiv++; - } - - bufIndex += 4; - px = buf[bufIndex]; - py = buf[bufIndex + 1]; - - bufEmpty = (bufIndex == bufSize - 2); - if (bufEmpty) { - bufIndex = bufSize; - bufType = SEG_LINETO; - } else { - bufSubdiv--; - } - break; - case SEG_CUBICTO: - if (bufEmpty) { - bufIndex -= 8; - buf[bufIndex + 0] = px; - buf[bufIndex + 1] = py; - System.arraycopy(coords, 0, buf, bufIndex + 2, 6); - bufSubdiv = 0; - } + bufIndex += 4; + px = buf[bufIndex]; + py = buf[bufIndex + 1]; - while (bufSubdiv < bufLimit) { - if (CubicCurve2D.getFlatnessSq(buf, bufIndex) < flatness2) { - break; + bufEmpty = (bufIndex == bufSize - 2); + if (bufEmpty) { + bufIndex = bufSize; + bufType = SEG_LINETO; + } else { + bufSubdiv--; } - - // Realloc buffer - if (bufIndex <= 6) { - double tmp[] = new double[bufSize + BUFFER_CAPACITY]; - System.arraycopy( - buf, bufIndex, - tmp, bufIndex + BUFFER_CAPACITY, - bufSize - bufIndex); - buf = tmp; - bufSize += BUFFER_CAPACITY; - bufIndex += BUFFER_CAPACITY; + break; + case SEG_CUBICTO: + if (bufEmpty) { + bufIndex -= 8; + buf[bufIndex + 0] = px; + buf[bufIndex + 1] = py; + System.arraycopy(coords, 0, buf, bufIndex + 2, 6); + bufSubdiv = 0; } - CubicCurve2D.subdivide(buf, bufIndex, buf, bufIndex - 6, buf, bufIndex); - - bufIndex -= 6; - bufSubdiv++; - } + while (bufSubdiv < bufLimit) { + if (CubicCurve2D.getFlatnessSq(buf, bufIndex) < flatness2) { + break; + } + + // Realloc buffer + if (bufIndex <= 6) { + double tmp[] = new double[bufSize + BUFFER_CAPACITY]; + System.arraycopy(buf, bufIndex, tmp, bufIndex + BUFFER_CAPACITY, bufSize + - bufIndex); + buf = tmp; + bufSize += BUFFER_CAPACITY; + bufIndex += BUFFER_CAPACITY; + } + + CubicCurve2D.subdivide(buf, bufIndex, buf, bufIndex - 6, buf, bufIndex); + + bufIndex -= 6; + bufSubdiv++; + } - bufIndex += 6; - px = buf[bufIndex]; - py = buf[bufIndex + 1]; + bufIndex += 6; + px = buf[bufIndex]; + py = buf[bufIndex + 1]; - bufEmpty = (bufIndex == bufSize - 2); - if (bufEmpty) { - bufIndex = bufSize; - bufType = SEG_LINETO; - } else { - bufSubdiv--; - } - break; + bufEmpty = (bufIndex == bufSize - 2); + if (bufEmpty) { + bufIndex = bufSize; + bufType = SEG_LINETO; + } else { + bufSubdiv--; + } + break; } } @@ -323,4 +356,3 @@ public class FlatteningPathIterator implements PathIterator { return type; } } - diff --git a/awt/java/awt/geom/GeneralPath.java b/awt/java/awt/geom/GeneralPath.java index 36b01c40a005ee2995e4b97ce1e3061a115325f1..0669bc77b00645258ba29bae7daaf311a4bb5685 100644 --- a/awt/java/awt/geom/GeneralPath.java +++ b/awt/java/awt/geom/GeneralPath.java @@ -18,6 +18,7 @@ * @author Denis M. Kishenko * @version $Revision$ */ + package java.awt.geom; import java.awt.Rectangle; @@ -28,81 +29,116 @@ import org.apache.harmony.awt.gl.Crossing; import org.apache.harmony.awt.internal.nls.Messages; /** - * The Class GeneralPath represents a shape whose outline is given - * by different types of curved and straight segments. + * The class GeneralPath represents a shape whose outline is given by different + * types of curved and straight segments. + * + * @since Android 1.0 */ public final class GeneralPath implements Shape, Cloneable { - /** The Constant WIND_EVEN_ODD see {@link PathIterator#WIND_EVEN_ODD}. */ + /** + * The Constant WIND_EVEN_ODD see {@link PathIterator#WIND_EVEN_ODD}. + */ public static final int WIND_EVEN_ODD = PathIterator.WIND_EVEN_ODD; - - /** The Constant WIND_NON_ZERO see {@link PathIterator#WIND_NON_ZERO}. */ + + /** + * The Constant WIND_NON_ZERO see {@link PathIterator#WIND_NON_ZERO}. + */ public static final int WIND_NON_ZERO = PathIterator.WIND_NON_ZERO; - /** The buffers size. */ + /** + * The buffers size. + */ private static final int BUFFER_SIZE = 10; - - /** The buffers capacity. */ + + /** + * The buffers capacity. + */ private static final int BUFFER_CAPACITY = 10; - /** The point's types buffer. */ + /** + * The point's types buffer. + */ byte[] types; - - /** The points buffer. */ + + /** + * The points buffer. + */ float[] points; - - /** The point's type buffer size. */ + + /** + * The point's type buffer size. + */ int typeSize; - - /** The points buffer size. */ + + /** + * The points buffer size. + */ int pointSize; - - /** The path rule. */ + + /** + * The path rule. + */ int rule; - /** The space amount in points buffer for different segmenet's types. */ + /** + * The space amount in points buffer for different segmenet's types. + */ static int pointShift[] = { - 2, // MOVETO - 2, // LINETO - 4, // QUADTO - 6, // CUBICTO - 0}; // CLOSE + 2, // MOVETO + 2, // LINETO + 4, // QUADTO + 6, // CUBICTO + 0 + }; // CLOSE /* - * GeneralPath path iterator + * GeneralPath path iterator */ /** - * The Class Iterator is the subclass of Iterator for traversing the - * outline of a GeneralPath. + * The Class Iterator is the subclass of Iterator for traversing the outline + * of a GeneralPath. */ class Iterator implements PathIterator { - /** The current cursor position in types buffer. */ + /** + * The current cursor position in types buffer. + */ int typeIndex; - - /** The current cursor position in points buffer. */ + + /** + * The current cursor position in points buffer. + */ int pointIndex; - - /** The source GeneralPath object. */ + + /** + * The source GeneralPath object. + */ GeneralPath p; - - /** The path iterator transformation. */ + + /** + * The path iterator transformation. + */ AffineTransform t; /** - * Constructs a new GeneralPath.Iterator for given general path + * Constructs a new GeneralPath.Iterator for given general path. * - * @param path - the source GeneralPath object + * @param path + * the source GeneralPath object. */ Iterator(GeneralPath path) { this(path, null); } /** - * Constructs a new GeneralPath.Iterator for given general path and transformation + * Constructs a new GeneralPath.Iterator for given general path and + * transformation. * - * @param path - the source GeneralPath object - * @param at - the AffineTransform object to apply rectangle path + * @param path + * the source GeneralPath object. + * @param at + * the AffineTransform object to apply rectangle path. */ Iterator(GeneralPath path, AffineTransform at) { this.p = path; @@ -156,33 +192,35 @@ public final class GeneralPath implements Shape, Cloneable { } /** - * Instantiates a new general path with the winding rule set - * to {@link PathIterator#WIND_NON_ZERO} and the initial capacity - * (number of segments) set to the default value 10. + * Instantiates a new general path with the winding rule set to + * {@link PathIterator#WIND_NON_ZERO} and the initial capacity (number of + * segments) set to the default value 10. */ public GeneralPath() { this(WIND_NON_ZERO, BUFFER_SIZE); } /** - * Instantiates a new general path with the given winding rule - * and the initial capacity (number of segments) set to the - * default value 10. + * Instantiates a new general path with the given winding rule and the + * initial capacity (number of segments) set to the default value 10. * - * @param rule the winding rule, either {@link PathIterator#WIND_EVEN_ODD} - * or {@link PathIterator#WIND_NON_ZERO} + * @param rule + * the winding rule, either {@link PathIterator#WIND_EVEN_ODD} or + * {@link PathIterator#WIND_NON_ZERO}. */ public GeneralPath(int rule) { this(rule, BUFFER_SIZE); } /** - * Instantiates a new general path with the given winding rule - * and initial capacity (number of segments). + * Instantiates a new general path with the given winding rule and initial + * capacity (number of segments). * - * @param rule the winding rule, either {@link PathIterator#WIND_EVEN_ODD} - * or {@link PathIterator#WIND_NON_ZERO} - * @param initialCapacity the number of segments the path is set to hold + * @param rule + * the winding rule, either {@link PathIterator#WIND_EVEN_ODD} or + * {@link PathIterator#WIND_NON_ZERO}. + * @param initialCapacity + * the number of segments the path is set to hold. */ public GeneralPath(int rule, int initialCapacity) { setWindingRule(rule); @@ -193,7 +231,8 @@ public final class GeneralPath implements Shape, Cloneable { /** * Creates a new GeneralPath from the outline of the given shape. * - * @param shape the shape + * @param shape + * the shape. */ public GeneralPath(Shape shape) { this(WIND_NON_ZERO, BUFFER_SIZE); @@ -203,14 +242,15 @@ public final class GeneralPath implements Shape, Cloneable { } /** - * Sets the winding rule, which determines how to decide whether - * a point that isn't on the path itself is inside or outside of - * the shape. - * - * @param rule the new winding rule + * Sets the winding rule, which determines how to decide whether a point + * that isn't on the path itself is inside or outside of the shape. * - * @throws IllegalArgumentException if the winding rule is neither - * {@link PathIterator#WIND_EVEN_ODD} nor {@link PathIterator#WIND_NON_ZERO}. + * @param rule + * the new winding rule. + * @throws IllegalArgumentException + * if the winding rule is neither + * {@link PathIterator#WIND_EVEN_ODD} nor + * {@link PathIterator#WIND_NON_ZERO}. */ public void setWindingRule(int rule) { if (rule != WIND_EVEN_ODD && rule != WIND_NON_ZERO) { @@ -223,8 +263,8 @@ public final class GeneralPath implements Shape, Cloneable { /** * Gets the winding rule. * - * @return the winding rule, either {@link PathIterator#WIND_EVEN_ODD} - * or {@link PathIterator#WIND_NON_ZERO} + * @return the winding rule, either {@link PathIterator#WIND_EVEN_ODD} or + * {@link PathIterator#WIND_NON_ZERO}. */ public int getWindingRule() { return rule; @@ -232,15 +272,16 @@ public final class GeneralPath implements Shape, Cloneable { /** * Checks the point data buffer sizes to see whether pointCount additional - * point-data elements can fit. (Note that the number of point data - * elements to add is more than one per point -- it depends on the type - * of point being added.) Reallocates the buffers to enlarge the size if necessary. + * point-data elements can fit. (Note that the number of point data elements + * to add is more than one per point -- it depends on the type of point + * being added.) Reallocates the buffers to enlarge the size if necessary. * - * @param pointCount - the number of point data elements to be added - * @param checkMove whether to check for existing points - * - * @throws IllegalPathStateException checkMove is true and the - * path is currently empty. + * @param pointCount + * the number of point data elements to be added. + * @param checkMove + * whether to check for existing points. + * @throws IllegalPathStateException + * checkMove is true and the path is currently empty. */ void checkBuf(int pointCount, boolean checkMove) { if (checkMove && typeSize == 0) { @@ -260,11 +301,13 @@ public final class GeneralPath implements Shape, Cloneable { } /** - * Appends a new point to the end of this general path, disconnected - * from the existing path. + * Appends a new point to the end of this general path, disconnected from + * the existing path. * - * @param x the x coordinate of the next point to append - * @param y the y coordinate of the next point to append + * @param x + * the x coordinate of the next point to append. + * @param y + * the y coordinate of the next point to append. */ public void moveTo(float x, float y) { if (typeSize > 0 && types[typeSize - 1] == PathIterator.SEG_MOVETO) { @@ -279,12 +322,13 @@ public final class GeneralPath implements Shape, Cloneable { } /** - * Appends a new segment to the end of this general path by making - * a straight line segment from the current endpoint to the - * given new point. + * Appends a new segment to the end of this general path by making a + * straight line segment from the current endpoint to the given new point. * - * @param x the x coordinate of the next point to append - * @param y the y coordinate of the next point to append + * @param x + * the x coordinate of the next point to append. + * @param y + * the y coordinate of the next point to append. */ public void lineTo(float x, float y) { checkBuf(2, true); @@ -294,14 +338,18 @@ public final class GeneralPath implements Shape, Cloneable { } /** - * Appends a new segment to the end of this general path by making - * a quadratic curve from the current endpoint to the point (x2, y2) - * using the point (x1, y1) as the quadratic curve's control point. + * Appends a new segment to the end of this general path by making a + * quadratic curve from the current endpoint to the point (x2, y2) using the + * point (x1, y1) as the quadratic curve's control point. * - * @param x1 the x coordinate of the quadratic curve's control point - * @param y1 the y coordinate of the quadratic curve's control point - * @param x2 the x coordinate of the quadratic curve's end point - * @param y2 the y coordinate of the quadratic curve's end point + * @param x1 + * the x coordinate of the quadratic curve's control point. + * @param y1 + * the y coordinate of the quadratic curve's control point. + * @param x2 + * the x coordinate of the quadratic curve's end point. + * @param y2 + * the y coordinate of the quadratic curve's end point. */ public void quadTo(float x1, float y1, float x2, float y2) { checkBuf(4, true); @@ -313,18 +361,27 @@ public final class GeneralPath implements Shape, Cloneable { } /** - * Appends a new segment to the end of this general path by making - * a cubic curve from the current endpoint to the point (x3, y3) - * using (x1, y1) and (x2, y2) as control points. + * Appends a new segment to the end of this general path by making a cubic + * curve from the current endpoint to the point (x3, y3) using (x1, y1) and + * (x2, y2) as control points. * * @see java.awt.geom.CubicCurve2D - * - * @param x1 the x coordinate of the new cubic segment's first control point - * @param y1 the y coordinate of the new cubic segment's first control point - * @param x2 the x coordinate of the new cubic segment's second control point - * @param y2 the y coordinate of the new cubic segment's second control point - * @param x3 the x coordinate of the new cubic segment's end point - * @param y3 the y coordinate of the new cubic segment's end point + * @param x1 + * the x coordinate of the new cubic segment's first control + * point. + * @param y1 + * the y coordinate of the new cubic segment's first control + * point. + * @param x2 + * the x coordinate of the new cubic segment's second control + * point. + * @param y2 + * the y coordinate of the new cubic segment's second control + * point. + * @param x3 + * the x coordinate of the new cubic segment's end point. + * @param y3 + * the y coordinate of the new cubic segment's end point. */ public void curveTo(float x1, float y1, float x2, float y2, float x3, float y3) { checkBuf(6, true); @@ -338,8 +395,8 @@ public final class GeneralPath implements Shape, Cloneable { } /** - * Appends the type information to declare that the current - * endpoint closes the curve. + * Appends the type information to declare that the current endpoint closes + * the curve. */ public void closePath() { if (typeSize == 0 || types[typeSize - 1] != PathIterator.SEG_CLOSE) { @@ -349,15 +406,17 @@ public final class GeneralPath implements Shape, Cloneable { } /** - * Appends the outline of the specified shape onto the end - * of this GeneralPath. - * - * @param shape the shape whose outline is to be appended - * @param connect true to connect this path's current - * endpoint to the first point of the shape's outline or - * false to append the shape's outline without connecting it + * Appends the outline of the specified shape onto the end of this + * GeneralPath. * - * @throws NullPointerException if the shape parameter is null + * @param shape + * the shape whose outline is to be appended. + * @param connect + * true to connect this path's current endpoint to the first + * point of the shape's outline or false to append the shape's + * outline without connecting it. + * @throws NullPointerException + * if the shape parameter is null. */ public void append(Shape shape, boolean connect) { PathIterator p = shape.getPathIterator(null); @@ -365,42 +424,43 @@ public final class GeneralPath implements Shape, Cloneable { } /** - * Appends the path defined by the specified PathIterator onto the end - * of this GeneralPath. + * Appends the path defined by the specified PathIterator onto the end of + * this GeneralPath. * - * @param path the PathIterator that defines the new path to append - * @param connect true to connect this path's current - * endpoint to the first point of the shape's outline or - * false to append the shape's outline without connecting it + * @param path + * the PathIterator that defines the new path to append. + * @param connect + * true to connect this path's current endpoint to the first + * point of the shape's outline or false to append the shape's + * outline without connecting it. */ public void append(PathIterator path, boolean connect) { while (!path.isDone()) { float coords[] = new float[6]; switch (path.currentSegment(coords)) { - case PathIterator.SEG_MOVETO: - if (!connect || typeSize == 0) { - moveTo(coords[0], coords[1]); + case PathIterator.SEG_MOVETO: + if (!connect || typeSize == 0) { + moveTo(coords[0], coords[1]); + break; + } + if (types[typeSize - 1] != PathIterator.SEG_CLOSE + && points[pointSize - 2] == coords[0] + && points[pointSize - 1] == coords[1]) { + break; + } + // NO BREAK; + case PathIterator.SEG_LINETO: + lineTo(coords[0], coords[1]); break; - } - if (types[typeSize - 1] != PathIterator.SEG_CLOSE && - points[pointSize - 2] == coords[0] && - points[pointSize - 1] == coords[1]) - { + case PathIterator.SEG_QUADTO: + quadTo(coords[0], coords[1], coords[2], coords[3]); + break; + case PathIterator.SEG_CUBICTO: + curveTo(coords[0], coords[1], coords[2], coords[3], coords[4], coords[5]); + break; + case PathIterator.SEG_CLOSE: + closePath(); break; - } - // NO BREAK; - case PathIterator.SEG_LINETO: - lineTo(coords[0], coords[1]); - break; - case PathIterator.SEG_QUADTO: - quadTo(coords[0], coords[1], coords[2], coords[3]); - break; - case PathIterator.SEG_CUBICTO: - curveTo(coords[0], coords[1], coords[2], coords[3], coords[4], coords[5]); - break; - case PathIterator.SEG_CLOSE: - closePath(); - break; } path.next(); connect = false; @@ -410,7 +470,7 @@ public final class GeneralPath implements Shape, Cloneable { /** * Gets the current end point of the path. * - * @return the current end point of the path + * @return the current end point of the path. */ public Point2D getCurrentPoint() { if (typeSize == 0) { @@ -431,9 +491,9 @@ public final class GeneralPath implements Shape, Cloneable { } /** - * Resets the GeneralPath to being an empty path. The underlying - * point and segment data is not deleted but rather the end indices - * of the data arrays are set to zero. + * Resets the GeneralPath to being an empty path. The underlying point and + * segment data is not deleted but rather the end indices of the data arrays + * are set to zero. */ public void reset() { typeSize = 0; @@ -441,23 +501,24 @@ public final class GeneralPath implements Shape, Cloneable { } /** - * Transform all of the coordinates of this path according to the - * specified AffineTransform. + * Transform all of the coordinates of this path according to the specified + * AffineTransform. * - * @param t the AffineTransform + * @param t + * the AffineTransform. */ public void transform(AffineTransform t) { t.transform(points, 0, points, 0, pointSize / 2); } /** - * Creates a new GeneralPath whose data is given by this path's - * data transformed according to the specified AffineTransform. - * - * @param t the AffineTransform + * Creates a new GeneralPath whose data is given by this path's data + * transformed according to the specified AffineTransform. * - * @return the new GeneralPath whose data is given by this path's - * data transformed according to the specified AffineTransform + * @param t + * the AffineTransform. + * @return the new GeneralPath whose data is given by this path's data + * transformed according to the specified AffineTransform. */ public Shape createTransformedShape(AffineTransform t) { GeneralPath p = (GeneralPath)clone(); @@ -480,16 +541,14 @@ public final class GeneralPath implements Shape, Cloneable { float x = points[i--]; if (x < rx1) { rx1 = x; - } else - if (x > rx2) { - rx2 = x; - } + } else if (x > rx2) { + rx2 = x; + } if (y < ry1) { ry1 = y; - } else - if (y > ry2) { - ry2 = y; - } + } else if (y > ry2) { + ry2 = y; + } } } return new Rectangle2D.Float(rx1, ry1, rx2 - rx1, ry2 - ry1); @@ -500,14 +559,14 @@ public final class GeneralPath implements Shape, Cloneable { } /** - * Checks the cross count (number of times a ray from the point - * crosses the shape's boundary) to determine whether the number - * of crossings corresponds to a point inside the shape or not - * (according to the shape's path rule). - * - * @param cross - the point's cross count + * Checks the cross count (number of times a ray from the point crosses the + * shape's boundary) to determine whether the number of crossings + * corresponds to a point inside the shape or not (according to the shape's + * path rule). * - * @return true if the point is inside the path, or false otherwise + * @param cross + * the point's cross count. + * @return true if the point is inside the path, or false otherwise. */ boolean isInside(int cross) { if (rule == WIND_NON_ZERO) { @@ -553,7 +612,7 @@ public final class GeneralPath implements Shape, Cloneable { @Override public Object clone() { try { - GeneralPath p = (GeneralPath) super.clone(); + GeneralPath p = (GeneralPath)super.clone(); p.types = types.clone(); p.points = points.clone(); return p; @@ -563,4 +622,3 @@ public final class GeneralPath implements Shape, Cloneable { } } - diff --git a/awt/java/awt/geom/IllegalPathStateException.java b/awt/java/awt/geom/IllegalPathStateException.java index 7f459e77fff7c8323e0a681b71d016a2ba57fd76..750ba29fe6c55ca1233c3617372e7479846e949f 100644 --- a/awt/java/awt/geom/IllegalPathStateException.java +++ b/awt/java/awt/geom/IllegalPathStateException.java @@ -18,16 +18,21 @@ * @author Denis M. Kishenko * @version $Revision$ */ + package java.awt.geom; /** - * The Class IllegalPathStateException indicates errors where the - * current state of a path object is imcompatible with the desired - * action, such as performing non-trivial actions on an empty path. + * The Class IllegalPathStateException indicates errors where the current state + * of a path object is incompatible with the desired action, such as performing + * non-trivial actions on an empty path. + * + * @since Android 1.0 */ public class IllegalPathStateException extends RuntimeException { - /** The Constant serialVersionUID. */ + /** + * The Constant serialVersionUID. + */ private static final long serialVersionUID = -5158084205220481094L; /** @@ -37,14 +42,14 @@ public class IllegalPathStateException extends RuntimeException { } /** - * Instantiates a new illegal path state exception with the - * specified detail message. + * Instantiates a new illegal path state exception with the specified detail + * message. * - * @param s the details of the error + * @param s + * the details of the error. */ public IllegalPathStateException(String s) { super(s); } } - diff --git a/awt/java/awt/geom/Line2D.java b/awt/java/awt/geom/Line2D.java index a53c4709016ca75274b13d985e04facd5bf66a02..fcd51b6dd15b81af36db3e74989035ecd3c1c3de 100644 --- a/awt/java/awt/geom/Line2D.java +++ b/awt/java/awt/geom/Line2D.java @@ -18,6 +18,7 @@ * @author Denis M. Kishenko * @version $Revision$ */ + package java.awt.geom; import java.awt.Rectangle; @@ -27,55 +28,71 @@ import java.util.NoSuchElementException; import org.apache.harmony.awt.internal.nls.Messages; /** - * The Class Line2D represents a line whose data is given in - * high-precision values appropriate for graphical operations. + * The Class Line2D represents a line whose data is given in high-precision + * values appropriate for graphical operations. + * + * @since Android 1.0 */ public abstract class Line2D implements Shape, Cloneable { /** - * The Class Float is the subclass of Line2D that has all - * of its data values stored with float-level precision. + * The Class Float is the subclass of Line2D that has all of its data values + * stored with float-level precision. + * + * @since Android 1.0 */ public static class Float extends Line2D { - /** The x coordinate of the starting point. */ + /** + * The x coordinate of the starting point. + */ public float x1; - - /** The y coordinate of the starting point. */ + + /** + * The y coordinate of the starting point. + */ public float y1; - - /** The x coordinate of the end point. */ + + /** + * The x coordinate of the end point. + */ public float x2; - - /** The y coordinate of the end point. */ + + /** + * The y coordinate of the end point. + */ public float y2; /** - * Instantiates a new float-valued Line2D with - * its data values set to zero. + * Instantiates a new float-valued Line2D with its data values set to + * zero. */ public Float() { } /** - * Instantiates a new float-valued Line2D with - * the specified endpoints. + * Instantiates a new float-valued Line2D with the specified endpoints. * - * @param x1 the x coordinate of the starting point - * @param y1 the y coordinate of the starting point - * @param x2 the x coordinate of the end point - * @param y2 the y coordinate of the end point + * @param x1 + * the x coordinate of the starting point. + * @param y1 + * the y coordinate of the starting point. + * @param x2 + * the x coordinate of the end point. + * @param y2 + * the y coordinate of the end point. */ public Float(float x1, float y1, float x2, float y2) { setLine(x1, y1, x2, y2); } /** - * Instantiates a new float-valued Line2D with - * the specified endpoints. + * Instantiates a new float-valued Line2D with the specified endpoints. * - * @param p1 the starting point - * @param p2 the end point + * @param p1 + * the starting point. + * @param p2 + * the end point. */ public Float(Point2D p1, Point2D p2) { setLine(p1, p2); @@ -122,10 +139,14 @@ public abstract class Line2D implements Shape, Cloneable { /** * Sets the data values that define the line. * - * @param x1 the x coordinate of the starting point - * @param y1 the y coordinate of the starting point - * @param x2 the x coordinate of the end point - * @param y2 the y coordinate of the end point + * @param x1 + * the x coordinate of the starting point. + * @param y1 + * the y coordinate of the starting point. + * @param x2 + * the x coordinate of the end point. + * @param y2 + * the y coordinate of the end point. */ public void setLine(float x1, float y1, float x2, float y2) { this.x1 = x1; @@ -155,49 +176,63 @@ public abstract class Line2D implements Shape, Cloneable { } /** - * The Class Double is the subclass of Line2D that has all - * of its data values stored with double-level precision. + * The Class Double is the subclass of Line2D that has all of its data + * values stored with double-level precision. + * + * @since Android 1.0 */ public static class Double extends Line2D { - /** The x coordinate of the starting point. */ + /** + * The x coordinate of the starting point. + */ public double x1; - - /** The y coordinate of the starting point. */ + + /** + * The y coordinate of the starting point. + */ public double y1; - - /** The x coordinate of the end point. */ + + /** + * The x coordinate of the end point. + */ public double x2; - - /** The y coordinate of the end point. */ + + /** + * The y coordinate of the end point. + */ public double y2; /** - * Instantiates a new double-valued Line2D with - * its data values set to zero. + * Instantiates a new double-valued Line2D with its data values set to + * zero. */ public Double() { } /** - * Instantiates a new double-valued Line2D with - * the specified endpoints. + * Instantiates a new double-valued Line2D with the specified endpoints. * - * @param x1 the x coordinate of the starting point - * @param y1 the y coordinate of the starting point - * @param x2 the x coordinate of the end point - * @param y2 the y coordinate of the end point + * @param x1 + * the x coordinate of the starting point. + * @param y1 + * the y coordinate of the starting point. + * @param x2 + * the x coordinate of the end point. + * @param y2 + * the y coordinate of the end point. */ public Double(double x1, double y1, double x2, double y2) { setLine(x1, y1, x2, y2); } /** - * Instantiates a new double-valued Line2D with - * the specified endpoints. + * Instantiates a new double-valued Line2D with the specified endpoints. * - * @param p1 the starting point - * @param p2 the end point + * @param p1 + * the starting point. + * @param p2 + * the end point. */ public Double(Point2D p1, Point2D p2) { setLine(p1, p2); @@ -262,36 +297,50 @@ public abstract class Line2D implements Shape, Cloneable { } /* - * Line2D path iterator + * Line2D path iterator */ /** * The subclass of PathIterator to traverse a Line2D. */ class Iterator implements PathIterator { - /** The x coordinate of the start line point. */ + /** + * The x coordinate of the start line point. + */ double x1; - - /** The y coordinate of the start line point. */ + + /** + * The y coordinate of the start line point. + */ double y1; - - /** The x coordinate of the end line point. */ + + /** + * The x coordinate of the end line point. + */ double x2; - - /** The y coordinate of the end line point. */ + + /** + * The y coordinate of the end line point. + */ double y2; - /** The path iterator transformation. */ + /** + * The path iterator transformation. + */ AffineTransform t; - /** The current segmenet index. */ + /** + * The current segment index. + */ int index; /** - * Constructs a new Line2D.Iterator for given line and transformation + * Constructs a new Line2D.Iterator for given line and transformation. * - * @param l - the source Line2D object - * @param at - the AffineTransform object to apply rectangle path + * @param l + * the source Line2D object. + * @param at + * the AffineTransform object to apply rectangle path. */ Iterator(Line2D l, AffineTransform at) { this.x1 = l.getX1(); @@ -366,60 +415,66 @@ public abstract class Line2D implements Shape, Cloneable { /** * Gets the x coordinate of the starting point. * - * @return the x coordinate of the starting point + * @return the x coordinate of the starting point. */ public abstract double getX1(); /** * Gets the y coordinate of the starting point. * - * @return the y coordinate of the starting point + * @return the y coordinate of the starting point. */ public abstract double getY1(); /** * Gets the x coordinate of the end point. * - * @return the x2 + * @return the x2. */ public abstract double getX2(); /** * Gets the y coordinate of the end point. * - * @return the y coordinate of the end point + * @return the y coordinate of the end point. */ public abstract double getY2(); /** * Gets the p the starting point. * - * @return the p the starting point + * @return the p the starting point. */ public abstract Point2D getP1(); /** * Gets the p end point. * - * @return the p end point + * @return the p end point. */ public abstract Point2D getP2(); /** * Sets the line's endpoints. * - * @param x1 the x coordinate of the starting point - * @param y1 the y coordinate of the starting point - * @param x2 the x coordinate of the end point - * @param y2 the y coordinate of the end point + * @param x1 + * the x coordinate of the starting point. + * @param y1 + * the y coordinate of the starting point. + * @param x2 + * the x coordinate of the end point. + * @param y2 + * the y coordinate of the end point. */ public abstract void setLine(double x1, double y1, double x2, double y2); /** * Sets the line's endpoints. * - * @param p1 the starting point - * @param p2 the end point + * @param p1 + * the starting point. + * @param p2 + * the end point. */ public void setLine(Point2D p1, Point2D p2) { setLine(p1.getX(), p1.getY(), p2.getX(), p2.getY()); @@ -428,39 +483,44 @@ public abstract class Line2D implements Shape, Cloneable { /** * Sets the line's endpoints by copying the data from another Line2D. * - * @param line the Line2D to copy the endpoint data from + * @param line + * the Line2D to copy the endpoint data from. */ public void setLine(Line2D line) { setLine(line.getX1(), line.getY1(), line.getX2(), line.getY2()); } public Rectangle getBounds() { - return getBounds2D().getBounds(); + return getBounds2D().getBounds(); } /** - * Tells where the point is with respect to the line segment, - * given the orientation of the line segment. If the ray - * found by extending the line segment from its starting point - * is rotated, this method tells whether the ray - * should rotate in a clockwise direction or a counter-clockwise - * direction to hit the point first. The return value is 0 if the - * point is on the line segment, it's 1 if the point is on the ray - * or if the ray should rotate in a counter-clockwise direction to get to the - * point, and it's -1 if the ray should rotate in a clockwise - * direction to get to the point or if the point is on the line - * determined by the line segment but not on the ray from the - * segment's starting point and through its end point. - * - * @param x1 the x coordinate of the starting point of the line segment - * @param y1 the y coordinate of the starting point of the line segment - * @param x2 the x coordinate of the end point of the line segment - * @param y2 the y coordinate of the end point of the line segment - * @param px the x coordinate of the test point - * @param py the p coordinate of the test point - * - * @return the value that describes where the point is with respect to the line segment, - * given the orientation of the line segment + * Tells where the point is with respect to the line segment, given the + * orientation of the line segment. If the ray found by extending the line + * segment from its starting point is rotated, this method tells whether the + * ray should rotate in a clockwise direction or a counter-clockwise + * direction to hit the point first. The return value is 0 if the point is + * on the line segment, it's 1 if the point is on the ray or if the ray + * should rotate in a counter-clockwise direction to get to the point, and + * it's -1 if the ray should rotate in a clockwise direction to get to the + * point or if the point is on the line determined by the line segment but + * not on the ray from the segment's starting point and through its end + * point. + * + * @param x1 + * the x coordinate of the starting point of the line segment. + * @param y1 + * the y coordinate of the starting point of the line segment. + * @param x2 + * the x coordinate of the end point of the line segment. + * @param y2 + * the y coordinate of the end point of the line segment. + * @param px + * the x coordinate of the test point. + * @param py + * the p coordinate of the test point. + * @return the value that describes where the point is with respect to the + * line segment, given the orientation of the line segment. */ public static int relativeCCW(double x1, double y1, double x2, double y2, double px, double py) { /* @@ -487,47 +547,46 @@ public abstract class Line2D implements Shape, Cloneable { } /** - * Tells where the point is with respect to this line segment, - * given the orientation of this line segment. If the ray - * found by extending the line segment from its starting point - * is rotated, this method tells whether the ray - * should rotate in a clockwise direction or a counter-clockwise - * direction to hit the point first. The return value is 0 if the - * point is on the line segment, it's 1 if the point is on the ray - * or if the ray should rotate in a counter-clockwise direction to get to the - * point, and it's -1 if the ray should rotate in a clockwise - * direction to get to the point or if the point is on the line - * determined by the line segment but not on the ray from the - * segment's starting point and through its end point. - * - * @param px the x coordinate of the test point - * @param py the p coordinate of the test point - * - * @return the value that describes where the point is with respect to - * this line segment, given the orientation of this line segment + * Tells where the point is with respect to this line segment, given the + * orientation of this line segment. If the ray found by extending the line + * segment from its starting point is rotated, this method tells whether the + * ray should rotate in a clockwise direction or a counter-clockwise + * direction to hit the point first. The return value is 0 if the point is + * on the line segment, it's 1 if the point is on the ray or if the ray + * should rotate in a counter-clockwise direction to get to the point, and + * it's -1 if the ray should rotate in a clockwise direction to get to the + * point or if the point is on the line determined by the line segment but + * not on the ray from the segment's starting point and through its end + * point. + * + * @param px + * the x coordinate of the test point. + * @param py + * the p coordinate of the test point. + * @return the value that describes where the point is with respect to this + * line segment, given the orientation of this line segment. */ public int relativeCCW(double px, double py) { return relativeCCW(getX1(), getY1(), getX2(), getY2(), px, py); } /** - * Tells where the point is with respect to this line segment, - * given the orientation of this line segment. If the ray - * found by extending the line segment from its starting point - * is rotated, this method tells whether the ray - * should rotate in a clockwise direction or a counter-clockwise - * direction to hit the point first. The return value is 0 if the - * point is on the line segment, it's 1 if the point is on the ray - * or if the ray should rotate in a counter-clockwise direction to get to the - * point, and it's -1 if the ray should rotate in a clockwise - * direction to get to the point or if the point is on the line - * determined by the line segment but not on the ray from the - * segment's starting point and through its end point. - * - * @param p the test point - * - * @return the value that describes where the point is with respect to - * this line segment, given the orientation of this line segment + * Tells where the point is with respect to this line segment, given the + * orientation of this line segment. If the ray found by extending the line + * segment from its starting point is rotated, this method tells whether the + * ray should rotate in a clockwise direction or a counter-clockwise + * direction to hit the point first. The return value is 0 if the point is + * on the line segment, it's 1 if the point is on the ray or if the ray + * should rotate in a counter-clockwise direction to get to the point, and + * it's -1 if the ray should rotate in a clockwise direction to get to the + * point or if the point is on the line determined by the line segment but + * not on the ray from the segment's starting point and through its end + * point. + * + * @param p + * the test point. + * @return the value that describes where the point is with respect to this + * line segment, given the orientation of this line segment. */ public int relativeCCW(Point2D p) { return relativeCCW(getX1(), getY1(), getX2(), getY2(), p.getX(), p.getY()); @@ -536,28 +595,31 @@ public abstract class Line2D implements Shape, Cloneable { /** * Tells whether the two line segments cross. * - * @param x1 the x coordinate of the starting point of the first segment - * @param y1 the y coordinate of the starting point of the first segment - * @param x2 the x coordinate of the end point of the first segment - * @param y2 the y coordinate of the end point of the first segment - * @param x3 the x coordinate of the starting point of the second segment - * @param y3 the y coordinate of the starting point of the second segment - * @param x4 the x coordinate of the end point of the second segment - * @param y4 the y coordinate of the end point of the second segment - * - * @return true, if the two line segments cross - */ - public static boolean linesIntersect(double x1, double y1, double x2, - double y2, double x3, double y3, double x4, double y4) - { + * @param x1 + * the x coordinate of the starting point of the first segment. + * @param y1 + * the y coordinate of the starting point of the first segment. + * @param x2 + * the x coordinate of the end point of the first segment. + * @param y2 + * the y coordinate of the end point of the first segment. + * @param x3 + * the x coordinate of the starting point of the second segment. + * @param y3 + * the y coordinate of the starting point of the second segment. + * @param x4 + * the x coordinate of the end point of the second segment. + * @param y4 + * the y coordinate of the end point of the second segment. + * @return true, if the two line segments cross. + */ + public static boolean linesIntersect(double x1, double y1, double x2, double y2, double x3, + double y3, double x4, double y4) { /* * A = (x2-x1, y2-y1) B = (x3-x1, y3-y1) C = (x4-x1, y4-y1) D = (x4-x3, - * y4-y3) = C-B E = (x1-x3, y1-y3) = -B F = (x2-x3, y2-y3) = A-B - * - * Result is ((AxB) * (AxC) <=0) and ((DxE) * (DxF) <= 0) - * - * DxE = (C-B)x(-B) = BxB-CxB = BxC DxF = (C-B)x(A-B) = CxA-CxB-BxA+BxB = - * AxB+BxC-AxC + * y4-y3) = C-B E = (x1-x3, y1-y3) = -B F = (x2-x3, y2-y3) = A-B Result + * is ((AxB) (AxC) <=0) and ((DxE) (DxF) <= 0) DxE = (C-B)x(-B) = + * BxB-CxB = BxC DxF = (C-B)x(A-B) = CxA-CxB-BxA+BxB = AxB+BxC-AxC */ x2 -= x1; // A @@ -573,16 +635,14 @@ public abstract class Line2D implements Shape, Cloneable { // Online if (AvB == 0.0 && AvC == 0.0) { if (x2 != 0.0) { - return - (x4 * x3 <= 0.0) || - ((x3 * x2 >= 0.0) && - (x2 > 0.0 ? x3 <= x2 || x4 <= x2 : x3 >= x2 || x4 >= x2)); + return (x4 * x3 <= 0.0) + || ((x3 * x2 >= 0.0) && (x2 > 0.0 ? x3 <= x2 || x4 <= x2 : x3 >= x2 + || x4 >= x2)); } if (y2 != 0.0) { - return - (y4 * y3 <= 0.0) || - ((y3 * y2 >= 0.0) && - (y2 > 0.0 ? y3 <= y2 || y4 <= y2 : y3 >= y2 || y4 >= y2)); + return (y4 * y3 <= 0.0) + || ((y3 * y2 >= 0.0) && (y2 > 0.0 ? y3 <= y2 || y4 <= y2 : y3 >= y2 + || y4 >= y2)); } return false; } @@ -595,12 +655,15 @@ public abstract class Line2D implements Shape, Cloneable { /** * Tells whether the specified line segments crosses this line segment. * - * @param x1 the x coordinate of the starting point of the test segment - * @param y1 the y coordinate of the starting point of the test segment - * @param x2 the x coordinate of the end point of the test segment - * @param y2 the y coordinate of the end point of the test segment - * - * @return true, if the specified line segments crosses this line segment + * @param x1 + * the x coordinate of the starting point of the test segment. + * @param y1 + * the y coordinate of the starting point of the test segment. + * @param x2 + * the x coordinate of the end point of the test segment. + * @param y2 + * the y coordinate of the end point of the test segment. + * @return true, if the specified line segments crosses this line segment. */ public boolean intersectsLine(double x1, double y1, double x2, double y2) { return linesIntersect(x1, y1, x2, y2, getX1(), getY1(), getX2(), getY2()); @@ -609,31 +672,37 @@ public abstract class Line2D implements Shape, Cloneable { /** * Tells whether the specified line segments crosses this line segment. * - * @param l the test segment - * - * @return true, if the specified line segments crosses this line segment - * - * @throws NullPointerException if l is null + * @param l + * the test segment. + * @return true, if the specified line segments crosses this line segment. + * @throws NullPointerException + * if l is null. */ public boolean intersectsLine(Line2D l) { - return linesIntersect(l.getX1(), l.getY1(), l.getX2(), l.getY2(), getX1(), getY1(), getX2(), getY2()); + return linesIntersect(l.getX1(), l.getY1(), l.getX2(), l.getY2(), getX1(), getY1(), + getX2(), getY2()); } /** - * Gives the square of the distance between the point and the - * line segment. - * - * @param x1 the x coordinate of the starting point of the line segment - * @param y1 the y coordinate of the starting point of the line segment - * @param x2 the x coordinate of the end point of the line segment - * @param y2 the y coordinate of the end point of the line segment - * @param px the x coordinate of the test point - * @param py the y coordinate of the test point - * - * @return the the square of the distance between the point and the - * line segment - */ - public static double ptSegDistSq(double x1, double y1, double x2, double y2, double px, double py) { + * Gives the square of the distance between the point and the line segment. + * + * @param x1 + * the x coordinate of the starting point of the line segment. + * @param y1 + * the y coordinate of the starting point of the line segment. + * @param x2 + * the x coordinate of the end point of the line segment. + * @param y2 + * the y coordinate of the end point of the line segment. + * @param px + * the x coordinate of the test point. + * @param py + * the y coordinate of the test point. + * @return the the square of the distance between the point and the line + * segment. + */ + public static double ptSegDistSq(double x1, double y1, double x2, double y2, double px, + double py) { /* * A = (x2 - x1, y2 - y1) P = (px - x1, py - y1) */ @@ -661,92 +730,95 @@ public abstract class Line2D implements Shape, Cloneable { } /** - * Gives the distance between the point and the - * line segment. - * - * @param x1 the x coordinate of the starting point of the line segment - * @param y1 the y coordinate of the starting point of the line segment - * @param x2 the x coordinate of the end point of the line segment - * @param y2 the y coordinate of the end point of the line segment - * @param px the x coordinate of the test point - * @param py the y coordinate of the test point - * - * @return the the distance between the point and the - * line segment + * Gives the distance between the point and the line segment. + * + * @param x1 + * the x coordinate of the starting point of the line segment. + * @param y1 + * the y coordinate of the starting point of the line segment. + * @param x2 + * the x coordinate of the end point of the line segment. + * @param y2 + * the y coordinate of the end point of the line segment. + * @param px + * the x coordinate of the test point. + * @param py + * the y coordinate of the test point. + * @return the the distance between the point and the line segment. */ public static double ptSegDist(double x1, double y1, double x2, double y2, double px, double py) { return Math.sqrt(ptSegDistSq(x1, y1, x2, y2, px, py)); } /** - * Gives the square of the distance between the point and this - * line segment. - * - * @param px the x coordinate of the test point - * @param py the y coordinate of the test point + * Gives the square of the distance between the point and this line segment. * - * @return the the square of the distance between the point and this - * line segment + * @param px + * the x coordinate of the test point. + * @param py + * the y coordinate of the test point. + * @return the the square of the distance between the point and this line + * segment. */ public double ptSegDistSq(double px, double py) { return ptSegDistSq(getX1(), getY1(), getX2(), getY2(), px, py); } /** - * Gives the square of the distance between the point and this - * line segment. + * Gives the square of the distance between the point and this line segment. * - * @param p the test point - * - * @return the square of the distance between the point and this - * line segment + * @param p + * the test point. + * @return the square of the distance between the point and this line + * segment. */ public double ptSegDistSq(Point2D p) { return ptSegDistSq(getX1(), getY1(), getX2(), getY2(), p.getX(), p.getY()); } /** - * Gives the distance between the point and this - * line segment. - * - * @param px the x coordinate of the test point - * @param py the y coordinate of the test point + * Gives the distance between the point and this line segment. * - * @return the distance between the point and this - * line segment + * @param px + * the x coordinate of the test point. + * @param py + * the y coordinate of the test point. + * @return the distance between the point and this line segment. */ public double ptSegDist(double px, double py) { return ptSegDist(getX1(), getY1(), getX2(), getY2(), px, py); } /** - * Gives the distance between the point and this - * line segment. + * Gives the distance between the point and this line segment. * - * @param p the test point - * - * @return the distance between the point and this - * line segment + * @param p + * the test point. + * @return the distance between the point and this line segment. */ public double ptSegDist(Point2D p) { return ptSegDist(getX1(), getY1(), getX2(), getY2(), p.getX(), p.getY()); } /** - * Gives the square of the distance between the point and the - * line. - * - * @param x1 the x coordinate of the starting point of the line segment - * @param y1 the y coordinate of the starting point of the line segment - * @param x2 the x coordinate of the end point of the line segment - * @param y2 the y coordinate of the end point of the line segment - * @param px the x coordinate of the test point - * @param py the y coordinate of the test point - * - * @return the square of the distance between the point and the - * line - */ - public static double ptLineDistSq(double x1, double y1, double x2, double y2, double px, double py) { + * Gives the square of the distance between the point and the line. + * + * @param x1 + * the x coordinate of the starting point of the line segment. + * @param y1 + * the y coordinate of the starting point of the line segment. + * @param x2 + * the x coordinate of the end point of the line segment. + * @param y2 + * the y coordinate of the end point of the line segment. + * @param px + * the x coordinate of the test point. + * @param py + * the y coordinate of the test point. + * @return the square of the distance between the point and the line. + */ + public static double ptLineDistSq(double x1, double y1, double x2, double y2, double px, + double py) { x2 -= x1; y2 -= y1; px -= x1; @@ -756,72 +828,77 @@ public abstract class Line2D implements Shape, Cloneable { } /** - * Gives the square of the distance between the point and the - * line. - * - * @param x1 the x coordinate of the starting point of the line segment - * @param y1 the y coordinate of the starting point of the line segment - * @param x2 the x coordinate of the end point of the line segment - * @param y2 the y coordinate of the end point of the line segment - * @param px the x coordinate of the test point - * @param py the y coordinate of the test point - * - * @return the square of the distance between the point and the - * line + * Gives the square of the distance between the point and the line. + * + * @param x1 + * the x coordinate of the starting point of the line segment. + * @param y1 + * the y coordinate of the starting point of the line segment. + * @param x2 + * the x coordinate of the end point of the line segment. + * @param y2 + * the y coordinate of the end point of the line segment. + * @param px + * the x coordinate of the test point. + * @param py + * the y coordinate of the test point. + * @return the square of the distance between the point and the line. */ public static double ptLineDist(double x1, double y1, double x2, double y2, double px, double py) { return Math.sqrt(ptLineDistSq(x1, y1, x2, y2, px, py)); } /** - * Gives the square of the distance between the point and the - * line determined by this Line2D. + * Gives the square of the distance between the point and the line + * determined by this Line2D. * - * @param px the x coordinate of the test point - * @param py the y coordinate of the test point - * - * @return the square of the distance between the point and the - * line determined by this Line2D + * @param px + * the x coordinate of the test point. + * @param py + * the y coordinate of the test point. + * @return the square of the distance between the point and the line + * determined by this Line2D. */ public double ptLineDistSq(double px, double py) { return ptLineDistSq(getX1(), getY1(), getX2(), getY2(), px, py); } /** - * Gives the square of the distance between the point and the - * line determined by this Line2D. - * - * @param p the test point + * Gives the square of the distance between the point and the line + * determined by this Line2D. * - * @return the square of the distance between the point and the - * line determined by this Line2D + * @param p + * the test point. + * @return the square of the distance between the point and the line + * determined by this Line2D. */ public double ptLineDistSq(Point2D p) { return ptLineDistSq(getX1(), getY1(), getX2(), getY2(), p.getX(), p.getY()); } /** - * Gives the distance between the point and the - * line determined by this Line2D. + * Gives the distance between the point and the line determined by this + * Line2D. * - * @param px the x coordinate of the test point - * @param py the y coordinate of the test point - * - * @return the distance between the point and the - * line determined by this Line2D + * @param px + * the x coordinate of the test point. + * @param py + * the y coordinate of the test point. + * @return the distance between the point and the line determined by this + * Line2D. */ public double ptLineDist(double px, double py) { return ptLineDist(getX1(), getY1(), getX2(), getY2(), px, py); } /** - * Gives the distance between the point and the - * line determined by this Line2D. - * - * @param p the test point + * Gives the distance between the point and the line determined by this + * Line2D. * - * @return the distance between the point and the - * line determined by this Line2D + * @param p + * the test point. + * @return the distance between the point and the line determined by this + * Line2D. */ public double ptLineDist(Point2D p) { return ptLineDist(getX1(), getY1(), getX2(), getY2(), p.getX(), p.getY()); diff --git a/awt/java/awt/geom/NoninvertibleTransformException.java b/awt/java/awt/geom/NoninvertibleTransformException.java index 2b7b5424768233121029d5f890d0f657f51b9c88..a4e6f0f859525f76cf27dba7da73965653b96928 100644 --- a/awt/java/awt/geom/NoninvertibleTransformException.java +++ b/awt/java/awt/geom/NoninvertibleTransformException.java @@ -18,26 +18,31 @@ * @author Denis M. Kishenko * @version $Revision$ */ + package java.awt.geom; /** - * The Class NoninvertibleTransformException is the exception that is thrown - * when an action requires inverting an {@link AffineTransform} that is - * not invertible (has determinant 0). + * The Class NoninvertibleTransformException is the exception that is thrown + * when an action requires inverting an {@link AffineTransform} that is not + * invertible (has determinant 0). + * + * @since Android 1.0 */ public class NoninvertibleTransformException extends java.lang.Exception { - /** The Constant serialVersionUID. */ + /** + * The Constant serialVersionUID. + */ private static final long serialVersionUID = 6137225240503990466L; /** - * Instantiates a new noninvertible transform exception. + * Instantiates a new non-invertible transform exception. * - * @param s the error message + * @param s + * the error message. */ public NoninvertibleTransformException(String s) { super(s); } } - diff --git a/awt/java/awt/geom/PathIterator.java b/awt/java/awt/geom/PathIterator.java index 5a98083473f5a5f1a8b7befd55a361bb2e904af5..2d1c0ffa641b18775bc85dfc1a954e1c11fd0204 100644 --- a/awt/java/awt/geom/PathIterator.java +++ b/awt/java/awt/geom/PathIterator.java @@ -18,72 +18,87 @@ * @author Denis M. Kishenko * @version $Revision$ */ + package java.awt.geom; /** - * The Interface PathIterator represents an iterator object that can - * be used to traverse the outline of a {@link java.awt.Shape}. - * It returns points along the boundary of the Shape - * which may be actual vertices (in the case of a shape made of line - * segments) or may be points on a curved segment with the distance - * between the points determined by a chosen flattening factor. + * The Interface PathIterator represents an iterator object that can be used to + * traverse the outline of a {@link java.awt.Shape}. It returns points along the + * boundary of the Shape which may be actual vertices (in the case of a shape + * made of line segments) or may be points on a curved segment with the distance + * between the points determined by a chosen flattening factor. *

    - * If the shape is closed, the outline is traversed in the counter-clockwise - * direction. That means that moving forward along the boundary is to travel - * in such a way that the interior of the shape is to the left of the - * outline path and the exterior of the shape is to the right of the outline - * path. The interior and exterior of the shape are determined by a - * winding rule. + * If the shape is closed, the outline is traversed in the counter-clockwise + * direction. That means that moving forward along the boundary is to travel in + * such a way that the interior of the shape is to the left of the outline path + * and the exterior of the shape is to the right of the outline path. The + * interior and exterior of the shape are determined by a winding rule. + *

    + * + * @since Android 1.0 */ public interface PathIterator { - /** The Constant WIND_EVEN_ODD indicates the winding rule that says - * that a point is outside the shape if any infinite ray from the point - * crosses the outline of the shape an even number of times, otherwise - * it is inside. */ + /** + * The Constant WIND_EVEN_ODD indicates the winding rule that says that a + * point is outside the shape if any infinite ray from the point crosses the + * outline of the shape an even number of times, otherwise it is inside. + */ public static final int WIND_EVEN_ODD = 0; - - /** The Constant WIND_NON_ZERO indicates the winding rule that says that - * a point is inside the shape if every infinite ray starting from that - * point crosses the outline of the shape a non-zero number of times. */ + + /** + * The Constant WIND_NON_ZERO indicates the winding rule that says that a + * point is inside the shape if every infinite ray starting from that point + * crosses the outline of the shape a non-zero number of times. + */ public static final int WIND_NON_ZERO = 1; - /** The Constant SEG_MOVETO indicates that to follow the shape's outline - * from the previous point to the current point, the cursor (traversal - * point) should be placed directly on the current point. */ - public static final int SEG_MOVETO = 0; - - /** The Constant SEG_LINETO indicates that to follow the shape's outline - * from the previous point to the current point, the cursor (traversal - * point) should follow a straight line. */ - public static final int SEG_LINETO = 1; - - /** The Constant SEG_QUADTO indicates that to follow the shape's outline - * from the previous point to the current point, the cursor (traversal - * point) should follow a quadratic curve. */ - public static final int SEG_QUADTO = 2; - - /** The Constant SEG_CUBICTO indicates that to follow the shape's outline - * from the previous point to the current point, the cursor (traversal - * point) should follow a cubic curve. */ + /** + * The Constant SEG_MOVETO indicates that to follow the shape's outline from + * the previous point to the current point, the cursor (traversal point) + * should be placed directly on the current point. + */ + public static final int SEG_MOVETO = 0; + + /** + * The Constant SEG_LINETO indicates that to follow the shape's outline from + * the previous point to the current point, the cursor (traversal point) + * should follow a straight line. + */ + public static final int SEG_LINETO = 1; + + /** + * The Constant SEG_QUADTO indicates that to follow the shape's outline from + * the previous point to the current point, the cursor (traversal point) + * should follow a quadratic curve. + */ + public static final int SEG_QUADTO = 2; + + /** + * The Constant SEG_CUBICTO indicates that to follow the shape's outline + * from the previous point to the current point, the cursor (traversal + * point) should follow a cubic curve. + */ public static final int SEG_CUBICTO = 3; - - /** The Constant SEG_CLOSE indicates that the previous point was the end - * of the shape's outline. */ - public static final int SEG_CLOSE = 4; + + /** + * The Constant SEG_CLOSE indicates that the previous point was the end of + * the shape's outline. + */ + public static final int SEG_CLOSE = 4; /** * Gets the winding rule, either {@link PathIterator#WIND_EVEN_ODD} or * {@link PathIterator#WIND_NON_ZERO}. * - * @return the winding rule + * @return the winding rule. */ public int getWindingRule(); /** * Checks if this PathIterator has been completely traversed. * - * @return true, if this PathIterator has been completely traversed + * @return true, if this PathIterator has been completely traversed. */ public boolean isDone(); @@ -93,40 +108,39 @@ public interface PathIterator { public void next(); /** - * Gets the coordinates of the next vertex point along the shape's outline - * and a flag that indicates what kind of segment to use in order to - * connect the previous vertex point to the current vertex point to form - * the current segment. - * - * @param coords the array that the coordinates of the end point of the current - * segment are written into. + * Gets the coordinates of the next vertex point along the shape's outline + * and a flag that indicates what kind of segment to use in order to connect + * the previous vertex point to the current vertex point to form the current + * segment. * - * @return the flag that indicates how to follow the shape's outline - * from the previous point to the current one, chosen from - * the following constants: - * {@link PathIterator#SEG_MOVETO}, {@link PathIterator#SEG_LINETO}, - * {@link PathIterator#SEG_QUADTO}, {@link PathIterator#SEG_CUBICTO}, - * or {@link PathIterator#SEG_CLOSE} + * @param coords + * the array that the coordinates of the end point of the current + * segment are written into. + * @return the flag that indicates how to follow the shape's outline from + * the previous point to the current one, chosen from the following + * constants: {@link PathIterator#SEG_MOVETO}, + * {@link PathIterator#SEG_LINETO}, {@link PathIterator#SEG_QUADTO}, + * {@link PathIterator#SEG_CUBICTO}, or + * {@link PathIterator#SEG_CLOSE}. */ public int currentSegment(float[] coords); /** - * Gets the coordinates of the next vertex point along the shape's outline - * and a flag that indicates what kind of segment to use in order to - * connect the previous vertex point to the current vertex point to form - * the current segment. + * Gets the coordinates of the next vertex point along the shape's outline + * and a flag that indicates what kind of segment to use in order to connect + * the previous vertex point to the current vertex point to form the current + * segment. * - * @param coords the array that the coordinates of the end point of the current - * segment are written into. - * - * @return the flag that indicates how to follow the shape's outline - * from the previous point to the current one, chosen from - * the following constants: - * {@link PathIterator#SEG_MOVETO}, {@link PathIterator#SEG_LINETO}, - * {@link PathIterator#SEG_QUADTO}, {@link PathIterator#SEG_CUBICTO}, - * or {@link PathIterator#SEG_CLOSE} + * @param coords + * the array that the coordinates of the end point of the current + * segment are written into. + * @return the flag that indicates how to follow the shape's outline from + * the previous point to the current one, chosen from the following + * constants: {@link PathIterator#SEG_MOVETO}, + * {@link PathIterator#SEG_LINETO}, {@link PathIterator#SEG_QUADTO}, + * {@link PathIterator#SEG_CUBICTO}, or + * {@link PathIterator#SEG_CLOSE}. */ public int currentSegment(double[] coords); } - diff --git a/awt/java/awt/geom/Point2D.java b/awt/java/awt/geom/Point2D.java index 7719e674e6529f2eafaa0dd1e34b75c929f382dd..f7026c8c6a0318061fa1f146b619d98c0943a02a 100644 --- a/awt/java/awt/geom/Point2D.java +++ b/awt/java/awt/geom/Point2D.java @@ -18,40 +18,51 @@ * @author Denis M. Kishenko * @version $Revision$ */ + package java.awt.geom; import org.apache.harmony.misc.HashCode; /** - * The Class Point2D represents a point whose data is given in - * high-precision values appropriate for graphical operations. + * The Class Point2D represents a point whose data is given in high-precision + * values appropriate for graphical operations. + * + * @since Android 1.0 */ public abstract class Point2D implements Cloneable { /** - * The Class Float is the subclass of Point2D that has all - * of its data values stored with float-level precision. + * The Class Float is the subclass of Point2D that has all of its data + * values stored with float-level precision. + * + * @since Android 1.0 */ public static class Float extends Point2D { - /** The x coordinate. */ + /** + * The x coordinate. + */ public float x; - - /** The y coordinate. */ + + /** + * The y coordinate. + */ public float y; /** - * Instantiates a new float-valued Point2D with its data - * set to zero. + * Instantiates a new float-valued Point2D with its data set to zero. */ public Float() { } /** - * Instantiates a new float-valued Point2D with the specified coordinates. + * Instantiates a new float-valued Point2D with the specified + * coordinates. * - * @param x the x coordinate - * @param y the y coordinate + * @param x + * the x coordinate. + * @param y + * the y coordinate. */ public Float(float x, float y) { this.x = x; @@ -71,8 +82,10 @@ public abstract class Point2D implements Cloneable { /** * Sets the point's coordinates. * - * @param x the x coordinate - * @param y the y coordinate + * @param x + * the x coordinate. + * @param y + * the y coordinate. */ public void setLocation(float x, float y) { this.x = x; @@ -92,29 +105,37 @@ public abstract class Point2D implements Cloneable { } /** - * The Class Double is the subclass of Point2D that has all - * of its data values stored with double-level precision. + * The Class Double is the subclass of Point2D that has all of its data + * values stored with double-level precision. + * + * @since Android 1.0 */ public static class Double extends Point2D { - /** The x coordinate. */ + /** + * The x coordinate. + */ public double x; - - /** The y coordinate. */ + + /** + * The y coordinate. + */ public double y; /** - * Instantiates a new double-valued Point2D with its data - * set to zero. + * Instantiates a new double-valued Point2D with its data set to zero. */ public Double() { } /** - * Instantiates a new double-valued Point2D with the specified coordinates. + * Instantiates a new double-valued Point2D with the specified + * coordinates. * - * @param x the x coordinate - * @param y the y coordinate + * @param x + * the x coordinate. + * @param y + * the y coordinate. */ public Double(double x, double y) { this.x = x; @@ -152,29 +173,32 @@ public abstract class Point2D implements Cloneable { /** * Gets the x coordinate. * - * @return the x coordinate + * @return the x coordinate. */ public abstract double getX(); /** * Gets the y coordinate. * - * @return the y coordinate + * @return the y coordinate. */ public abstract double getY(); /** * Sets the point's coordinates. * - * @param x the x coordinate - * @param y the y coordinate + * @param x + * the x coordinate. + * @param y + * the y coordinate. */ public abstract void setLocation(double x, double y); /** * Sets the point's coordinates by copying them from another point. * - * @param p the point to copy the data from + * @param p + * the point to copy the data from. */ public void setLocation(Point2D p) { setLocation(p.getX(), p.getY()); @@ -183,12 +207,15 @@ public abstract class Point2D implements Cloneable { /** * Finds the square of the distance between the two specified points. * - * @param x1 the x coordinate of the first point - * @param y1 the y coordinate of the first point - * @param x2 the x coordinate of the second point - * @param y2 the y coordinate of the second point - * - * @return the square of the distance between the two specified points + * @param x1 + * the x coordinate of the first point. + * @param y1 + * the y coordinate of the first point. + * @param x2 + * the x coordinate of the second point. + * @param y2 + * the y coordinate of the second point. + * @return the square of the distance between the two specified points. */ public static double distanceSq(double x1, double y1, double x2, double y2) { x2 -= x1; @@ -197,23 +224,28 @@ public abstract class Point2D implements Cloneable { } /** - * Finds the square of the distance between this point and the specified point. - * - * @param px the x coordinate of the point - * @param py the y coordinate of the point + * Finds the square of the distance between this point and the specified + * point. * - * @return the square of the distance between this point and the specified point + * @param px + * the x coordinate of the point. + * @param py + * the y coordinate of the point. + * @return the square of the distance between this point and the specified + * point. */ public double distanceSq(double px, double py) { return Point2D.distanceSq(getX(), getY(), px, py); } /** - * Finds the square of the distance between this point and the specified point. + * Finds the square of the distance between this point and the specified + * point. * - * @param p the other point - * - * @return the square of the distance between this point and the specified point + * @param p + * the other point. + * @return the square of the distance between this point and the specified + * point. */ public double distanceSq(Point2D p) { return Point2D.distanceSq(getX(), getY(), p.getX(), p.getY()); @@ -222,12 +254,15 @@ public abstract class Point2D implements Cloneable { /** * Finds the distance between the two specified points. * - * @param x1 the x coordinate of the first point - * @param y1 the y coordinate of the first point - * @param x2 the x coordinate of the second point - * @param y2 the y coordinate of the second point - * - * @return the distance between the two specified points + * @param x1 + * the x coordinate of the first point. + * @param y1 + * the y coordinate of the first point. + * @param x2 + * the x coordinate of the second point. + * @param y2 + * the y coordinate of the second point. + * @return the distance between the two specified points. */ public static double distance(double x1, double y1, double x2, double y2) { return Math.sqrt(distanceSq(x1, y1, x2, y2)); @@ -236,10 +271,11 @@ public abstract class Point2D implements Cloneable { /** * Finds the distance between this point and the specified point. * - * @param px the x coordinate of the point - * @param py the y coordinate of the point - * - * @return the distance between this point and the specified point + * @param px + * the x coordinate of the point. + * @param py + * the y coordinate of the point. + * @return the distance between this point and the specified point. */ public double distance(double px, double py) { return Math.sqrt(distanceSq(px, py)); @@ -248,9 +284,9 @@ public abstract class Point2D implements Cloneable { /** * Finds the distance between this point and the specified point. * - * @param p the other point - * - * @return the distance between this point and the specified point + * @param p + * the other point. + * @return the distance between this point and the specified point. */ public double distance(Point2D p) { return Math.sqrt(distanceSq(p)); @@ -279,10 +315,9 @@ public abstract class Point2D implements Cloneable { return true; } if (obj instanceof Point2D) { - Point2D p = (Point2D) obj; + Point2D p = (Point2D)obj; return getX() == p.getX() && getY() == p.getY(); } return false; } } - diff --git a/awt/java/awt/geom/QuadCurve2D.java b/awt/java/awt/geom/QuadCurve2D.java index 64ea6d68b8bb14c9c0ea7180a456e17319e2bb37..7a86a4840fb7cef342f2ef17eaff8b855d099c0d 100644 --- a/awt/java/awt/geom/QuadCurve2D.java +++ b/awt/java/awt/geom/QuadCurve2D.java @@ -18,6 +18,7 @@ * @author Denis M. Kishenko * @version $Revision$ */ + package java.awt.geom; import java.awt.Rectangle; @@ -28,42 +29,58 @@ import org.apache.harmony.awt.gl.Crossing; import org.apache.harmony.awt.internal.nls.Messages; /** - * The Class QuadCurve2D is a Shape that represents a segment of a - * quadratic (Bezier) curve. The curved segment is determined by three points: - * a start point, an end point, and a control point. The line from the control - * point to the starting point gives the tangent to the curve at the - * starting point, and the line from the control point to the end point - * gives the tangent to the curve at the end point. + * The Class QuadCurve2D is a Shape that represents a segment of a quadratic + * (Bezier) curve. The curved segment is determined by three points: a start + * point, an end point, and a control point. The line from the control point to + * the starting point gives the tangent to the curve at the starting point, and + * the line from the control point to the end point gives the tangent to the + * curve at the end point. + * + * @since Android 1.0 */ public abstract class QuadCurve2D implements Shape, Cloneable { /** - * The Class Float is the subclass of QuadCurve2D that has all - * of its data values stored with float-level precision. + * The Class Float is the subclass of QuadCurve2D that has all of its data + * values stored with float-level precision. + * + * @since Android 1.0 */ public static class Float extends QuadCurve2D { - /** The x coordinate of the starting point of the curved segment. */ + /** + * The x coordinate of the starting point of the curved segment. + */ public float x1; - - /** The y coordinate of the starting point of the curved segment. */ + + /** + * The y coordinate of the starting point of the curved segment. + */ public float y1; - - /** The x coordinate of the control point. */ + + /** + * The x coordinate of the control point. + */ public float ctrlx; - - /** The y coordinate of the control point. */ + + /** + * The y coordinate of the control point. + */ public float ctrly; - - /** The x coordinate of the end point of the curved segment. */ + + /** + * The x coordinate of the end point of the curved segment. + */ public float x2; - - /** The y coordinate of the end point of the curved segment. */ + + /** + * The y coordinate of the end point of the curved segment. + */ public float y2; /** - * Instantiates a new float-valued QuadCurve2D with all coordinate values - * set to zero. + * Instantiates a new float-valued QuadCurve2D with all coordinate + * values set to zero. */ public Float() { } @@ -72,12 +89,20 @@ public abstract class QuadCurve2D implements Shape, Cloneable { * Instantiates a new float-valued QuadCurve2D with the specified * coordinate values. * - * @param x1 the x coordinate of the starting point of the curved segment - * @param y1 the y coordinate of the starting point of the curved segment - * @param ctrlx the x coordinate of the control point - * @param ctrly the y coordinate of the control point - * @param x2 the x coordinate of the end point of the curved segment - * @param y2 the y coordinate of the end point of the curved segment + * @param x1 + * the x coordinate of the starting point of the curved + * segment. + * @param y1 + * the y coordinate of the starting point of the curved + * segment. + * @param ctrlx + * the x coordinate of the control point. + * @param ctrly + * the y coordinate of the control point. + * @param x2 + * the x coordinate of the end point of the curved segment. + * @param y2 + * the y coordinate of the end point of the curved segment. */ public Float(float x1, float y1, float ctrlx, float ctrly, float x2, float y2) { setCurve(x1, y1, ctrlx, ctrly, x2, y2); @@ -141,12 +166,20 @@ public abstract class QuadCurve2D implements Shape, Cloneable { /** * Sets the data values of the curve. * - * @param x1 the x coordinate of the starting point of the curved segment - * @param y1 the y coordinate of the starting point of the curved segment - * @param ctrlx the x coordinate of the control point - * @param ctrly the y coordinate of the control point - * @param x2 the x coordinate of the end point of the curved segment - * @param y2 the y coordinate of the end point of the curved segment + * @param x1 + * the x coordinate of the starting point of the curved + * segment. + * @param y1 + * the y coordinate of the starting point of the curved + * segment. + * @param ctrlx + * the x coordinate of the control point. + * @param ctrly + * the y coordinate of the control point. + * @param x2 + * the x coordinate of the end point of the curved segment. + * @param y2 + * the y coordinate of the end point of the curved segment. */ public void setCurve(float x1, float y1, float ctrlx, float ctrly, float x2, float y2) { this.x1 = x1; @@ -167,32 +200,46 @@ public abstract class QuadCurve2D implements Shape, Cloneable { } /** - * The Class Double is the subclass of QuadCurve2D that has all - * of its data values stored with double-level precision. + * The Class Double is the subclass of QuadCurve2D that has all of its data + * values stored with double-level precision. + * + * @since Android 1.0 */ public static class Double extends QuadCurve2D { - /** The x coordinate of the starting point of the curved segment. */ + /** + * The x coordinate of the starting point of the curved segment. + */ public double x1; - - /** The y coordinate of the starting point of the curved segment. */ + + /** + * The y coordinate of the starting point of the curved segment. + */ public double y1; - - /** The x coordinate of the control point. */ + + /** + * The x coordinate of the control point. + */ public double ctrlx; - - /** The y coordinate of the control point. */ + + /** + * The y coordinate of the control point. + */ public double ctrly; - - /** The x coordinate of the end point of the curved segment. */ + + /** + * The x coordinate of the end point of the curved segment. + */ public double x2; - - /** The y coordinate of the end point of the curved segment. */ + + /** + * The y coordinate of the end point of the curved segment. + */ public double y2; /** - * Instantiates a new double-valued QuadCurve2D with all coordinate values - * set to zero. + * Instantiates a new double-valued QuadCurve2D with all coordinate + * values set to zero. */ public Double() { } @@ -201,12 +248,20 @@ public abstract class QuadCurve2D implements Shape, Cloneable { * Instantiates a new double-valued QuadCurve2D with the specified * coordinate values. * - * @param x1 the x coordinate of the starting point of the curved segment - * @param y1 the y coordinate of the starting point of the curved segment - * @param ctrlx the x coordinate of the control point - * @param ctrly the y coordinate of the control point - * @param x2 the x coordinate of the end point of the curved segment - * @param y2 the y coordinate of the end point of the curved segment + * @param x1 + * the x coordinate of the starting point of the curved + * segment. + * @param y1 + * the y coordinate of the starting point of the curved + * segment. + * @param ctrlx + * the x coordinate of the control point. + * @param ctrly + * the y coordinate of the control point. + * @param x2 + * the x coordinate of the end point of the curved segment. + * @param y2 + * the y coordinate of the end point of the curved segment. */ public Double(double x1, double y1, double ctrlx, double ctrly, double x2, double y2) { setCurve(x1, y1, ctrlx, ctrly, x2, y2); @@ -277,28 +332,37 @@ public abstract class QuadCurve2D implements Shape, Cloneable { } /* - * QuadCurve2D path iterator + * QuadCurve2D path iterator */ /** * The PathIterator for a Quad2D curve. */ class Iterator implements PathIterator { - /** The source QuadCurve2D object. */ + /** + * The source QuadCurve2D object. + */ QuadCurve2D c; - /** The path iterator transformation. */ + /** + * The path iterator transformation. + */ AffineTransform t; - /** The current segment index. */ + /** + * The current segment index. + */ int index; /** - * Constructs a new QuadCurve2D.Iterator for given curve and transformation + * Constructs a new QuadCurve2D.Iterator for given curve and + * transformation * - * @param q - the source QuadCurve2D object - * @param t the AffineTransform that acts on the coordinates before - * returning them (or null) + * @param q + * the source QuadCurve2D object. + * @param t + * the AffineTransform that acts on the coordinates before + * returning them (or null). */ Iterator(QuadCurve2D q, AffineTransform t) { this.c = q; @@ -380,284 +444,307 @@ public abstract class QuadCurve2D implements Shape, Cloneable { /** * Gets the x coordinate of the starting point. * - * @return the x coordinate of the starting point + * @return the x coordinate of the starting point. */ public abstract double getX1(); /** * Gets the y coordinate of the starting point. * - * @return the y coordinate of the starting point + * @return the y coordinate of the starting point. */ public abstract double getY1(); /** * Gets the starting point. * - * @return the starting point + * @return the starting point. */ public abstract Point2D getP1(); /** * Gets the x coordinate of the control point. * - * @return the x coordinate of the control point + * @return the x coordinate of the control point. */ public abstract double getCtrlX(); /** * Gets the y coordinate of the control point. * - * @return y coordinate of the control point + * @return y coordinate of the control point. */ public abstract double getCtrlY(); /** * Gets the control point. * - * @return the control point + * @return the control point. */ public abstract Point2D getCtrlPt(); /** * Gets the x coordinate of the end point. * - * @return the x coordinate of the end point + * @return the x coordinate of the end point. */ public abstract double getX2(); /** * Gets the y coordinate of the end point. * - * @return the y coordinate of the end point + * @return the y coordinate of the end point. */ public abstract double getY2(); /** * Gets the end point. * - * @return the end point + * @return the end point. */ public abstract Point2D getP2(); /** * Sets the data of the curve. * - * @param x1 the x coordinate of the starting point of the curved segment - * @param y1 the y coordinate of the starting point of the curved segment - * @param ctrlx the x coordinate of the control point - * @param ctrly the y coordinate of the control point - * @param x2 the x coordinate of the end point of the curved segment - * @param y2 the y coordinate of the end point of the curved segment + * @param x1 + * the x coordinate of the starting point of the curved segment. + * @param y1 + * the y coordinate of the starting point of the curved segment. + * @param ctrlx + * the x coordinate of the control point. + * @param ctrly + * the y coordinate of the control point. + * @param x2 + * the x coordinate of the end point of the curved segment. + * @param y2 + * the y coordinate of the end point of the curved segment. */ - public abstract void setCurve(double x1, double y1, double ctrlx, double ctrly, double x2, double y2); + public abstract void setCurve(double x1, double y1, double ctrlx, double ctrly, double x2, + double y2); /** * Sets the data of the curve. * - * @param p1 the starting point of the curved segment - * @param cp the control point - * @param p2 the end point of the curved segment - * - * @throws NullPointerException if any of the three points is null. + * @param p1 + * the starting point of the curved segment. + * @param cp + * the control point. + * @param p2 + * the end point of the curved segment. + * @throws NullPointerException + * if any of the three points is null. */ public void setCurve(Point2D p1, Point2D cp, Point2D p2) { setCurve(p1.getX(), p1.getY(), cp.getX(), cp.getY(), p2.getX(), p2.getY()); } /** - * Sets the data of the curve by reading the data from an array - * of values. The values are read in the same order as the arguments - * of the method {@link QuadCurve2D#setCurve(double, double, double, double, double, double)}. - * - * @param coords the array of values containing the new coordinates - * @param offset the offset of the data to read within the array - * - * @throws ArrayIndexOutOfBoundsException if coords.length < offset + 6. - * @throws NullPointerException if the coordinate array is null. + * Sets the data of the curve by reading the data from an array of values. + * The values are read in the same order as the arguments of the method + * {@link QuadCurve2D#setCurve(double, double, double, double, double, double)} + * . + * + * @param coords + * the array of values containing the new coordinates. + * @param offset + * the offset of the data to read within the array. + * @throws ArrayIndexOutOfBoundsException + * if {@code coords.length} < offset + 6. + * @throws NullPointerException + * if the coordinate array is null. */ public void setCurve(double[] coords, int offset) { - setCurve( - coords[offset + 0], coords[offset + 1], - coords[offset + 2], coords[offset + 3], + setCurve(coords[offset + 0], coords[offset + 1], coords[offset + 2], coords[offset + 3], coords[offset + 4], coords[offset + 5]); } /** - * Sets the data of the curve by reading the data from an array - * of points. The values are read in the same order as the arguments - * of the method {@link QuadCurve2D#setCurve(Point2D, Point2D, Point2D)} - * - * @param points the array of points containing the new coordinates - * @param offset the offset of the data to read within the array - * - * @throws ArrayIndexOutOfBoundsException if points.length < offset + 3. - * @throws NullPointerException if the point array is null. + * Sets the data of the curve by reading the data from an array of points. + * The values are read in the same order as the arguments of the method + * {@link QuadCurve2D#setCurve(Point2D, Point2D, Point2D)}. + * + * @param points + * the array of points containing the new coordinates. + * @param offset + * the offset of the data to read within the array. + * @throws ArrayIndexOutOfBoundsException + * if points.length < offset + 3. + * @throws NullPointerException + * if the point array is null. */ public void setCurve(Point2D[] points, int offset) { - setCurve( - points[offset + 0].getX(), points[offset + 0].getY(), - points[offset + 1].getX(), points[offset + 1].getY(), - points[offset + 2].getX(), points[offset + 2].getY()); + setCurve(points[offset + 0].getX(), points[offset + 0].getY(), points[offset + 1].getX(), + points[offset + 1].getY(), points[offset + 2].getX(), points[offset + 2].getY()); } /** * Sets the data of the curve by copying it from another QuadCurve2D. * - * @param curve the curve to copy the data points from - * - * @throws NullPointerException if the curve is null. + * @param curve + * the curve to copy the data points from. + * @throws NullPointerException + * if the curve is null. */ public void setCurve(QuadCurve2D curve) { - setCurve( - curve.getX1(), curve.getY1(), - curve.getCtrlX(), curve.getCtrlY(), - curve.getX2(), curve.getY2()); + setCurve(curve.getX1(), curve.getY1(), curve.getCtrlX(), curve.getCtrlY(), curve.getX2(), + curve.getY2()); } /** - * Gets the square of the distance from the control point to the - * straight line segment connecting the start point and the end point - * for this curve. + * Gets the square of the distance from the control point to the straight + * line segment connecting the start point and the end point for this curve. * - * @return the square of the distance from the control point to the - * straight line segment connecting the start point and the end point. + * @return the square of the distance from the control point to the straight + * line segment connecting the start point and the end point. */ public double getFlatnessSq() { - return Line2D.ptSegDistSq( - getX1(), getY1(), - getX2(), getY2(), - getCtrlX(), getCtrlY()); + return Line2D.ptSegDistSq(getX1(), getY1(), getX2(), getY2(), getCtrlX(), getCtrlY()); } /** - * Gets the square of the distance from the control point to the - * straight line segment connecting the start point and the end point. - * - * @param x1 the x coordinate of the starting point of the curved segment - * @param y1 the y coordinate of the starting point of the curved segment - * @param ctrlx the x coordinate of the control point - * @param ctrly the y coordinate of the control point - * @param x2 the x coordinate of the end point of the curved segment - * @param y2 the y coordinate of the end point of the curved segment - * - * @return the square of the distance from the control point to the - * straight line segment connecting the start point and the end point. + * Gets the square of the distance from the control point to the straight + * line segment connecting the start point and the end point. + * + * @param x1 + * the x coordinate of the starting point of the curved segment. + * @param y1 + * the y coordinate of the starting point of the curved segment. + * @param ctrlx + * the x coordinate of the control point. + * @param ctrly + * the y coordinate of the control point. + * @param x2 + * the x coordinate of the end point of the curved segment. + * @param y2 + * the y coordinate of the end point of the curved segment. + * @return the square of the distance from the control point to the straight + * line segment connecting the start point and the end point. */ - public static double getFlatnessSq(double x1, double y1, double ctrlx, double ctrly, double x2, double y2) { + public static double getFlatnessSq(double x1, double y1, double ctrlx, double ctrly, double x2, + double y2) { return Line2D.ptSegDistSq(x1, y1, x2, y2, ctrlx, ctrly); } /** - * Gets the square of the distance from the control point to the - * straight line segment connecting the start point and the end point - * by reading the coordinates of the points from an array of values. - * The values are read in the same order as the arguments - * of the method {@link QuadCurve2D#getFlatnessSq(double, double, double, double, double, double)}. - * - * @param coords the array of points containing the coordinates to use for - * the calculation - * @param offset the offset of the data to read within the array - * - * @return the square of the distance from the control point to the - * straight line segment connecting the start point and the end point. - * - * @throws ArrayIndexOutOfBoundsException if coords.length < offset + 6. - * @throws NullPointerException if the coordinate array is null. + * Gets the square of the distance from the control point to the straight + * line segment connecting the start point and the end point by reading the + * coordinates of the points from an array of values. The values are read in + * the same order as the arguments of the method + * {@link QuadCurve2D#getFlatnessSq(double, double, double, double, double, double)} + * . + * + * @param coords + * the array of points containing the coordinates to use for the + * calculation + * @param offset + * the offset of the data to read within the array + * @return the square of the distance from the control point to the straight + * line segment connecting the start point and the end point. + * @throws ArrayIndexOutOfBoundsException + * if {@code coords.length} < offset + 6. + * @throws NullPointerException + * if the coordinate array is null. */ public static double getFlatnessSq(double coords[], int offset) { - return Line2D.ptSegDistSq( - coords[offset + 0], coords[offset + 1], - coords[offset + 4], coords[offset + 5], - coords[offset + 2], coords[offset + 3]); + return Line2D.ptSegDistSq(coords[offset + 0], coords[offset + 1], coords[offset + 4], + coords[offset + 5], coords[offset + 2], coords[offset + 3]); } /** - * Gets the distance from the control point to the - * straight line segment connecting the start point and the end point - * of this QuadCurve2D. + * Gets the distance from the control point to the straight line segment + * connecting the start point and the end point of this QuadCurve2D. * - * @return the the distance from the control point to the - * straight line segment connecting the start point and the end point - * of this QuadCurve2D + * @return the the distance from the control point to the straight line + * segment connecting the start point and the end point of this + * QuadCurve2D. */ public double getFlatness() { return Line2D.ptSegDist(getX1(), getY1(), getX2(), getY2(), getCtrlX(), getCtrlY()); } /** - * Gets the distance from the control point to the - * straight line segment connecting the start point and the end point. - * - * @param x1 the x coordinate of the starting point of the curved segment - * @param y1 the y coordinate of the starting point of the curved segment - * @param ctrlx the x coordinate of the control point - * @param ctrly the y coordinate of the control point - * @param x2 the x coordinate of the end point of the curved segment - * @param y2 the y coordinate of the end point of the curved segment - * - * @return the the distance from the control point to the - * straight line segment connecting the start point and the end point + * Gets the distance from the control point to the straight line segment + * connecting the start point and the end point. + * + * @param x1 + * the x coordinate of the starting point of the curved segment. + * @param y1 + * the y coordinate of the starting point of the curved segment. + * @param ctrlx + * the x coordinate of the control point. + * @param ctrly + * the y coordinate of the control point. + * @param x2 + * the x coordinate of the end point of the curved segment. + * @param y2 + * the y coordinate of the end point of the curved segment. + * @return the the distance from the control point to the straight line + * segment connecting the start point and the end point. */ - public static double getFlatness(double x1, double y1, double ctrlx, - double ctrly, double x2, double y2) - { + public static double getFlatness(double x1, double y1, double ctrlx, double ctrly, double x2, + double y2) { return Line2D.ptSegDist(x1, y1, x2, y2, ctrlx, ctrly); } /** - * Gets the the distance from the control point to the - * straight line segment connecting the start point and the end point. - * The values are read in the same order as the arguments - * of the method {@link QuadCurve2D#getFlatness(double, double, double, double, double, double)}. - * - * @param coords the array of points containing the coordinates to use for - * the calculation - * @param offset the offset of the data to read within the array - * - * @return the the distance from the control point to the - * straight line segment connecting the start point and the end point - * - * @throws ArrayIndexOutOfBoundsException if coords.length < offset + 6. - * @throws NullPointerException if the coordinate array is null. + * Gets the the distance from the control point to the straight line segment + * connecting the start point and the end point. The values are read in the + * same order as the arguments of the method + * {@link QuadCurve2D#getFlatness(double, double, double, double, double, double)} + * . + * + * @param coords + * the array of points containing the coordinates to use for the + * calculation. + * @param offset + * the offset of the data to read within the array. + * @return the the distance from the control point to the straight line + * segment connecting the start point and the end point. + * @throws ArrayIndexOutOfBoundsException + * if {code coords.length} < offset + 6. + * @throws NullPointerException + * if the coordinate array is null. */ public static double getFlatness(double coords[], int offset) { - return Line2D.ptSegDist( - coords[offset + 0], coords[offset + 1], - coords[offset + 4], coords[offset + 5], - coords[offset + 2], coords[offset + 3]); + return Line2D.ptSegDist(coords[offset + 0], coords[offset + 1], coords[offset + 4], + coords[offset + 5], coords[offset + 2], coords[offset + 3]); } /** - * Creates the data for two quadratic curves by dividing this - * curve in two. The division point is the point on the curve - * that is closest to this curve's control point. The data of - * this curve is left unchanged. - * - * @param left the QuadCurve2D where the left (start) segment's - * data is written - * @param right the QuadCurve2D where the right (end) segment's - * data is written - * - * @throws NullPointerException if either curve is null. + * Creates the data for two quadratic curves by dividing this curve in two. + * The division point is the point on the curve that is closest to this + * curve's control point. The data of this curve is left unchanged. + * + * @param left + * the QuadCurve2D where the left (start) segment's data is + * written. + * @param right + * the QuadCurve2D where the right (end) segment's data is + * written. + * @throws NullPointerException + * if either curve is null. */ public void subdivide(QuadCurve2D left, QuadCurve2D right) { subdivide(this, left, right); } /** - * Creates the data for two quadratic curves by dividing a source - * curve in two. The division point is the point on the curve - * that is closest to the source curve's control point. The data of - * the source curve is left unchanged. - * - * @param src the curve that provides the initial data - * @param left the QuadCurve2D where the left (start) segment's - * data is written - * @param right the QuadCurve2D where the right (end) segment's - * data is written - * - * @throws NullPointerException if one of the curves is null. + * Creates the data for two quadratic curves by dividing a source curve in + * two. The division point is the point on the curve that is closest to the + * source curve's control point. The data of the source curve is left + * unchanged. + * + * @param src + * the curve that provides the initial data. + * @param left + * the QuadCurve2D where the left (start) segment's data is + * written. + * @param right + * the QuadCurve2D where the right (end) segment's data is + * written. + * @throws NullPointerException + * if one of the curves is null. */ public static void subdivide(QuadCurve2D src, QuadCurve2D left, QuadCurve2D right) { double x1 = src.getX1(); @@ -681,26 +768,33 @@ public abstract class QuadCurve2D implements Shape, Cloneable { } /** - * Creates the data for two quadratic curves by dividing a source - * curve in two. The division point is the point on the curve - * that is closest to the source curve's control point. The data - * for the three curves is read and written from arrays of values in - * the usual order: x1, y1, cx, cy, x2, y2. - * - * @param src the array that gives the data values for the source curve - * @param srcoff the offset in the src array to read the values from - * @param left the array where the coordinates of the start curve should be written - * @param leftOff the offset in the left array to start writing the values - * @param right the array where the coordinates of the end curve should be written - * @param rightOff the offset in the right array to start writing the values - * - * @throws ArrayIndexOutOfBoundsException if src.length < srcoff + 6 - * or if left.length < leftOff + 6 or if right.length < rightOff + 6. - * @throws NullPointerException if one of the arrays is null. + * Creates the data for two quadratic curves by dividing a source curve in + * two. The division point is the point on the curve that is closest to the + * source curve's control point. The data for the three curves is read and + * written from arrays of values in the usual order: x1, y1, cx, cy, x2, y2. + * + * @param src + * the array that gives the data values for the source curve. + * @param srcoff + * the offset in the src array to read the values from. + * @param left + * the array where the coordinates of the start curve should be + * written. + * @param leftOff + * the offset in the left array to start writing the values. + * @param right + * the array where the coordinates of the end curve should be + * written. + * @param rightOff + * the offset in the right array to start writing the values. + * @throws ArrayIndexOutOfBoundsException + * if {@code src.length} < srcoff + 6 or if {@code left.length} + * < leftOff + 6 or if {@code right.length} < rightOff + 6. + * @throws NullPointerException + * if one of the arrays is null. */ - public static void subdivide(double src[], int srcoff, double left[], - int leftOff, double right[], int rightOff) - { + public static void subdivide(double src[], int srcoff, double left[], int leftOff, + double right[], int rightOff) { double x1 = src[srcoff + 0]; double y1 = src[srcoff + 1]; double cx = src[srcoff + 2]; @@ -732,42 +826,43 @@ public abstract class QuadCurve2D implements Shape, Cloneable { } /** - * Finds the roots of the quadratic polynomial. This is - * accomplished by finding the (real) values of x that solve - * the following equation: eqn[2]*x*x + eqn[1]*x + eqn[0] = 0. - * The solutions are written back into the array eqn starting - * from the index 0 in the array. The return value tells how - * many array elements have been changed by this method call. - * - * @param eqn an array containing the coefficients of the - * quadratic polynomial to solve. - * - * @return the number of roots of the quadratic polynomial - * - * @throws ArrayIndexOutOfBoundsException if eqn.length < 3. - * @throws NullPointerException if the array is null. + * Finds the roots of the quadratic polynomial. This is accomplished by + * finding the (real) values of x that solve the following equation: + * eqn[2]*x*x + eqn[1]*x + eqn[0] = 0. The solutions are written back into + * the array eqn starting from the index 0 in the array. The return value + * tells how many array elements have been changed by this method call. + * + * @param eqn + * an array containing the coefficients of the quadratic + * polynomial to solve. + * @return the number of roots of the quadratic polynomial. + * @throws ArrayIndexOutOfBoundsException + * if {@code eqn.length} < 3. + * @throws NullPointerException + * if the array is null. */ public static int solveQuadratic(double eqn[]) { return solveQuadratic(eqn, eqn); } /** - * Finds the roots of the quadratic polynomial. This is - * accomplished by finding the (real) values of x that solve - * the following equation: eqn[2]*x*x + eqn[1]*x + eqn[0] = 0. - * The solutions are written into the array res starting - * from the index 0 in the array. The return value tells how - * many array elements have been written by this method call. - * - * @param eqn an array containing the coefficients of the - * quadratic polynomial to solve. - * @param res the array that this method writes the results into - * - * @return the number of roots of the quadratic polynomial - * - * @throws ArrayIndexOutOfBoundsException if eqn.length < 3 or - * if res.length is less than the number of roots. - * @throws NullPointerException if either array is null. + * Finds the roots of the quadratic polynomial. This is accomplished by + * finding the (real) values of x that solve the following equation: + * eqn[2]*x*x + eqn[1]*x + eqn[0] = 0. The solutions are written into the + * array res starting from the index 0 in the array. The return value tells + * how many array elements have been written by this method call. + * + * @param eqn + * an array containing the coefficients of the quadratic + * polynomial to solve. + * @param res + * the array that this method writes the results into. + * @return the number of roots of the quadratic polynomial. + * @throws ArrayIndexOutOfBoundsException + * if {@code eqn.length} < 3 or if {@code res.length} is less + * than the number of roots. + * @throws NullPointerException + * if either array is null. */ public static int solveQuadratic(double eqn[], double res[]) { return Crossing.solveQuad(eqn, res); @@ -821,4 +916,3 @@ public abstract class QuadCurve2D implements Shape, Cloneable { } } - diff --git a/awt/java/awt/geom/Rectangle2D.java b/awt/java/awt/geom/Rectangle2D.java index d33dd91d429d4361db4fcb2d4e2e1405570328ba..8166134afd6177ea902932e93e4f40551b671af9 100644 --- a/awt/java/awt/geom/Rectangle2D.java +++ b/awt/java/awt/geom/Rectangle2D.java @@ -18,6 +18,7 @@ * @author Denis M. Kishenko * @version $Revision$ */ + package java.awt.geom; import java.util.NoSuchElementException; @@ -26,44 +27,64 @@ import org.apache.harmony.awt.internal.nls.Messages; import org.apache.harmony.misc.HashCode; /** - * The Class Rectangle2D represents a rectangle whose coordinates are given - * with the correct precision to be used with the Graphics2D classes. + * The Class Rectangle2D represents a rectangle whose coordinates are given with + * the correct precision to be used with the Graphics2D classes. + * + * @since Android 1.0 */ public abstract class Rectangle2D extends RectangularShape { - /** The Constant OUT_LEFT is a mask that is used to indicate that a - * given point is outside the rectangle and to its left. */ - public static final int OUT_LEFT = 1; - - /** The Constant OUT_TOP is a mask that is used to indicate that a - * given point is outside the rectangle and above it. */ - public static final int OUT_TOP = 2; - - /** The Constant OUT_RIGHT is a mask that is used to indicate that a - * given point is outside the rectangle and to its right. */ - public static final int OUT_RIGHT = 4; - - /** The Constant OUT_BOTTOM is a mask that is used to indicate that a - * given point is outside the rectangle and above it. */ + /** + * The Constant OUT_LEFT is a mask that is used to indicate that a given + * point is outside the rectangle and to its left. + */ + public static final int OUT_LEFT = 1; + + /** + * The Constant OUT_TOP is a mask that is used to indicate that a given + * point is outside the rectangle and above it. + */ + public static final int OUT_TOP = 2; + + /** + * The Constant OUT_RIGHT is a mask that is used to indicate that a given + * point is outside the rectangle and to its right. + */ + public static final int OUT_RIGHT = 4; + + /** + * The Constant OUT_BOTTOM is a mask that is used to indicate that a given + * point is outside the rectangle and above it. + */ public static final int OUT_BOTTOM = 8; /** - * The Class Float is the subclass of Rectangle2D that represents a + * The Class Float is the subclass of Rectangle2D that represents a * rectangle whose data values are given as floats (with float-level * precision). + * + * @since Android 1.0 */ public static class Float extends Rectangle2D { - /** The x coordinate of the rectangle's upper left corner. */ + /** + * The x coordinate of the rectangle's upper left corner. + */ public float x; - - /** The y coordinate of the rectangle's upper left corner. */ + + /** + * The y coordinate of the rectangle's upper left corner. + */ public float y; - - /** The width of the rectangle. */ + + /** + * The width of the rectangle. + */ public float width; - - /** The height of the rectangle. */ + + /** + * The height of the rectangle. + */ public float height; /** @@ -75,10 +96,14 @@ public abstract class Rectangle2D extends RectangularShape { /** * Instantiates a new rectangle with the specified float-precision data. * - * @param x the x coordinate of the rectangle's upper left corner - * @param y the y coordinate of the rectangle's upper left corner - * @param width the width of the rectangle - * @param height the height of the rectangle + * @param x + * the x coordinate of the rectangle's upper left corner. + * @param y + * the y coordinate of the rectangle's upper left corner. + * @param width + * the width of the rectangle. + * @param height + * the height of the rectangle. */ public Float(float x, float y, float width, float height) { setRect(x, y, width, height); @@ -112,10 +137,14 @@ public abstract class Rectangle2D extends RectangularShape { /** * Sets the rectangle's data to the given values. * - * @param x the x coordinate of the rectangle's upper left corner - * @param y the y coordinate of the rectangle's upper left corner - * @param width the width of the rectangle - * @param height the height of the rectangle + * @param x + * the x coordinate of the rectangle's upper left corner. + * @param y + * the y coordinate of the rectangle's upper left corner. + * @param width + * the width of the rectangle. + * @param height + * the height of the rectangle. */ public void setRect(float x, float y, float width, float height) { this.x = x; @@ -146,23 +175,19 @@ public abstract class Rectangle2D extends RectangularShape { if (width <= 0.0f) { code |= OUT_LEFT | OUT_RIGHT; - } else - if (px < x) { - code |= OUT_LEFT; - } else - if (px > x + width) { - code |= OUT_RIGHT; - } + } else if (px < x) { + code |= OUT_LEFT; + } else if (px > x + width) { + code |= OUT_RIGHT; + } if (height <= 0.0f) { code |= OUT_TOP | OUT_BOTTOM; - } else - if (py < y) { - code |= OUT_TOP; - } else - if (py > y + height) { - code |= OUT_BOTTOM; - } + } else if (py < y) { + code |= OUT_TOP; + } else if (py > y + height) { + code |= OUT_BOTTOM; + } return code; } @@ -198,29 +223,41 @@ public abstract class Rectangle2D extends RectangularShape { @Override public String toString() { - // The output format based on 1.5 release behaviour. It could be obtained in the following way + // The output format based on 1.5 release behaviour. It could be + // obtained in the following way // System.out.println(new Rectangle2D.Float().toString()) - return getClass().getName() + "[x=" + x + ",y=" + y + ",width=" + width + ",height=" + height + "]"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ + return getClass().getName() + + "[x=" + x + ",y=" + y + ",width=" + width + ",height=" + height + "]"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ } } /** - * The Class Double is the subclass of Rectangle2D that represents a - * rectangle whose data values are given as doubles (with double-precision-level - * precision). + * The Class Double is the subclass of Rectangle2D that represents a + * rectangle whose data values are given as doubles (with + * double-precision-level precision). + * + * @since Android 1.0 */ public static class Double extends Rectangle2D { - /** The x coordinate of the rectangle's upper left corner. */ + /** + * The x coordinate of the rectangle's upper left corner. + */ public double x; - - /** The y coordinate of the rectangle's upper left corner. */ + + /** + * The y coordinate of the rectangle's upper left corner. + */ public double y; - - /** The width of the rectangle. */ + + /** + * The width of the rectangle. + */ public double width; - - /** The height of the rectangle. */ + + /** + * The height of the rectangle. + */ public double height; /** @@ -232,10 +269,14 @@ public abstract class Rectangle2D extends RectangularShape { /** * Instantiates a new rectangle with the given double values. * - * @param x the x coordinate of the rectangle's upper left corner - * @param y the y coordinate of the rectangle's upper left corner - * @param width the width of the rectangle - * @param height the height of the rectangle + * @param x + * the x coordinate of the rectangle's upper left corner. + * @param y + * the y coordinate of the rectangle's upper left corner. + * @param width + * the width of the rectangle. + * @param height + * the height of the rectangle. */ public Double(double x, double y, double width, double height) { setRect(x, y, width, height); @@ -288,23 +329,19 @@ public abstract class Rectangle2D extends RectangularShape { if (width <= 0.0) { code |= OUT_LEFT | OUT_RIGHT; - } else - if (px < x) { - code |= OUT_LEFT; - } else - if (px > x + width) { - code |= OUT_RIGHT; - } + } else if (px < x) { + code |= OUT_LEFT; + } else if (px > x + width) { + code |= OUT_RIGHT; + } if (height <= 0.0) { code |= OUT_TOP | OUT_BOTTOM; - } else - if (py < y) { - code |= OUT_TOP; - } else - if (py > y + height) { - code |= OUT_BOTTOM; - } + } else if (py < y) { + code |= OUT_TOP; + } else if (py > y + height) { + code |= OUT_BOTTOM; + } return code; } @@ -330,45 +367,60 @@ public abstract class Rectangle2D extends RectangularShape { @Override public String toString() { - // The output format based on 1.5 release behaviour. It could be obtained in the following way + // The output format based on 1.5 release behaviour. It could be + // obtained in the following way // System.out.println(new Rectangle2D.Double().toString()) - return getClass().getName() + "[x=" + x + ",y=" + y + ",width=" + width + ",height=" + height + "]"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ + return getClass().getName() + + "[x=" + x + ",y=" + y + ",width=" + width + ",height=" + height + "]"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ } } /** - * The Class Iterator provides - * access to the coordinates of the Rectangle2D's boundary modified - * by an AffineTransform. + * The Class Iterator provides access to the coordinates of the + * Rectangle2D's boundary modified by an AffineTransform. */ class Iterator implements PathIterator { - /** The x coordinate of the rectangle's upper left corner. */ + /** + * The x coordinate of the rectangle's upper left corner. + */ double x; - - /** The y coordinate of the rectangle's upper left corner. */ + + /** + * The y coordinate of the rectangle's upper left corner. + */ double y; - - - /** The width of the rectangle. */ + + /** + * The width of the rectangle. + */ double width; - - /** The height of the rectangle. */ + + /** + * The height of the rectangle. + */ double height; - - /** The AffineTransform that is used to modify the coordinates - * that are returned by the path iterator. */ + + /** + * The AffineTransform that is used to modify the coordinates that are + * returned by the path iterator. + */ AffineTransform t; - - /** The current segment index. */ + + /** + * The current segment index. + */ int index; - + /** - * Constructs a new Rectangle2D.Iterator for given rectangle and transformation. + * Constructs a new Rectangle2D.Iterator for given rectangle and + * transformation. * - * @param r - the source Rectangle2D object - * @param at - the AffineTransform object to apply to the coordinates - * before returning them + * @param r + * the source Rectangle2D object. + * @param at + * the AffineTransform object to apply to the coordinates + * before returning them. */ Iterator(Rectangle2D r, AffineTransform at) { this.x = r.getX(); @@ -407,23 +459,23 @@ public abstract class Rectangle2D extends RectangularShape { coords[1] = y; } else { type = SEG_LINETO; - switch(index) { - case 1: - coords[0] = x + width; - coords[1] = y; - break; - case 2: - coords[0] = x + width; - coords[1] = y + height; - break; - case 3: - coords[0] = x; - coords[1] = y + height; - break; - case 4: - coords[0] = x; - coords[1] = y; - break; + switch (index) { + case 1: + coords[0] = x + width; + coords[1] = y; + break; + case 2: + coords[0] = x + width; + coords[1] = y + height; + break; + case 3: + coords[0] = x; + coords[1] = y + height; + break; + case 4: + coords[0] = x; + coords[1] = y; + break; } } if (t != null) { @@ -446,23 +498,23 @@ public abstract class Rectangle2D extends RectangularShape { type = SEG_MOVETO; } else { type = SEG_LINETO; - switch(index) { - case 1: - coords[0] = (float)(x + width); - coords[1] = (float)y; - break; - case 2: - coords[0] = (float)(x + width); - coords[1] = (float)(y + height); - break; - case 3: - coords[0] = (float)x; - coords[1] = (float)(y + height); - break; - case 4: - coords[0] = (float)x; - coords[1] = (float)y; - break; + switch (index) { + case 1: + coords[0] = (float)(x + width); + coords[1] = (float)y; + break; + case 2: + coords[0] = (float)(x + width); + coords[1] = (float)(y + height); + break; + case 3: + coords[0] = (float)x; + coords[1] = (float)(y + height); + break; + case 4: + coords[0] = (float)x; + coords[1] = (float)y; + break; } } if (t != null) { @@ -474,7 +526,7 @@ public abstract class Rectangle2D extends RectangularShape { } /** - * Instantiates a new rectangle2 d. + * Instantiates a new Rectangle2D. */ protected Rectangle2D() { } @@ -482,58 +534,64 @@ public abstract class Rectangle2D extends RectangularShape { /** * Sets the rectangle's location and dimension. * - * @param x the x coordinate of the rectangle's upper left corner - * @param y the y coordinate of the rectangle's upper left corner - * @param width the width of the rectangle - * @param height the height of the rectangle + * @param x + * the x coordinate of the rectangle's upper left corner. + * @param y + * the y coordinate of the rectangle's upper left corner. + * @param width + * the width of the rectangle. + * @param height + * the height of the rectangle. */ public abstract void setRect(double x, double y, double width, double height); /** - * Gets the location of the point with respect to the rectangle and - * packs the information into a single int using the bitmasks - * {@link Rectangle2D#OUT_LEFT}, {@link Rectangle2D#OUT_RIGHT}, - * {@link Rectangle2D#OUT_TOP}, and {@link Rectangle2D#OUT_BOTTOM}. - * If the rectangle has zero or negative width, then every point - * is regarded as being both to the left and to the right of the - * rectangle. Similarly, if the height is zero or negative then - * all points are considered to be both both above and below it. - * - * @param x the x coordinate of the point to check - * @param y the y coordinate of the point to check + * Gets the location of the point with respect to the rectangle and packs + * the information into a single integer using the bitmasks + * {@link Rectangle2D#OUT_LEFT}, {@link Rectangle2D#OUT_RIGHT}, + * {@link Rectangle2D#OUT_TOP}, and {@link Rectangle2D#OUT_BOTTOM}. If the + * rectangle has zero or negative width, then every point is regarded as + * being both to the left and to the right of the rectangle. Similarly, if + * the height is zero or negative then all points are considered to be both + * both above and below it. * + * @param x + * the x coordinate of the point to check. + * @param y + * the y coordinate of the point to check. * @return the point's location with respect to the rectangle. */ public abstract int outcode(double x, double y); /** - * Creates an new rectangle that is the intersection of this rectangle - * with the given rectangle. The resulting rectangle may be empty. - * The data of this rectangle is left unchanged. - * - * @param r the rectangle to intersect with this rectangle. + * Creates an new rectangle that is the intersection of this rectangle with + * the given rectangle. The resulting rectangle may be empty. The data of + * this rectangle is left unchanged. * + * @param r + * the rectangle to intersect with this rectangle. * @return the new rectangle given by intersection. */ public abstract Rectangle2D createIntersection(Rectangle2D r); /** - * Creates an new rectangle that is the union of this rectangle - * with the given rectangle. The new rectangle is the smallest - * rectangle which contains both this rectangle and the rectangle - * specified as a parameter. The data of this rectangle is left unchanged. - * - * @param r the rectangle to combine with this rectangle + * Creates an new rectangle that is the union of this rectangle with the + * given rectangle. The new rectangle is the smallest rectangle which + * contains both this rectangle and the rectangle specified as a parameter. + * The data of this rectangle is left unchanged. * - * @return the new rectangle given by union + * @param r + * the rectangle to combine with this rectangle. + * @return the new rectangle given by union. */ public abstract Rectangle2D createUnion(Rectangle2D r); /** - * Sets the data of this rectangle to match the data of the given - * rectangle. + * Sets the data of this rectangle to match the data of the given rectangle. * - * @param r the rectangle whose data is to be copied into this rectangle's fields. + * @param r + * the rectangle whose data is to be copied into this rectangle's + * fields. */ public void setRect(Rectangle2D r) { setRect(r.getX(), r.getY(), r.getWidth(), r.getHeight()); @@ -549,61 +607,63 @@ public abstract class Rectangle2D extends RectangularShape { } /** - * Determines whether any part of the line segment between (and including) - * the two given points touches any - * part of the rectangle, including its boundary. + * Determines whether any part of the line segment between (and including) + * the two given points touches any part of the rectangle, including its + * boundary. * - * @param x1 the x coordinate of one of the points that determines the - * line segment to test - * @param y1 the y coordinate of one of the points that determines the - * line segment to test - * @param x2 the x coordinate of one of the points that determines the - * line segment to test - * @param y2 the y coordinate of one of the points that determines the - * line segment to test - * - * @return true, if at least one point of the line segment between the - * two points matches any point of the interior of the rectangle or the - * rectangle's boundary. + * @param x1 + * the x coordinate of one of the points that determines the line + * segment to test. + * @param y1 + * the y coordinate of one of the points that determines the line + * segment to test. + * @param x2 + * the x coordinate of one of the points that determines the line + * segment to test. + * @param y2 + * the y coordinate of one of the points that determines the line + * segment to test. + * @return true, if at least one point of the line segment between the two + * points matches any point of the interior of the rectangle or the + * rectangle's boundary. */ public boolean intersectsLine(double x1, double y1, double x2, double y2) { double rx1 = getX(); double ry1 = getY(); double rx2 = rx1 + getWidth(); double ry2 = ry1 + getHeight(); - return - (rx1 <= x1 && x1 <= rx2 && ry1 <= y1 && y1 <= ry2) || - (rx1 <= x2 && x2 <= rx2 && ry1 <= y2 && y2 <= ry2) || - Line2D.linesIntersect(rx1, ry1, rx2, ry2, x1, y1, x2, y2) || - Line2D.linesIntersect(rx2, ry1, rx1, ry2, x1, y1, x2, y2); + return (rx1 <= x1 && x1 <= rx2 && ry1 <= y1 && y1 <= ry2) + || (rx1 <= x2 && x2 <= rx2 && ry1 <= y2 && y2 <= ry2) + || Line2D.linesIntersect(rx1, ry1, rx2, ry2, x1, y1, x2, y2) + || Line2D.linesIntersect(rx2, ry1, rx1, ry2, x1, y1, x2, y2); } /** - * Determines whether any part of the specified line segment touches any + * Determines whether any part of the specified line segment touches any * part of the rectangle, including its boundary. * - * @param l the line segment to test - * - * @return true, if at least one point of the given line segment - * matches any point of the interior of the rectangle or the - * rectangle's boundary. + * @param l + * the line segment to test. + * @return true, if at least one point of the given line segment matches any + * point of the interior of the rectangle or the rectangle's + * boundary. */ public boolean intersectsLine(Line2D l) { return intersectsLine(l.getX1(), l.getY1(), l.getX2(), l.getY2()); } /** - * Gets the location of the point with respect to the rectangle and - * packs the information into a single int using the bitmasks - * {@link Rectangle2D#OUT_LEFT}, {@link Rectangle2D#OUT_RIGHT}, - * {@link Rectangle2D#OUT_TOP}, and {@link Rectangle2D#OUT_BOTTOM}. - * If the rectangle has zero or negative width, then every point - * is regarded as being both to the left and to the right of the - * rectangle. Similarly, if the height is zero or negative then - * all points are considered to be both both above and below it. - * - * @param p the point to check + * Gets the location of the point with respect to the rectangle and packs + * the information into a single integer using the bitmasks + * {@link Rectangle2D#OUT_LEFT}, {@link Rectangle2D#OUT_RIGHT}, + * {@link Rectangle2D#OUT_TOP}, and {@link Rectangle2D#OUT_BOTTOM}. If the + * rectangle has zero or negative width, then every point is regarded as + * being both to the left and to the right of the rectangle. Similarly, if + * the height is zero or negative then all points are considered to be both + * both above and below it. * + * @param p + * the point to check. * @return the point's location with respect to the rectangle. */ public int outcode(Point2D p) { @@ -620,9 +680,7 @@ public abstract class Rectangle2D extends RectangularShape { double x2 = x1 + getWidth(); double y2 = y1 + getHeight(); - return - x1 <= x && x < x2 && - y1 <= y && y < y2; + return x1 <= x && x < x2 && y1 <= y && y < y2; } public boolean intersects(double x, double y, double width, double height) { @@ -635,9 +693,7 @@ public abstract class Rectangle2D extends RectangularShape { double x2 = x1 + getWidth(); double y2 = y1 + getHeight(); - return - x + width > x1 && x < x2 && - y + height > y1 && y < y2; + return x + width > x1 && x < x2 && y + height > y1 && y < y2; } public boolean contains(double x, double y, double width, double height) { @@ -650,19 +706,21 @@ public abstract class Rectangle2D extends RectangularShape { double x2 = x1 + getWidth(); double y2 = y1 + getHeight(); - return - x1 <= x && x + width <= x2 && - y1 <= y && y + height <= y2; + return x1 <= x && x + width <= x2 && y1 <= y && y + height <= y2; } /** - * Changes the data values of the destination rectangle to match - * the intersection of the two source rectangles, leaving the - * two source rectangles unchanged. The resulting rectangle may be empty. + * Changes the data values of the destination rectangle to match the + * intersection of the two source rectangles, leaving the two source + * rectangles unchanged. The resulting rectangle may be empty. * - * @param src1 one of the two source rectangles giving the data to intersect - * @param src2 one of the two source rectangles giving the data to intersect - * @param dst the destination object where the data of the intersection is written + * @param src1 + * one of the two source rectangles giving the data to intersect. + * @param src2 + * one of the two source rectangles giving the data to intersect. + * @param dst + * the destination object where the data of the intersection is + * written. */ public static void intersect(Rectangle2D src1, Rectangle2D src2, Rectangle2D dst) { double x1 = Math.max(src1.getMinX(), src2.getMinX()); @@ -673,14 +731,17 @@ public abstract class Rectangle2D extends RectangularShape { } /** - * Changes the data values of the destination rectangle to match - * the union of the two source rectangles, leaving the - * two source rectangles unchanged. The union is the smallest rectangle - * tha completely covers the two source rectangles. + * Changes the data values of the destination rectangle to match the union + * of the two source rectangles, leaving the two source rectangles + * unchanged. The union is the smallest rectangle that completely covers the + * two source rectangles. * - * @param src1 one of the two source rectangles giving the data - * @param src2 one of the two source rectangles giving the data - * @param dst the destination object where the data of the union is written + * @param src1 + * one of the two source rectangles giving the data. + * @param src2 + * one of the two source rectangles giving the data. + * @param dst + * the destination object where the data of the union is written. */ public static void union(Rectangle2D src1, Rectangle2D src2, Rectangle2D dst) { double x1 = Math.min(src1.getMinX(), src2.getMinX()); @@ -693,8 +754,12 @@ public abstract class Rectangle2D extends RectangularShape { /** * Enlarges the rectangle so that it includes the given point. * - * @param x the x coordinate of the new point to be covered by the rectangle - * @param y the y coordinate of the new point to be covered by the rectangle + * @param x + * the x coordinate of the new point to be covered by the + * rectangle. + * @param y + * the y coordinate of the new point to be covered by the + * rectangle. */ public void add(double x, double y) { double x1 = Math.min(getMinX(), x); @@ -707,7 +772,8 @@ public abstract class Rectangle2D extends RectangularShape { /** * Enlarges the rectangle so that it includes the given point. * - * @param p the new point to be covered by the rectangle + * @param p + * the new point to be covered by the rectangle. */ public void add(Point2D p) { add(p.getX(), p.getY()); @@ -716,7 +782,8 @@ public abstract class Rectangle2D extends RectangularShape { /** * Enlarges the rectangle so that it covers the given rectangle. * - * @param r the new rectangle to be covered by this rectangle + * @param r + * the new rectangle to be covered by this rectangle. */ public void add(Rectangle2D r) { union(this, r, this); @@ -748,14 +815,10 @@ public abstract class Rectangle2D extends RectangularShape { } if (obj instanceof Rectangle2D) { Rectangle2D r = (Rectangle2D)obj; - return - getX() == r.getX() && - getY() == r.getY() && - getWidth() == r.getWidth() && - getHeight() == r.getHeight(); + return getX() == r.getX() && getY() == r.getY() && getWidth() == r.getWidth() + && getHeight() == r.getHeight(); } return false; } } - diff --git a/awt/java/awt/geom/RectangularShape.java b/awt/java/awt/geom/RectangularShape.java index 0a77dfdbcdaa527de83718b67b5c20a09eb6a86a..0b0d05cad67c03e81123a57e7e0ff3ae45f4ad09 100644 --- a/awt/java/awt/geom/RectangularShape.java +++ b/awt/java/awt/geom/RectangularShape.java @@ -18,17 +18,19 @@ * @author Denis M. Kishenko * @version $Revision$ */ + package java.awt.geom; import java.awt.Rectangle; import java.awt.Shape; /** - * The Class RectangularShape represents a Shape whose data is - * (at least partially) described by a rectangular frame. This includes - * shapes which are obviously rectangular (such as Rectangle2D) as well as - * shapes like Arc2D which are largely determined by the rectangle they - * fit inside. + * The Class RectangularShape represents a Shape whose data is (at least + * partially) described by a rectangular frame. This includes shapes which are + * obviously rectangular (such as Rectangle2D) as well as shapes like Arc2D + * which are largely determined by the rectangle they fit inside. + * + * @since Android 1.0 */ public abstract class RectangularShape implements Shape, Cloneable { @@ -67,25 +69,30 @@ public abstract class RectangularShape implements Shape, Cloneable { public abstract double getHeight(); /** - * Checks if this is an empty rectangle: one with zero as its width or height. + * Checks if this is an empty rectangle: one with zero as its width or + * height. * * @return true, if the width or height is empty. */ public abstract boolean isEmpty(); /** - * Sets the data for the bounding rectangle in terms of double values. + * Sets the data for the bounding rectangle in terms of double values. * - * @param x the x coordinate of the upper left corner of the rectangle. - * @param y the y coordinate of the upper left corner of the rectangle. - * @param w the width of the rectangle. - * @param h the height of the rectangle. + * @param x + * the x coordinate of the upper left corner of the rectangle. + * @param y + * the y coordinate of the upper left corner of the rectangle. + * @param w + * the width of the rectangle. + * @param h + * the height of the rectangle. */ public abstract void setFrame(double x, double y, double w, double h); /** - * Gets the minimum x value of the bounding rectangle (the x - * coordinate of the upper left corner of the rectangle). + * Gets the minimum x value of the bounding rectangle (the x coordinate of + * the upper left corner of the rectangle). * * @return the minimum x value of the bounding rectangle. */ @@ -94,8 +101,8 @@ public abstract class RectangularShape implements Shape, Cloneable { } /** - * Gets the minimum y value of the bounding rectangle (the y - * coordinate of the upper left corner of the rectangle). + * Gets the minimum y value of the bounding rectangle (the y coordinate of + * the upper left corner of the rectangle). * * @return the minimum y value of the bounding rectangle. */ @@ -104,9 +111,8 @@ public abstract class RectangularShape implements Shape, Cloneable { } /** - * Gets the maximum x value of the bounding rectangle (the x - * coordinate of the upper left corner of the rectangle plus the - * rectangle's width). + * Gets the maximum x value of the bounding rectangle (the x coordinate of + * the upper left corner of the rectangle plus the rectangle's width). * * @return the maximum x value of the bounding rectangle. */ @@ -115,9 +121,8 @@ public abstract class RectangularShape implements Shape, Cloneable { } /** - * Gets the maximum y value of the bounding rectangle (the y - * coordinate of the upper left corner of the rectangle plus the - * rectangle's height). + * Gets the maximum y value of the bounding rectangle (the y coordinate of + * the upper left corner of the rectangle plus the rectangle's height). * * @return the maximum y value of the bounding rectangle. */ @@ -144,8 +149,8 @@ public abstract class RectangularShape implements Shape, Cloneable { } /** - * Places the rectangle's size and location data in a new Rectangle2D - * object and returns it. + * Places the rectangle's size and location data in a new Rectangle2D object + * and returns it. * * @return the bounding rectangle as a new Rectangle2D object. */ @@ -154,21 +159,24 @@ public abstract class RectangularShape implements Shape, Cloneable { } /** - * Sets the bounding rectangle in terms of a Point2D which gives its - * upper left corner and a Dimension2D object giving its width and height. + * Sets the bounding rectangle in terms of a Point2D which gives its upper + * left corner and a Dimension2D object giving its width and height. * - * @param loc the new upper left corner coordinate. - * @param size the new size dimensions. + * @param loc + * the new upper left corner coordinate. + * @param size + * the new size dimensions. */ public void setFrame(Point2D loc, Dimension2D size) { setFrame(loc.getX(), loc.getY(), size.getWidth(), size.getHeight()); } /** - * Sets the bounding rectangle to match the data contained in the - * specified Rectangle2D. + * Sets the bounding rectangle to match the data contained in the specified + * Rectangle2D. * - * @param r the rectangle that gives the new frame data. + * @param r + * the rectangle that gives the new frame data. */ public void setFrame(Rectangle2D r) { setFrame(r.getX(), r.getY(), r.getWidth(), r.getHeight()); @@ -176,12 +184,17 @@ public abstract class RectangularShape implements Shape, Cloneable { /** * Sets the framing rectangle given two opposite corners. Any two corners - * may be used in any order as long as they are diagonally opposite one another. + * may be used in any order as long as they are diagonally opposite one + * another. * - * @param x1 the x coordinate of one of the corner points. - * @param y1 the y coordinate of one of the corner points. - * @param x2 the x coordinate of the other corner point. - * @param y2 the y coordinate of the other corner point. + * @param x1 + * the x coordinate of one of the corner points. + * @param y1 + * the y coordinate of one of the corner points. + * @param x2 + * the x coordinate of the other corner point. + * @param y2 + * the y coordinate of the other corner point. */ public void setFrameFromDiagonal(double x1, double y1, double x2, double y2) { double rx, ry, rw, rh; @@ -204,10 +217,13 @@ public abstract class RectangularShape implements Shape, Cloneable { /** * Sets the framing rectangle given two opposite corners. Any two corners - * may be used in any order as long as they are diagonally opposite one another. + * may be used in any order as long as they are diagonally opposite one + * another. * - * @param p1 one of the corner points. - * @param p2 the other corner point. + * @param p1 + * one of the corner points. + * @param p2 + * the other corner point. */ public void setFrameFromDiagonal(Point2D p1, Point2D p2) { setFrameFromDiagonal(p1.getX(), p1.getY(), p2.getX(), p2.getY()); @@ -217,10 +233,14 @@ public abstract class RectangularShape implements Shape, Cloneable { * Sets the framing rectangle given the center point and one corner. Any * corner may be used. * - * @param centerX the x coordinate of the center point. - * @param centerY the y coordinate of the center point. - * @param cornerX the x coordinate of one of the corner points. - * @param cornerY the y coordinate of one of the corner points. + * @param centerX + * the x coordinate of the center point. + * @param centerY + * the y coordinate of the center point. + * @param cornerX + * the x coordinate of one of the corner points. + * @param cornerY + * the y coordinate of one of the corner points. */ public void setFrameFromCenter(double centerX, double centerY, double cornerX, double cornerY) { double width = Math.abs(cornerX - centerX); @@ -232,8 +252,10 @@ public abstract class RectangularShape implements Shape, Cloneable { * Sets the framing rectangle given the center point and one corner. Any * corner may be used. * - * @param center the center point. - * @param corner a corner point. + * @param center + * the center point. + * @param corner + * a corner point. */ public void setFrameFromCenter(Point2D center, Point2D corner) { setFrameFromCenter(center.getX(), center.getY(), corner.getX(), corner.getY()); @@ -273,4 +295,3 @@ public abstract class RectangularShape implements Shape, Cloneable { } } - diff --git a/awt/java/awt/geom/RoundRectangle2D.java b/awt/java/awt/geom/RoundRectangle2D.java index 680a146bfd10181830a7da34408b36c42d651456..8fbddd64d9db16d317142f91c670fa80fc59cc53 100644 --- a/awt/java/awt/geom/RoundRectangle2D.java +++ b/awt/java/awt/geom/RoundRectangle2D.java @@ -18,6 +18,7 @@ * @author Denis M. Kishenko * @version $Revision$ */ + package java.awt.geom; import java.util.NoSuchElementException; @@ -25,53 +26,74 @@ import java.util.NoSuchElementException; import org.apache.harmony.awt.internal.nls.Messages; /** - * The Class RoundRectangle2D describes a rectangle with rounded - * corners with high-precision data that is appropriate for geometric - * operations. + * The Class RoundRectangle2D describes a rectangle with rounded corners with + * high-precision data that is appropriate for geometric operations. + * + * @since Android 1.0 */ public abstract class RoundRectangle2D extends RectangularShape { /** - * The Class Float is the subclass of RoundRectangle2D that has all - * of its data values stored with float-level precision. + * The Class Float is the subclass of RoundRectangle2D that has all of its + * data values stored with float-level precision. + * + * @since Android 1.0 */ public static class Float extends RoundRectangle2D { - /** The x coordinate of the rectangle's upper left corner. */ + /** + * The x coordinate of the rectangle's upper left corner. + */ public float x; - - /** The y coordinate of the rectangle's upper left corner. */ + + /** + * The y coordinate of the rectangle's upper left corner. + */ public float y; - - /** The width of the rectangle. */ + + /** + * The width of the rectangle. + */ public float width; - - /** The height of the rectangle. */ + + /** + * The height of the rectangle. + */ public float height; - - /** The arcwidth of the rounded corners. */ + + /** + * The arc width of the rounded corners. + */ public float arcwidth; - - /** The archeight of the rounded corners. */ + + /** + * The arc height of the rounded corners. + */ public float archeight; /** - * Instantiates a new float-valued RoundRectangle2D with - * its data-values set to zero. + * Instantiates a new float-valued RoundRectangle2D with its data-values + * set to zero. */ public Float() { } /** - * Instantiates a new float-valued RoundRectangle2D with - * the specified data values + * Instantiates a new float-valued RoundRectangle2D with the specified + * data values. * - * @param x the x coordinate of the rectangle's upper left corner - * @param y the y coordinate of the rectangle's upper left corner - * @param width the width of the rectangle - * @param height the height of the rectangle - * @param arcwidth the arcwidth of the rounded corners - * @param archeight the archeight of the rounded corners + * @param x + * the x coordinate of the rectangle's upper left corner. + * @param y + * the y coordinate of the rectangle's upper left corner. + * @param width + * the width of the rectangle. + * @param height + * the height of the rectangle. + * @param arcwidth + * the arc width of the rounded corners. + * @param archeight + * the arc height of the rounded corners. */ public Float(float x, float y, float width, float height, float arcwidth, float archeight) { setRoundRect(x, y, width, height, arcwidth, archeight); @@ -113,16 +135,23 @@ public abstract class RoundRectangle2D extends RectangularShape { } /** - * Sets the data of the round rect. + * Sets the data of the round rectangle. * - * @param x the x coordinate of the rectangle's upper left corner - * @param y the y coordinate of the rectangle's upper left corner - * @param width the width of the rectangle - * @param height the height of the rectangle - * @param arcwidth the arcwidth of the rounded corners - * @param archeight the archeight of the rounded corners + * @param x + * the x coordinate of the rectangle's upper left corner. + * @param y + * the y coordinate of the rectangle's upper left corner. + * @param width + * the width of the rectangle. + * @param height + * the height of the rectangle. + * @param arcwidth + * the arc width of the rounded corners. + * @param archeight + * the arc height of the rounded corners. */ - public void setRoundRect(float x, float y, float width, float height, float arcwidth, float archeight) { + public void setRoundRect(float x, float y, float width, float height, float arcwidth, + float archeight) { this.x = x; this.y = y; this.width = width; @@ -132,7 +161,8 @@ public abstract class RoundRectangle2D extends RectangularShape { } @Override - public void setRoundRect(double x, double y, double width, double height, double arcwidth, double archeight) { + public void setRoundRect(double x, double y, double width, double height, double arcwidth, + double archeight) { this.x = (float)x; this.y = (float)y; this.width = (float)width; @@ -157,48 +187,69 @@ public abstract class RoundRectangle2D extends RectangularShape { } /** - * The Class Double is the subclass of RoundRectangle2D that has all - * of its data values stored with double-level precision. + * The Class Double is the subclass of RoundRectangle2D that has all of its + * data values stored with double-level precision. + * + * @since Android 1.0 */ public static class Double extends RoundRectangle2D { - /** The x coordinate of the rectangle's upper left corner. */ + /** + * The x coordinate of the rectangle's upper left corner. + */ public double x; - - /** The y coordinate of the rectangle's upper left corner. */ + + /** + * The y coordinate of the rectangle's upper left corner. + */ public double y; - - /** The width of the rectangle. */ + + /** + * The width of the rectangle. + */ public double width; - - /** The height of the rectangle. */ + + /** + * The height of the rectangle. + */ public double height; - - /** The arcwidth of the rounded corners. */ + + /** + * The arc width of the rounded corners. + */ public double arcwidth; - - /** The archeight of the rounded corners. */ + + /** + * The arc height of the rounded corners. + */ public double archeight; /** - * Instantiates a new double-valued RoundRectangle2D with - * its data-values set to zero. + * Instantiates a new double-valued RoundRectangle2D with its + * data-values set to zero. */ public Double() { } /** - * Instantiates a new double-valued RoundRectangle2D with - * the specified data values. + * Instantiates a new double-valued RoundRectangle2D with the specified + * data values. * - * @param x the x coordinate of the rectangle's upper left corner - * @param y the y coordinate of the rectangle's upper left corner - * @param width the width of the rectangle - * @param height the height of the rectangle - * @param arcwidth the arcwidth of the rounded corners - * @param archeight the archeight of the rounded corners + * @param x + * the x coordinate of the rectangle's upper left corner. + * @param y + * the y coordinate of the rectangle's upper left corner. + * @param width + * the width of the rectangle. + * @param height + * the height of the rectangle. + * @param arcwidth + * the arc width of the rounded corners. + * @param archeight + * the arc height of the rounded corners. */ - public Double(double x, double y, double width, double height, double arcwidth, double archeight) { + public Double(double x, double y, double width, double height, double arcwidth, + double archeight) { setRoundRect(x, y, width, height, arcwidth, archeight); } @@ -238,7 +289,8 @@ public abstract class RoundRectangle2D extends RectangularShape { } @Override - public void setRoundRect(double x, double y, double width, double height, double arcwidth, double archeight) { + public void setRoundRect(double x, double y, double width, double height, double arcwidth, + double archeight) { this.x = x; this.y = y; this.width = width; @@ -263,7 +315,7 @@ public abstract class RoundRectangle2D extends RectangularShape { } /* - * RoundRectangle2D path iterator + * RoundRectangle2D path iterator */ /** * The subclass of PathIterator to traverse a RoundRectangle2D. @@ -274,70 +326,101 @@ public abstract class RoundRectangle2D extends RectangularShape { * Path for round corners generated the same way as Ellipse2D */ - /** The coefficient to calculate control points of Bezier curves. */ + /** + * The coefficient to calculate control points of Bezier curves. + */ double u = 0.5 - 2.0 / 3.0 * (Math.sqrt(2.0) - 1.0); - /** The points coordinates calculation table. */ + /** + * The points coordinates calculation table. + */ double points[][] = { - { 0.0, 0.5, 0.0, 0.0 }, // MOVETO - { 1.0, -0.5, 0.0, 0.0 }, // LINETO - { 1.0, -u, 0.0, 0.0, // CUBICTO - 1.0, 0.0, 0.0, u, - 1.0, 0.0, 0.0, 0.5 }, - { 1.0, 0.0, 1.0, -0.5 }, // LINETO - { 1.0, 0.0, 1.0, -u, // CUBICTO - 1.0, -u, 1.0, 0.0, - 1.0, -0.5, 1.0, 0.0 }, - { 0.0, 0.5, 1.0, 0.0 }, // LINETO - { 0.0, u, 1.0, 0.0, // CUBICTO - 0.0, 0.0, 1.0, -u, - 0.0, 0.0, 1.0, -0.5 }, - { 0.0, 0.0, 0.0, 0.5 }, // LINETO - { 0.0, 0.0, 0.0, u, // CUBICTO - 0.0, u, 0.0, 0.0, - 0.0, 0.5, 0.0, 0.0 } }; - - /** The segment types correspond to points array. */ + { + 0.0, 0.5, 0.0, 0.0 + }, // MOVETO + { + 1.0, -0.5, 0.0, 0.0 + }, // LINETO + { + 1.0, -u, 0.0, 0.0, // CUBICTO + 1.0, 0.0, 0.0, u, 1.0, 0.0, 0.0, 0.5 + }, { + 1.0, 0.0, 1.0, -0.5 + }, // LINETO + { + 1.0, 0.0, 1.0, -u, // CUBICTO + 1.0, -u, 1.0, 0.0, 1.0, -0.5, 1.0, 0.0 + }, { + 0.0, 0.5, 1.0, 0.0 + }, // LINETO + { + 0.0, u, 1.0, 0.0, // CUBICTO + 0.0, 0.0, 1.0, -u, 0.0, 0.0, 1.0, -0.5 + }, { + 0.0, 0.0, 0.0, 0.5 + }, // LINETO + { + 0.0, 0.0, 0.0, u, // CUBICTO + 0.0, u, 0.0, 0.0, 0.0, 0.5, 0.0, 0.0 + } + }; + + /** + * The segment types correspond to points array. + */ int types[] = { - SEG_MOVETO, - SEG_LINETO, - SEG_CUBICTO, - SEG_LINETO, - SEG_CUBICTO, - SEG_LINETO, - SEG_CUBICTO, - SEG_LINETO, - SEG_CUBICTO}; - - /** The x coordinate of left-upper corner of the round rectangle bounds. */ + SEG_MOVETO, SEG_LINETO, SEG_CUBICTO, SEG_LINETO, SEG_CUBICTO, SEG_LINETO, + SEG_CUBICTO, SEG_LINETO, SEG_CUBICTO + }; + + /** + * The x coordinate of left-upper corner of the round rectangle bounds. + */ double x; - - /** The y coordinate of left-upper corner of the round rectangle bounds. */ + + /** + * The y coordinate of left-upper corner of the round rectangle bounds. + */ double y; - - /** The width of the round rectangle bounds. */ + + /** + * The width of the round rectangle bounds. + */ double width; - - /** The height of the round rectangle bounds. */ + + /** + * The height of the round rectangle bounds. + */ double height; - - /** The width of arc corners of the round rectangle. */ + + /** + * The width of arc corners of the round rectangle. + */ double aw; - - /** The height of arc corners of the round rectangle. */ + + /** + * The height of arc corners of the round rectangle. + */ double ah; - /** The path iterator transformation. */ + /** + * The path iterator transformation. + */ AffineTransform t; - /** The current segmenet index. */ + /** + * The current segment index. + */ int index; /** - * Constructs a new RoundRectangle2D.Iterator for given round rectangle and transformation. + * Constructs a new RoundRectangle2D.Iterator for given round rectangle + * and transformation. * - * @param rr - the source RoundRectangle2D object - * @param at - the AffineTransform object to apply rectangle path + * @param rr + * - the source RoundRectangle2D object + * @param at + * - the AffineTransform object to apply rectangle path */ Iterator(RoundRectangle2D rr, AffineTransform at) { this.x = rr.getX(); @@ -415,41 +498,48 @@ public abstract class RoundRectangle2D extends RectangularShape { /** * Gets the arc width. * - * @return the arc width + * @return the arc width. */ public abstract double getArcWidth(); /** * Gets the arc height. * - * @return the arc height + * @return the arc height. */ public abstract double getArcHeight(); /** * Sets the data of the RoundRectangle2D. * - * @param x the x coordinate of the rectangle's upper left corner - * @param y the y coordinate of the rectangle's upper left corner - * @param width the width of the rectangle - * @param height the height of the rectangle - * @param arcWidth the arcwidth of the rounded corners - * @param arcHeight the archeight of the rounded corners + * @param x + * the x coordinate of the rectangle's upper left corner. + * @param y + * the y coordinate of the rectangle's upper left corner. + * @param width + * the width of the rectangle. + * @param height + * the height of the rectangle. + * @param arcWidth + * the arc width of the rounded corners. + * @param arcHeight + * the arc height of the rounded corners. */ public abstract void setRoundRect(double x, double y, double width, double height, double arcWidth, double arcHeight); /** - * Sets the data of the RoundRectangle2D by copying the values - * from an existing RoundRectangle2D. + * Sets the data of the RoundRectangle2D by copying the values from an + * existing RoundRectangle2D. * - * @param rr the round rectangle to copy the data from - * - * @throws NullPointerException if rr is null + * @param rr + * the round rectangle to copy the data from. + * @throws NullPointerException + * if rr is null. */ public void setRoundRect(RoundRectangle2D rr) { - setRoundRect(rr.getX(), rr.getY(), rr.getWidth(), rr.getHeight(), rr - .getArcWidth(), rr.getArcHeight()); + setRoundRect(rr.getX(), rr.getY(), rr.getWidth(), rr.getHeight(), rr.getArcWidth(), rr + .getArcHeight()); } @Override @@ -478,21 +568,19 @@ public abstract class RoundRectangle2D extends RectangularShape { if (px < rx1 + aw) { cx = rx1 + aw; - } else - if (px > rx2 - aw) { - cx = rx2 - aw; - } else { - return true; - } + } else if (px > rx2 - aw) { + cx = rx2 - aw; + } else { + return true; + } if (py < ry1 + ah) { cy = ry1 + ah; - } else - if (py > ry2 - ah) { - cy = ry2 - ah; - } else { - return true; - } + } else if (py > ry2 - ah) { + cy = ry2 - ah; + } else { + return true; + } px = (px - cx) / aw; py = (py - cy) / ah; @@ -537,11 +625,7 @@ public abstract class RoundRectangle2D extends RectangularShape { double rx2 = rx + rw; double ry2 = ry + rh; - return - contains(rx1, ry1) && - contains(rx2, ry1) && - contains(rx2, ry2) && - contains(rx1, ry2); + return contains(rx1, ry1) && contains(rx2, ry1) && contains(rx2, ry2) && contains(rx1, ry2); } public PathIterator getPathIterator(AffineTransform at) { @@ -549,4 +633,3 @@ public abstract class RoundRectangle2D extends RectangularShape { } } - diff --git a/awt/java/awt/geom/package.html b/awt/java/awt/geom/package.html new file mode 100644 index 0000000000000000000000000000000000000000..e3a236ee34aaca6a53612e193f405b21030c5e71 --- /dev/null +++ b/awt/java/awt/geom/package.html @@ -0,0 +1,8 @@ + + +

    + This package contains classes and interfaces related to Java2D shapes and geometry. +

    + @since Android 1.0 + + diff --git a/awt/java/awt/im/InputContext.java b/awt/java/awt/im/InputContext.java index 3468474686cab4ccfe3465574519d5bf33960ffc..cce514842201697bec884119725adcb0083257e4 100644 --- a/awt/java/awt/im/InputContext.java +++ b/awt/java/awt/im/InputContext.java @@ -26,6 +26,12 @@ import java.util.Locale; import org.apache.harmony.awt.im.InputMethodContext; +/** + * This class is not supported in Android 1.0. It is merely provided to maintain + * interface compatibility with desktop Java implementations. + * + * @since Android 1.0 + */ public class InputContext { protected InputContext() { } diff --git a/awt/java/awt/im/InputMethodHighlight.java b/awt/java/awt/im/InputMethodHighlight.java index 53bb20bb642332b4d362f68fc1f0ba3870fe12cd..865d47c807012b3c4ebbb7fc4761c7c0b569a734 100644 --- a/awt/java/awt/im/InputMethodHighlight.java +++ b/awt/java/awt/im/InputMethodHighlight.java @@ -25,6 +25,12 @@ import java.awt.font.TextAttribute; import org.apache.harmony.awt.internal.nls.Messages; +/** + * This class is not supported in Android 1.0. It is merely provided to maintain + * interface compatibility with desktop Java implementations. + * + * @since Android 1.0 + */ public class InputMethodHighlight { public static final int RAW_TEXT = 0; diff --git a/awt/java/awt/im/InputMethodRequests.java b/awt/java/awt/im/InputMethodRequests.java index bdd25e610a3da287f6f0df1916648281ff811013..b12d397b5273d118268475dc73f1abcab7dd4614 100644 --- a/awt/java/awt/im/InputMethodRequests.java +++ b/awt/java/awt/im/InputMethodRequests.java @@ -24,6 +24,12 @@ import java.awt.Rectangle; import java.awt.font.TextHitInfo; import java.text.AttributedCharacterIterator; +/** + * This class is not supported in Android 1.0. It is merely provided to maintain + * interface compatibility with desktop Java implementations. + * + * @since Android 1.0 + */ public interface InputMethodRequests { public AttributedCharacterIterator cancelLatestCommittedText(AttributedCharacterIterator.Attribute[] attributes); diff --git a/awt/java/awt/im/InputSubset.java b/awt/java/awt/im/InputSubset.java index 02a1049684f38a72cc9699265ef15642ad7ddb01..708881eaee39a8327c339ff11fa111be51e70887 100644 --- a/awt/java/awt/im/InputSubset.java +++ b/awt/java/awt/im/InputSubset.java @@ -20,6 +20,12 @@ */ package java.awt.im; +/** + * This class is not supported in Android 1.0. It is merely provided to maintain + * interface compatibility with desktop Java implementations. + * + * @since Android 1.0 + */ public final class InputSubset extends Character.Subset { public static final InputSubset LATIN = new InputSubset("LATIN"); //$NON-NLS-1$ diff --git a/awt/java/awt/im/spi/InputMethod.java b/awt/java/awt/im/spi/InputMethod.java index 2c98c46cb35417f30322940e6cb23bf6fee819f7..67a88346c814f60eb5e0846cea46932775ff5d59 100644 --- a/awt/java/awt/im/spi/InputMethod.java +++ b/awt/java/awt/im/spi/InputMethod.java @@ -24,6 +24,12 @@ import java.awt.AWTEvent; import java.awt.Rectangle; import java.util.Locale; +/** + * This class is not supported in Android 1.0. It is merely provided to maintain + * interface compatibility with desktop Java implementations. + * + * @since Android 1.0 + */ public interface InputMethod { public void activate(); diff --git a/awt/java/awt/im/spi/InputMethodContext.java b/awt/java/awt/im/spi/InputMethodContext.java index ca33e879ec7a9def9a09e5b7f155d0657d78900e..bfc773cf05fae4874d905c5f32e9963098a72d59 100644 --- a/awt/java/awt/im/spi/InputMethodContext.java +++ b/awt/java/awt/im/spi/InputMethodContext.java @@ -26,6 +26,12 @@ import java.awt.im.InputMethodRequests; import java.text.AttributedCharacterIterator; //???AWT: import javax.swing.JFrame; +/** + * This class is not supported in Android 1.0. It is merely provided to maintain + * interface compatibility with desktop Java implementations. + * + * @since Android 1.0 + */ public interface InputMethodContext extends InputMethodRequests { // ???AWT: public JFrame createInputMethodJFrame(String title, boolean attachToInputContext); diff --git a/awt/java/awt/im/spi/InputMethodDescriptor.java b/awt/java/awt/im/spi/InputMethodDescriptor.java index 3068cac1b6771f91649372535541d56349f1cadd..c800bc1791e16611784ac14875c9d0ba80367c35 100644 --- a/awt/java/awt/im/spi/InputMethodDescriptor.java +++ b/awt/java/awt/im/spi/InputMethodDescriptor.java @@ -24,6 +24,12 @@ import java.awt.AWTException; import java.awt.Image; import java.util.Locale; +/** + * This class is not supported in Android 1.0. It is merely provided to maintain + * interface compatibility with desktop Java implementations. + * + * @since Android 1.0 + */ public interface InputMethodDescriptor { public Locale[] getAvailableLocales() throws AWTException; diff --git a/awt/java/awt/image/AffineTransformOp.java b/awt/java/awt/image/AffineTransformOp.java index 546837a48e1f57890e583159c28d268f059f2339..db25e1aeccbf27643f779a35cbf979861e2dc915 100644 --- a/awt/java/awt/image/AffineTransformOp.java +++ b/awt/java/awt/image/AffineTransformOp.java @@ -32,50 +32,60 @@ import org.apache.harmony.awt.gl.AwtImageBackdoorAccessor; import org.apache.harmony.awt.internal.nls.Messages; /** - * The AffineTransform class translates coordinates from 2D coordinates - * in the source image or Raster to 2D coordinates in the destination - * image or Raster using Affine transformation. The number of bands in - * the source Raster should equal to the number of bands in the destination - * Raster. + * The AffineTransform class translates coordinates from 2D coordinates in the + * source image or Raster to 2D coordinates in the destination image or Raster + * using affine transformation. The number of bands in the source Raster should + * equal to the number of bands in the destination Raster. + * + * @since Android 1.0 */ public class AffineTransformOp implements BufferedImageOp, RasterOp { - - /** - * The Constant TYPE_NEAREST_NEIGHBOR indicates nearest-neighbor - * interpolation type. + + /** + * The Constant TYPE_NEAREST_NEIGHBOR indicates nearest-neighbor + * interpolation type. */ public static final int TYPE_NEAREST_NEIGHBOR = 1; - - /** - * The Constant TYPE_BILINEAR indicates bilinear interpolation type. + + /** + * The Constant TYPE_BILINEAR indicates bilinear interpolation type. */ public static final int TYPE_BILINEAR = 2; - - /** The Constant TYPE_BICUBIC indicates bicubic interpolation type. */ + + /** + * The Constant TYPE_BICUBIC indicates bi-cubic interpolation type. + */ public static final int TYPE_BICUBIC = 3; - /** The i type. */ + /** + * The i type. + */ private int iType; // interpolation type - - /** The at. */ + + /** + * The at. + */ private AffineTransform at; - - /** The hints. */ + + /** + * The hints. + */ private RenderingHints hints; static { // TODO - uncomment - //System.loadLibrary("imageops"); + // System.loadLibrary("imageops"); } /** - * Instantiates a new AffineTransformOp with the specified - * AffineTransform and RenderingHints object which defines - * the interpolation type. + * Instantiates a new AffineTransformOp with the specified AffineTransform + * and RenderingHints object which defines the interpolation type. * - * @param xform the AffineTransform. - * @param hints the RenderingHints object which defines - * the interpolation type. + * @param xform + * the AffineTransform. + * @param hints + * the RenderingHints object which defines the interpolation + * type. */ public AffineTransformOp(AffineTransform xform, RenderingHints hints) { this(xform, TYPE_NEAREST_NEIGHBOR); @@ -95,20 +105,22 @@ public class AffineTransformOp implements BufferedImageOp, RasterOp { // Determine from rendering quality if (hint == RenderingHints.VALUE_RENDER_QUALITY) { this.iType = TYPE_BILINEAR; - // For speed use nearest neighbor + // For speed use nearest neighbor } } } } /** - * Instantiates a new AffineTransformOp with the specified - * AffineTransform and a specified interpolation type from the - * list of predefined interpolation types. + * Instantiates a new AffineTransformOp with the specified AffineTransform + * and a specified interpolation type from the list of predefined + * interpolation types. * - * @param xform the AffineTransform. - * @param interp the one of predefined interpolation types: - * TYPE_NEAREST_NEIGHBOR, TYPE_BILINEAR, or TYPE_BICUBIC. + * @param xform + * the AffineTransform. + * @param interp + * the one of predefined interpolation types: + * TYPE_NEAREST_NEIGHBOR, TYPE_BILINEAR, or TYPE_BICUBIC. */ public AffineTransformOp(AffineTransform xform, int interp) { if (Math.abs(xform.getDeterminant()) <= Double.MIN_VALUE) { @@ -116,7 +128,7 @@ public class AffineTransformOp implements BufferedImageOp, RasterOp { throw new ImagingOpException(Messages.getString("awt.24F", xform)); //$NON-NLS-1$ } - this.at = (AffineTransform) xform.clone(); + this.at = (AffineTransform)xform.clone(); if (interp != TYPE_NEAREST_NEIGHBOR && interp != TYPE_BILINEAR && interp != TYPE_BICUBIC) { // awt.250=Unknown interpolation type: {0} @@ -129,7 +141,7 @@ public class AffineTransformOp implements BufferedImageOp, RasterOp { /** * Gets the interpolation type. * - * @return the interpolation type + * @return the interpolation type. */ public final int getInterpolationType() { return iType; @@ -165,7 +177,7 @@ public class AffineTransformOp implements BufferedImageOp, RasterOp { * @return the AffineTransform. */ public final AffineTransform getTransform() { - return (AffineTransform) at.clone(); + return (AffineTransform)at.clone(); } public final Point2D getPoint2D(Point2D srcPt, Point2D dstPt) { @@ -177,21 +189,19 @@ public class AffineTransformOp implements BufferedImageOp, RasterOp { } public final Rectangle2D getBounds2D(Raster src) { - // We position source raster to (0,0) even if it is translated child raster. + // We position source raster to (0,0) even if it is translated child + // raster. // This means that we need only width and height of the src int width = src.getWidth(); int height = src.getHeight(); float[] corners = { - 0, 0, - width, 0, - width, height, - 0, height + 0, 0, width, 0, width, height, 0, height }; at.transform(corners, 0, corners, 0, 4); - Rectangle2D.Float bounds = new Rectangle2D.Float(corners[0], corners[1], 0 , 0); + Rectangle2D.Float bounds = new Rectangle2D.Float(corners[0], corners[1], 0, 0); bounds.add(corners[2], corners[3]); bounds.add(corners[4], corners[5]); bounds.add(corners[6], corners[7]); @@ -208,17 +218,14 @@ public class AffineTransformOp implements BufferedImageOp, RasterOp { double dstHeight = newBounds.getY() + newBounds.getHeight(); if (dstWidth <= 0 || dstHeight <= 0) { - // awt.251=Transformed width ({0}) and height ({1}) should be greater than 0 - throw new RasterFormatException( - Messages.getString("awt.251", dstWidth, dstHeight)); //$NON-NLS-1$ + // awt.251=Transformed width ({0}) and height ({1}) should be + // greater than 0 + throw new RasterFormatException(Messages.getString("awt.251", dstWidth, dstHeight)); //$NON-NLS-1$ } if (destCM != null) { - return new BufferedImage(destCM, - destCM.createCompatibleWritableRaster((int)dstWidth, (int)dstHeight), - destCM.isAlphaPremultiplied(), - null - ); + return new BufferedImage(destCM, destCM.createCompatibleWritableRaster((int)dstWidth, + (int)dstHeight), destCM.isAlphaPremultiplied(), null); } ColorModel cm = src.getColorModel(); @@ -229,23 +236,18 @@ public class AffineTransformOp implements BufferedImageOp, RasterOp { } // OK, we can get source color model - return new BufferedImage(cm, - src.getRaster().createCompatibleWritableRaster((int)dstWidth, (int)dstHeight), - cm.isAlphaPremultiplied(), - null - ); + return new BufferedImage(cm, src.getRaster().createCompatibleWritableRaster((int)dstWidth, + (int)dstHeight), cm.isAlphaPremultiplied(), null); } - public WritableRaster createCompatibleDestRaster (Raster src) { + public WritableRaster createCompatibleDestRaster(Raster src) { // Here approach is other then in createCompatibleDestImage - // destination should include only // transformed image, but not (0,0) in source coordinate system Rectangle2D newBounds = getBounds2D(src); - return src.createCompatibleWritableRaster( - (int) newBounds.getX(), (int) newBounds.getY(), - (int) newBounds.getWidth(), (int)newBounds.getHeight() - ); + return src.createCompatibleWritableRaster((int)newBounds.getX(), (int)newBounds.getY(), + (int)newBounds.getWidth(), (int)newBounds.getHeight()); } public final BufferedImage filter(BufferedImage src, BufferedImage dst) { @@ -257,10 +259,8 @@ public class AffineTransformOp implements BufferedImageOp, RasterOp { ColorModel srcCM = src.getColorModel(); BufferedImage finalDst = null; - if ( - srcCM instanceof IndexColorModel && - (iType != TYPE_NEAREST_NEIGHBOR || srcCM.getPixelSize() % 8 != 0) - ) { + if (srcCM instanceof IndexColorModel + && (iType != TYPE_NEAREST_NEIGHBOR || srcCM.getPixelSize() % 8 != 0)) { src = ((IndexColorModel)srcCM).convertToIntDiscrete(src.getRaster(), true); srcCM = src.getColorModel(); } @@ -269,15 +269,10 @@ public class AffineTransformOp implements BufferedImageOp, RasterOp { dst = createCompatibleDestImage(src, srcCM); } else { if (!srcCM.equals(dst.getColorModel())) { - // Treat BufferedImage.TYPE_INT_RGB and BufferedImage.TYPE_INT_ARGB as same - if ( - !( - (src.getType() == BufferedImage.TYPE_INT_RGB || - src.getType() == BufferedImage.TYPE_INT_ARGB) && - (dst.getType() == BufferedImage.TYPE_INT_RGB || - dst.getType() == BufferedImage.TYPE_INT_ARGB) - ) - ) { + // Treat BufferedImage.TYPE_INT_RGB and + // BufferedImage.TYPE_INT_ARGB as same + if (!((src.getType() == BufferedImage.TYPE_INT_RGB || src.getType() == BufferedImage.TYPE_INT_ARGB) && (dst + .getType() == BufferedImage.TYPE_INT_RGB || dst.getType() == BufferedImage.TYPE_INT_ARGB))) { finalDst = dst; dst = createCompatibleDestImage(src, srcCM); } @@ -287,10 +282,11 @@ public class AffineTransformOp implements BufferedImageOp, RasterOp { // Skip alpha channel for TYPE_INT_RGB images if (slowFilter(src.getRaster(), dst.getRaster()) != 0) { // awt.21F=Unable to transform source - throw new ImagingOpException (Messages.getString("awt.21F")); //$NON-NLS-1$ - // TODO - uncomment - //if (ippFilter(src.getRaster(), dst.getRaster(), src.getType()) != 0) - //throw new ImagingOpException ("Unable to transform source"); + throw new ImagingOpException(Messages.getString("awt.21F")); //$NON-NLS-1$ + // TODO - uncomment + // if (ippFilter(src.getRaster(), dst.getRaster(), src.getType()) != + // 0) + // throw new ImagingOpException ("Unable to transform source"); } if (finalDst != null) { @@ -320,9 +316,9 @@ public class AffineTransformOp implements BufferedImageOp, RasterOp { if (slowFilter(src, dst) != 0) { // awt.21F=Unable to transform source throw new ImagingOpException(Messages.getString("awt.21F")); //$NON-NLS-1$ - // TODO - uncomment - //if (ippFilter(src, dst, BufferedImage.TYPE_CUSTOM) != 0) - // throw new ImagingOpException("Unable to transform source"); + // TODO - uncomment + // if (ippFilter(src, dst, BufferedImage.TYPE_CUSTOM) != 0) + // throw new ImagingOpException("Unable to transform source"); } return dst; @@ -332,11 +328,13 @@ public class AffineTransformOp implements BufferedImageOp, RasterOp { /** * Ipp filter. * - * @param src the src - * @param dst the dst - * @param imageType the image type - * - * @return the int + * @param src + * the src. + * @param dst + * the dst. + * @param imageType + * the image type. + * @return the int. */ @SuppressWarnings("unused") private int ippFilter(Raster src, WritableRaster dst, int imageType) { @@ -349,8 +347,8 @@ public class AffineTransformOp implements BufferedImageOp, RasterOp { case BufferedImage.TYPE_INT_RGB: case BufferedImage.TYPE_INT_BGR: { channels = 4; - srcStride = src.getWidth()*4; - dstStride = dst.getWidth()*4; + srcStride = src.getWidth() * 4; + dstStride = dst.getWidth() * 4; skipChannel = true; break; } @@ -360,8 +358,8 @@ public class AffineTransformOp implements BufferedImageOp, RasterOp { case BufferedImage.TYPE_4BYTE_ABGR: case BufferedImage.TYPE_4BYTE_ABGR_PRE: { channels = 4; - srcStride = src.getWidth()*4; - dstStride = dst.getWidth()*4; + srcStride = src.getWidth() * 4; + dstStride = dst.getWidth() * 4; break; } @@ -375,12 +373,13 @@ public class AffineTransformOp implements BufferedImageOp, RasterOp { case BufferedImage.TYPE_3BYTE_BGR: { channels = 3; - srcStride = src.getWidth()*3; - dstStride = dst.getWidth()*3; + srcStride = src.getWidth() * 3; + dstStride = dst.getWidth() * 3; break; } - case BufferedImage.TYPE_USHORT_GRAY: // TODO - could be done in native code? + case BufferedImage.TYPE_USHORT_GRAY: // TODO - could be done in + // native code? case BufferedImage.TYPE_USHORT_565_RGB: case BufferedImage.TYPE_USHORT_555_RGB: case BufferedImage.TYPE_BYTE_BINARY: { @@ -391,34 +390,29 @@ public class AffineTransformOp implements BufferedImageOp, RasterOp { SampleModel srcSM = src.getSampleModel(); SampleModel dstSM = dst.getSampleModel(); - if ( - srcSM instanceof PixelInterleavedSampleModel && - dstSM instanceof PixelInterleavedSampleModel - ) { + if (srcSM instanceof PixelInterleavedSampleModel + && dstSM instanceof PixelInterleavedSampleModel) { // Check PixelInterleavedSampleModel - if ( - srcSM.getDataType() != DataBuffer.TYPE_BYTE || - dstSM.getDataType() != DataBuffer.TYPE_BYTE - ) { + if (srcSM.getDataType() != DataBuffer.TYPE_BYTE + || dstSM.getDataType() != DataBuffer.TYPE_BYTE) { return slowFilter(src, dst); } - channels = srcSM.getNumBands(); // Have IPP functions for 1, 3 and 4 channels + channels = srcSM.getNumBands(); // Have IPP functions for 1, + // 3 and 4 channels if (channels != 1 && channels != 3 && channels != 4) { return slowFilter(src, dst); } int dataTypeSize = DataBuffer.getDataTypeSize(srcSM.getDataType()) / 8; - srcStride = ((ComponentSampleModel) srcSM).getScanlineStride() * dataTypeSize; - dstStride = ((ComponentSampleModel) dstSM).getScanlineStride() * dataTypeSize; - } else if ( - srcSM instanceof SinglePixelPackedSampleModel && - dstSM instanceof SinglePixelPackedSampleModel - ) { + srcStride = ((ComponentSampleModel)srcSM).getScanlineStride() * dataTypeSize; + dstStride = ((ComponentSampleModel)dstSM).getScanlineStride() * dataTypeSize; + } else if (srcSM instanceof SinglePixelPackedSampleModel + && dstSM instanceof SinglePixelPackedSampleModel) { // Check SinglePixelPackedSampleModel - SinglePixelPackedSampleModel sppsm1 = (SinglePixelPackedSampleModel) srcSM; - SinglePixelPackedSampleModel sppsm2 = (SinglePixelPackedSampleModel) dstSM; + SinglePixelPackedSampleModel sppsm1 = (SinglePixelPackedSampleModel)srcSM; + SinglePixelPackedSampleModel sppsm2 = (SinglePixelPackedSampleModel)dstSM; // No IPP function for this type if (sppsm1.getDataType() == DataBuffer.TYPE_USHORT) { @@ -432,15 +426,13 @@ public class AffineTransformOp implements BufferedImageOp, RasterOp { } // Check compatibility of sample models - if ( - sppsm1.getDataType() != sppsm2.getDataType() || - !Arrays.equals(sppsm1.getBitOffsets(), sppsm2.getBitOffsets()) || - !Arrays.equals(sppsm1.getBitMasks(), sppsm2.getBitMasks()) - ) { + if (sppsm1.getDataType() != sppsm2.getDataType() + || !Arrays.equals(sppsm1.getBitOffsets(), sppsm2.getBitOffsets()) + || !Arrays.equals(sppsm1.getBitMasks(), sppsm2.getBitMasks())) { return slowFilter(src, dst); } - for (int i=0; i> 8; int py = sy >> 8; if (px >= minSrcX && py >= minSrcY && px < maxSrcX && py < maxSrcY) { - Object val = src.getDataElements(px , py , null); + Object val = src.getDataElements(px, py, null); dst.setDataElements(x, y, val); } sx += hx; @@ -585,33 +573,46 @@ public class AffineTransformOp implements BufferedImageOp, RasterOp { /** * Ipp affine transform. * - * @param m00 the m00 - * @param m01 the m01 - * @param m02 the m02 - * @param m10 the m10 - * @param m11 the m11 - * @param m12 the m12 - * @param src the src - * @param srcWidth the src width - * @param srcHeight the src height - * @param srcStride the src stride - * @param dst the dst - * @param dstWidth the dst width - * @param dstHeight the dst height - * @param dstStride the dst stride - * @param iType the i type - * @param channels the channels - * @param skipChannel the skip channel - * @param offsets the offsets - * - * @return the int + * @param m00 + * the m00. + * @param m01 + * the m01. + * @param m02 + * the m02. + * @param m10 + * the m10. + * @param m11 + * the m11. + * @param m12 + * the m12. + * @param src + * the src. + * @param srcWidth + * the src width. + * @param srcHeight + * the src height. + * @param srcStride + * the src stride. + * @param dst + * the dst. + * @param dstWidth + * the dst width. + * @param dstHeight + * the dst height. + * @param dstStride + * the dst stride. + * @param iType + * the i type. + * @param channels + * the channels. + * @param skipChannel + * the skip channel. + * @param offsets + * the offsets. + * @return the int. */ - private native int ippAffineTransform( - double m00, double m01, - double m02, double m10, - double m11, double m12, - Object src, int srcWidth, int srcHeight, int srcStride, - Object dst, int dstWidth, int dstHeight, int dstStride, - int iType, int channels, boolean skipChannel, - int offsets[]); + private native int ippAffineTransform(double m00, double m01, double m02, double m10, + double m11, double m12, Object src, int srcWidth, int srcHeight, int srcStride, + Object dst, int dstWidth, int dstHeight, int dstStride, int iType, int channels, + boolean skipChannel, int offsets[]); } \ No newline at end of file diff --git a/awt/java/awt/image/AreaAveragingScaleFilter.java b/awt/java/awt/image/AreaAveragingScaleFilter.java index f4933db67b19cf856c69ad0a180f9cf10b973bd9..7fb138e7fa22547bf3c04b8834fa539fc5ddae46 100644 --- a/awt/java/awt/image/AreaAveragingScaleFilter.java +++ b/awt/java/awt/image/AreaAveragingScaleFilter.java @@ -18,72 +18,101 @@ * @author Igor V. Stolyarov * @version $Revision$ */ + package java.awt.image; import java.util.Arrays; - /** - * The AreaAveragingScaleFilter class scales the source image using - * area averaging algorithm. This algorithm provides a source image - * with a new image containing the resampled image. + * The AreaAveragingScaleFilter class scales the source image using area + * averaging algorithm. This algorithm provides a source image with a new image + * containing the resampled image. + * + * @since Android 1.0 */ public class AreaAveragingScaleFilter extends ReplicateScaleFilter { - /** The Constant rgbCM. */ + /** + * The Constant rgbCM. + */ private static final ColorModel rgbCM = ColorModel.getRGBdefault(); - - /** The Constant averagingFlags. */ - private static final int averagingFlags = (ImageConsumer.TOPDOWNLEFTRIGHT | - ImageConsumer.COMPLETESCANLINES); - - /** The reset. */ - private boolean reset = true; // Flag for used superclass filter - - /** The inited. */ + + /** + * The Constant averagingFlags. + */ + private static final int averagingFlags = (ImageConsumer.TOPDOWNLEFTRIGHT | ImageConsumer.COMPLETESCANLINES); + + /** + * The reset. + */ + private boolean reset = true; // Flag for used superclass filter + + /** + * The inited. + */ private boolean inited = false; // All data inited - /** The sum_r. */ + /** + * The sum_r. + */ private int sum_r[]; // Array for average Red samples - - /** The sum_g. */ + + /** + * The sum_g. + */ private int sum_g[]; // Array for average Green samples - - /** The sum_b. */ + + /** + * The sum_b. + */ private int sum_b[]; // Array for average Blue samples - - /** The sum_a. */ + + /** + * The sum_a. + */ private int sum_a[]; // Array for average Alpha samples - /** The buff. */ - private int buff[]; // Stride buffer - - /** The avg factor. */ - private int avgFactor; // Global averaging factor - - /** The cached dy. */ - private int cachedDY; // Cached number of the destination scanline - - /** The cached dv rest. */ - private int cachedDVRest; // Cached value of rest src scanlines for sum - // pixel samples - // Because data if transfering by whole scanlines - // we are caching only Y coordinate values - /** - * Instantiates a new AreaAveragingScaleFilter object which scales - * a source image with the specified width and height. + * The buff. + */ + private int buff[]; // Stride buffer + + /** + * The avg factor. + */ + private int avgFactor; // Global averaging factor + + /** + * The cached dy. + */ + private int cachedDY; // Cached number of the destination scanline + + /** + * The cached dv rest. + */ + private int cachedDVRest; // Cached value of rest src scanlines for sum + + // pixel samples + // Because data if transferring by whole scanlines + // we are caching only Y coordinate values + + /** + * Instantiates a new AreaAveragingScaleFilter object which scales a source + * image with the specified width and height. * - * @param width the scaled width of the image. - * @param height the scaled height of the image. + * @param width + * the scaled width of the image. + * @param height + * the scaled height of the image. */ public AreaAveragingScaleFilter(int width, int height) { super(width, height); } @Override - public void setPixels(int x, int y, int w, int h, ColorModel model, int[] pixels, int off, int scansize) { - if(reset) { + public void setPixels(int x, int y, int w, int h, ColorModel model, int[] pixels, int off, + int scansize) { + if (reset) { super.setPixels(x, y, w, h, model, pixels, off, scansize); } else { setFilteredPixels(x, y, w, h, model, pixels, off, scansize); @@ -91,8 +120,9 @@ public class AreaAveragingScaleFilter extends ReplicateScaleFilter { } @Override - public void setPixels(int x, int y, int w, int h, ColorModel model, byte[] pixels, int off, int scansize) { - if(reset) { + public void setPixels(int x, int y, int w, int h, ColorModel model, byte[] pixels, int off, + int scansize) { + if (reset) { super.setPixels(x, y, w, h, model, pixels, off, scansize); } else { setFilteredPixels(x, y, w, h, model, pixels, off, scansize); @@ -106,37 +136,44 @@ public class AreaAveragingScaleFilter extends ReplicateScaleFilter { } /** - * This method implements the Area Averaging Scale filter. - * The description of algorithm is presented in Java API Specification. - * - * Arrays sum_r, sum_g, sum_b, sum_a have length equals width of destination - * image. In each array's element is accumulating pixel's component values, - * proportional to the area which source pixels will occupy in destination - * image. Then that values will divide by Global averaging - * factor (area of the destination image) for receiving - * average values of destination pixels. + * This method implements the Area Averaging Scale filter. The description + * of algorithm is presented in Java API Specification. Arrays sum_r, sum_g, + * sum_b, sum_a have length equals width of destination image. In each + * array's element is accumulating pixel's component values, proportional to + * the area which source pixels will occupy in destination image. Then that + * values will divide by Global averaging factor (area of the destination + * image) for receiving average values of destination pixels. * - * @param x - Src pixels X coordinate - * @param y - Src pixels Y coordinate - * @param w - width of the area of Src pixels - * @param h - height of the area of Src pixels - * @param model - Color Model of Src pixels - * @param pixels - array of Src pixels - * @param off - offset into the Src pixels array - * @param scansize - length of scanline in the pixels array + * @param x + * the source pixels X coordinate. + * @param y + * the source pixels Y coordinate. + * @param w + * the width of the area of the source pixels. + * @param h + * the height of the area of the source pixels. + * @param model + * the color model of the source pixels. + * @param pixels + * the array of source pixels. + * @param off + * the offset into the source pixels array. + * @param scansize + * the length of scanline in the pixels array. */ - private void setFilteredPixels(int x, int y, int w, int h, ColorModel model, Object pixels, int off, int scansize){ - if(!inited){ + private void setFilteredPixels(int x, int y, int w, int h, ColorModel model, Object pixels, + int off, int scansize) { + if (!inited) { initialize(); } int srcX, srcY, dx, dy; int svRest, dvRest, shRest, dhRest, vDif, hDif; - if(y == 0){ + if (y == 0) { dy = 0; dvRest = srcHeight; - }else{ + } else { dy = cachedDY; dvRest = cachedDVRest; } @@ -166,9 +203,9 @@ public class AreaAveragingScaleFilter extends ReplicateScaleFilter { int rgb, pix; if (pixels instanceof int[]) { - pix = ((int[]) pixels)[srcOff + srcX]; + pix = ((int[])pixels)[srcOff + srcX]; } else { - pix = ((byte[]) pixels)[srcOff + srcX] & 0xff; + pix = ((byte[])pixels)[srcOff + srcX] & 0xff; } rgb = model.getRGB(pix); @@ -208,7 +245,7 @@ public class AreaAveragingScaleFilter extends ReplicateScaleFilter { if (dvRest == 0) { // averaging destination pixel's values - for(int i = 0; i < destWidth; i++){ + for (int i = 0; i < destWidth; i++) { int a = (sum_a[i] / avgFactor) & 0xff; int r = (sum_r[i] / avgFactor) & 0xff; int g = (sum_g[i] / avgFactor) & 0xff; @@ -216,8 +253,7 @@ public class AreaAveragingScaleFilter extends ReplicateScaleFilter { int frgb = (a << 24) | (r << 16) | (g << 8) | b; buff[i] = frgb; } - consumer.setPixels(0, dy, destWidth, 1, rgbCM, buff, 0, - destWidth); + consumer.setPixels(0, dy, destWidth, 1, rgbCM, buff, 0, destWidth); dy++; dvRest = srcHeight; Arrays.fill(sum_a, 0); @@ -236,18 +272,17 @@ public class AreaAveragingScaleFilter extends ReplicateScaleFilter { /** * Initialization of the auxiliary data. */ - private void initialize(){ + private void initialize() { - sum_a = new int[destWidth]; - sum_r = new int[destWidth]; - sum_g = new int[destWidth]; - sum_b = new int[destWidth]; + sum_a = new int[destWidth]; + sum_r = new int[destWidth]; + sum_g = new int[destWidth]; + sum_b = new int[destWidth]; - buff = new int[destWidth]; + buff = new int[destWidth]; outpixbuf = buff; - avgFactor = srcWidth * srcHeight; + avgFactor = srcWidth * srcHeight; inited = true; } } - diff --git a/awt/java/awt/image/AwtImageBackdoorAccessorImpl.java b/awt/java/awt/image/AwtImageBackdoorAccessorImpl.java index ce85ddda4b2d0cc24fddf8f4f2fdf1d0811d4990..6dffee88f61d5e5ab0f02bada39d90394f17605b 100644 --- a/awt/java/awt/image/AwtImageBackdoorAccessorImpl.java +++ b/awt/java/awt/image/AwtImageBackdoorAccessorImpl.java @@ -20,6 +20,7 @@ * Created on 23.11.2005 * */ + package java.awt.image; import java.awt.Image; @@ -40,41 +41,43 @@ import org.apache.harmony.awt.internal.nls.Messages; /** * This class not part of public API. It useful for receiving package private * data from other packages. + * + * @since Android 1.0 */ class AwtImageBackdoorAccessorImpl extends AwtImageBackdoorAccessor { - static void init(){ + static void init() { inst = new AwtImageBackdoorAccessorImpl(); } @Override public Surface getImageSurface(Image image) { - if (image instanceof BufferedImage){ + if (image instanceof BufferedImage) { return ((BufferedImage)image).getImageSurface(); - } else if (image instanceof GLVolatileImage){ + } else if (image instanceof GLVolatileImage) { return ((GLVolatileImage)image).getImageSurface(); } return null; } @Override - public boolean isGrayPallete(IndexColorModel icm){ + public boolean isGrayPallete(IndexColorModel icm) { return icm.isGrayPallete(); } @Override public Object getData(DataBuffer db) { - if (db instanceof DataBufferByte){ + if (db instanceof DataBufferByte) { return ((DataBufferByte)db).getData(); - } else if (db instanceof DataBufferUShort){ + } else if (db instanceof DataBufferUShort) { return ((DataBufferUShort)db).getData(); - } else if (db instanceof DataBufferShort){ + } else if (db instanceof DataBufferShort) { return ((DataBufferShort)db).getData(); - } else if (db instanceof DataBufferInt){ + } else if (db instanceof DataBufferInt) { return ((DataBufferInt)db).getData(); - } else if (db instanceof DataBufferFloat){ + } else if (db instanceof DataBufferFloat) { return ((DataBufferFloat)db).getData(); - } else if (db instanceof DataBufferDouble){ + } else if (db instanceof DataBufferDouble) { return ((DataBufferDouble)db).getData(); } else { // awt.235=Wrong Data Buffer type : {0} @@ -85,7 +88,7 @@ class AwtImageBackdoorAccessorImpl extends AwtImageBackdoorAccessor { @Override public int[] getDataInt(DataBuffer db) { - if (db instanceof DataBufferInt){ + if (db instanceof DataBufferInt) { return ((DataBufferInt)db).getData(); } return null; @@ -93,7 +96,7 @@ class AwtImageBackdoorAccessorImpl extends AwtImageBackdoorAccessor { @Override public byte[] getDataByte(DataBuffer db) { - if (db instanceof DataBufferByte){ + if (db instanceof DataBufferByte) { return ((DataBufferByte)db).getData(); } return null; @@ -101,7 +104,7 @@ class AwtImageBackdoorAccessorImpl extends AwtImageBackdoorAccessor { @Override public short[] getDataShort(DataBuffer db) { - if (db instanceof DataBufferShort){ + if (db instanceof DataBufferShort) { return ((DataBufferShort)db).getData(); } return null; @@ -109,7 +112,7 @@ class AwtImageBackdoorAccessorImpl extends AwtImageBackdoorAccessor { @Override public short[] getDataUShort(DataBuffer db) { - if (db instanceof DataBufferUShort){ + if (db instanceof DataBufferUShort) { return ((DataBufferUShort)db).getData(); } return null; @@ -117,7 +120,7 @@ class AwtImageBackdoorAccessorImpl extends AwtImageBackdoorAccessor { @Override public double[] getDataDouble(DataBuffer db) { - if (db instanceof DataBufferDouble){ + if (db instanceof DataBufferDouble) { return ((DataBufferDouble)db).getData(); } return null; @@ -125,7 +128,7 @@ class AwtImageBackdoorAccessorImpl extends AwtImageBackdoorAccessor { @Override public float[] getDataFloat(DataBuffer db) { - if (db instanceof DataBufferFloat){ + if (db instanceof DataBufferFloat) { return ((DataBufferFloat)db).getData(); } return null; diff --git a/awt/java/awt/image/BandCombineOp.java b/awt/java/awt/image/BandCombineOp.java index cd77a21ff8286b87087d4bbebade3a977f11918d..da2cc8944df8463b80e366eeab056f4dfcf2515b 100644 --- a/awt/java/awt/image/BandCombineOp.java +++ b/awt/java/awt/image/BandCombineOp.java @@ -32,82 +32,124 @@ import org.apache.harmony.awt.gl.AwtImageBackdoorAccessor; import org.apache.harmony.awt.internal.nls.Messages; /** - * The BandCombineOp class translates coordinates from - * coordinates in the source Raster to coordinates in - * the destination Raster by an arbitrary linear combination - * of the bands in a source Raster, using a specified matrix. - * The number of bands in the matrix should equal to - * the number of bands in the source Raster plus 1. + * The BandCombineOp class translates coordinates from coordinates in the source + * Raster to coordinates in the destination Raster by an arbitrary linear + * combination of the bands in a source Raster, using a specified matrix. The + * number of bands in the matrix should equal to the number of bands in the + * source Raster plus 1. + * + * @since Android 1.0 */ public class BandCombineOp implements RasterOp { - - /** The Constant offsets3c. */ - static final int offsets3c[] = {16, 8, 0}; - - /** The Constant offsets4ac. */ - static final int offsets4ac[] = {16, 8, 0, 24}; - - /** The Constant masks3c. */ - static final int masks3c[] = {0xFF0000, 0xFF00, 0xFF}; - - /** The Constant masks4ac. */ - static final int masks4ac[] = {0xFF0000, 0xFF00, 0xFF, 0xFF000000}; - - /** The Constant piOffsets. */ - private static final int piOffsets[] = {0, 1, 2}; - - /** The Constant piInvOffsets. */ - private static final int piInvOffsets[] = {2, 1, 0}; - - /** The Constant TYPE_BYTE3C. */ + + /** + * The Constant offsets3c. + */ + static final int offsets3c[] = { + 16, 8, 0 + }; + + /** + * The Constant offsets4ac. + */ + static final int offsets4ac[] = { + 16, 8, 0, 24 + }; + + /** + * The Constant masks3c. + */ + static final int masks3c[] = { + 0xFF0000, 0xFF00, 0xFF + }; + + /** + * The Constant masks4ac. + */ + static final int masks4ac[] = { + 0xFF0000, 0xFF00, 0xFF, 0xFF000000 + }; + + /** + * The Constant piOffsets. + */ + private static final int piOffsets[] = { + 0, 1, 2 + }; + + /** + * The Constant piInvOffsets. + */ + private static final int piInvOffsets[] = { + 2, 1, 0 + }; + + /** + * The Constant TYPE_BYTE3C. + */ private static final int TYPE_BYTE3C = 0; - - /** The Constant TYPE_BYTE4AC. */ + + /** + * The Constant TYPE_BYTE4AC. + */ private static final int TYPE_BYTE4AC = 1; - - /** The Constant TYPE_USHORT3C. */ + + /** + * The Constant TYPE_USHORT3C. + */ private static final int TYPE_USHORT3C = 2; - - /** The Constant TYPE_SHORT3C. */ + + /** + * The Constant TYPE_SHORT3C. + */ private static final int TYPE_SHORT3C = 3; - /** The mx width. */ + /** + * The mx width. + */ private int mxWidth; - - /** The mx height. */ + + /** + * The mx height. + */ private int mxHeight; - - /** The matrix. */ + + /** + * The matrix. + */ private float matrix[][]; - - /** The r hints. */ + + /** + * The r hints. + */ private RenderingHints rHints; static { // XXX - todo - //System.loadLibrary("imageops"); + // System.loadLibrary("imageops"); } /** - * Instantiates a new BandCombineOp object with the specified - * matrix. + * Instantiates a new BandCombineOp object with the specified matrix. * - * @param matrix the specified matrix for band combining. - * @param hints the RenderingHints. + * @param matrix + * the specified matrix for band combining. + * @param hints + * the RenderingHints. */ public BandCombineOp(float matrix[][], RenderingHints hints) { this.mxHeight = matrix.length; this.mxWidth = matrix[0].length; this.matrix = new float[mxHeight][mxWidth]; - for (int i=0; i= dstInfo.channelsOrder.length) { continue; } - for (int i=0; i= srcInfo.channelsOrder.length) { break; } - reorderedMatrix[dstInfo.channelsOrder[j]*rmxWidth + srcInfo.channelsOrder[i]] = - matrix[j][i]; + reorderedMatrix[dstInfo.channelsOrder[j] * rmxWidth + srcInfo.channelsOrder[i]] = matrix[j][i]; } if (mxWidth == rmxWidth) { - reorderedMatrix[(dstInfo.channelsOrder[j]+1)*rmxWidth - 1] = matrix[j][mxWidth-1]; + reorderedMatrix[(dstInfo.channelsOrder[j] + 1) * rmxWidth - 1] = matrix[j][mxWidth - 1]; } } @@ -311,11 +365,9 @@ public class BandCombineOp implements RasterOp { return -1; // Unknown data buffer type } - simpleCombineBands( - srcData, src.getWidth(), src.getHeight(), srcInfo.stride, srcInfo.channels, - dstData, dstInfo.stride, dstInfo.channels, - reorderedMatrix, offsets - ); + simpleCombineBands(srcData, src.getWidth(), src.getHeight(), srcInfo.stride, + srcInfo.channels, dstData, dstInfo.stride, dstInfo.channels, reorderedMatrix, + offsets); return res; } @@ -323,10 +375,11 @@ public class BandCombineOp implements RasterOp { /** * Very slow filter. * - * @param src the src - * @param dst the dst - * - * @return the int + * @param src + * the src. + * @param dst + * the dst. + * @return the int. */ private int verySlowFilter(Raster src, WritableRaster dst) { int numBands = src.getNumBands(); @@ -337,33 +390,35 @@ public class BandCombineOp implements RasterOp { int dstMinX = dst.getMinX(); int dstY = dst.getMinY(); - int dX = src.getWidth();//< dst.getWidth() ? src.getWidth() : dst.getWidth(); - int dY = src.getHeight();//< dst.getHeight() ? src.getHeight() : dst.getHeight(); + int dX = src.getWidth();// < dst.getWidth() ? src.getWidth() : + // dst.getWidth(); + int dY = src.getHeight();// < dst.getHeight() ? src.getHeight() : + // dst.getHeight(); float sample; - int srcPixels[] = new int[numBands*dX*dY]; - int dstPixels[] = new int[mxHeight*dX*dY]; + int srcPixels[] = new int[numBands * dX * dY]; + int dstPixels[] = new int[mxHeight * dX * dY]; srcPixels = src.getPixels(srcMinX, srcY, dX, dY, srcPixels); if (numBands == mxWidth) { - for (int i=0, j=0; i numBands) { - // awt.64=The number of the bands in the subset is greater than the number of bands in the sample model + // awt.64=The number of the bands in the subset is greater than the + // number of bands in the sample model throw new RasterFormatException(Messages.getString("awt.64")); //$NON-NLS-1$ } @@ -141,94 +151,93 @@ public final class BandedSampleModel extends ComponentSampleModel { offsets[i] = bandOffsets[bands[i]]; } - return new BandedSampleModel(dataType, width, height, scanlineStride, - indices, offsets); + return new BandedSampleModel(dataType, width, height, scanlineStride, indices, offsets); } @Override public Object getDataElements(int x, int y, Object obj, DataBuffer data) { switch (dataType) { - case DataBuffer.TYPE_BYTE: { - byte bdata[]; + case DataBuffer.TYPE_BYTE: { + byte bdata[]; - if (obj == null) { - bdata = new byte[numBands]; - } else { - bdata = (byte[]) obj; - } + if (obj == null) { + bdata = new byte[numBands]; + } else { + bdata = (byte[])obj; + } - for (int i = 0; i < numBands; i++) { - bdata[i] = (byte) getSample(x, y, i, data); - } + for (int i = 0; i < numBands; i++) { + bdata[i] = (byte)getSample(x, y, i, data); + } - obj = bdata; - break; - } - case DataBuffer.TYPE_SHORT: - case DataBuffer.TYPE_USHORT: { - short sdata[]; - - if (obj == null) { - sdata = new short[numBands]; - } else { - sdata = (short[]) obj; + obj = bdata; + break; } + case DataBuffer.TYPE_SHORT: + case DataBuffer.TYPE_USHORT: { + short sdata[]; + + if (obj == null) { + sdata = new short[numBands]; + } else { + sdata = (short[])obj; + } - for (int i = 0; i < numBands; i++) { - sdata[i] = (short) getSample(x, y, i, data); + for (int i = 0; i < numBands; i++) { + sdata[i] = (short)getSample(x, y, i, data); + } + + obj = sdata; + break; } + case DataBuffer.TYPE_INT: { + int idata[]; - obj = sdata; - break; - } - case DataBuffer.TYPE_INT: { - int idata[]; + if (obj == null) { + idata = new int[numBands]; + } else { + idata = (int[])obj; + } - if (obj == null) { - idata = new int[numBands]; - } else { - idata = (int[]) obj; - } + for (int i = 0; i < numBands; i++) { + idata[i] = getSample(x, y, i, data); + } - for (int i = 0; i < numBands; i++) { - idata[i] = getSample(x, y, i, data); + obj = idata; + break; } + case DataBuffer.TYPE_FLOAT: { + float fdata[]; - obj = idata; - break; - } - case DataBuffer.TYPE_FLOAT: { - float fdata[]; + if (obj == null) { + fdata = new float[numBands]; + } else { + fdata = (float[])obj; + } - if (obj == null) { - fdata = new float[numBands]; - } else { - fdata = (float[]) obj; - } + for (int i = 0; i < numBands; i++) { + fdata[i] = getSampleFloat(x, y, i, data); + } - for (int i = 0; i < numBands; i++) { - fdata[i] = getSampleFloat(x, y, i, data); + obj = fdata; + break; } + case DataBuffer.TYPE_DOUBLE: { + double ddata[]; - obj = fdata; - break; - } - case DataBuffer.TYPE_DOUBLE: { - double ddata[]; + if (obj == null) { + ddata = new double[numBands]; + } else { + ddata = (double[])obj; + } - if (obj == null) { - ddata = new double[numBands]; - } else { - ddata = (double[]) obj; - } + for (int i = 0; i < numBands; i++) { + ddata[i] = getSampleDouble(x, y, i, data); + } - for (int i = 0; i < numBands; i++) { - ddata[i] = getSampleDouble(x, y, i, data); + obj = ddata; + break; } - - obj = ddata; - break; - } } return obj; @@ -257,8 +266,7 @@ public final class BandedSampleModel extends ComponentSampleModel { throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ } - return data.getElem(bankIndices[b], y * scanlineStride + x + - bandOffsets[b]); + return data.getElem(bankIndices[b], y * scanlineStride + x + bandOffsets[b]); } @Override @@ -268,8 +276,7 @@ public final class BandedSampleModel extends ComponentSampleModel { throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ } - return data.getElemDouble(bankIndices[b], y * scanlineStride + x + - bandOffsets[b]); + return data.getElemDouble(bankIndices[b], y * scanlineStride + x + bandOffsets[b]); } @Override @@ -279,13 +286,11 @@ public final class BandedSampleModel extends ComponentSampleModel { throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ } - return data.getElemFloat(bankIndices[b], y * scanlineStride + x + - bandOffsets[b]); + return data.getElemFloat(bankIndices[b], y * scanlineStride + x + bandOffsets[b]); } @Override - public int[] getSamples(int x, int y, int w, int h, int b, int iArray[], - DataBuffer data) { + public int[] getSamples(int x, int y, int w, int h, int b, int iArray[], DataBuffer data) { int samples[]; int idx = 0; @@ -317,41 +322,41 @@ public final class BandedSampleModel extends ComponentSampleModel { @Override public void setDataElements(int x, int y, Object obj, DataBuffer data) { switch (dataType) { - case DataBuffer.TYPE_BYTE: - byte bdata[] = (byte[]) obj; - for (int i = 0; i < numBands; i++) { - setSample(x, y, i, bdata[i] & 0xff, data); - } - break; + case DataBuffer.TYPE_BYTE: + byte bdata[] = (byte[])obj; + for (int i = 0; i < numBands; i++) { + setSample(x, y, i, bdata[i] & 0xff, data); + } + break; - case DataBuffer.TYPE_SHORT: - case DataBuffer.TYPE_USHORT: - short sdata[] = (short[]) obj; - for (int i = 0; i < numBands; i++) { - setSample(x, y, i, sdata[i] & 0xffff, data); - } - break; + case DataBuffer.TYPE_SHORT: + case DataBuffer.TYPE_USHORT: + short sdata[] = (short[])obj; + for (int i = 0; i < numBands; i++) { + setSample(x, y, i, sdata[i] & 0xffff, data); + } + break; - case DataBuffer.TYPE_INT: - int idata[] = (int[]) obj; - for (int i = 0; i < numBands; i++) { - setSample(x, y, i, idata[i], data); - } - break; + case DataBuffer.TYPE_INT: + int idata[] = (int[])obj; + for (int i = 0; i < numBands; i++) { + setSample(x, y, i, idata[i], data); + } + break; - case DataBuffer.TYPE_FLOAT: - float fdata[] = (float[]) obj; - for (int i = 0; i < numBands; i++) { - setSample(x, y, i, fdata[i], data); - } - break; + case DataBuffer.TYPE_FLOAT: + float fdata[] = (float[])obj; + for (int i = 0; i < numBands; i++) { + setSample(x, y, i, fdata[i], data); + } + break; - case DataBuffer.TYPE_DOUBLE: - double ddata[] = (double[]) obj; - for (int i = 0; i < numBands; i++) { - setSample(x, y, i, ddata[i], data); - } - break; + case DataBuffer.TYPE_DOUBLE: + double ddata[] = (double[])obj; + for (int i = 0; i < numBands; i++) { + setSample(x, y, i, ddata[i], data); + } + break; } } @@ -363,8 +368,7 @@ public final class BandedSampleModel extends ComponentSampleModel { } @Override - public void setPixels(int x, int y, int w, int h, int iArray[], - DataBuffer data) { + public void setPixels(int x, int y, int w, int h, int iArray[], DataBuffer data) { int idx = 0; for (int i = y; i < y + h; i++) { @@ -383,8 +387,7 @@ public final class BandedSampleModel extends ComponentSampleModel { throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ } - data.setElemDouble(bankIndices[b], y * scanlineStride + x + - bandOffsets[b], s); + data.setElemDouble(bankIndices[b], y * scanlineStride + x + bandOffsets[b], s); } @Override @@ -394,8 +397,7 @@ public final class BandedSampleModel extends ComponentSampleModel { throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ } - data.setElemFloat(bankIndices[b], y * scanlineStride + x + - bandOffsets[b], s); + data.setElemFloat(bankIndices[b], y * scanlineStride + x + bandOffsets[b], s); } @Override @@ -405,13 +407,11 @@ public final class BandedSampleModel extends ComponentSampleModel { throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ } - data.setElem(bankIndices[b], y * scanlineStride + x + - bandOffsets[b], s); + data.setElem(bankIndices[b], y * scanlineStride + x + bandOffsets[b], s); } @Override - public void setSamples(int x, int y, int w, int h, int b, int iArray[], - DataBuffer data) { + public void setSamples(int x, int y, int w, int h, int b, int iArray[], DataBuffer data) { int idx = 0; for (int i = y; i < y + h; i++) { @@ -423,4 +423,3 @@ public final class BandedSampleModel extends ComponentSampleModel { } } - diff --git a/awt/java/awt/image/BufferStrategy.java b/awt/java/awt/image/BufferStrategy.java index e0508f0cf1e59df03d56fa83cdec9ed879e1e879..3c8779dac990cd84a926d4e1646a52def4de0495 100644 --- a/awt/java/awt/image/BufferStrategy.java +++ b/awt/java/awt/image/BufferStrategy.java @@ -18,35 +18,37 @@ * @author Igor V. Stolyarov * @version $Revision$ */ + package java.awt.image; import java.awt.BufferCapabilities; import java.awt.Graphics; /** - * The BufferStrategy abstract class provides an opportunity - * to organize the buffers for a Canvas or Window. The BufferStrategy - * implementation depends on hardware and software limitations. - * These limitations are detectible through the capabilities - * object which can be obtained by the GraphicsConfiguration of the Canvas - * or Window. + * The BufferStrategy abstract class provides an opportunity to organize the + * buffers for a Canvas or Window. The BufferStrategy implementation depends on + * hardware and software limitations. These limitations are detectable through + * the capabilities object which can be obtained by the GraphicsConfiguration of + * the Canvas or Window. + * + * @since Android 1.0 */ public abstract class BufferStrategy { /** - * Returns true if the drawing buffer was lost since the last call - * of getDrawGraphics. + * Returns true if the drawing buffer was lost since the last call of + * getDrawGraphics. * - * @return true if the drawing buffer was lost since the last call - * of getDrawGraphics, false otherwise. + * @return true if the drawing buffer was lost since the last call of + * getDrawGraphics, false otherwise. */ public abstract boolean contentsLost(); /** - * Returns true if the drawing buffer is restored from a lost state. + * Returns true if the drawing buffer is restored from a lost state. * - * @return true if the drawing buffer is restored from a lost state, - * false otherwise. + * @return true if the drawing buffer is restored from a lost state, false + * otherwise. */ public abstract boolean contentsRestored(); diff --git a/awt/java/awt/image/BufferedImage.java b/awt/java/awt/image/BufferedImage.java index d305d660b946df3c8ca99b92f320e7f2720441e6..c9d58d97f2635f638c14737f30a3d418dfb6e7e2 100644 --- a/awt/java/awt/image/BufferedImage.java +++ b/awt/java/awt/image/BufferedImage.java @@ -18,6 +18,7 @@ * @author Igor V. Stolyarov * @version $Revision$ */ + package java.awt.image; import com.android.internal.awt.AndroidGraphics2D; @@ -39,184 +40,215 @@ import org.apache.harmony.awt.gl.Surface; import org.apache.harmony.awt.gl.image.BufferedImageSource; import org.apache.harmony.awt.internal.nls.Messages; - /** - * The BufferedImage class describes an Image which contains a buffer - * of image data and includes a ColorModel and a Raster for this data. - * This class provides methods for obtaining and setting the Raster - * and for manipulating the ColorModel parameters. + * The BufferedImage class describes an Image which contains a buffer of image + * data and includes a ColorModel and a Raster for this data. This class + * provides methods for obtaining and setting the Raster and for manipulating + * the ColorModel parameters. + * + * @since Android 1.0 */ -public class BufferedImage extends -Image implements WritableRenderedImage, Transparency{ +public class BufferedImage extends Image implements WritableRenderedImage, Transparency { - /** - * The Constant TYPE_CUSTOM indicates that Image type - * is unknown. + /** + * The Constant TYPE_CUSTOM indicates that Image type is unknown. */ public static final int TYPE_CUSTOM = 0; - /** - * The Constant TYPE_INT_RGB indicates an image with - * 8 bit RGB color components, it has a DirectColorModel - * without alpha. + /** + * The Constant TYPE_INT_RGB indicates an image with 8 bit RGB color + * components, it has a DirectColorModel without alpha. */ public static final int TYPE_INT_RGB = 1; - /** - * The Constant TYPE_INT_ARGB indicates an image with - * 8 bit RGBA color components, it has a DirectColorModel - * with alpha. + /** + * The Constant TYPE_INT_ARGB indicates an image with 8 bit RGBA color + * components, it has a DirectColorModel with alpha. */ public static final int TYPE_INT_ARGB = 2; - /** - * The Constant TYPE_INT_ARGB_PRE indicates an image with - * 8 bit RGBA color components, it has a DirectColorModel - * with alpha, and image data is premultiplied by alpha. + /** + * The Constant TYPE_INT_ARGB_PRE indicates an image with 8 bit RGBA color + * components, it has a DirectColorModel with alpha, and image data is + * pre-multiplied by alpha. */ public static final int TYPE_INT_ARGB_PRE = 3; - /** - * The Constant TYPE_INT_BGR indicates an image with - * 8 bit RGB color components, BGR color model - * (with the colors Blue, Green, and Red). There is no - * alpha. The image has a DirectColorModel. + /** + * The Constant TYPE_INT_BGR indicates an image with 8 bit RGB color + * components, BGR color model (with the colors Blue, Green, and Red). There + * is no alpha. The image has a DirectColorModel. */ public static final int TYPE_INT_BGR = 4; - /** - * The Constant TYPE_3BYTE_BGR indicates an image with - * 8 bit RGB color components, BGR color model - * (with the colors Blue, Green, and Red stored in 3 bytes). - * There is no alpha. The image has a ComponentColorModel. + /** + * The Constant TYPE_3BYTE_BGR indicates an image with 8 bit RGB color + * components, BGR color model (with the colors Blue, Green, and Red stored + * in 3 bytes). There is no alpha. The image has a ComponentColorModel. */ public static final int TYPE_3BYTE_BGR = 5; - /** - * The Constant TYPE_4BYTE_ABGR indicates an image with - * 8 bit RGBA color components stored in 3 bytes and 1 byte of alpha. - * It has a ComponentColorModel with alpha. + /** + * The Constant TYPE_4BYTE_ABGR indicates an image with 8 bit RGBA color + * components stored in 3 bytes and 1 byte of alpha. It has a + * ComponentColorModel with alpha. */ public static final int TYPE_4BYTE_ABGR = 6; - /** - * The Constant TYPE_4BYTE_ABGR_PRE indicates an image with - * 8 bit RGBA color components stored in 3 bytes and 1 byte - * for alpha. The image has a ComponentColorModel with alpha. - * The color data is premultiplied with alpha. + /** + * The Constant TYPE_4BYTE_ABGR_PRE indicates an image with 8 bit RGBA color + * components stored in 3 bytes and 1 byte for alpha. The image has a + * ComponentColorModel with alpha. The color data is pre-multiplied with + * alpha. */ public static final int TYPE_4BYTE_ABGR_PRE = 7; - /** - * The Constant TYPE_USHORT_565_RGB indicates an image with - * 565 RGB color components (5-bits red, 6-bits green, 5-bits blue) - * with no alpha. This image has a DirectColorModel. + /** + * The Constant TYPE_USHORT_565_RGB indicates an image with 565 RGB color + * components (5-bits red, 6-bits green, 5-bits blue) with no alpha. This + * image has a DirectColorModel. */ public static final int TYPE_USHORT_565_RGB = 8; - /** - * The Constant TYPE_USHORT_555_RGB indicates an image with - * 555 RGB color components (5-bits red, 5-bits green, 5-bits blue) - * with no alpha. This image has a DirectColorModel. + /** + * The Constant TYPE_USHORT_555_RGB indicates an image with 555 RGB color + * components (5-bits red, 5-bits green, 5-bits blue) with no alpha. This + * image has a DirectColorModel. */ public static final int TYPE_USHORT_555_RGB = 9; - /** - * The Constant TYPE_BYTE_GRAY indicates a unsigned byte - * image. This image has a ComponentColorModel with - * a CS_GRAY ColorSpace. + /** + * The Constant TYPE_BYTE_GRAY indicates a unsigned byte image. This image + * has a ComponentColorModel with a CS_GRAY ColorSpace. */ public static final int TYPE_BYTE_GRAY = 10; - /** - * The Constant TYPE_USHORT_GRAY indicates an unsigned short - * image. This image has a ComponentColorModel with a CS_GRAY - * ColorSpace. + /** + * The Constant TYPE_USHORT_GRAY indicates an unsigned short image. This + * image has a ComponentColorModel with a CS_GRAY ColorSpace. */ public static final int TYPE_USHORT_GRAY = 11; - /** - * The Constant TYPE_BYTE_BINARY indicates an opaque byte-packed - * 1, 2 or 4 bit image. The image has an IndexColorModel without - * alpha. + /** + * The Constant TYPE_BYTE_BINARY indicates an opaque byte-packed 1, 2 or 4 + * bit image. The image has an IndexColorModel without alpha. */ public static final int TYPE_BYTE_BINARY = 12; - /** - * The Constant TYPE_BYTE_INDEXED indicates an indexed byte image. + /** + * The Constant TYPE_BYTE_INDEXED indicates an indexed byte image. */ public static final int TYPE_BYTE_INDEXED = 13; - /** The Constant ALPHA_MASK. */ + /** + * The Constant ALPHA_MASK. + */ private static final int ALPHA_MASK = 0xff000000; - /** The Constant RED_MASK. */ + /** + * The Constant RED_MASK. + */ private static final int RED_MASK = 0x00ff0000; - /** The Constant GREEN_MASK. */ + /** + * The Constant GREEN_MASK. + */ private static final int GREEN_MASK = 0x0000ff00; - /** The Constant BLUE_MASK. */ + /** + * The Constant BLUE_MASK. + */ private static final int BLUE_MASK = 0x000000ff; - /** The Constant RED_BGR_MASK. */ + /** + * The Constant RED_BGR_MASK. + */ private static final int RED_BGR_MASK = 0x000000ff; - /** The Constant GREEN_BGR_MASK. */ + /** + * The Constant GREEN_BGR_MASK. + */ private static final int GREEN_BGR_MASK = 0x0000ff00; - /** The Constant BLUE_BGR_MASK. */ + /** + * The Constant BLUE_BGR_MASK. + */ private static final int BLUE_BGR_MASK = 0x00ff0000; - /** The Constant RED_565_MASK. */ + /** + * The Constant RED_565_MASK. + */ private static final int RED_565_MASK = 0xf800; - /** The Constant GREEN_565_MASK. */ + /** + * The Constant GREEN_565_MASK. + */ private static final int GREEN_565_MASK = 0x07e0; - /** The Constant BLUE_565_MASK. */ + /** + * The Constant BLUE_565_MASK. + */ private static final int BLUE_565_MASK = 0x001f; - /** The Constant RED_555_MASK. */ + /** + * The Constant RED_555_MASK. + */ private static final int RED_555_MASK = 0x7c00; - /** The Constant GREEN_555_MASK. */ + /** + * The Constant GREEN_555_MASK. + */ private static final int GREEN_555_MASK = 0x03e0; - /** The Constant BLUE_555_MASK. */ + /** + * The Constant BLUE_555_MASK. + */ private static final int BLUE_555_MASK = 0x001f; - /** The cm. */ + /** + * The cm. + */ private ColorModel cm; - /** The raster. */ + /** + * The raster. + */ private final WritableRaster raster; - /** The image type. */ + /** + * The image type. + */ private final int imageType; - /** The properties. */ + /** + * The properties. + */ private Hashtable properties; - // Surface of the Buffered Image - used for blitting one Buffered Image + // Surface of the Buffered Image - used for blitting one Buffered Image // on the other one or on the Component - /** The image surf. */ + /** + * The image surf. + */ private final ImageSurface imageSurf; /** - * Instantiates a new BufferedImage with the specified ColorModel, - * and WritableRaster objects. The Raster data can be - * be divided or multiplied by alpha. It depends on the - * alphaPremultiplied state in the ColorModel. + * Instantiates a new BufferedImage with the specified ColorModel, and + * WritableRaster objects. The Raster data can be be divided or multiplied + * by alpha. It depends on the alphaPremultiplied state in the ColorModel. * - * @param cm the ColorModel of the new image. - * @param raster the WritableRaster of the new image. - * @param isRasterPremultiplied if true the data of the specified - * Raster is premultiplied by alpha. - * @param properties the properties of new Image. - */ - public BufferedImage(ColorModel cm, WritableRaster raster, - boolean isRasterPremultiplied, Hashtable properties) { + * @param cm + * the ColorModel of the new image. + * @param raster + * the WritableRaster of the new image. + * @param isRasterPremultiplied + * if true the data of the specified Raster is pre-multiplied by + * alpha. + * @param properties + * the properties of new Image. + */ + public BufferedImage(ColorModel cm, WritableRaster raster, boolean isRasterPremultiplied, + Hashtable properties) { if (!cm.isCompatibleRaster(raster)) { // awt.4D=The raster is incompatible with this ColorModel throw new IllegalArgumentException(Messages.getString("awt.4D")); //$NON-NLS-1$ @@ -227,7 +259,7 @@ Image implements WritableRenderedImage, Transparency{ throw new IllegalArgumentException(Messages.getString("awt.228")); //$NON-NLS-1$ } - this.cm = cm; + this.cm = cm; this.raster = raster; this.properties = properties; @@ -240,47 +272,52 @@ Image implements WritableRenderedImage, Transparency{ /** * Instantiates a new BufferedImage with the specified width, height - * predefined image type (TYPE_BYTE_BINARY or TYPE_BYTE_INDEXED) - * and the specified IndexColorModel. + * predefined image type (TYPE_BYTE_BINARY or TYPE_BYTE_INDEXED) and the + * specified IndexColorModel. * - * @param width the width of new image. - * @param height the height of new image. - * @param imageType the predefined image type. - * @param cm the specified IndexColorModel. + * @param width + * the width of new image. + * @param height + * the height of new image. + * @param imageType + * the predefined image type. + * @param cm + * the specified IndexColorModel. */ - public BufferedImage(int width, int height, int imageType, - IndexColorModel cm) { + public BufferedImage(int width, int height, int imageType, IndexColorModel cm) { switch (imageType) { - case TYPE_BYTE_BINARY: - if (cm.hasAlpha()) { - // awt.227=This image type can't have alpha - throw new IllegalArgumentException(Messages.getString("awt.227")); //$NON-NLS-1$ - } - int pixel_bits = 0; - int mapSize = cm.getMapSize(); - if (mapSize <= 2) { - pixel_bits = 1; - } else if (mapSize <= 4) { - pixel_bits = 2; - } else if (mapSize <= 16) { - pixel_bits = 4; - } else { - // awt.221=The imageType is TYPE_BYTE_BINARY and the color map has more than 16 entries - throw new IllegalArgumentException(Messages.getString("awt.221")); //$NON-NLS-1$ - } + case TYPE_BYTE_BINARY: + if (cm.hasAlpha()) { + // awt.227=This image type can't have alpha + throw new IllegalArgumentException(Messages.getString("awt.227")); //$NON-NLS-1$ + } + int pixel_bits = 0; + int mapSize = cm.getMapSize(); + if (mapSize <= 2) { + pixel_bits = 1; + } else if (mapSize <= 4) { + pixel_bits = 2; + } else if (mapSize <= 16) { + pixel_bits = 4; + } else { + // awt.221=The imageType is TYPE_BYTE_BINARY and the color + // map has more than 16 entries + throw new IllegalArgumentException(Messages.getString("awt.221")); //$NON-NLS-1$ + } - raster = Raster.createPackedRaster(DataBuffer.TYPE_BYTE, width, - height, 1, pixel_bits, null); - break; + raster = Raster.createPackedRaster(DataBuffer.TYPE_BYTE, width, height, 1, + pixel_bits, null); + break; - case TYPE_BYTE_INDEXED: - raster = Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE, - width, height, 1, null); - break; + case TYPE_BYTE_INDEXED: + raster = Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE, width, height, 1, + null); + break; - default: - // awt.222=The imageType is not TYPE_BYTE_BINARY or TYPE_BYTE_INDEXED - throw new IllegalArgumentException(Messages.getString("awt.222")); //$NON-NLS-1$ + default: + // awt.222=The imageType is not TYPE_BYTE_BINARY or + // TYPE_BYTE_INDEXED + throw new IllegalArgumentException(Messages.getString("awt.222")); //$NON-NLS-1$ } @@ -296,187 +333,159 @@ Image implements WritableRenderedImage, Transparency{ } /** - * Instantiates a new BufferedImage with the specified width, height - * and predefined image type. + * Instantiates a new BufferedImage with the specified width, height and + * predefined image type. * - * @param width the width of new image. - * @param height the height of new image. - * @param imageType the predefined image type. + * @param width + * the width of new image. + * @param height + * the height of new image. + * @param imageType + * the predefined image type. */ public BufferedImage(int width, int height, int imageType) { switch (imageType) { - case TYPE_INT_RGB: - cm = new DirectColorModel(24, RED_MASK, GREEN_MASK, BLUE_MASK); - raster = cm.createCompatibleWritableRaster(width, height); - break; - - case TYPE_INT_ARGB: - cm = ColorModel.getRGBdefault(); - raster = cm.createCompatibleWritableRaster(width, height); - break; - - case TYPE_INT_ARGB_PRE: - cm = new DirectColorModel( - ColorSpace.getInstance(ColorSpace.CS_sRGB), - 32, - RED_MASK, - GREEN_MASK, - BLUE_MASK, - ALPHA_MASK, - true, - DataBuffer.TYPE_INT); - - raster = cm.createCompatibleWritableRaster(width, height); - break; - - case TYPE_INT_BGR: - cm = new DirectColorModel(24, - RED_BGR_MASK, - GREEN_BGR_MASK, - BLUE_BGR_MASK); - - raster = cm.createCompatibleWritableRaster(width, height); - break; - - case TYPE_3BYTE_BGR: { - int bits[] = { 8, 8, 8 }; - int bandOffsets[] = { 2, 1, 0 }; - cm = new ComponentColorModel( - ColorSpace.getInstance(ColorSpace.CS_sRGB), - bits, - false, - false, - Transparency.OPAQUE, - DataBuffer.TYPE_BYTE); - - raster = Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE, - width, height, width * 3, 3, bandOffsets, null); + case TYPE_INT_RGB: + cm = new DirectColorModel(24, RED_MASK, GREEN_MASK, BLUE_MASK); + raster = cm.createCompatibleWritableRaster(width, height); + break; + + case TYPE_INT_ARGB: + cm = ColorModel.getRGBdefault(); + raster = cm.createCompatibleWritableRaster(width, height); + break; + + case TYPE_INT_ARGB_PRE: + cm = new DirectColorModel(ColorSpace.getInstance(ColorSpace.CS_sRGB), 32, RED_MASK, + GREEN_MASK, BLUE_MASK, ALPHA_MASK, true, DataBuffer.TYPE_INT); + + raster = cm.createCompatibleWritableRaster(width, height); + break; + + case TYPE_INT_BGR: + cm = new DirectColorModel(24, RED_BGR_MASK, GREEN_BGR_MASK, BLUE_BGR_MASK); + + raster = cm.createCompatibleWritableRaster(width, height); + break; + + case TYPE_3BYTE_BGR: { + int bits[] = { + 8, 8, 8 + }; + int bandOffsets[] = { + 2, 1, 0 + }; + cm = new ComponentColorModel(ColorSpace.getInstance(ColorSpace.CS_sRGB), bits, + false, false, Transparency.OPAQUE, DataBuffer.TYPE_BYTE); + + raster = Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE, width, height, + width * 3, 3, bandOffsets, null); } - break; - - case TYPE_4BYTE_ABGR: { - int bits[] = { 8, 8, 8, 8 }; - int bandOffsets[] = { 3, 2, 1, 0 }; - cm = new ComponentColorModel( - ColorSpace.getInstance(ColorSpace.CS_sRGB), - bits, - true, - false, - Transparency.TRANSLUCENT, - DataBuffer.TYPE_BYTE); - - raster = Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE, - width, height, width * 4, 4, bandOffsets, null); + break; + + case TYPE_4BYTE_ABGR: { + int bits[] = { + 8, 8, 8, 8 + }; + int bandOffsets[] = { + 3, 2, 1, 0 + }; + cm = new ComponentColorModel(ColorSpace.getInstance(ColorSpace.CS_sRGB), bits, + true, false, Transparency.TRANSLUCENT, DataBuffer.TYPE_BYTE); + + raster = Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE, width, height, + width * 4, 4, bandOffsets, null); } - break; - - case TYPE_4BYTE_ABGR_PRE: { - int bits[] = { 8, 8, 8, 8 }; - int bandOffsets[] = { 3, 2, 1, 0 }; - cm = new ComponentColorModel( - ColorSpace.getInstance(ColorSpace.CS_sRGB), - bits, - true, - true, - Transparency.TRANSLUCENT, DataBuffer.TYPE_BYTE); - - raster = Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE, - width, height, width * 4, 4, bandOffsets, null); + break; + + case TYPE_4BYTE_ABGR_PRE: { + int bits[] = { + 8, 8, 8, 8 + }; + int bandOffsets[] = { + 3, 2, 1, 0 + }; + cm = new ComponentColorModel(ColorSpace.getInstance(ColorSpace.CS_sRGB), bits, + true, true, Transparency.TRANSLUCENT, DataBuffer.TYPE_BYTE); + + raster = Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE, width, height, + width * 4, 4, bandOffsets, null); } - break; - - case TYPE_USHORT_565_RGB: - cm = new DirectColorModel( - ColorSpace.getInstance(ColorSpace.CS_sRGB), - 16, - RED_565_MASK, - GREEN_565_MASK, - BLUE_565_MASK, - 0, - false, - DataBuffer.TYPE_USHORT); - - raster = cm.createCompatibleWritableRaster(width, height); - break; - - case TYPE_USHORT_555_RGB: - cm = new DirectColorModel( - ColorSpace.getInstance(ColorSpace.CS_sRGB), - 15, - RED_555_MASK, - GREEN_555_MASK, - BLUE_555_MASK, - 0, - false, - DataBuffer.TYPE_USHORT); - - raster = cm.createCompatibleWritableRaster(width, height); - break; - - case TYPE_BYTE_GRAY: { - int bits[] = { 8 }; - cm = new ComponentColorModel( - ColorSpace.getInstance(ColorSpace.CS_GRAY), - bits, - false, - false, - Transparency.OPAQUE, - DataBuffer.TYPE_BYTE); - - raster = cm.createCompatibleWritableRaster(width, height); + break; + + case TYPE_USHORT_565_RGB: + cm = new DirectColorModel(ColorSpace.getInstance(ColorSpace.CS_sRGB), 16, + RED_565_MASK, GREEN_565_MASK, BLUE_565_MASK, 0, false, + DataBuffer.TYPE_USHORT); + + raster = cm.createCompatibleWritableRaster(width, height); + break; + + case TYPE_USHORT_555_RGB: + cm = new DirectColorModel(ColorSpace.getInstance(ColorSpace.CS_sRGB), 15, + RED_555_MASK, GREEN_555_MASK, BLUE_555_MASK, 0, false, + DataBuffer.TYPE_USHORT); + + raster = cm.createCompatibleWritableRaster(width, height); + break; + + case TYPE_BYTE_GRAY: { + int bits[] = { + 8 + }; + cm = new ComponentColorModel(ColorSpace.getInstance(ColorSpace.CS_GRAY), bits, + false, false, Transparency.OPAQUE, DataBuffer.TYPE_BYTE); + + raster = cm.createCompatibleWritableRaster(width, height); } - break; - - case TYPE_USHORT_GRAY: { - int bits[] = { 16 }; - cm = new ComponentColorModel( - ColorSpace.getInstance(ColorSpace.CS_GRAY), - bits, - false, - false, - Transparency.OPAQUE, - DataBuffer.TYPE_USHORT); - raster = cm.createCompatibleWritableRaster(width, height); + break; + + case TYPE_USHORT_GRAY: { + int bits[] = { + 16 + }; + cm = new ComponentColorModel(ColorSpace.getInstance(ColorSpace.CS_GRAY), bits, + false, false, Transparency.OPAQUE, DataBuffer.TYPE_USHORT); + raster = cm.createCompatibleWritableRaster(width, height); } - break; + break; - case TYPE_BYTE_BINARY: { - int colorMap[] = { 0, 0xffffff }; - cm = new IndexColorModel(1, 2, colorMap, 0, false, -1, - DataBuffer.TYPE_BYTE); + case TYPE_BYTE_BINARY: { + int colorMap[] = { + 0, 0xffffff + }; + cm = new IndexColorModel(1, 2, colorMap, 0, false, -1, DataBuffer.TYPE_BYTE); - raster = Raster.createPackedRaster(DataBuffer.TYPE_BYTE, width, - height, 1, 1, null); + raster = Raster.createPackedRaster(DataBuffer.TYPE_BYTE, width, height, 1, 1, null); } - break; - - case TYPE_BYTE_INDEXED: { - int colorMap[] = new int[256]; - int i = 0; - for (int r = 0; r < 256; r += 51) { - for (int g = 0; g < 256; g += 51) { - for (int b = 0; b < 256; b += 51) { - colorMap[i] = (r << 16) | (g << 8) | b; - i++; + break; + + case TYPE_BYTE_INDEXED: { + int colorMap[] = new int[256]; + int i = 0; + for (int r = 0; r < 256; r += 51) { + for (int g = 0; g < 256; g += 51) { + for (int b = 0; b < 256; b += 51) { + colorMap[i] = (r << 16) | (g << 8) | b; + i++; + } } } - } - int gray = 0x12; - for (; i < 256; i++, gray += 6) { - colorMap[i] = (gray << 16) | (gray << 8) | gray; - } - cm = new IndexColorModel(8, 256, colorMap, 0, false, -1, - DataBuffer.TYPE_BYTE); - raster = Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE, - width, height, 1, null); + int gray = 0x12; + for (; i < 256; i++, gray += 6) { + colorMap[i] = (gray << 16) | (gray << 8) | gray; + } + cm = new IndexColorModel(8, 256, colorMap, 0, false, -1, DataBuffer.TYPE_BYTE); + raster = Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE, width, height, 1, + null); } - break; - default: - // awt.224=Unknown image type - throw new IllegalArgumentException(Messages.getString("awt.224")); //$NON-NLS-1$ + break; + default: + // awt.224=Unknown image type + throw new IllegalArgumentException(Messages.getString("awt.224")); //$NON-NLS-1$ } this.imageType = imageType; imageSurf = createImageSurface(imageType); @@ -488,7 +497,7 @@ Image implements WritableRenderedImage, Transparency{ } public Object getProperty(String name) { - if(name == null) { + if (name == null) { // awt.225=Property name is null throw new NullPointerException(Messages.getString("awt.225")); //$NON-NLS-1$ } @@ -504,9 +513,8 @@ Image implements WritableRenderedImage, Transparency{ public WritableRaster copyData(WritableRaster outRaster) { if (outRaster == null) { - outRaster = Raster.createWritableRaster(raster.getSampleModel(), - new Point(raster.getSampleModelTranslateX(), - raster.getSampleModelTranslateY())); + outRaster = Raster.createWritableRaster(raster.getSampleModel(), new Point(raster + .getSampleModelTranslateX(), raster.getSampleModelTranslateY())); } int w = outRaster.getWidth(); @@ -530,8 +538,7 @@ Image implements WritableRenderedImage, Transparency{ SampleModel sm = raster.getSampleModel(); SampleModel nsm = sm.createCompatibleSampleModel(w, h); - WritableRaster outr = Raster.createWritableRaster(nsm, - rect.getLocation()); + WritableRaster outr = Raster.createWritableRaster(nsm, rect.getLocation()); Object data = null; data = raster.getDataElements(minX, minY, w, h, data); @@ -550,7 +557,7 @@ Image implements WritableRenderedImage, Transparency{ Vector v = new Vector(); for (Enumeration e = properties.keys(); e.hasMoreElements();) { try { - v.add((String) e.nextElement()); + v.add((String)e.nextElement()); } catch (ClassCastException ex) { } } @@ -573,7 +580,7 @@ Image implements WritableRenderedImage, Transparency{ @Override public String toString() { return "BufferedImage@" + Integer.toHexString(hashCode()) + //$NON-NLS-1$ - ": type = " + imageType + " " + cm + " " + raster; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + ": type = " + imageType + " " + cm + " " + raster; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ } public WritableRaster getWritableTile(int tileX, int tileY) { @@ -590,13 +597,12 @@ Image implements WritableRenderedImage, Transparency{ } /** - * Gets a WritableRaster object which contains the alpha channel of - * BufferedImage object with ColorModel objects that supports - * a separate alpha channel such as ComponentColorModel - * or DirectColorModel. + * Gets a WritableRaster object which contains the alpha channel of + * BufferedImage object with ColorModel objects that supports a separate + * alpha channel such as ComponentColorModel or DirectColorModel. * - * @return the WritableRaster object which contains the alpha - * channel of this BufferedImage. + * @return the WritableRaster object which contains the alpha channel of + * this BufferedImage. */ public WritableRaster getAlphaRaster() { return cm.getAlphaRaster(raster); @@ -643,10 +649,8 @@ Image implements WritableRenderedImage, Transparency{ int minX = raster.getMinX(); int minY = raster.getMinY(); - WritableRaster outr = Raster.createWritableRaster( - raster.getSampleModel(), - new Point(raster.getSampleModelTranslateX(), - raster.getSampleModelTranslateY())); + WritableRaster outr = Raster.createWritableRaster(raster.getSampleModel(), new Point(raster + .getSampleModelTranslateX(), raster.getSampleModelTranslateY())); Object data = null; @@ -678,11 +682,14 @@ Image implements WritableRenderedImage, Transparency{ /** * Gets the rectangular area of this BufferedImage as a subimage. * - * @param x the x coordinate. - * @param y the y coordinate. - * @param w the width of the subimage. - * @param h the height of the subimage. - * + * @param x + * the x coordinate. + * @param y + * the y coordinate. + * @param w + * the width of the subimage. + * @param h + * the height of the subimage. * @return the BufferedImage. */ public BufferedImage getSubimage(int x, int y, int w, int h) { @@ -697,18 +704,17 @@ Image implements WritableRenderedImage, Transparency{ } /** - * Creates the Graphics2D object which allows to draw into - * this BufferedImage. + * Creates the Graphics2D object which allows to draw into this + * BufferedImage. * * @return the graphics2D object. */ public Graphics2D createGraphics() { - GraphicsEnvironment ge = - GraphicsEnvironment.getLocalGraphicsEnvironment(); - //return ge.createGraphics(this); - //???AWT hack, FIXME - //return AndroidGraphics2D.getInstance(); - //throw new RuntimeException("Not implemented!"); + GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment(); + // return ge.createGraphics(this); + // ???AWT hack, FIXME + // return AndroidGraphics2D.getInstance(); + // throw new RuntimeException("Not implemented!"); return null; } @@ -718,38 +724,44 @@ Image implements WritableRenderedImage, Transparency{ } /** - * Coerces the data to achieve the state which is specified by - * the isAlphaPremultiplied variable. + * Coerces the data to achieve the state which is specified by the + * isAlphaPremultiplied variable. * - * @param isAlphaPremultiplied the is alpha premultiplied state. + * @param isAlphaPremultiplied + * the is alpha pre-multiplied state. */ public void coerceData(boolean isAlphaPremultiplied) { - if (cm.hasAlpha() && - cm.isAlphaPremultiplied() != isAlphaPremultiplied) { + if (cm.hasAlpha() && cm.isAlphaPremultiplied() != isAlphaPremultiplied) { cm = cm.coerceData(raster, isAlphaPremultiplied); } } /** - * Gets an array of colors in the TYPE_INT_ARGB color model and - * default sRGB colorspace of the specified area of this - * BufferedImage. The result array is composed by the following - * algirithm: - *

    - * pixel = rgbArray[offset + (y-startY)*scansize + (x-startX)] - * - * @param startX the start X area coordinate. - * @param startY the start Y area coordinate. - * @param w the width of the area. - * @param h the height of the area. - * @param rgbArray the result array will be stored to this array. - * @param offset the offset of the rgbArray array. - * @param scansize the scanline stride for the rgbArray. + * Gets an array of colors in the TYPE_INT_ARGB color model and default sRGB + * color space of the specified area of this BufferedImage. The result array + * is composed by the following algorithm: + *

    + * pixel = rgbArray[offset + (y-startY)*scansize + (x-startX)] + *

    * + * @param startX + * the start X area coordinate. + * @param startY + * the start Y area coordinate. + * @param w + * the width of the area. + * @param h + * the height of the area. + * @param rgbArray + * the result array will be stored to this array. + * @param offset + * the offset of the rgbArray array. + * @param scansize + * the scanline stride for the rgbArray. * @return an array of colors for the specified area. */ - public int[] getRGB(int startX, int startY, int w, int h, int[] rgbArray, - int offset, int scansize) { + public int[] getRGB(int startX, int startY, int w, int h, int[] rgbArray, int offset, + int scansize) { if (rgbArray == null) { rgbArray = new int[offset + h * scansize]; } @@ -765,38 +777,47 @@ Image implements WritableRenderedImage, Transparency{ } /** - * Sets RGB values from the specified array to the specified - * BufferedImage area. The pixels are in the default RGB color model - * (TYPE_INT_ARGB) and default sRGB color space. + * Sets RGB values from the specified array to the specified BufferedImage + * area. The pixels are in the default RGB color model (TYPE_INT_ARGB) and + * default sRGB color space. * - * @param startX the start X coordinate. - * @param startY the start Y coordinate. - * @param w the width of the BufferedImage area. - * @param h the height of the BufferedImage area. - * @param rgbArray the array of RGB values. - * @param offset the offset of the rgbArray array. - * @param scansize the scanline stride for the rgbArray. - */ - public void setRGB(int startX, int startY, int w, int h, int[] rgbArray, - int offset, int scansize) { + * @param startX + * the start X coordinate. + * @param startY + * the start Y coordinate. + * @param w + * the width of the BufferedImage area. + * @param h + * the height of the BufferedImage area. + * @param rgbArray + * the array of RGB values. + * @param offset + * the offset of the rgbArray array. + * @param scansize + * the scanline stride for the rgbArray. + */ + public void setRGB(int startX, int startY, int w, int h, int[] rgbArray, int offset, + int scansize) { int off = offset; for (int y = startY; y < startY + h; y++, off += scansize) { int i = off; for (int x = startX; x < startX + w; x++, i++) { - raster.setDataElements(x, y, - cm.getDataElements(rgbArray[i], null)); + raster.setDataElements(x, y, cm.getDataElements(rgbArray[i], null)); } } } /** - * Sets a the specified RGB value to the specified pixel of - * this BufferedImage. The pixel should be in the default - * RGB color model (TYPE_INT_ARGB) and default sRGB color space. - * - * @param x the X coordinate of the pixel. - * @param y the Y coordinate of the pixel. - * @param rgb the RGB value to be set. + * Sets a the specified RGB value to the specified pixel of this + * BufferedImage. The pixel should be in the default RGB color model + * (TYPE_INT_ARGB) and default sRGB color space. + * + * @param x + * the X coordinate of the pixel. + * @param y + * the Y coordinate of the pixel. + * @param rgb + * the RGB value to be set. */ public synchronized void setRGB(int x, int y, int rgb) { raster.setDataElements(x, y, cm.getDataElements(rgb, null)); @@ -814,25 +835,26 @@ Image implements WritableRenderedImage, Transparency{ } /** - * Gets a color in the TYPE_INT_ARGB color model and default - * sRGB colorspace of the specified pixel. - * - * @param x the X coordinate of the pixel. - * @param y the Y coordinate of the pixel. + * Gets a color in the TYPE_INT_ARGB color model and default sRGB color + * space of the specified pixel. * - * @return the color of the specified pixel in the TYPE_INT_ARGB - * color model and default sRGB colorspace. + * @param x + * the X coordinate of the pixel. + * @param y + * the Y coordinate of the pixel. + * @return the color of the specified pixel in the TYPE_INT_ARGB color model + * and default sRGB color space. */ public int getRGB(int x, int y) { return cm.getRGB(raster.getDataElements(x, y, null)); } /** - * Returnes true if alpha is premultiplied, - * false if alpha is not premultiplied or there is no alpha. + * Returns true if alpha is pre-multiplied, false if alpha is not + * pre-multiplied or there is no alpha. * - * @return true if alpha is premultiplied, - * false if alpha is not premultiplied or there is no alpha. + * @return true if alpha is pre-multiplied, false if alpha is not + * pre-multiplied or there is no alpha. */ public boolean isAlphaPremultiplied() { return cm.isAlphaPremultiplied(); @@ -907,9 +929,9 @@ Image implements WritableRenderedImage, Transparency{ /** * Creates the image surface. * - * @param type the type - * - * @return the image surface + * @param type + * the type. + * @return the image surface. */ private ImageSurface createImageSurface(int type) { return new ImageSurface(getColorModel(), getRaster(), type); @@ -918,7 +940,7 @@ Image implements WritableRenderedImage, Transparency{ /** * Gets the image surface. * - * @return the image surface + * @return the image surface. */ ImageSurface getImageSurface() { return imageSurf; @@ -928,4 +950,3 @@ Image implements WritableRenderedImage, Transparency{ return cm.getTransparency(); } } - diff --git a/awt/java/awt/image/BufferedImageFilter.java b/awt/java/awt/image/BufferedImageFilter.java index 44b3c2ed2ab69b595b2f75ab04027acaaaaa2e38..8b6fcf0465054c0380f441e39e9e5bf04f543f7b 100644 --- a/awt/java/awt/image/BufferedImageFilter.java +++ b/awt/java/awt/image/BufferedImageFilter.java @@ -27,49 +27,72 @@ import org.apache.harmony.awt.gl.AwtImageBackdoorAccessor; import org.apache.harmony.awt.internal.nls.Messages; /** - * The BufferedImageFilter class provides filtering operations to - * the BufferedImage objects using operators which implement - * BufferedImageOp interface. + * The BufferedImageFilter class provides filtering operations to the + * BufferedImage objects using operators which implement BufferedImageOp + * interface. + * + * @since Android 1.0 */ public class BufferedImageFilter extends ImageFilter implements Cloneable { - - /** The Constant accessor. */ + + /** + * The Constant accessor. + */ private static final AwtImageBackdoorAccessor accessor = AwtImageBackdoorAccessor.getInstance(); - /** The op. */ + /** + * The op. + */ private BufferedImageOp op; - /** The raster. */ + /** + * The raster. + */ private WritableRaster raster; - /** The i data. */ + /** + * The i data. + */ private int iData[]; - - /** The b data. */ + + /** + * The b data. + */ private byte bData[]; - /** The width. */ + /** + * The width. + */ private int width; - - /** The height. */ + + /** + * The height. + */ private int height; - /** The cm. */ + /** + * The cm. + */ private ColorModel cm; - /** The forced rgb. */ + /** + * The forced rgb. + */ private boolean forcedRGB = false; - - /** The transfer type. */ + + /** + * The transfer type. + */ private int transferType = DataBuffer.TYPE_UNDEFINED; /** - * Instantiates a new BufferedImageFilter with the specified - * BufferedImageOp operator. + * Instantiates a new BufferedImageFilter with the specified BufferedImageOp + * operator. * - * @param op the specified BufferedImageOp operator. - * - * @throws NullPointerException if BufferedImageOp is null. + * @param op + * the specified BufferedImageOp operator. + * @throws NullPointerException + * if BufferedImageOp is null. */ public BufferedImageFilter(BufferedImageOp op) { if (op == null) { @@ -79,11 +102,11 @@ public class BufferedImageFilter extends ImageFilter implements Cloneable { } /** - * Gets the BufferedImageOp operator associated with this + * Gets the BufferedImageOp operator associated with this * BufferedImageFilter object. * - * @return the BufferedImageOp associated with this - * BufferedImageFilter object. + * @return the BufferedImageOp associated with this BufferedImageFilter + * object. */ public BufferedImageOp getBufferedImageOp() { return op; @@ -110,22 +133,14 @@ public class BufferedImageFilter extends ImageFilter implements Cloneable { } @Override - public void setPixels( - int x, int y, int - w, int h, - ColorModel model, byte[] pixels, - int off, int scansize - ) { + public void setPixels(int x, int y, int w, int h, ColorModel model, byte[] pixels, int off, + int scansize) { setPixels(x, y, w, h, model, pixels, off, scansize, true); } @Override - public void setPixels( - int x, int y, - int w, int h, - ColorModel model, int[] pixels, - int off, int scansize - ) { + public void setPixels(int x, int y, int w, int h, ColorModel model, int[] pixels, int off, + int scansize) { setPixels(x, y, w, h, model, pixels, off, scansize, false); } @@ -163,22 +178,27 @@ public class BufferedImageFilter extends ImageFilter implements Cloneable { /** * Sets the pixels. * - * @param x the x - * @param y the y - * @param w the w - * @param h the h - * @param model the model - * @param pixels the pixels - * @param off the off - * @param scansize the scansize - * @param isByteData the is byte data + * @param x + * the x. + * @param y + * the y. + * @param w + * the w. + * @param h + * the h. + * @param model + * the model. + * @param pixels + * the pixels. + * @param off + * the off. + * @param scansize + * the scansize. + * @param isByteData + * the is byte data. */ - private void setPixels( - int x, int y, - int w, int h, - ColorModel model, Object pixels, - int off, int scansize, boolean isByteData - ) { + private void setPixels(int x, int y, int w, int h, ColorModel model, Object pixels, int off, + int scansize, boolean isByteData) { // Check bounds // Need to copy only the pixels that will fit into the destination area if (x < 0) { @@ -216,23 +236,24 @@ public class BufferedImageFilter extends ImageFilter implements Cloneable { boolean canArraycopy; // Process pixels - switch(transferType) { + switch (transferType) { case DataBuffer.TYPE_UNDEFINED: { if (isByteData) { transferType = DataBuffer.TYPE_BYTE; createRaster(transferType); - //bData = new byte[width*height]; + // bData = new byte[width*height]; canArraycopy = !forcedRGB; break; } transferType = DataBuffer.TYPE_INT; createRaster(transferType); - //iData = new int[width*height]; + // iData = new int[width*height]; canArraycopy = !forcedRGB || model.equals(ColorModel.getRGBdefault()); break; } // And proceed to copy the pixels case DataBuffer.TYPE_INT: { - if (isByteData) { // There are int data already but the new data are bytes + if (isByteData) { // There are int data already but the new data + // are bytes forceRGB(); canArraycopy = false; break; @@ -250,7 +271,8 @@ public class BufferedImageFilter extends ImageFilter implements Cloneable { // RGB conversion canArraycopy = false; break; - } default: { + } + default: { throw new IllegalStateException(Messages.getString("awt.06")); //$NON-NLS-1$ } } @@ -260,7 +282,7 @@ public class BufferedImageFilter extends ImageFilter implements Cloneable { int dstOffset = x + y * width; if (canArraycopy) { - Object dstArray = isByteData ? (Object) bData : (Object) iData; + Object dstArray = isByteData ? (Object)bData : (Object)iData; for (; off < maxOffset; off += scansize, dstOffset += width) { System.arraycopy(pixels, off, dstArray, dstOffset, w); } @@ -271,11 +293,8 @@ public class BufferedImageFilter extends ImageFilter implements Cloneable { int dstPos = dstOffset; int maxDstPos = dstOffset + w; for (; dstPos < maxDstPos; dstPos++, srcPos++) { - iData[dstPos] = model.getRGB( - isByteData ? - ((byte[])pixels)[srcPos] : - ((int[])pixels)[srcPos] - ); + iData[dstPos] = model.getRGB(isByteData ? ((byte[])pixels)[srcPos] + : ((int[])pixels)[srcPos]); } } } @@ -287,22 +306,24 @@ public class BufferedImageFilter extends ImageFilter implements Cloneable { private void forceRGB() { if (!forcedRGB) { forcedRGB = true; - int size = width*height; + int size = width * height; int rgbData[] = new int[size]; if (bData != null) { - for (int i=0; i profiles = new ArrayList(10); - ArrayList sequence = new ArrayList(10); + ArrayList sequence = new ArrayList(10); // We need this profile anyway ICC_Profile xyzProfile = ICC_Profile.getInstance(ColorSpace.CS_CIEXYZ); @@ -149,41 +168,42 @@ public class ColorConvertOp implements BufferedImageOp, RasterOp { int conversionLength = conversionSequence.length; if (conversionLength > 0) { conversionFirst = conversionSequence[0]; - conversionLast = conversionSequence[conversionLength-1]; + conversionLast = conversionSequence[conversionLength - 1]; } boolean iccSequenceStarted = false; - + if (src != conversionFirst && src != null) { if (src instanceof ICC_Profile) { profiles.add(src); iccSequenceStarted = true; } else { profiles.add(xyzProfile); - sequence.add(src); // Add non-ICC color space to the sequence - } + sequence.add(src); // Add non-ICC color space to the + // sequence + } } else { profiles.add(xyzProfile); } - - for (int i=0; i 1) { @@ -192,109 +212,111 @@ public class ColorConvertOp implements BufferedImageOp, RasterOp { // Add non-ICC color space to the sequence sequence.add(conversionSequence[i]); } - + profiles.clear(); profiles.add(xyzProfile); - iccSequenceStarted = false; // Sequence of ICC profiles is processed + iccSequenceStarted = false; // Sequence of ICC profiles is + // processed } else { // Add non-ICC color space to the sequence - sequence.add(conversionSequence[i]); - } + sequence.add(conversionSequence[i]); + } } - - if (dst != conversionLast && dst != null) { // Add last profile if needed + + if (dst != conversionLast && dst != null) { // Add last profile if + // needed if (dst instanceof ICC_Profile) { profiles.add(dst); iccSequenceStarted = true; } else if (iccSequenceStarted) { profiles.add(xyzProfile); } else { - sequence.add(dst); // Add last non-ICC color space to the sequence + sequence.add(dst); // Add last non-ICC color space to the + // sequence } } - + if (iccSequenceStarted) { // Make last transform if needed sequence.add(new ICC_Transform(profiles.toArray(new ICC_Profile[0]))); if (dst != null && !(dst instanceof ICC_Profile)) { sequence.add(dst); // Add last non-ICC color space to the - // sequence + // sequence } } // Calculate max number of components // This number will be used for memory allocation maxComponents = 0; - Object o; - for (int i=0, size = sequence.size(); i t.getNumInputChannels() + 1) ? - maxComponents : - t.getNumInputChannels() + 1; - maxComponents = - (maxComponents > t.getNumOutputChannels() + 1) ? - maxComponents : - t.getNumOutputChannels() + 1; + ICC_Transform t = (ICC_Transform)o; + maxComponents = (maxComponents > t.getNumInputChannels() + 1) ? maxComponents + : t.getNumInputChannels() + 1; + maxComponents = (maxComponents > t.getNumOutputChannels() + 1) ? maxComponents + : t.getNumOutputChannels() + 1; } else { - ColorSpace cs = (ColorSpace) o; - maxComponents = - (maxComponents > cs.getNumComponents() + 1) ? - maxComponents : - cs.getNumComponents() + 1; - } + ColorSpace cs = (ColorSpace)o; + maxComponents = (maxComponents > cs.getNumComponents() + 1) ? maxComponents + : cs.getNumComponents() + 1; + } } - + return sequence.toArray(); } } - + /** - * Instantiates a new ColorConvertOp object using two specified - * ColorSpace objects. + * Instantiates a new ColorConvertOp object using two specified ColorSpace + * objects. * - * @param srcCS the source ColorSpace. - * @param dstCS the destination ColorSpace. - * @param hints the RenderingHints object used for - * the color conversion, or null. + * @param srcCS + * the source ColorSpace. + * @param dstCS + * the destination ColorSpace. + * @param hints + * the RenderingHints object used for the color conversion, or + * null. */ public ColorConvertOp(ColorSpace srcCS, ColorSpace dstCS, RenderingHints hints) { if (srcCS == null || dstCS == null) { throw new NullPointerException(Messages.getString("awt.25B")); //$NON-NLS-1$ } - + renderingHints = hints; - + boolean srcICC = srcCS instanceof ICC_ColorSpace; boolean dstICC = dstCS instanceof ICC_ColorSpace; - + if (srcICC && dstICC) { conversionSequence = new ICC_Profile[2]; } else { conversionSequence = new Object[2]; isICC = false; } - + if (srcICC) { - conversionSequence[0] = ((ICC_ColorSpace) srcCS).getProfile(); + conversionSequence[0] = ((ICC_ColorSpace)srcCS).getProfile(); } else { conversionSequence[0] = srcCS; } - + if (dstICC) { - conversionSequence[1] = ((ICC_ColorSpace) dstCS).getProfile(); + conversionSequence[1] = ((ICC_ColorSpace)dstCS).getProfile(); } else { conversionSequence[1] = dstCS; } } /** - * Instantiates a new ColorConvertOp object from the specified - * ICC_Profile objects. + * Instantiates a new ColorConvertOp object from the specified ICC_Profile + * objects. * - * @param profiles the array of ICC_Profile objects. - * @param hints the RenderingHints object used for - * the color conversion, or null. + * @param profiles + * the array of ICC_Profile objects. + * @param hints + * the RenderingHints object used for the color conversion, or + * null. */ public ColorConvertOp(ICC_Profile profiles[], RenderingHints hints) { if (profiles == null) { @@ -302,37 +324,39 @@ public class ColorConvertOp implements BufferedImageOp, RasterOp { } renderingHints = hints; - + // This array is not used in the program logic, so don't need to copy it // Store it only to return back - midProfiles = profiles; - + midProfiles = profiles; + conversionSequence = new ICC_Profile[midProfiles.length]; - + // Add profiles to the conversion sequence - for (int i=0, length=midProfiles.length; i Transparency.TRANSLUCENT) { + if (transparency < Transparency.OPAQUE || transparency > Transparency.TRANSLUCENT) { // awt.270=The transparency is not a valid value throw new IllegalArgumentException(Messages.getString("awt.270")); //$NON-NLS-1$ } @@ -148,11 +181,12 @@ public abstract class ColorModel implements Transparency { } /** - * Instantiates a new color model with the specified pixel bit depth. - * The transferType is chosen based on the pixel bits, and the other - * data fields are given default values. + * Instantiates a new color model with the specified pixel bit depth. The + * transferType is chosen based on the pixel bits, and the other data fields + * are given default values. * - * @param bits the array of component masks + * @param bits + * the array of component masks. */ public ColorModel(int bits) { @@ -178,14 +212,17 @@ public abstract class ColorModel implements Transparency { * Gets the data elements from the specified component array, transforming * them according to rules of the color model. * - * @param components the components - * @param offset the offset in the normComponents array - * @param obj the array that the result is written to: an array of values - * whose length must be the number of components used by the color model and - * whose type depends on the transfer type (based on the pixel bit depth), - * or null to have the appropriate array created - * - * @return the array of data elements + * @param components + * the components. + * @param offset + * the offset in the normComponents array. + * @param obj + * the array that the result is written to: an array of values + * whose length must be the number of components used by the + * color model and whose type depends on the transfer type (based + * on the pixel bit depth), or null to have the appropriate array + * created. + * @return the array of data elements. */ public Object getDataElements(int[] components, int offset, Object obj) { throw new UnsupportedOperationException("This method is not " + //$NON-NLS-1$ @@ -195,33 +232,36 @@ public abstract class ColorModel implements Transparency { /** * Gets the data elements from the specified array of normalized components. * - * @param normComponents the array normalized components - * @param normOffset the offset in the normComponents array - * @param obj the array that the result is written to: an array of values - * whose length must be the number of components used by the color model and - * whose type depends on the transfer type (based on the pixel bit depth), - * or null to have the appropriate array created - * - * @return the array of data elements - */ - public Object getDataElements(float[] normComponents, int normOffset, - Object obj) { - int unnormComponents[] = getUnnormalizedComponents(normComponents, - normOffset, null, 0); + * @param normComponents + * the array normalized components. + * @param normOffset + * the offset in the normComponents array. + * @param obj + * the array that the result is written to: an array of values + * whose length must be the number of components used by the + * color model and whose type depends on the transfer type (based + * on the pixel bit depth), or null to have the appropriate array + * created. + * @return the array of data elements. + */ + public Object getDataElements(float[] normComponents, int normOffset, Object obj) { + int unnormComponents[] = getUnnormalizedComponents(normComponents, normOffset, null, 0); return getDataElements(unnormComponents, 0, obj); } /** - * Gets the data elements corresponding to the pixel determined by the - * RGB data. - * - * @param rgb the rgb int that defines the pixel - * @param pixel the array that the result is written to: an array of values - * whose length must be the number of components used by the color model and - * whose type depends on the transfer type (based on the pixel bit depth), - * or null to have the appropriate array created + * Gets the data elements corresponding to the pixel determined by the RGB + * data. * - * @return the array of data elements + * @param rgb + * the RGB integer value that defines the pixel. + * @param pixel + * the array that the result is written to: an array of values + * whose length must be the number of components used by the + * color model and whose type depends on the transfer type (based + * on the pixel bit depth), or null to have the appropriate array + * created. + * @return the array of data elements. */ public Object getDataElements(int rgb, Object pixel) { throw new UnsupportedOperationException("This method is not " + //$NON-NLS-1$ @@ -229,38 +269,38 @@ public abstract class ColorModel implements Transparency { } /** - * Gets the child raster corresponding to the alpha channel of the - * specified writable raster, or null if alpha is not supported. + * Gets the child raster corresponding to the alpha channel of the specified + * writable raster, or null if alpha is not supported. * - * @param raster the raster - * - * @return the alpha raster + * @param raster + * the raster. + * @return the alpha raster. */ public WritableRaster getAlphaRaster(WritableRaster raster) { return null; } /** - * Creates a new color model by coercing the data in the writable raster - * in accordance with the alpha strategy of this color model. - * - * @param raster the raster - * @param isAlphaPremultiplied whether the alpha is premultiplied in this - * color model + * Creates a new color model by coercing the data in the writable raster in + * accordance with the alpha strategy of this color model. * - * @return the new color model + * @param raster + * the raster. + * @param isAlphaPremultiplied + * whether the alpha is pre-multiplied in this color model + * @return the new color model. */ - public ColorModel coerceData(WritableRaster raster, - boolean isAlphaPremultiplied) { + public ColorModel coerceData(WritableRaster raster, boolean isAlphaPremultiplied) { throw new UnsupportedOperationException("This method is not " + //$NON-NLS-1$ "supported by this ColorModel"); //$NON-NLS-1$ } @Override public String toString() { - // The output format based on 1.5 release behaviour. + // The output format based on 1.5 release behavior. // It could be reveled such way: - // ColorModel cm = new ComponentColorModel(ColorSpace.getInstance(ColorSpace.CS_sRGB, + // ColorModel cm = new + // ComponentColorModel(ColorSpace.getInstance(ColorSpace.CS_sRGB, // false, false, Transparency.OPAQUE, DataBuffer.TYPE_BYTE); // System.out.println(cm.toString()); return "ColorModel: Color Space = " + cs.toString() + "; has alpha = " //$NON-NLS-1$ //$NON-NLS-2$ @@ -274,15 +314,17 @@ public abstract class ColorModel implements Transparency { /** * Gets the components of the pixel determined by the data array. * - * @param pixel the data array that defines the pixel (whose - * primitive type corresponds to the pixel length in bits, + * @param pixel + * the data array that defines the pixel (whose primitive type + * corresponds to the pixel length in bits. * @see ColorModel#getTransferType() - * @param components the the array where the resulting components - * are written (or null to prompt the method to create the return array) - * @param offset the offset that tells where the results should be written - * in the return array - * - * @return the array of components + * @param components + * the the array where the resulting components are written (or + * null to prompt the method to create the return array). + * @param offset + * the offset that tells where the results should be written in + * the return array. + * @return the array of components. */ public int[] getComponents(Object pixel, int[] components, int offset) { throw new UnsupportedOperationException("This method is not " + //$NON-NLS-1$ @@ -292,18 +334,20 @@ public abstract class ColorModel implements Transparency { /** * Gets the normalized components of the pixel determined by the data array. * - * @param pixel the data array that defines the pixel (whose - * primitive type corresponds to the pixel length in bits, + * @param pixel + * the data array that defines the pixel (whose primitive type + * corresponds to the pixel length in bits. * @see ColorModel#getTransferType() - * @param normComponents the array where the resulting normalised components - * are written (or null to prompt the method to create the return array) - * @param normOffset the offset that tells where the results should be written - * in the return array - * - * @return the array of normalized components + * @param normComponents + * the array where the resulting normalized components are + * written (or null to prompt the method to create the return + * array). + * @param normOffset + * the offset that tells where the results should be written in + * the return array. + * @return the array of normalized components. */ - public float[] getNormalizedComponents(Object pixel, - float[] normComponents, int normOffset) { + public float[] getNormalizedComponents(Object pixel, float[] normComponents, int normOffset) { if (pixel == null) { // awt.294=pixel is null @@ -311,8 +355,7 @@ public abstract class ColorModel implements Transparency { } int unnormComponents[] = getComponents(pixel, null, 0); - return getNormalizedComponents(unnormComponents, 0, normComponents, - normOffset); + return getNormalizedComponents(unnormComponents, 0, normComponents, normOffset); } @Override @@ -320,54 +363,52 @@ public abstract class ColorModel implements Transparency { if (!(obj instanceof ColorModel)) { return false; } - ColorModel cm = (ColorModel) obj; + ColorModel cm = (ColorModel)obj; - return (pixel_bits == cm.getPixelSize() && - transferType == cm.getTransferType() && - cs.getType() == cm.getColorSpace().getType() && - hasAlpha == cm.hasAlpha() && - isAlphaPremultiplied == cm.isAlphaPremultiplied() && - transparency == cm.getTransparency() && - numColorComponents == cm.getNumColorComponents() && - numComponents == cm.getNumComponents() && - Arrays.equals(bits, cm.getComponentSize())); + return (pixel_bits == cm.getPixelSize() && transferType == cm.getTransferType() + && cs.getType() == cm.getColorSpace().getType() && hasAlpha == cm.hasAlpha() + && isAlphaPremultiplied == cm.isAlphaPremultiplied() + && transparency == cm.getTransparency() + && numColorComponents == cm.getNumColorComponents() + && numComponents == cm.getNumComponents() && Arrays.equals(bits, cm + .getComponentSize())); } /** * Gets the red component of the pixel determined by the data array. * - * @param inData the data array that defines the pixel (whose - * primitive type corresponds to the pixel length in bits, + * @param inData + * the data array that defines the pixel (whose primitive type + * corresponds to the pixel length in bits. * @see ColorModel#getTransferType() - * - * @return the red + * @return the red. */ public int getRed(Object inData) { return getRed(constructPixel(inData)); } /** - * Gets the RGB int corresponding to the pixel defined by the data array. + * Gets the RGB integer value corresponding to the pixel defined by the data + * array. * - * @param inData the data array that defines the pixel (whose - * primitive type corresponds to the pixel length in bits, + * @param inData + * the data array that defines the pixel (whose primitive type + * corresponds to the pixel length in bits. * @see ColorModel#getTransferType() - * - * @return the int that gives the pixel's colors in RGB format + * @return the integer value that gives the pixel's colors in RGB format. */ public int getRGB(Object inData) { - return (getAlpha(inData) << 24 | getRed(inData) << 16 | - getGreen(inData) << 8 | getBlue(inData)); + return (getAlpha(inData) << 24 | getRed(inData) << 16 | getGreen(inData) << 8 | getBlue(inData)); } /** * Gets the green component of the pixel defined by the data array. * - * @param inData the data array that defines the pixel (whose - * primitive type corresponds to the pixel length in bits, + * @param inData + * the data array that defines the pixel (whose primitive type + * corresponds to the pixel length in bits. * @see ColorModel#getTransferType() - * - * @return the green + * @return the green. */ public int getGreen(Object inData) { return getGreen(constructPixel(inData)); @@ -376,11 +417,11 @@ public abstract class ColorModel implements Transparency { /** * Gets the blue component of the pixel defined by the data array. * - * @param inData the data array that defines the pixel (whose - * primitive type corresponds to the pixel length in bits, + * @param inData + * the data array that defines the pixel (whose primitive type + * corresponds to the pixel length in bits. * @see ColorModel#getTransferType() - * - * @return the blue + * @return the blue. */ public int getBlue(Object inData) { return getBlue(constructPixel(inData)); @@ -389,11 +430,11 @@ public abstract class ColorModel implements Transparency { /** * Gets the alpha component of the pixel defined by the data array. * - * @param inData the data array that defines the pixel (whose - * primitive type corresponds to the pixel length in bits, + * @param inData + * the data array that defines the pixel (whose primitive type + * corresponds to the pixel length in bits. * @see ColorModel#getTransferType() - * - * @return the alpha + * @return the alpha. */ public int getAlpha(Object inData) { return getAlpha(constructPixel(inData)); @@ -402,10 +443,11 @@ public abstract class ColorModel implements Transparency { /** * Creates a compatible writable raster. * - * @param w the width of the desired writable raster - * @param h the height of the desired writable raster - * - * @return the writable raster + * @param w + * the width of the desired writable raster. + * @param h + * the height of the desired writable raster. + * @return the writable raster. */ public WritableRaster createCompatibleWritableRaster(int w, int h) { throw new UnsupportedOperationException("This method is not " + //$NON-NLS-1$ @@ -415,9 +457,9 @@ public abstract class ColorModel implements Transparency { /** * Checks if the sample model is compatible with this color model. * - * @param sm the sample model - * - * @return true, if the sample model is compatible with this color model + * @param sm + * the sample model. + * @return true, if the sample model is compatible with this color model. */ public boolean isCompatibleSampleModel(SampleModel sm) { throw new UnsupportedOperationException("This method is not " + //$NON-NLS-1$ @@ -427,10 +469,11 @@ public abstract class ColorModel implements Transparency { /** * Creates the compatible sample model. * - * @param w the width of the desired sample model - * @param h the height of the desired sample model - * - * @return the sample model + * @param w + * the width of the desired sample model. + * @param h + * the height of the desired sample model. + * @return the sample model. */ public SampleModel createCompatibleSampleModel(int w, int h) { throw new UnsupportedOperationException("This method is not " + //$NON-NLS-1$ @@ -440,9 +483,9 @@ public abstract class ColorModel implements Transparency { /** * Checks if the specified raster is compatible with this color model. * - * @param raster the raster to inspect - * - * @return true, if the raster is compatible with this color model + * @param raster + * the raster to inspect. + * @return true, if the raster is compatible with this color model. */ public boolean isCompatibleRaster(Raster raster) { throw new UnsupportedOperationException("This method is not " + //$NON-NLS-1$ @@ -452,28 +495,32 @@ public abstract class ColorModel implements Transparency { /** * Gets the color space of this color model. * - * @return the color space + * @return the color space. */ public final ColorSpace getColorSpace() { return cs; } /** - * Gets the normalized components corresponding to the specified + * Gets the normalized components corresponding to the specified * unnormalized components. * - * @param components the array of unnormalized components - * @param offset the offset where the components should be read - * from the array of unnormalized components - * @param normComponents the array where the resulting normalised components - * are written (or null to prompt the method to create the return array) - * @param normOffset the offset that tells where the results should be written - * in the return array - * - * @return the normalized components - */ - public float[] getNormalizedComponents(int[] components, int offset, - float normComponents[], int normOffset) { + * @param components + * the array of unnormalized components. + * @param offset + * the offset where the components should be read from the array + * of unnormalized components. + * @param normComponents + * the array where the resulting normalized components are + * written (or null to prompt the method to create the return + * array). + * @param normOffset + * the offset that tells where the results should be written in + * the return array. + * @return the normalized components. + */ + public float[] getNormalizedComponents(int[] components, int offset, float normComponents[], + int normOffset) { if (bits == null) { // awt.26C=bits is null throw new UnsupportedOperationException(Messages.getString("awt.26C")); //$NON-NLS-1$ @@ -484,14 +531,12 @@ public abstract class ColorModel implements Transparency { } if (hasAlpha && isAlphaPremultiplied) { - float normAlpha = - (float) components[offset + numColorComponents] / - maxValues[numColorComponents]; + float normAlpha = (float)components[offset + numColorComponents] + / maxValues[numColorComponents]; if (normAlpha != 0.0f) { for (int i = 0; i < numColorComponents; i++) { - normComponents[normOffset + i] = - components[offset + i] / - (normAlpha * maxValues[i]); + normComponents[normOffset + i] = components[offset + i] + / (normAlpha * maxValues[i]); } normComponents[normOffset + numColorComponents] = normAlpha; } else { @@ -501,9 +546,7 @@ public abstract class ColorModel implements Transparency { } } else { for (int i = 0; i < numComponents; i++) { - normComponents[normOffset + i] = - (float) components[offset + i] / - maxValues[i]; + normComponents[normOffset + i] = (float)components[offset + i] / maxValues[i]; } } @@ -513,11 +556,12 @@ public abstract class ColorModel implements Transparency { /** * Gets the data element corresponding to the unnormalized components. * - * @param components the components - * @param offset the offset to start reading the components from the - * array of components - * - * @return the data element + * @param components + * the components. + * @param offset + * the offset to start reading the components from the array of + * components. + * @return the data element. */ public int getDataElement(int[] components, int offset) { throw new UnsupportedOperationException("This method is not " + //$NON-NLS-1$ @@ -525,21 +569,25 @@ public abstract class ColorModel implements Transparency { } /** - * Gets the unnormalized components corresponding to the specified + * Gets the unnormalized components corresponding to the specified * normalized components. * - * @param normComponents the array of normalized components - * @param normOffset the offset where the components should be read - * from the array of normalized components - * @param components the array where the resulting unnormalised components - * are written (or null to prompt the method to create the return array) - * @param offset the offset that tells where the results should be written - * in the return array - * - * @return the unnormalized components - */ - public int[] getUnnormalizedComponents(float normComponents[], - int normOffset, int components[], int offset) { + * @param normComponents + * the array of normalized components. + * @param normOffset + * the offset where the components should be read from the array + * of normalized components. + * @param components + * the array where the resulting unnormalized components are + * written (or null to prompt the method to create the return + * array). + * @param offset + * the offset that tells where the results should be written in + * the return array. + * @return the unnormalized components. + */ + public int[] getUnnormalizedComponents(float normComponents[], int normOffset, + int components[], int offset) { if (bits == null) { // awt.26C=bits is null @@ -547,7 +595,8 @@ public abstract class ColorModel implements Transparency { } if (normComponents.length - normOffset < numComponents) { - // awt.273=The length of normComponents minus normOffset is less than numComponents + // awt.273=The length of normComponents minus normOffset is less + // than numComponents throw new IllegalArgumentException(Messages.getString("awt.273")); //$NON-NLS-1$ } @@ -555,7 +604,8 @@ public abstract class ColorModel implements Transparency { components = new int[numComponents + offset]; } else { if (components.length - offset < numComponents) { - // awt.272=The length of components minus offset is less than numComponents + // awt.272=The length of components minus offset is less than + // numComponents throw new IllegalArgumentException(Messages.getString("awt.272")); //$NON-NLS-1$ } } @@ -563,17 +613,15 @@ public abstract class ColorModel implements Transparency { if (hasAlpha && isAlphaPremultiplied) { float alpha = normComponents[normOffset + numColorComponents]; for (int i = 0; i < numColorComponents; i++) { - components[offset + i] = (int) (normComponents[normOffset + i] - * maxValues[i] * alpha + 0.5f); + components[offset + i] = (int)(normComponents[normOffset + i] * maxValues[i] + * alpha + 0.5f); } - components[offset + numColorComponents] = - (int) (normComponents[normOffset + numColorComponents] * - maxValues[numColorComponents] + 0.5f); + components[offset + numColorComponents] = (int)(normComponents[normOffset + + numColorComponents] + * maxValues[numColorComponents] + 0.5f); } else { for (int i = 0; i < numComponents; i++) { - components[offset + i] = - (int) (normComponents[normOffset + i] * - maxValues[i] + 0.5f); + components[offset + i] = (int)(normComponents[normOffset + i] * maxValues[i] + 0.5f); } } @@ -583,30 +631,32 @@ public abstract class ColorModel implements Transparency { /** * Gets the data element corresponding to the normalized components. * - * @param normComponents the normalized components - * @param normOffset the offset where the normalized components should - * be read from the normalized component array - * - * @return the data element + * @param normComponents + * the normalized components. + * @param normOffset + * the offset where the normalized components should be read from + * the normalized component array. + * @return the data element. */ public int getDataElement(float normComponents[], int normOffset) { - int unnormComponents[] = getUnnormalizedComponents(normComponents, - normOffset, null, 0); + int unnormComponents[] = getUnnormalizedComponents(normComponents, normOffset, null, 0); return getDataElement(unnormComponents, 0); } /** - * Takes a pixel whose data is defined by an int, and writes the - * corresponding components into the components array, starting - * from the index offset. + * Takes a pixel whose data is defined by an integer, and writes the + * corresponding components into the components array, starting from the + * index offset. * - * @param pixel the pixel data - * @param components the data array to write the components to (or - * null to have the method create the return array) - * @param offset the offset that determines where the results are - * written in the components array - * - * @return the array of components corresponding to the pixel + * @param pixel + * the pixel data. + * @param components + * the data array to write the components to (or null to have the + * method create the return array). + * @param offset + * the offset that determines where the results are written in + * the components array. + * @return the array of components corresponding to the pixel. */ public int[] getComponents(int pixel, int components[], int offset) { throw new UnsupportedOperationException("This method is not " + //$NON-NLS-1$ @@ -616,45 +666,45 @@ public abstract class ColorModel implements Transparency { /** * Gets the red component of the pixel determined by the pixel data. * - * @param pixel the pixel data - * - * @return the red component of the pixel + * @param pixel + * the pixel. + * @return the red component of the given pixel. */ public abstract int getRed(int pixel); /** - * Takes the pixel data and returns the int corresponding - * to the pixel's color in RGB format. - * - * @param pixel the pixel data + * Takes the pixel data and returns the integer value corresponding to the + * pixel's color in RGB format. * - * @return the corresponding RGB int + * @param pixel + * the pixel data. + * @return the corresponding RGB integer value. */ public int getRGB(int pixel) { - return (getAlpha(pixel) << 24 | getRed(pixel) << 16 - | getGreen(pixel) << 8 | getBlue(pixel)); + return (getAlpha(pixel) << 24 | getRed(pixel) << 16 | getGreen(pixel) << 8 | getBlue(pixel)); } /** * Gets the green component of the pixel determined by the pixel data. * - * @param pixel the pixel data - * - * @return the green component of the pixel + * @param pixel + * the pixel. + * @return the green component of the given pixel. */ public abstract int getGreen(int pixel); /** * Gets the size of the desired component of this color model. * - * @param componentIdx the index that determines which component size to get - * - * @return the component size corresponding to the index - * - * @throws NullPointerException if this color model doesn't support - * an array of separate components. - * @throws ArrayIndexOutOfBoundsException if the index is negative or - * greater than or equal to the number of components + * @param componentIdx + * the index that determines which component size to get. + * @return the component size corresponding to the index. + * @throws NullPointerException + * if this color model doesn't support an array of separate + * components. + * @throws ArrayIndexOutOfBoundsException + * if the index is negative or greater than or equal to the + * number of components. */ public int getComponentSize(int componentIdx) { if (bits == null) { @@ -663,7 +713,8 @@ public abstract class ColorModel implements Transparency { } if (componentIdx < 0 || componentIdx >= bits.length) { - // awt.274=componentIdx is greater than the number of components or less than zero + // awt.274=componentIdx is greater than the number of components or + // less than zero throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.274")); //$NON-NLS-1$ } @@ -673,25 +724,25 @@ public abstract class ColorModel implements Transparency { /** * Gets the blue component of the pixel determined by the pixel data. * - * @param pixel the pixel - * - * @return the blue component of the pixel + * @param pixel + * the pixel. + * @return the blue component of the given pixel. */ public abstract int getBlue(int pixel); /** * Gets the alpha component of the pixel determined by the pixel data. * - * @param pixel the pixel - * - * @return the alpha component of the pixel + * @param pixel + * the pixel. + * @return the alpha component of the given pixel. */ public abstract int getAlpha(int pixel); /** * Gets the array of sizes of the different components. * - * @return the array of sizes of the different components + * @return the array of sizes of the different components. */ public int[] getComponentSize() { if (bits != null) { @@ -701,9 +752,9 @@ public abstract class ColorModel implements Transparency { } /** - * Checks if the alpha component is premultiplied. + * Checks if the alpha component is pre-multiplied. * - * @return true, if the alpha component is premultiplied + * @return true, if the alpha component is pre-multiplied. */ public final boolean isAlphaPremultiplied() { return isAlphaPremultiplied; @@ -712,7 +763,7 @@ public abstract class ColorModel implements Transparency { /** * Checks whether this color model supports alpha. * - * @return true, if this color model has alpha + * @return true, if this color model has alpha. */ public final boolean hasAlpha() { return hasAlpha; @@ -776,12 +827,12 @@ public abstract class ColorModel implements Transparency { } /** - * Gets the transfer type, which is the type of Java primitive - * value that corresponds to the bit length per pixel: either - * {@link DataBuffer#TYPE_BYTE}, {@link DataBuffer#TYPE_USHORT}, + * Gets the transfer type, which is the type of Java primitive value that + * corresponds to the bit length per pixel: either + * {@link DataBuffer#TYPE_BYTE}, {@link DataBuffer#TYPE_USHORT}, * {@link DataBuffer#TYPE_INT}, or {@link DataBuffer#TYPE_UNDEFINED}. * - * @return the transfer type + * @return the transfer type. */ public final int getTransferType() { return transferType; @@ -790,7 +841,7 @@ public abstract class ColorModel implements Transparency { /** * Gets the pixel size in bits. * - * @return the pixel size + * @return the pixel size. */ public int getPixelSize() { return pixel_bits; @@ -799,7 +850,7 @@ public abstract class ColorModel implements Transparency { /** * Gets the number of components of this color model. * - * @return the number of components + * @return the number of components. */ public int getNumComponents() { return numComponents; @@ -808,7 +859,7 @@ public abstract class ColorModel implements Transparency { /** * Gets the number of color components of this color model. * - * @return the number color components + * @return the number color components. */ public int getNumColorComponents() { return numColorComponents; @@ -817,12 +868,11 @@ public abstract class ColorModel implements Transparency { /** * Gets the default RGB color model. * - * @return the default RGB color model + * @return the default RGB color model. */ public static ColorModel getRGBdefault() { if (RGBdefault == null) { - RGBdefault = new DirectColorModel(32, 0x00ff0000, 0x0000ff00, - 0x000000ff, 0xff000000); + RGBdefault = new DirectColorModel(32, 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000); } return RGBdefault; } @@ -830,66 +880,69 @@ public abstract class ColorModel implements Transparency { /* * Construct INT pixel representation from Object * @param obj - * * @return */ /** * Construct pixel. * - * @param obj the obj - * - * @return the int + * @param obj + * the obj. + * @return the int. */ private int constructPixel(Object obj) { int pixel = 0; switch (getTransferType()) { - case DataBuffer.TYPE_BYTE: - byte[] bPixel = (byte[]) obj; - if(bPixel.length > 1) { - // awt.275=This pixel representation is not suuported by tis Color Model - throw new UnsupportedOperationException(Messages.getString("awt.275")); //$NON-NLS-1$ - } - pixel = bPixel[0] & 0xff; - break; - - case DataBuffer.TYPE_USHORT: - short[] sPixel = (short[]) obj; - if(sPixel.length > 1) { - // awt.275=This pixel representation is not suuported by tis Color Model - throw new UnsupportedOperationException(Messages.getString("awt.275")); //$NON-NLS-1$ - } - pixel = sPixel[0] & 0xffff; - break; - - case DataBuffer.TYPE_INT: - int[] iPixel = (int[]) obj; - if(iPixel.length > 1) { - // awt.275=This pixel representation is not suuported by tis Color Model - throw new UnsupportedOperationException(Messages.getString("awt.275")); //$NON-NLS-1$ - } - pixel = iPixel[0]; - break; + case DataBuffer.TYPE_BYTE: + byte[] bPixel = (byte[])obj; + if (bPixel.length > 1) { + // awt.275=This pixel representation is not suuported by tis + // Color Model + throw new UnsupportedOperationException(Messages.getString("awt.275")); //$NON-NLS-1$ + } + pixel = bPixel[0] & 0xff; + break; + + case DataBuffer.TYPE_USHORT: + short[] sPixel = (short[])obj; + if (sPixel.length > 1) { + // awt.275=This pixel representation is not suuported by tis + // Color Model + throw new UnsupportedOperationException(Messages.getString("awt.275")); //$NON-NLS-1$ + } + pixel = sPixel[0] & 0xffff; + break; + + case DataBuffer.TYPE_INT: + int[] iPixel = (int[])obj; + if (iPixel.length > 1) { + // awt.275=This pixel representation is not suuported by tis + // Color Model + throw new UnsupportedOperationException(Messages.getString("awt.275")); //$NON-NLS-1$ + } + pixel = iPixel[0]; + break; - default: - // awt.22D=This transferType ( {0} ) is not supported by this color model - throw new UnsupportedOperationException(Messages.getString("awt.22D", //$NON-NLS-1$ - transferType)); + default: + // awt.22D=This transferType ( {0} ) is not supported by this + // color model + throw new UnsupportedOperationException(Messages.getString("awt.22D", //$NON-NLS-1$ + transferType)); } return pixel; } /** - * Gets the transfer type, which is the type of Java primitive - * value that corresponds to the bit length per pixel: either - * {@link DataBuffer#TYPE_BYTE}, {@link DataBuffer#TYPE_USHORT}, + * Gets the transfer type, which is the type of Java primitive value that + * corresponds to the bit length per pixel: either + * {@link DataBuffer#TYPE_BYTE}, {@link DataBuffer#TYPE_USHORT}, * {@link DataBuffer#TYPE_INT}, or {@link DataBuffer#TYPE_UNDEFINED}. * - * @param bits the array of component masks - * - * @return the transfer type + * @param bits + * the array of component masks. + * @return the transfer type. */ static int getTransferType(int bits) { if (bits <= 8) { diff --git a/awt/java/awt/image/ComponentColorModel.java b/awt/java/awt/image/ComponentColorModel.java index a152f55a793f86da18ab9658ae076bd27d66ad53..4328fd37e732a8939ea0b8ff3a3a05250f0278b2 100644 --- a/awt/java/awt/image/ComponentColorModel.java +++ b/awt/java/awt/image/ComponentColorModel.java @@ -18,6 +18,7 @@ * @author Igor V. Stolyarov * @version $Revision$ */ + package java.awt.image; import java.awt.color.ColorSpace; @@ -26,154 +27,202 @@ import org.apache.harmony.awt.gl.color.LUTColorConverter; import org.apache.harmony.awt.internal.nls.Messages; /** - * The Class ComponentColorModel represents a color model that is defined - * in terms of its components. + * The Class ComponentColorModel represents a color model that is defined in + * terms of its components. + * + * @since Android 1.0 */ public class ComponentColorModel extends ColorModel { - /** The signed. */ - private boolean signed; // Pixel samples are signed. - // Samples with TransferType DataBuffer.TYPE_BYTE, - // DataBuffer.TYPE_USHORT, DataBuffer.TYPE_INT - - // unsigned. Samples with others TransferType - - // signed. + /** + * The signed. + */ + private boolean signed; // Pixel samples are signed. + + // Samples with TransferType DataBuffer.TYPE_BYTE, + // DataBuffer.TYPE_USHORT, DataBuffer.TYPE_INT - + // unsigned. Samples with others TransferType - + // signed. - /** The integral. */ + /** + * The integral. + */ private boolean integral; // Pixel samples are integral. - // Samples with TransferType DataBuffer.TYPE_BYTE, - // DataBuffer.TYPE_USHORT, DataBuffer.Short and - // DataBuffer.TYPE_INT - integral. - /** The scale factors. */ - private float scaleFactors[]; // Array of factors for reduction components - // values into the form scaled from 0 to 255 + // Samples with TransferType DataBuffer.TYPE_BYTE, + // DataBuffer.TYPE_USHORT, DataBuffer.Short and + // DataBuffer.TYPE_INT - integral. - /** The donot support unnormalized. */ + /** + * The scale factors. + */ + private float scaleFactors[]; // Array of factors for reduction components + + // values into the form scaled from 0 to 255 + + /** + * The donot support unnormalized. + */ private boolean donotSupportUnnormalized; // This Color Model don't support - // unnormolized form - /** The need alpha divide. */ + // unnormolized form + + /** + * The need alpha divide. + */ private boolean needAlphaDivide; // hasAlpha && isAlphaPremultiplied - /** The calc value. */ - private boolean calcValue; // Value was culculated + /** + * The calc value. + */ + private boolean calcValue; // Value was culculated - /** The need scale. */ - private boolean needScale; // Normalized value need to scale + /** + * The need scale. + */ + private boolean needScale; // Normalized value need to scale - /** The min vals. */ - private float minVals[]; // Array of Min normalized values + /** + * The min vals. + */ + private float minVals[]; // Array of Min normalized values - /** The ranges. */ - private float ranges[]; // Array of range normalized values + /** + * The ranges. + */ + private float ranges[]; // Array of range normalized values - /** The alpha lut. */ - private byte alphaLUT[]; // Lookup table for scale alpha value + /** + * The alpha lut. + */ + private byte alphaLUT[]; // Lookup table for scale alpha value - /** The color lu ts. */ - private byte colorLUTs[][]; // Lookup tables for scale color values + /** + * The color lu ts. + */ + private byte colorLUTs[][]; // Lookup tables for scale color values - /** The from_ linea r_ rg b_ lut. */ - private byte from_LINEAR_RGB_LUT[]; // Lookup table for conversion from - // Linear RGB Color Space into sRGB + /** + * The from_ linea r_ rg b_ lut. + */ + private byte from_LINEAR_RGB_LUT[]; // Lookup table for conversion from + + // Linear RGB Color Space into sRGB + + /** + * The to_ linea r_8 rg b_ lut. + */ + private byte to_LINEAR_8RGB_LUT[]; // Lookup table for conversion from - /** The to_ linea r_8 rg b_ lut. */ - private byte to_LINEAR_8RGB_LUT[]; // Lookup table for conversion from - // sRGB Color Space into Linear RGB - // 8 bit + // sRGB Color Space into Linear RGB + // 8 bit - /** The to_ linea r_16 rg b_ lut. */ + /** + * The to_ linea r_16 rg b_ lut. + */ private short to_LINEAR_16RGB_LUT[]; // Lookup table for conversion from - // sRGB Color Space into Linear RGB - // 16 bit - /** The LINEA r_ rg b_ length. */ - private int LINEAR_RGB_Length; // Linear RGB bit length + // sRGB Color Space into Linear RGB + // 16 bit + + /** + * The LINEA r_ rg b_ length. + */ + private int LINEAR_RGB_Length; // Linear RGB bit length + + /** + * The factor. + */ + private float fFactor; // Scale factor - /** The factor. */ - private float fFactor; // Scale factor + /** + * The is_s rgb. + */ + private boolean is_sRGB; // ColorModel has sRGB ColorSpace - /** The is_s rgb. */ - private boolean is_sRGB; // ColorModel has sRGB ColorSpace + /** + * The is_ linea r_ rgb. + */ + private boolean is_LINEAR_RGB; // Color Model has Linear RGB Color - /** The is_ linea r_ rgb. */ - private boolean is_LINEAR_RGB; // Color Model has Linear RGB Color - // Space + // Space /** * Instantiates a new component color model. * - * @param colorSpace the color space - * @param bits the array of component masks - * @param hasAlpha whether the color model has alpha - * @param isAlphaPremultiplied whether the alpha is premultiplied - * @param transparency the transparency strategy, @see java.awt.Transparency - * @param transferType the transfer type (primitive java type - * to use for the components) + * @param colorSpace + * the color space. + * @param bits + * the array of component masks. + * @param hasAlpha + * whether the color model has alpha. + * @param isAlphaPremultiplied + * whether the alpha is pre-multiplied. + * @param transparency + * the transparency strategy, @see java.awt.Transparency. + * @param transferType + * the transfer type (primitive java type to use for the + * components). */ - public ComponentColorModel(ColorSpace colorSpace, int bits[], - boolean hasAlpha, boolean isAlphaPremultiplied, int transparency, - int transferType) { - super(createPixelBits(colorSpace, hasAlpha, transferType), - validateBits(bits, colorSpace, hasAlpha, transferType), - colorSpace, hasAlpha, isAlphaPremultiplied, transparency, + public ComponentColorModel(ColorSpace colorSpace, int bits[], boolean hasAlpha, + boolean isAlphaPremultiplied, int transparency, int transferType) { + super(createPixelBits(colorSpace, hasAlpha, transferType), validateBits(bits, colorSpace, + hasAlpha, transferType), colorSpace, hasAlpha, isAlphaPremultiplied, transparency, transferType); needScale = false; switch (transferType) { - case DataBuffer.TYPE_BYTE: - case DataBuffer.TYPE_USHORT: - case DataBuffer.TYPE_INT: - signed = false; - integral = true; - donotSupportUnnormalized = false; - scaleFactors = new float[numComponents]; - for (int i = 0; i < numColorComponents; i++) { - scaleFactors[i] = 1.0f / maxValues[i]; - if (cs.getMinValue(i) != 0.0f || cs.getMaxValue(i) != 1.0f) { - donotSupportUnnormalized = true; + case DataBuffer.TYPE_BYTE: + case DataBuffer.TYPE_USHORT: + case DataBuffer.TYPE_INT: + signed = false; + integral = true; + donotSupportUnnormalized = false; + scaleFactors = new float[numComponents]; + for (int i = 0; i < numColorComponents; i++) { + scaleFactors[i] = 1.0f / maxValues[i]; + if (cs.getMinValue(i) != 0.0f || cs.getMaxValue(i) != 1.0f) { + donotSupportUnnormalized = true; + } } - } - if (hasAlpha) { - maxValues[numColorComponents] = - (1 << bits[numColorComponents]) - 1; - scaleFactors[numColorComponents] = - 1.0f / maxValues[numColorComponents]; - } - break; - case DataBuffer.TYPE_SHORT: - signed = true; - integral = true; - donotSupportUnnormalized = true; - scaleFactors = new float[numComponents]; - for (int i = 0; i < numComponents; i++) { - maxValues[i] = Short.MAX_VALUE; - scaleFactors[i] = 1.0f / maxValues[i]; - if (cs.getMinValue(i) != 0.0f || cs.getMaxValue(i) != 1.0f) { - needScale = true; + if (hasAlpha) { + maxValues[numColorComponents] = (1 << bits[numColorComponents]) - 1; + scaleFactors[numColorComponents] = 1.0f / maxValues[numColorComponents]; } - } - if (needScale) { - minVals = new float[numColorComponents]; - ranges = new float[numColorComponents]; - for (int i = 0; i < numColorComponents; i++) { - minVals[i] = cs.getMinValue(i); - ranges[i] = cs.getMaxValue(i) - minVals[i]; + break; + case DataBuffer.TYPE_SHORT: + signed = true; + integral = true; + donotSupportUnnormalized = true; + scaleFactors = new float[numComponents]; + for (int i = 0; i < numComponents; i++) { + maxValues[i] = Short.MAX_VALUE; + scaleFactors[i] = 1.0f / maxValues[i]; + if (cs.getMinValue(i) != 0.0f || cs.getMaxValue(i) != 1.0f) { + needScale = true; + } } - } - break; - case DataBuffer.TYPE_FLOAT: - case DataBuffer.TYPE_DOUBLE: - signed = true; - integral = false; - donotSupportUnnormalized = true; - break; - default: - // awt.215=transferType is not one of DataBuffer.TYPE_BYTE, - // DataBuffer.TYPE_USHORT, DataBuffer.TYPE_INT, - // DataBuffer.TYPE_SHORT, DataBuffer.TYPE_FLOAT, or - // DataBuffer.TYPE_DOUBLE - throw new IllegalArgumentException(Messages.getString("awt.215")); //$NON-NLS-1$ + if (needScale) { + minVals = new float[numColorComponents]; + ranges = new float[numColorComponents]; + for (int i = 0; i < numColorComponents; i++) { + minVals[i] = cs.getMinValue(i); + ranges[i] = cs.getMaxValue(i) - minVals[i]; + } + } + break; + case DataBuffer.TYPE_FLOAT: + case DataBuffer.TYPE_DOUBLE: + signed = true; + integral = false; + donotSupportUnnormalized = true; + break; + default: + // awt.215=transferType is not one of DataBuffer.TYPE_BYTE, + // DataBuffer.TYPE_USHORT, DataBuffer.TYPE_INT, + // DataBuffer.TYPE_SHORT, DataBuffer.TYPE_FLOAT, or + // DataBuffer.TYPE_DOUBLE + throw new IllegalArgumentException(Messages.getString("awt.215")); //$NON-NLS-1$ } needAlphaDivide = hasAlpha && isAlphaPremultiplied; @@ -183,36 +232,40 @@ public class ComponentColorModel extends ColorModel { /** * Instantiates a new component color model. * - * @param colorSpace the color space - * @param hasAlpha whether the color model has alpha - * @param isAlphaPremultiplied whether the alpha is premultiplied - * @param transparency the transparency strategy, @see java.awt.Transparency - * @param transferType the transfer type (primitive java type - * to use for the components) + * @param colorSpace + * the color space. + * @param hasAlpha + * whether the color model has alpha. + * @param isAlphaPremultiplied + * whether the alpha is pre-multiplied. + * @param transparency + * the transparency strategy, @see java.awt.Transparency. + * @param transferType + * the transfer type (primitive java type to use for the + * components). */ public ComponentColorModel(ColorSpace colorSpace, boolean hasAlpha, boolean isAlphaPremultiplied, int transparency, int transferType) { - - this(colorSpace, - createPixelBitsArray(colorSpace, hasAlpha, transferType), - hasAlpha, - isAlphaPremultiplied, - transparency, - transferType); + + this(colorSpace, createPixelBitsArray(colorSpace, hasAlpha, transferType), hasAlpha, + isAlphaPremultiplied, transparency, transferType); } /** * Validate bits. * - * @param bits the bits - * @param colorSpace the color space - * @param hasAlpha the has alpha - * @param transferType the transfer type - * - * @return the int[] + * @param bits + * the bits. + * @param colorSpace + * the color space. + * @param hasAlpha + * the has alpha. + * @param transferType + * the transfer type. + * @return the int[]. */ - private static int[] validateBits(int bits[], ColorSpace colorSpace, - boolean hasAlpha, int transferType) { + private static int[] validateBits(int bits[], ColorSpace colorSpace, boolean hasAlpha, + int transferType) { if (bits != null) { return bits; } @@ -235,14 +288,15 @@ public class ComponentColorModel extends ColorModel { /** * Creates the pixel bits. * - * @param colorSpace the color space - * @param hasAlpha the has alpha - * @param transferType the transfer type - * - * @return the int + * @param colorSpace + * the color space. + * @param hasAlpha + * the has alpha. + * @param transferType + * the transfer type. + * @return the int. */ - private static int createPixelBits(ColorSpace colorSpace, boolean hasAlpha, - int transferType) { + private static int createPixelBits(ColorSpace colorSpace, boolean hasAlpha, int transferType) { int numComponents = colorSpace.getNumComponents(); if (hasAlpha) { numComponents++; @@ -254,22 +308,24 @@ public class ComponentColorModel extends ColorModel { /** * Creates the pixel bits array. * - * @param colorSpace the color space - * @param hasAlpha the has alpha - * @param transferType the transfer type - * - * @return the int[] + * @param colorSpace + * the color space. + * @param hasAlpha + * the has alpha. + * @param transferType + * the transfer type. + * @return the int[]. */ - private static int[] createPixelBitsArray(ColorSpace colorSpace, - boolean hasAlpha, int transferType) { - + private static int[] createPixelBitsArray(ColorSpace colorSpace, boolean hasAlpha, + int transferType) { + int numComponents = colorSpace.getNumComponents(); if (hasAlpha) { numComponents++; } int bits[] = new int[numComponents]; - for(int i = 0; i < numComponents; i++){ + for (int i = 0; i < numComponents; i++) { bits[i] = DataBuffer.getDataTypeSize(transferType); } return bits; @@ -278,217 +334,200 @@ public class ComponentColorModel extends ColorModel { @Override public Object getDataElements(int components[], int offset, Object obj) { if (donotSupportUnnormalized) { - // awt.213=This ComponentColorModel does not support the unnormalized form + // awt.213=This ComponentColorModel does not support the + // unnormalized form throw new IllegalArgumentException(Messages.getString("awt.213")); //$NON-NLS-1$ } if (offset + numComponents > components.length) { - // awt.216=The components array is not large enough to hold all the color and alpha components + // awt.216=The components array is not large enough to hold all the + // color and alpha components throw new IllegalArgumentException(Messages.getString("awt.216")); //$NON-NLS-1$ } switch (transferType) { - case DataBuffer.TYPE_BYTE: - byte ba[]; - if (obj == null) { - ba = new byte[numComponents]; - } else { - ba = (byte[]) obj; - } - for (int i = 0, idx = offset; i < numComponents; i++, idx++) { - ba[i] = (byte) components[idx]; - } - return ba; - case DataBuffer.TYPE_USHORT: - short sa[]; - if (obj == null) { - sa = new short[numComponents]; - } else { - sa = (short[]) obj; - } - for (int i = 0, idx = offset; i < numComponents; i++, idx++) { - sa[i] = (short) components[idx]; - } - return sa; - case DataBuffer.TYPE_INT: - int ia[]; - if (obj == null) { - ia = new int[numComponents]; - } else { - ia = (int[]) obj; - } - for (int i = 0, idx = offset; i < numComponents; i++, idx++) { - ia[i] = components[idx]; - } - return ia; - default: - // awt.217=The transfer type of this ComponentColorModel is not one - // of the following transfer types: DataBuffer.TYPE_BYTE, - // DataBuffer.TYPE_USHORT, or DataBuffer.TYPE_INT - throw new UnsupportedOperationException(Messages - .getString("awt.217")); //$NON-NLS-1$ + case DataBuffer.TYPE_BYTE: + byte ba[]; + if (obj == null) { + ba = new byte[numComponents]; + } else { + ba = (byte[])obj; + } + for (int i = 0, idx = offset; i < numComponents; i++, idx++) { + ba[i] = (byte)components[idx]; + } + return ba; + case DataBuffer.TYPE_USHORT: + short sa[]; + if (obj == null) { + sa = new short[numComponents]; + } else { + sa = (short[])obj; + } + for (int i = 0, idx = offset; i < numComponents; i++, idx++) { + sa[i] = (short)components[idx]; + } + return sa; + case DataBuffer.TYPE_INT: + int ia[]; + if (obj == null) { + ia = new int[numComponents]; + } else { + ia = (int[])obj; + } + for (int i = 0, idx = offset; i < numComponents; i++, idx++) { + ia[i] = components[idx]; + } + return ia; + default: + // awt.217=The transfer type of this ComponentColorModel is not + // one + // of the following transfer types: DataBuffer.TYPE_BYTE, + // DataBuffer.TYPE_USHORT, or DataBuffer.TYPE_INT + throw new UnsupportedOperationException(Messages.getString("awt.217")); //$NON-NLS-1$ } } @Override - public Object getDataElements(float normComponents[], int normOffset, - Object obj) { + public Object getDataElements(float normComponents[], int normOffset, Object obj) { if (needScale) { for (int i = 0, idx = 0; i < numColorComponents; i++, idx++) { - normComponents[idx] = - (normComponents[idx] - minVals[i]) / ranges[i]; + normComponents[idx] = (normComponents[idx] - minVals[i]) / ranges[i]; } } switch (transferType) { - case DataBuffer.TYPE_BYTE: - byte ba[]; - if (obj == null) { - ba = new byte[numComponents]; - } else { - ba = (byte[]) obj; - } - - if (needAlphaDivide) { - float alpha = normComponents[normOffset + numColorComponents]; - for (int i = 0, idx = normOffset; i < numColorComponents; - i++, idx++) { - ba[i] = (byte) (normComponents[idx] * alpha * - maxValues[i] + 0.5f); - } - ba[numColorComponents] = - (byte) (normComponents[normOffset + numColorComponents] * - maxValues[numColorComponents] + 0.5f); - } else { - for (int i = 0, idx = normOffset; i < numComponents; - i++, idx++) { - ba[idx] = - (byte) (normComponents[idx] * maxValues[i] + 0.5f); + case DataBuffer.TYPE_BYTE: + byte ba[]; + if (obj == null) { + ba = new byte[numComponents]; + } else { + ba = (byte[])obj; } - } - return ba; - case DataBuffer.TYPE_USHORT: - short usa[]; - if (obj == null) { - usa = new short[numComponents]; - } else { - usa = (short[]) obj; - } - - if (needAlphaDivide) { - float alpha = normComponents[normOffset + numColorComponents]; - for (int i = 0, idx = 0; i < numColorComponents; i++, idx++) { - usa[i] = (short) (normComponents[idx] * alpha * - maxValues[i] + 0.5f); - } - usa[numColorComponents] = (short) (alpha * - maxValues[numColorComponents] + 0.5f); - } else { - for (int i = 0, idx = normOffset; i < numComponents; - i++, idx++) { - usa[i] = (short) (normComponents[idx] * - maxValues[i] + 0.5f); + if (needAlphaDivide) { + float alpha = normComponents[normOffset + numColorComponents]; + for (int i = 0, idx = normOffset; i < numColorComponents; i++, idx++) { + ba[i] = (byte)(normComponents[idx] * alpha * maxValues[i] + 0.5f); + } + ba[numColorComponents] = (byte)(normComponents[normOffset + numColorComponents] + * maxValues[numColorComponents] + 0.5f); + } else { + for (int i = 0, idx = normOffset; i < numComponents; i++, idx++) { + ba[idx] = (byte)(normComponents[idx] * maxValues[i] + 0.5f); + } } - } - return usa; + return ba; - case DataBuffer.TYPE_INT: - int ia[]; - if (obj == null) { - ia = new int[numComponents]; - } else { - ia = (int[]) obj; - } - - if (needAlphaDivide) { - float alpha = normComponents[normOffset + numColorComponents]; - for (int i = 0, idx = 0; i < numColorComponents; i++, idx++) { - ia[i] = (int) (normComponents[idx] * alpha * - maxValues[i] + 0.5f); - } - ia[numColorComponents] = (int) (alpha * - maxValues[numColorComponents] + 0.5f); - } else { - for (int i = 0, idx = normOffset; i < numComponents; - i++, idx++) { - ia[i] = (int) (normComponents[idx] * maxValues[i] + 0.5f); + case DataBuffer.TYPE_USHORT: + short usa[]; + if (obj == null) { + usa = new short[numComponents]; + } else { + usa = (short[])obj; } - } - return ia; - case DataBuffer.TYPE_SHORT: - short sa[]; - if (obj == null) { - sa = new short[numComponents]; - } else { - sa = (short[]) obj; - } + if (needAlphaDivide) { + float alpha = normComponents[normOffset + numColorComponents]; + for (int i = 0, idx = 0; i < numColorComponents; i++, idx++) { + usa[i] = (short)(normComponents[idx] * alpha * maxValues[i] + 0.5f); + } + usa[numColorComponents] = (short)(alpha * maxValues[numColorComponents] + 0.5f); + } else { + for (int i = 0, idx = normOffset; i < numComponents; i++, idx++) { + usa[i] = (short)(normComponents[idx] * maxValues[i] + 0.5f); + } + } + return usa; - if (needAlphaDivide) { - float alpha = normComponents[normOffset + numColorComponents]; - for (int i = 0, idx = 0; i < numColorComponents; i++, idx++) { - sa[i] = (short) (normComponents[idx] * alpha * - maxValues[i] + 0.5f); + case DataBuffer.TYPE_INT: + int ia[]; + if (obj == null) { + ia = new int[numComponents]; + } else { + ia = (int[])obj; } - sa[numColorComponents] = (short) (alpha * - maxValues[numColorComponents] + 0.5f); - } else { - for (int i = 0, idx = normOffset; i < numComponents; - i++, idx++) { - sa[i] = (short) (normComponents[idx] * - maxValues[i] + 0.5f); + + if (needAlphaDivide) { + float alpha = normComponents[normOffset + numColorComponents]; + for (int i = 0, idx = 0; i < numColorComponents; i++, idx++) { + ia[i] = (int)(normComponents[idx] * alpha * maxValues[i] + 0.5f); + } + ia[numColorComponents] = (int)(alpha * maxValues[numColorComponents] + 0.5f); + } else { + for (int i = 0, idx = normOffset; i < numComponents; i++, idx++) { + ia[i] = (int)(normComponents[idx] * maxValues[i] + 0.5f); + } } - } - return sa; + return ia; - case DataBuffer.TYPE_FLOAT: - float fa[]; - if (obj == null) { - fa = new float[numComponents]; - } else { - fa = (float[]) obj; - } + case DataBuffer.TYPE_SHORT: + short sa[]; + if (obj == null) { + sa = new short[numComponents]; + } else { + sa = (short[])obj; + } - if (needAlphaDivide) { - float alpha = normComponents[normOffset + numColorComponents]; - for (int i = 0, idx = 0; i < numColorComponents; i++, idx++) { - fa[i] = normComponents[idx] * alpha; + if (needAlphaDivide) { + float alpha = normComponents[normOffset + numColorComponents]; + for (int i = 0, idx = 0; i < numColorComponents; i++, idx++) { + sa[i] = (short)(normComponents[idx] * alpha * maxValues[i] + 0.5f); + } + sa[numColorComponents] = (short)(alpha * maxValues[numColorComponents] + 0.5f); + } else { + for (int i = 0, idx = normOffset; i < numComponents; i++, idx++) { + sa[i] = (short)(normComponents[idx] * maxValues[i] + 0.5f); + } } - fa[numColorComponents] = alpha; - } else { - for (int i = 0, idx = normOffset; i < numComponents; - i++, idx++) { - fa[i] = normComponents[idx]; + return sa; + + case DataBuffer.TYPE_FLOAT: + float fa[]; + if (obj == null) { + fa = new float[numComponents]; + } else { + fa = (float[])obj; } - } - return fa; - case DataBuffer.TYPE_DOUBLE: - double da[]; - if (obj == null) { - da = new double[numComponents]; - } else { - da = (double[]) obj; - } + if (needAlphaDivide) { + float alpha = normComponents[normOffset + numColorComponents]; + for (int i = 0, idx = 0; i < numColorComponents; i++, idx++) { + fa[i] = normComponents[idx] * alpha; + } + fa[numColorComponents] = alpha; + } else { + for (int i = 0, idx = normOffset; i < numComponents; i++, idx++) { + fa[i] = normComponents[idx]; + } + } + return fa; - if (needAlphaDivide) { - double alpha = normComponents[normOffset + numColorComponents]; - for (int i = 0, idx = 0; i < numColorComponents; i++, idx++) { - da[i] = normComponents[idx] * alpha; + case DataBuffer.TYPE_DOUBLE: + double da[]; + if (obj == null) { + da = new double[numComponents]; + } else { + da = (double[])obj; } - da[numColorComponents] = alpha; - } else { - for (int i = 0, idx = normOffset; i < numComponents; - i++, idx++) { - da[i] = normComponents[idx]; + + if (needAlphaDivide) { + double alpha = normComponents[normOffset + numColorComponents]; + for (int i = 0, idx = 0; i < numColorComponents; i++, idx++) { + da[i] = normComponents[idx] * alpha; + } + da[numColorComponents] = alpha; + } else { + for (int i = 0, idx = normOffset; i < numComponents; i++, idx++) { + da[i] = normComponents[idx]; + } } - } - return da; + return da; - default: - // awt.213=This ComponentColorModel does not support the unnormalized form - throw new IllegalArgumentException(Messages.getString("awt.213")); //$NON-NLS-1$ + default: + // awt.213=This ComponentColorModel does not support the + // unnormalized form + throw new IllegalArgumentException(Messages.getString("awt.213")); //$NON-NLS-1$ } } @@ -544,7 +583,7 @@ public class ComponentColorModel extends ColorModel { normComp[numColorComponents] = normAlpha; } } - if(hasAlpha && isAlphaPremultiplied){ + if (hasAlpha && isAlphaPremultiplied) { normComp[0] *= normComp[numColorComponents]; normComp[1] *= normComp[numColorComponents]; normComp[2] *= normComp[numColorComponents]; @@ -555,7 +594,7 @@ public class ComponentColorModel extends ColorModel { @Override public WritableRaster getAlphaRaster(WritableRaster raster) { - if(!hasAlpha) { + if (!hasAlpha) { return null; } @@ -564,13 +603,12 @@ public class ComponentColorModel extends ColorModel { int bandList[] = new int[1]; bandList[0] = raster.getNumBands() - 1; - return raster.createWritableChild(x, y, raster.getWidth(), - raster.getHeight(), x, y, bandList); + return raster.createWritableChild(x, y, raster.getWidth(), raster.getHeight(), x, y, + bandList); } @Override - public ColorModel coerceData(WritableRaster raster, - boolean isAlphaPremultiplied) { + public ColorModel coerceData(WritableRaster raster, boolean isAlphaPremultiplied) { if (!hasAlpha || this.isAlphaPremultiplied == isAlphaPremultiplied) { return this; } @@ -582,333 +620,311 @@ public class ComponentColorModel extends ColorModel { if (isAlphaPremultiplied) { switch (transferType) { - case DataBuffer.TYPE_BYTE: - case DataBuffer.TYPE_USHORT: - case DataBuffer.TYPE_INT: - float alphaFactor = maxValues[numColorComponents]; - int iComponents[] = null; - int iTransparentComponents[] = new int[numComponents]; - for (int i = 0; i < h; i++, minY++) { - for (int j = 0, x = minX; j < w; j++, x++) { - iComponents = raster.getPixel(x, minY, - iComponents); - if (iComponents[numColorComponents] == 0) { - raster.setPixel(x, minY, iTransparentComponents); - } else { - float alpha = - iComponents[numColorComponents] / - alphaFactor; - for (int n = 0; n < numColorComponents; n++) { - iComponents[n] = - (int) (alpha * iComponents[n] + 0.5f); + case DataBuffer.TYPE_BYTE: + case DataBuffer.TYPE_USHORT: + case DataBuffer.TYPE_INT: + float alphaFactor = maxValues[numColorComponents]; + int iComponents[] = null; + int iTransparentComponents[] = new int[numComponents]; + for (int i = 0; i < h; i++, minY++) { + for (int j = 0, x = minX; j < w; j++, x++) { + iComponents = raster.getPixel(x, minY, iComponents); + if (iComponents[numColorComponents] == 0) { + raster.setPixel(x, minY, iTransparentComponents); + } else { + float alpha = iComponents[numColorComponents] / alphaFactor; + for (int n = 0; n < numColorComponents; n++) { + iComponents[n] = (int)(alpha * iComponents[n] + 0.5f); + } + raster.setPixel(x, minY, iComponents); } - raster.setPixel(x, minY, iComponents); } - } - - } - break; - case DataBuffer.TYPE_SHORT: - float sAlphaFactor = maxValues[numColorComponents]; - short sComponents[] = null; - short sTransparentComponents[] = new short[numComponents]; - for (int i = 0; i < h; i++, minY++) { - for (int j = 0, x = minX; j < w; j++, x++) { - sComponents = (short[]) raster.getDataElements(x, minY, - sComponents); - if (sComponents[numColorComponents] == 0) { - raster.setDataElements(x, minY, - sTransparentComponents); - } else { - float alpha = - sComponents[numColorComponents] / - sAlphaFactor; - for (int n = 0; n < numColorComponents; n++) { - sComponents[n] = - (byte) (alpha * sComponents[n] + 0.5f); + } + break; + + case DataBuffer.TYPE_SHORT: + float sAlphaFactor = maxValues[numColorComponents]; + short sComponents[] = null; + short sTransparentComponents[] = new short[numComponents]; + for (int i = 0; i < h; i++, minY++) { + for (int j = 0, x = minX; j < w; j++, x++) { + sComponents = (short[])raster.getDataElements(x, minY, sComponents); + if (sComponents[numColorComponents] == 0) { + raster.setDataElements(x, minY, sTransparentComponents); + } else { + float alpha = sComponents[numColorComponents] / sAlphaFactor; + for (int n = 0; n < numColorComponents; n++) { + sComponents[n] = (byte)(alpha * sComponents[n] + 0.5f); + } + raster.setDataElements(x, minY, sComponents); } - raster.setDataElements(x, minY, sComponents); } - } - - } - break; - case DataBuffer.TYPE_FLOAT: - float fComponents[] = null; - float fTransparentComponents[] = new float[numComponents]; - for (int i = 0; i < h; i++, minY++) { - for (int j = 0, x = minX; j < w; j++, x++) { - fComponents = raster.getPixel(x, minY, fComponents); - if (fComponents[numColorComponents] == 0.0f) { - raster.setDataElements(x, minY, - fTransparentComponents); - } else { - float alpha = fComponents[numColorComponents]; - for (int n = 0; n < numColorComponents; n++) { - fComponents[n] = fComponents[n] * alpha; + } + break; + + case DataBuffer.TYPE_FLOAT: + float fComponents[] = null; + float fTransparentComponents[] = new float[numComponents]; + for (int i = 0; i < h; i++, minY++) { + for (int j = 0, x = minX; j < w; j++, x++) { + fComponents = raster.getPixel(x, minY, fComponents); + if (fComponents[numColorComponents] == 0.0f) { + raster.setDataElements(x, minY, fTransparentComponents); + } else { + float alpha = fComponents[numColorComponents]; + for (int n = 0; n < numColorComponents; n++) { + fComponents[n] = fComponents[n] * alpha; + } + raster.setPixel(x, minY, fComponents); } - raster.setPixel(x, minY, fComponents); } - } - } - break; - - case DataBuffer.TYPE_DOUBLE: - double dComponents[] = null; - double dTransparentComponents[] = new double[numComponents]; - for (int i = 0; i < h; i++, minY++) { - for (int j = 0, x = minX; j < w; j++, x++) { - dComponents = raster.getPixel(x, minY, dComponents); - if (dComponents[numColorComponents] == 0.0) { - raster.setPixel(x, minY, dTransparentComponents); - } else { - double alpha = dComponents[numColorComponents]; - for (int n = 0; n < numColorComponents; n++) { - dComponents[n] = dComponents[n] * alpha; + } + break; + + case DataBuffer.TYPE_DOUBLE: + double dComponents[] = null; + double dTransparentComponents[] = new double[numComponents]; + for (int i = 0; i < h; i++, minY++) { + for (int j = 0, x = minX; j < w; j++, x++) { + dComponents = raster.getPixel(x, minY, dComponents); + if (dComponents[numColorComponents] == 0.0) { + raster.setPixel(x, minY, dTransparentComponents); + } else { + double alpha = dComponents[numColorComponents]; + for (int n = 0; n < numColorComponents; n++) { + dComponents[n] = dComponents[n] * alpha; + } + raster.setPixel(x, minY, dComponents); } - raster.setPixel(x, minY, dComponents); } - } - } - break; + } + break; - default: - // awt.219=This transferType is not supported by this color model - throw new UnsupportedOperationException(Messages.getString("awt.219")); //$NON-NLS-1$ + default: + // awt.219=This transferType is not supported by this color + // model + throw new UnsupportedOperationException(Messages.getString("awt.219")); //$NON-NLS-1$ } } else { switch (transferType) { - case DataBuffer.TYPE_BYTE: - case DataBuffer.TYPE_USHORT: - case DataBuffer.TYPE_INT: - float alphaFactor = maxValues[numColorComponents]; - int iComponents[] = null; - int iTransparentComponents[] = new int[numComponents]; - for (int i = 0; i < h; i++, minY++) { - for (int j = 0, x = minX; j < w; j++, x++) { - iComponents = raster.getPixel(x, minY, - iComponents); - if (iComponents[numColorComponents] == 0) { - raster.setPixel(x, minY, iTransparentComponents); - } else { - float alpha = - iComponents[numColorComponents] / - alphaFactor; - for (int n = 0; n < numColorComponents; n++) { - iComponents[n] = - (int) (iComponents[n] / - alpha + 0.5f); + case DataBuffer.TYPE_BYTE: + case DataBuffer.TYPE_USHORT: + case DataBuffer.TYPE_INT: + float alphaFactor = maxValues[numColorComponents]; + int iComponents[] = null; + int iTransparentComponents[] = new int[numComponents]; + for (int i = 0; i < h; i++, minY++) { + for (int j = 0, x = minX; j < w; j++, x++) { + iComponents = raster.getPixel(x, minY, iComponents); + if (iComponents[numColorComponents] == 0) { + raster.setPixel(x, minY, iTransparentComponents); + } else { + float alpha = iComponents[numColorComponents] / alphaFactor; + for (int n = 0; n < numColorComponents; n++) { + iComponents[n] = (int)(iComponents[n] / alpha + 0.5f); + } + raster.setPixel(x, minY, iComponents); } - raster.setPixel(x, minY, iComponents); } - } - } - break; - - case DataBuffer.TYPE_SHORT: - float sAlphaFactor = maxValues[numColorComponents]; - short sComponents[] = null; - short sTransparentComponents[] = new short[numComponents]; - for (int i = 0; i < h; i++, minY++) { - for (int j = 0, x = minX; j < w; j++, x++) { - sComponents = (short[]) raster.getDataElements(x, minY, - sComponents); - if (sComponents[numColorComponents] == 0) { - raster.setDataElements(x, minY, - sTransparentComponents); - } else { - float alpha = - sComponents[numColorComponents] / - sAlphaFactor; - for (int n = 0; n < numColorComponents; n++) { - sComponents[n] = - (byte) (sComponents[n] / - alpha + 0.5f); + } + break; + + case DataBuffer.TYPE_SHORT: + float sAlphaFactor = maxValues[numColorComponents]; + short sComponents[] = null; + short sTransparentComponents[] = new short[numComponents]; + for (int i = 0; i < h; i++, minY++) { + for (int j = 0, x = minX; j < w; j++, x++) { + sComponents = (short[])raster.getDataElements(x, minY, sComponents); + if (sComponents[numColorComponents] == 0) { + raster.setDataElements(x, minY, sTransparentComponents); + } else { + float alpha = sComponents[numColorComponents] / sAlphaFactor; + for (int n = 0; n < numColorComponents; n++) { + sComponents[n] = (byte)(sComponents[n] / alpha + 0.5f); + } + raster.setDataElements(x, minY, sComponents); } - raster.setDataElements(x, minY, sComponents); } - } - } - break; - - case DataBuffer.TYPE_FLOAT: - float fComponents[] = null; - float fTransparentComponents[] = new float[numComponents]; - for (int i = 0; i < h; i++, minY++) { - for (int j = 0, x = minX; j < w; j++, x++) { - fComponents = raster.getPixel(x, minY, fComponents); - if (fComponents[numColorComponents] == 0.0f) { - raster.setDataElements(x, minY, - fTransparentComponents); - } else { - float alpha = fComponents[numColorComponents]; - for (int n = 0; n < numColorComponents; n++) { - fComponents[n] = fComponents[n] / alpha; + } + break; + + case DataBuffer.TYPE_FLOAT: + float fComponents[] = null; + float fTransparentComponents[] = new float[numComponents]; + for (int i = 0; i < h; i++, minY++) { + for (int j = 0, x = minX; j < w; j++, x++) { + fComponents = raster.getPixel(x, minY, fComponents); + if (fComponents[numColorComponents] == 0.0f) { + raster.setDataElements(x, minY, fTransparentComponents); + } else { + float alpha = fComponents[numColorComponents]; + for (int n = 0; n < numColorComponents; n++) { + fComponents[n] = fComponents[n] / alpha; + } + raster.setPixel(x, minY, fComponents); } - raster.setPixel(x, minY, fComponents); } - } - - } - break; - case DataBuffer.TYPE_DOUBLE: - double dComponents[] = null; - double dTransparentComponents[] = new double[numComponents]; - for (int i = 0; i < h; i++, minY++) { - for (int j = 0, x = minX; j < w; j++, x++) { - dComponents = raster.getPixel(x, minY, dComponents); - if (dComponents[numColorComponents] == 0.0) { - raster.setPixel(x, minY, dTransparentComponents); - } else { - double alpha = dComponents[numColorComponents]; - for (int n = 0; n < numColorComponents; n++) { - dComponents[n] = dComponents[n] / alpha; + } + break; + + case DataBuffer.TYPE_DOUBLE: + double dComponents[] = null; + double dTransparentComponents[] = new double[numComponents]; + for (int i = 0; i < h; i++, minY++) { + for (int j = 0, x = minX; j < w; j++, x++) { + dComponents = raster.getPixel(x, minY, dComponents); + if (dComponents[numColorComponents] == 0.0) { + raster.setPixel(x, minY, dTransparentComponents); + } else { + double alpha = dComponents[numColorComponents]; + for (int n = 0; n < numColorComponents; n++) { + dComponents[n] = dComponents[n] / alpha; + } + raster.setPixel(x, minY, dComponents); } - raster.setPixel(x, minY, dComponents); } - } - } - break; - default: - // awt.219=This transferType is not supported by this color model - throw new UnsupportedOperationException(Messages.getString("awt.219")); //$NON-NLS-1$ + } + break; + default: + // awt.219=This transferType is not supported by this color + // model + throw new UnsupportedOperationException(Messages.getString("awt.219")); //$NON-NLS-1$ } } if (!signed) { - return new ComponentColorModel(cs, bits, hasAlpha, - isAlphaPremultiplied, transparency, transferType); + return new ComponentColorModel(cs, bits, hasAlpha, isAlphaPremultiplied, transparency, + transferType); } - return new ComponentColorModel(cs, null, hasAlpha, - isAlphaPremultiplied, transparency, transferType); + return new ComponentColorModel(cs, null, hasAlpha, isAlphaPremultiplied, transparency, + transferType); } @Override public int[] getComponents(Object pixel, int[] components, int offset) { if (donotSupportUnnormalized) { - // awt.213=This ComponentColorModel does not support the unnormalized form + // awt.213=This ComponentColorModel does not support the + // unnormalized form throw new IllegalArgumentException(Messages.getString("awt.213")); //$NON-NLS-1$ } if (components == null) { components = new int[offset + numComponents]; } else if (offset + numComponents > components.length) { - // awt.218=The components array is not large enough to hold all the color and alpha components + // awt.218=The components array is not large enough to hold all the + // color and alpha components throw new IllegalArgumentException(Messages.getString("awt.218")); //$NON-NLS-1$ } switch (transferType) { - case DataBuffer.TYPE_BYTE: - byte ba[] = (byte[]) pixel; + case DataBuffer.TYPE_BYTE: + byte ba[] = (byte[])pixel; - for (int i = 0, idx = offset; i < numComponents; i++, idx++) { - components[idx] = ba[i] & 0xff; - } - return components; + for (int i = 0, idx = offset; i < numComponents; i++, idx++) { + components[idx] = ba[i] & 0xff; + } + return components; - case DataBuffer.TYPE_USHORT: - short sa[] = (short[]) pixel; - for (int i = 0, idx = offset; i < numComponents; i++, idx++) { - components[idx] = sa[i] & 0xffff; - } - return components; + case DataBuffer.TYPE_USHORT: + short sa[] = (short[])pixel; + for (int i = 0, idx = offset; i < numComponents; i++, idx++) { + components[idx] = sa[i] & 0xffff; + } + return components; - case DataBuffer.TYPE_INT: - int ia[] = (int[]) pixel; - for (int i = 0, idx = offset; i < numComponents; i++, idx++) { - components[idx] = ia[i]; - } - return components; - - default: - // awt.217=The transfer type of this ComponentColorModel is not one - // of the following transfer types: DataBuffer.TYPE_BYTE, - // DataBuffer.TYPE_USHORT, or DataBuffer.TYPE_INT - throw new UnsupportedOperationException(Messages - .getString("awt.217")); //$NON-NLS-1$ + case DataBuffer.TYPE_INT: + int ia[] = (int[])pixel; + for (int i = 0, idx = offset; i < numComponents; i++, idx++) { + components[idx] = ia[i]; + } + return components; + + default: + // awt.217=The transfer type of this ComponentColorModel is not + // one + // of the following transfer types: DataBuffer.TYPE_BYTE, + // DataBuffer.TYPE_USHORT, or DataBuffer.TYPE_INT + throw new UnsupportedOperationException(Messages.getString("awt.217")); //$NON-NLS-1$ } } @Override - public float[] getNormalizedComponents(Object pixel, - float normComponents[], int normOffset) { + public float[] getNormalizedComponents(Object pixel, float normComponents[], int normOffset) { if (normComponents == null) { normComponents = new float[numComponents + normOffset]; } switch (transferType) { - case DataBuffer.TYPE_BYTE: - byte ba[] = (byte[]) pixel; - for (int i = 0, idx = normOffset; i < numComponents; i++, idx++) { - normComponents[idx] = (ba[i] & 0xff) * scaleFactors[i]; - } - break; + case DataBuffer.TYPE_BYTE: + byte ba[] = (byte[])pixel; + for (int i = 0, idx = normOffset; i < numComponents; i++, idx++) { + normComponents[idx] = (ba[i] & 0xff) * scaleFactors[i]; + } + break; - case DataBuffer.TYPE_USHORT: - short usa[] = (short[]) pixel; - for (int i = 0, idx = normOffset; i < numComponents; i++, idx++) { - normComponents[idx] = (usa[i] & 0xffff) - * scaleFactors[i]; - } - break; + case DataBuffer.TYPE_USHORT: + short usa[] = (short[])pixel; + for (int i = 0, idx = normOffset; i < numComponents; i++, idx++) { + normComponents[idx] = (usa[i] & 0xffff) * scaleFactors[i]; + } + break; - case DataBuffer.TYPE_INT: - int ia[] = (int[]) pixel; - for (int i = 0, idx = normOffset; i < numComponents; i++, idx++) { - normComponents[idx] = ia[i] * scaleFactors[i]; - } - break; + case DataBuffer.TYPE_INT: + int ia[] = (int[])pixel; + for (int i = 0, idx = normOffset; i < numComponents; i++, idx++) { + normComponents[idx] = ia[i] * scaleFactors[i]; + } + break; - case DataBuffer.TYPE_SHORT: - short sa[] = (short[]) pixel; - for (int i = 0, idx = normOffset; i < numComponents; i++, idx++) { - normComponents[idx] = sa[i] * scaleFactors[i]; - } - break; + case DataBuffer.TYPE_SHORT: + short sa[] = (short[])pixel; + for (int i = 0, idx = normOffset; i < numComponents; i++, idx++) { + normComponents[idx] = sa[i] * scaleFactors[i]; + } + break; - case DataBuffer.TYPE_FLOAT: - float fa[] = (float[]) pixel; - for (int i = 0, idx = normOffset; i < numComponents; i++, idx++) { - normComponents[idx] = fa[i]; - } - break; + case DataBuffer.TYPE_FLOAT: + float fa[] = (float[])pixel; + for (int i = 0, idx = normOffset; i < numComponents; i++, idx++) { + normComponents[idx] = fa[i]; + } + break; - case DataBuffer.TYPE_DOUBLE: - double da[] = (double[]) pixel; - for (int i = 0, idx = normOffset; i < numComponents; i++, idx++) { - normComponents[idx] = (float) da[i]; - } - break; + case DataBuffer.TYPE_DOUBLE: + double da[] = (double[])pixel; + for (int i = 0, idx = normOffset; i < numComponents; i++, idx++) { + normComponents[idx] = (float)da[i]; + } + break; - default: - // awt.21A=This ComponentColorModel does not support this transferType - throw new IllegalArgumentException(Messages.getString("awt.21A")); //$NON-NLS-1$ + default: + // awt.21A=This ComponentColorModel does not support this + // transferType + throw new IllegalArgumentException(Messages.getString("awt.21A")); //$NON-NLS-1$ } if (needAlphaDivide) { float alpha = normComponents[normOffset + numColorComponents]; - for (int i = 0, idx = normOffset; i < numColorComponents; - i++, idx++) { + for (int i = 0, idx = normOffset; i < numColorComponents; i++, idx++) { normComponents[idx] /= alpha; } } if (needScale) { - for (int i = 0, idx = normOffset; i < numColorComponents; - i++, idx++) { - normComponents[idx] = minVals[i] + - ranges[i] * normComponents[idx]; + for (int i = 0, idx = normOffset; i < numColorComponents; i++, idx++) { + normComponents[idx] = minVals[i] + ranges[i] * normComponents[idx]; } } return normComponents; @@ -934,8 +950,7 @@ public class ComponentColorModel extends ColorModel { int gray = getRed(inData); return (alpha << 24 | gray << 16 | gray << 8 | gray); } - return (alpha << 24 | getRed(inData) << 16 | getGreen(inData) << 8 | - getBlue(inData)); + return (alpha << 24 | getRed(inData) << 16 | getGreen(inData) << 8 | getBlue(inData)); } @Override @@ -956,50 +971,50 @@ public class ComponentColorModel extends ColorModel { int alpha = 0; switch (transferType) { - case DataBuffer.TYPE_BYTE: { - byte ba[] = (byte[]) inData; - alpha = ba[numColorComponents] & 0xff; - if (bits[numColorComponents] != 8) { - return alphaLUT[alpha] & 0xff; + case DataBuffer.TYPE_BYTE: { + byte ba[] = (byte[])inData; + alpha = ba[numColorComponents] & 0xff; + if (bits[numColorComponents] != 8) { + return alphaLUT[alpha] & 0xff; + } + return alpha; } - return alpha; - } - case DataBuffer.TYPE_USHORT: { - short usa[] = (short[]) inData; - alpha = usa[numColorComponents] & 0xffff; - if (bits[numColorComponents] != 8) { - return alphaLUT[alpha] & 0xff; + case DataBuffer.TYPE_USHORT: { + short usa[] = (short[])inData; + alpha = usa[numColorComponents] & 0xffff; + if (bits[numColorComponents] != 8) { + return alphaLUT[alpha] & 0xff; + } + return alpha; } - return alpha; - } - case DataBuffer.TYPE_INT: { - int ia[] = (int[]) inData; - alpha = ia[numColorComponents]; - if (bits[numColorComponents] != 8) { - return alphaLUT[alpha] & 0xff; + case DataBuffer.TYPE_INT: { + int ia[] = (int[])inData; + alpha = ia[numColorComponents]; + if (bits[numColorComponents] != 8) { + return alphaLUT[alpha] & 0xff; + } + return alpha; } - return alpha; - } - case DataBuffer.TYPE_SHORT: { - short sa[] = (short[]) inData; - alpha = sa[numColorComponents]; - if (bits[numColorComponents] != 8) { - return alphaLUT[alpha] & 0xff; + case DataBuffer.TYPE_SHORT: { + short sa[] = (short[])inData; + alpha = sa[numColorComponents]; + if (bits[numColorComponents] != 8) { + return alphaLUT[alpha] & 0xff; + } + return alpha; + } + case DataBuffer.TYPE_FLOAT: { + float fa[] = (float[])inData; + return (int)(fa[numColorComponents] * 255.0f + 0.5f); + } + case DataBuffer.TYPE_DOUBLE: { + double da[] = (double[])inData; + return (int)(da[numColorComponents] * 255.0 + 0.5); + } + default: { + // awt.214=This Color Model doesn't support this transferType + throw new UnsupportedOperationException(Messages.getString("awt.214")); //$NON-NLS-1$ } - return alpha; - } - case DataBuffer.TYPE_FLOAT: { - float fa[] = (float[]) inData; - return (int) (fa[numColorComponents] * 255.0f + 0.5f); - } - case DataBuffer.TYPE_DOUBLE: { - double da[] = (double[]) inData; - return (int) (da[numColorComponents] * 255.0 + 0.5); - } - default: { - // awt.214=This Color Model doesn't support this transferType - throw new UnsupportedOperationException(Messages.getString("awt.214")); //$NON-NLS-1$ - } } } @@ -1032,14 +1047,14 @@ public class ComponentColorModel extends ColorModel { } switch (transferType) { - case DataBuffer.TYPE_BYTE: - case DataBuffer.TYPE_USHORT: - return new PixelInterleavedSampleModel(transferType, w, h, - numComponents, w * numComponents, bandOffsets); - - default: - return new ComponentSampleModel(transferType, w, h, numComponents, - w * numComponents, bandOffsets); + case DataBuffer.TYPE_BYTE: + case DataBuffer.TYPE_USHORT: + return new PixelInterleavedSampleModel(transferType, w, h, numComponents, w + * numComponents, bandOffsets); + + default: + return new ComponentSampleModel(transferType, w, h, numComponents, w + * numComponents, bandOffsets); } } @@ -1067,15 +1082,15 @@ public class ComponentColorModel extends ColorModel { } @Override - public float[] getNormalizedComponents(int components[], int offset, - float normComponents[], int normOffset) { + public float[] getNormalizedComponents(int components[], int offset, float normComponents[], + int normOffset) { if (donotSupportUnnormalized) { - // awt.213=This ComponentColorModel does not support the unnormalized form + // awt.213=This ComponentColorModel does not support the + // unnormalized form throw new IllegalArgumentException(Messages.getString("awt.213")); //$NON-NLS-1$ } - return super.getNormalizedComponents(components, offset, - normComponents, normOffset); + return super.getNormalizedComponents(components, offset, normComponents, normOffset); } @Override @@ -1085,28 +1100,30 @@ public class ComponentColorModel extends ColorModel { throw new IllegalArgumentException(Messages.getString("awt.212")); //$NON-NLS-1$ } if (donotSupportUnnormalized) { - // awt.213=This ComponentColorModel does not support the unnormalized form + // awt.213=This ComponentColorModel does not support the + // unnormalized form throw new IllegalArgumentException(Messages.getString("awt.213")); //$NON-NLS-1$ } return components[offset]; } @Override - public int[] getUnnormalizedComponents(float[] normComponents, - int normOffset, int[] components, int offset) { + public int[] getUnnormalizedComponents(float[] normComponents, int normOffset, + int[] components, int offset) { if (donotSupportUnnormalized) { - // awt.213=This ComponentColorModel does not support the unnormalized form + // awt.213=This ComponentColorModel does not support the + // unnormalized form throw new IllegalArgumentException(Messages.getString("awt.213")); //$NON-NLS-1$ } if (normComponents.length - normOffset < numComponents) { - // awt.21B=The length of normComponents minus normOffset is less than numComponents + // awt.21B=The length of normComponents minus normOffset is less + // than numComponents throw new IllegalArgumentException(Messages.getString("awt.21B")); //$NON-NLS-1$ } - return super.getUnnormalizedComponents(normComponents, normOffset, - components, offset); + return super.getUnnormalizedComponents(normComponents, normOffset, components, offset); } @Override @@ -1123,19 +1140,19 @@ public class ComponentColorModel extends ColorModel { Object pixel = getDataElements(normComponents, normOffset, null); switch (transferType) { - case DataBuffer.TYPE_BYTE: - byte ba[] = (byte[]) pixel; - return ba[0] & 0xff; - case DataBuffer.TYPE_USHORT: - short sa[] = (short[]) pixel; - return sa[0] & 0xffff; - case DataBuffer.TYPE_INT: - int ia[] = (int[]) pixel; - return ia[0]; - default: - // awt.211=Pixel values for this ColorModel are not conveniently - // representable as a single int - throw new IllegalArgumentException(Messages.getString("awt.211")); //$NON-NLS-1$ + case DataBuffer.TYPE_BYTE: + byte ba[] = (byte[])pixel; + return ba[0] & 0xff; + case DataBuffer.TYPE_USHORT: + short sa[] = (short[])pixel; + return sa[0] & 0xffff; + case DataBuffer.TYPE_INT: + int ia[] = (int[])pixel; + return ia[0]; + default: + // awt.211=Pixel values for this ColorModel are not conveniently + // representable as a single int + throw new IllegalArgumentException(Messages.getString("awt.211")); //$NON-NLS-1$ } } @@ -1146,7 +1163,8 @@ public class ComponentColorModel extends ColorModel { throw new IllegalArgumentException(Messages.getString("awt.212")); //$NON-NLS-1$ } if (donotSupportUnnormalized) { - // awt.213=This ComponentColorModel does not support the unnormalized form + // awt.213=This ComponentColorModel does not support the + // unnormalized form throw new IllegalArgumentException(Messages.getString("awt.213")); //$NON-NLS-1$ } @@ -1161,31 +1179,31 @@ public class ComponentColorModel extends ColorModel { @Override public int getRed(int pixel) { float rgb[] = toRGB(pixel); - return (int) (rgb[0] * 255.0f + 0.5f); + return (int)(rgb[0] * 255.0f + 0.5f); } @Override public int getRGB(int pixel) { - return (getAlpha(pixel) << 24) | (getRed(pixel) << 16) | - (getGreen(pixel) << 8) | getBlue(pixel); + return (getAlpha(pixel) << 24) | (getRed(pixel) << 16) | (getGreen(pixel) << 8) + | getBlue(pixel); } @Override public int getGreen(int pixel) { float rgb[] = toRGB(pixel); - return (int) (rgb[1] * 255.0f + 0.5f); + return (int)(rgb[1] * 255.0f + 0.5f); } @Override public int getBlue(int pixel) { float rgb[] = toRGB(pixel); - return (int) (rgb[2] * 255.0f + 0.5f); + return (int)(rgb[2] * 255.0f + 0.5f); } @Override public int getAlpha(int pixel) { - // This method throw IllegalArgumentException according to + // This method throw IllegalArgumentException according to // Java API Spacification if (signed) { // awt.210=The component value for this ColorModel is signed @@ -1210,24 +1228,19 @@ public class ComponentColorModel extends ColorModel { if (hasAlpha && bits[numColorComponents] != 8 && integral) { alphaLUT = new byte[maxValues[numColorComponents] + 1]; for (int i = 0; i <= maxValues[numColorComponents]; i++) { - alphaLUT[i] = (byte) (scaleFactors[numColorComponents] * i + - 0.5f); + alphaLUT[i] = (byte)(scaleFactors[numColorComponents] * i + 0.5f); } } if (is_LINEAR_RGB) { if (maxBitLength > 8) { LINEAR_RGB_Length = 16; - from_LINEAR_RGB_LUT = - LUTColorConverter.getFrom16lRGBtosRGB_LUT(); - to_LINEAR_16RGB_LUT = - LUTColorConverter.getFromsRGBto16lRGB_LUT(); + from_LINEAR_RGB_LUT = LUTColorConverter.getFrom16lRGBtosRGB_LUT(); + to_LINEAR_16RGB_LUT = LUTColorConverter.getFromsRGBto16lRGB_LUT(); } else { LINEAR_RGB_Length = 8; - from_LINEAR_RGB_LUT = - LUTColorConverter.getFrom8lRGBtosRGB_LUT(); - to_LINEAR_8RGB_LUT = - LUTColorConverter.getFromsRGBto8lRGB_LUT(); + from_LINEAR_RGB_LUT = LUTColorConverter.getFrom8lRGBtosRGB_LUT(); + to_LINEAR_8RGB_LUT = LUTColorConverter.getFromsRGBto8lRGB_LUT(); } fFactor = ((1 << LINEAR_RGB_Length) - 1); } else { @@ -1248,8 +1261,7 @@ public class ComponentColorModel extends ColorModel { } colorLUTs[i] = new byte[maxValues[i] + 1]; for (int j = 0; j <= maxValues[0]; j++) { - colorLUTs[i][j] = - (byte) (scaleFactors[i] * j + 0.5f); + colorLUTs[i][j] = (byte)(scaleFactors[i] * j + 0.5f); } } } @@ -1269,10 +1281,9 @@ public class ComponentColorModel extends ColorModel { for (int j = 0; j <= maxValues[0]; j++) { int idx; if (LINEAR_RGB_Length == 8) { - idx = (int) (scaleFactors[i] * j + 0.5f); + idx = (int)(scaleFactors[i] * j + 0.5f); } else { - idx = (int) (scaleFactors[i] * j * 257.0f + - 0.5f); + idx = (int)(scaleFactors[i] * j * 257.0f + 0.5f); } colorLUTs[i][j] = from_LINEAR_RGB_LUT[idx]; } @@ -1286,13 +1297,13 @@ public class ComponentColorModel extends ColorModel { /** * To rgb. * - * @param pixel - int representation of pixel - * - * @return - array of normalized sRGB components + * @param pixel + * the integer representation of the pixel. + * @return the array of normalized sRGB components. */ private float[] toRGB(int pixel) { - - // This method throw IllegalArgumentException according to + + // This method throw IllegalArgumentException according to // Java API Spacification if (signed) { // awt.210=The component value for this ColorModel is signed @@ -1307,23 +1318,23 @@ public class ComponentColorModel extends ColorModel { Object obj = null; switch (transferType) { - case DataBuffer.TYPE_BYTE: - byte ba[] = new byte[1]; - ba[0] = (byte) pixel; - obj = ba; - break; - - case DataBuffer.TYPE_USHORT: - short sa[] = new short[1]; - sa[0] = (short) pixel; - obj = sa; - break; - - case DataBuffer.TYPE_INT: - int ia[] = new int[1]; - ia[0] = pixel; - obj = ia; - break; + case DataBuffer.TYPE_BYTE: + byte ba[] = new byte[1]; + ba[0] = (byte)pixel; + obj = ba; + break; + + case DataBuffer.TYPE_USHORT: + short sa[] = new short[1]; + sa[0] = (short)pixel; + obj = sa; + break; + + case DataBuffer.TYPE_INT: + int ia[] = new int[1]; + ia[0] = pixel; + obj = ia; + break; } @@ -1331,12 +1342,13 @@ public class ComponentColorModel extends ColorModel { } /** - * Gets the rgb component. + * Gets the RGB component. * - * @param pixel - pixel - * @param idx - index of component - * - * @return - RGB value from 0 to 255 pixel's component + * @param pixel + * the pixel. + * @param idx + * the index of component. + * @return the RGB value from 0 to 255 pixel's component. */ private int getRGBComponent(Object pixel, int idx) { if (is_sRGB) { @@ -1355,117 +1367,116 @@ public class ComponentColorModel extends ColorModel { float normComp[] = getNormalizedComponents(pixel, null, 0); float rgbComp[] = cs.toRGB(normComp); - return (int) (rgbComp[idx] * 255.0f + 0.5f); + return (int)(rgbComp[idx] * 255.0f + 0.5f); } /** * Gets the def component. * - * @param pixel - pixel - * @param idx - index of component - * - * @return - tentative value of the pixel component + * @param pixel + * the pixel. + * @param idx + * the index of component. + * @return the tentative value of the pixel component. */ private int getDefComponent(Object pixel, int idx) { int comp = 0; calcValue = false; switch (transferType) { - case DataBuffer.TYPE_BYTE: - byte ba[] = (byte[]) pixel; - comp = ba[idx] & 0xff; - if (needAlphaDivide) { - int alpha = ba[numColorComponents] & 0xff; - if (alpha == 0) { - comp = 0; - } else { - float normAlpha = scaleFactors[numColorComponents] * alpha; - comp = (int) (comp * fFactor / normAlpha + 0.5f); + case DataBuffer.TYPE_BYTE: + byte ba[] = (byte[])pixel; + comp = ba[idx] & 0xff; + if (needAlphaDivide) { + int alpha = ba[numColorComponents] & 0xff; + if (alpha == 0) { + comp = 0; + } else { + float normAlpha = scaleFactors[numColorComponents] * alpha; + comp = (int)(comp * fFactor / normAlpha + 0.5f); + } + calcValue = true; } - calcValue = true; - } - return comp; - - case DataBuffer.TYPE_USHORT: - short usa[] = (short[]) pixel; - comp = usa[idx] & 0xffff; - if (needAlphaDivide) { - int alpha = usa[numColorComponents] & 0xffff; - if (alpha == 0) { - comp = 0; - } else { - float normAlpha = scaleFactors[numColorComponents] * alpha; - comp = (int) (comp * fFactor / normAlpha + 0.5f); + return comp; + + case DataBuffer.TYPE_USHORT: + short usa[] = (short[])pixel; + comp = usa[idx] & 0xffff; + if (needAlphaDivide) { + int alpha = usa[numColorComponents] & 0xffff; + if (alpha == 0) { + comp = 0; + } else { + float normAlpha = scaleFactors[numColorComponents] * alpha; + comp = (int)(comp * fFactor / normAlpha + 0.5f); + } + calcValue = true; } - calcValue = true; - } - return comp; - - case DataBuffer.TYPE_INT: - int ia[] = (int[]) pixel; - comp = ia[idx]; - if (needAlphaDivide) { - int alpha = ia[numColorComponents]; - if (alpha == 0) { - comp = 0; - } else { - float normAlpha = scaleFactors[numColorComponents] * alpha; - comp = (int) (comp * fFactor / normAlpha + 0.5f); + return comp; + + case DataBuffer.TYPE_INT: + int ia[] = (int[])pixel; + comp = ia[idx]; + if (needAlphaDivide) { + int alpha = ia[numColorComponents]; + if (alpha == 0) { + comp = 0; + } else { + float normAlpha = scaleFactors[numColorComponents] * alpha; + comp = (int)(comp * fFactor / normAlpha + 0.5f); + } + calcValue = true; } - calcValue = true; - } - return comp; - - case DataBuffer.TYPE_SHORT: - short sa[] = (short[]) pixel; - comp = sa[idx]; - if (needAlphaDivide) { - int alpha = sa[numColorComponents]; - if (alpha == 0) { - comp = 0; - } else { - float normAlpha = scaleFactors[numColorComponents] * alpha; - comp = (int) (comp * fFactor / normAlpha + 0.5f); + return comp; + + case DataBuffer.TYPE_SHORT: + short sa[] = (short[])pixel; + comp = sa[idx]; + if (needAlphaDivide) { + int alpha = sa[numColorComponents]; + if (alpha == 0) { + comp = 0; + } else { + float normAlpha = scaleFactors[numColorComponents] * alpha; + comp = (int)(comp * fFactor / normAlpha + 0.5f); + } + calcValue = true; } - calcValue = true; - } - return comp; - - case DataBuffer.TYPE_FLOAT: - float fa[] = (float[]) pixel; - if (needAlphaDivide) { - float alpha = fa[numColorComponents]; - if (fa[numColorComponents] == 0.0f) { - comp = 0; + return comp; + + case DataBuffer.TYPE_FLOAT: + float fa[] = (float[])pixel; + if (needAlphaDivide) { + float alpha = fa[numColorComponents]; + if (fa[numColorComponents] == 0.0f) { + comp = 0; + } else { + comp = (int)(fa[idx] * fFactor / alpha + 0.5f); + } } else { - comp = (int) (fa[idx] * fFactor / alpha + 0.5f); + comp = (int)(fa[idx] * fFactor + 0.5f); } - } else { - comp = (int) (fa[idx] * fFactor + 0.5f); - } - calcValue = true; - return comp; - - case DataBuffer.TYPE_DOUBLE: - double da[] = (double[]) pixel; - if (needAlphaDivide) { - if (da[numColorComponents] == 0.0) { - comp = 0; + calcValue = true; + return comp; + + case DataBuffer.TYPE_DOUBLE: + double da[] = (double[])pixel; + if (needAlphaDivide) { + if (da[numColorComponents] == 0.0) { + comp = 0; + } else { + comp = (int)(da[idx] * fFactor / da[numColorComponents] + 0.5); + } } else { - comp = (int) (da[idx] * fFactor / da[numColorComponents] + - 0.5); + comp = (int)(da[idx] * fFactor + 0.5); } - } else { - comp = (int) (da[idx] * fFactor + 0.5); - } - calcValue = true; - return comp; + calcValue = true; + return comp; - default: - // awt.214=This Color Model doesn't support this transferType - throw new UnsupportedOperationException(Messages.getString("awt.214")); //$NON-NLS-1$ + default: + // awt.214=This Color Model doesn't support this transferType + throw new UnsupportedOperationException(Messages.getString("awt.214")); //$NON-NLS-1$ } } } - diff --git a/awt/java/awt/image/ComponentSampleModel.java b/awt/java/awt/image/ComponentSampleModel.java index 2ff4f1a2b213ae6695f242cd113c1c4502d5a4aa..7f8140918deab435694e10ef532c99638ec827c3 100644 --- a/awt/java/awt/image/ComponentSampleModel.java +++ b/awt/java/awt/image/ComponentSampleModel.java @@ -18,6 +18,7 @@ * @author Igor V. Stolyarov * @version $Revision$ */ + package java.awt.image; import java.util.Arrays; @@ -25,55 +26,73 @@ import java.util.Arrays; import org.apache.harmony.awt.internal.nls.Messages; /** - * The ComponentSampleModel class represents a set of image data whose - * each element - the sample of a pixel - takes one data element of - * the DataBuffer. + * The ComponentSampleModel class represents a set of image data whose each + * element - the sample of a pixel - takes one data element of the DataBuffer. *

    - * The Bank indices denote the correspondence between the bank of data - * buffers and a band of image data. The Pixel stride is the number of data - * array elements between two samples for the same band on the same - * scanline. The pixel stride for a BandedSampleModel is one. The Scanline - * stride represents the number of data array elements between a - * specified sample and the corresponding sample in the same column in - * the next scanline. The array of band offsets gives the starting - * offsets within each data banks of the in the DataBuffer. The bank - * indices represents the indices within each bank of the DataBuffer - * corresponding to a band of image data. + * The Bank indices denote the correspondence between the bank of data buffers + * and a band of image data. The Pixel stride is the number of data array + * elements between two samples for the same band on the same scanline. The + * pixel stride for a BandedSampleModel is one. The scanline stride represents + * the number of data array elements between a specified sample and the + * corresponding sample in the same column in the next scanline. The array of + * band offsets gives the starting offsets within each data banks of the in the + * DataBuffer. The bank indices represents the indices within each bank of the + * DataBuffer corresponding to a band of image data. + * + * @since Android 1.0 */ public class ComponentSampleModel extends SampleModel { - /** The band offsets array of this ComponentSampleModel. */ + /** + * The band offsets array of this ComponentSampleModel. + */ protected int bandOffsets[]; - /** The bank indices array of this ComponentSampleModel. */ + /** + * The bank indices array of this ComponentSampleModel. + */ protected int bankIndices[]; - /** The number of bands in this ComponentSampleModel. */ + /** + * The number of bands in this ComponentSampleModel. + */ protected int numBands; - /** The number banks of this ComponentSampleModel. */ + /** + * The number banks of this ComponentSampleModel. + */ protected int numBanks; - /** The scanline stride of this ComponentSampleModel. */ + /** + * The scanline stride of this ComponentSampleModel. + */ protected int scanlineStride; - /** The pixel stride of this ComponentSampleModel. */ + /** + * The pixel stride of this ComponentSampleModel. + */ protected int pixelStride; /** - * Instantiates a new ComponentSampleModel with the specified - * properties. + * Instantiates a new ComponentSampleModel with the specified properties. * - * @param dataType the data type of samples. - * @param w the width of the image data. - * @param h the height of the image data. - * @param pixelStride the pixel stride of the image data. - * @param scanlineStride the scanline stride of the image data. - * @param bankIndices the array of the bank indices. - * @param bandOffsets the array of the band offsets. + * @param dataType + * the data type of samples. + * @param w + * the width of the image data. + * @param h + * the height of the image data. + * @param pixelStride + * the pixel stride of the image data. + * @param scanlineStride + * the scanline stride of the image data. + * @param bankIndices + * the array of the bank indices. + * @param bandOffsets + * the array of the band offsets. */ - public ComponentSampleModel(int dataType, int w, int h, int pixelStride, - int scanlineStride, int bankIndices[], int bandOffsets[]) { + public ComponentSampleModel(int dataType, int w, int h, int pixelStride, int scanlineStride, + int bankIndices[], int bandOffsets[]) { super(dataType, w, h, bandOffsets.length); @@ -113,18 +132,23 @@ public class ComponentSampleModel extends SampleModel { } /** - * Instantiates a new ComponentSampleModel with the specified - * properties. + * Instantiates a new ComponentSampleModel with the specified properties. * - * @param dataType the data type of the samples. - * @param w the width of the image data. - * @param h the height of the image data. - * @param pixelStride the pixel stride of the image data. - * @param scanlineStride the scanline stride of the image data. - * @param bandOffsets the band offsets. + * @param dataType + * the data type of the samples. + * @param w + * the width of the image data. + * @param h + * the height of the image data. + * @param pixelStride + * the pixel stride of the image data. + * @param scanlineStride + * the scanline stride of the image data. + * @param bandOffsets + * the band offsets. */ - public ComponentSampleModel(int dataType, int w, int h, int pixelStride, - int scanlineStride, int bandOffsets[]) { + public ComponentSampleModel(int dataType, int w, int h, int pixelStride, int scanlineStride, + int bandOffsets[]) { super(dataType, w, h, bandOffsets.length); if (pixelStride < 0) { @@ -156,81 +180,81 @@ public class ComponentSampleModel extends SampleModel { throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ } switch (dataType) { - case DataBuffer.TYPE_BYTE: - byte bdata[]; - if (obj == null) { - bdata = new byte[numBands]; - } else { - bdata = (byte[]) obj; - } + case DataBuffer.TYPE_BYTE: + byte bdata[]; + if (obj == null) { + bdata = new byte[numBands]; + } else { + bdata = (byte[])obj; + } - for (int i = 0; i < numBands; i++) { - bdata[i] = (byte) getSample(x, y, i, data); - } + for (int i = 0; i < numBands; i++) { + bdata[i] = (byte)getSample(x, y, i, data); + } - obj = bdata; - break; + obj = bdata; + break; - case DataBuffer.TYPE_SHORT: - case DataBuffer.TYPE_USHORT: - short sdata[]; - if (obj == null) { - sdata = new short[numBands]; - } else { - sdata = (short[]) obj; - } + case DataBuffer.TYPE_SHORT: + case DataBuffer.TYPE_USHORT: + short sdata[]; + if (obj == null) { + sdata = new short[numBands]; + } else { + sdata = (short[])obj; + } - for (int i = 0; i < numBands; i++) { - sdata[i] = (short) getSample(x, y, i, data); - } + for (int i = 0; i < numBands; i++) { + sdata[i] = (short)getSample(x, y, i, data); + } - obj = sdata; - break; + obj = sdata; + break; - case DataBuffer.TYPE_INT: - int idata[]; - if (obj == null) { - idata = new int[numBands]; - } else { - idata = (int[]) obj; - } + case DataBuffer.TYPE_INT: + int idata[]; + if (obj == null) { + idata = new int[numBands]; + } else { + idata = (int[])obj; + } - for (int i = 0; i < numBands; i++) { - idata[i] = getSample(x, y, i, data); - } + for (int i = 0; i < numBands; i++) { + idata[i] = getSample(x, y, i, data); + } - obj = idata; - break; + obj = idata; + break; - case DataBuffer.TYPE_FLOAT: - float fdata[]; - if (obj == null) { - fdata = new float[numBands]; - } else { - fdata = (float[]) obj; - } + case DataBuffer.TYPE_FLOAT: + float fdata[]; + if (obj == null) { + fdata = new float[numBands]; + } else { + fdata = (float[])obj; + } - for (int i = 0; i < numBands; i++) { - fdata[i] = getSampleFloat(x, y, i, data); - } + for (int i = 0; i < numBands; i++) { + fdata[i] = getSampleFloat(x, y, i, data); + } - obj = fdata; - break; + obj = fdata; + break; - case DataBuffer.TYPE_DOUBLE: - double ddata[]; - if (obj == null) { - ddata = new double[numBands]; - } else { - ddata = (double[]) obj; - } + case DataBuffer.TYPE_DOUBLE: + double ddata[]; + if (obj == null) { + ddata = new double[numBands]; + } else { + ddata = (double[])obj; + } - for (int i = 0; i < numBands; i++) { - ddata[i] = getSampleDouble(x, y, i, data); - } + for (int i = 0; i < numBands; i++) { + ddata[i] = getSampleDouble(x, y, i, data); + } - obj = ddata; - break; + obj = ddata; + break; } return obj; @@ -243,76 +267,75 @@ public class ComponentSampleModel extends SampleModel { throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ } switch (dataType) { - case DataBuffer.TYPE_BYTE: - byte barr[] = (byte[]) obj; - for (int i = 0; i < numBands; i++) { - setSample(x, y, i, barr[i] & 0xff, data); - } - break; + case DataBuffer.TYPE_BYTE: + byte barr[] = (byte[])obj; + for (int i = 0; i < numBands; i++) { + setSample(x, y, i, barr[i] & 0xff, data); + } + break; - case DataBuffer.TYPE_SHORT: - case DataBuffer.TYPE_USHORT: - short sarr[] = (short[]) obj; - for (int i = 0; i < numBands; i++) { - setSample(x, y, i, sarr[i] & 0xffff, data); - } - break; + case DataBuffer.TYPE_SHORT: + case DataBuffer.TYPE_USHORT: + short sarr[] = (short[])obj; + for (int i = 0; i < numBands; i++) { + setSample(x, y, i, sarr[i] & 0xffff, data); + } + break; - case DataBuffer.TYPE_INT: - int iarr[] = (int[]) obj; - for (int i = 0; i < numBands; i++) { - setSample(x, y, i, iarr[i], data); - } - break; + case DataBuffer.TYPE_INT: + int iarr[] = (int[])obj; + for (int i = 0; i < numBands; i++) { + setSample(x, y, i, iarr[i], data); + } + break; - case DataBuffer.TYPE_FLOAT: - float farr[] = (float[]) obj; - for (int i = 0; i < numBands; i++) { - setSample(x, y, i, farr[i], data); - } - break; + case DataBuffer.TYPE_FLOAT: + float farr[] = (float[])obj; + for (int i = 0; i < numBands; i++) { + setSample(x, y, i, farr[i], data); + } + break; - case DataBuffer.TYPE_DOUBLE: - double darr[] = (double[]) obj; - for (int i = 0; i < numBands; i++) { - setSample(x, y, i, darr[i], data); - } - break; + case DataBuffer.TYPE_DOUBLE: + double darr[] = (double[])obj; + for (int i = 0; i < numBands; i++) { + setSample(x, y, i, darr[i], data); + } + break; } } /** * Compares this ComponentSampleModel with the specified Object. * - * @param o the Object. - * - * @return true, if the object is a ComponentSampleModel with - * identical data values to this ComponentSampleModel, false otherwise. + * @param o + * the Object. + * @return true, if the object is a ComponentSampleModel with identical data + * values to this ComponentSampleModel, false otherwise. */ @Override public boolean equals(Object o) { if ((o == null) || !(o instanceof ComponentSampleModel)) { return false; } - ComponentSampleModel model = (ComponentSampleModel) o; - return this.width == model.width && this.height == model.height && - this.numBands == model.numBands && - this.dataType == model.dataType && - Arrays.equals(this.bandOffsets, model.bandOffsets) && - Arrays.equals(this.bankIndices, model.bankIndices) && - this.numBands == model.numBands && - this.numBanks == model.numBanks && - this.scanlineStride == model.scanlineStride && - this.pixelStride == model.pixelStride; + ComponentSampleModel model = (ComponentSampleModel)o; + return this.width == model.width && this.height == model.height + && this.numBands == model.numBands && this.dataType == model.dataType + && Arrays.equals(this.bandOffsets, model.bandOffsets) + && Arrays.equals(this.bankIndices, model.bankIndices) + && this.numBands == model.numBands && this.numBanks == model.numBanks + && this.scanlineStride == model.scanlineStride + && this.pixelStride == model.pixelStride; } - /** + /** * @see java.awt.image.SampleModel#createSubsetSampleModel(int[]) */ @Override public SampleModel createSubsetSampleModel(int bands[]) { if (bands.length > this.numBands) { - // awt.64=The number of the bands in the subset is greater than the number of bands in the sample model + // awt.64=The number of the bands in the subset is greater than the + // number of bands in the sample model throw new RasterFormatException(Messages.getString("awt.64")); //$NON-NLS-1$ } @@ -324,15 +347,15 @@ public class ComponentSampleModel extends SampleModel { offsets[i] = bandOffsets[bands[i]]; } - return new ComponentSampleModel(dataType, width, height, pixelStride, - scanlineStride, indices, offsets); + return new ComponentSampleModel(dataType, width, height, pixelStride, scanlineStride, + indices, offsets); } @Override public SampleModel createCompatibleSampleModel(int w, int h) { - return new ComponentSampleModel(dataType, w, h, pixelStride, - pixelStride * w, bankIndices, bandOffsets); + return new ComponentSampleModel(dataType, w, h, pixelStride, pixelStride * w, bankIndices, + bandOffsets); } @Override @@ -366,8 +389,7 @@ public class ComponentSampleModel extends SampleModel { throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ } - return data.getElem(bankIndices[b], y * scanlineStride + - x * pixelStride + bandOffsets[b]); + return data.getElem(bankIndices[b], y * scanlineStride + x * pixelStride + bandOffsets[b]); } @Override @@ -377,8 +399,8 @@ public class ComponentSampleModel extends SampleModel { throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ } - return data.getElemFloat(bankIndices[b], y * scanlineStride + - x * pixelStride + bandOffsets[b]); + return data.getElemFloat(bankIndices[b], y * scanlineStride + x * pixelStride + + bandOffsets[b]); } @Override @@ -388,15 +410,14 @@ public class ComponentSampleModel extends SampleModel { throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ } - return data.getElemDouble(bankIndices[b], y * scanlineStride + - x * pixelStride + bandOffsets[b]); + return data.getElemDouble(bankIndices[b], y * scanlineStride + x * pixelStride + + bandOffsets[b]); } @Override - public int[] getPixels(int x, int y, int w, int h, int iArray[], - DataBuffer data) { - if (x < 0 || y < 0 || x > this.width || x + w > this.width - || y > this.height || y + h > this.height) { + public int[] getPixels(int x, int y, int w, int h, int iArray[], DataBuffer data) { + if (x < 0 || y < 0 || x > this.width || x + w > this.width || y > this.height + || y + h > this.height) { // awt.63=Coordinates are not in bounds throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ } @@ -421,8 +442,7 @@ public class ComponentSampleModel extends SampleModel { } @Override - public void setPixels(int x, int y, int w, int h, int iArray[], - DataBuffer data) { + public void setPixels(int x, int y, int w, int h, int iArray[], DataBuffer data) { if (x < 0 || y < 0 || x + w > this.width || y + h > this.height) { // awt.63=Coordinates are not in bounds throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ @@ -444,13 +464,11 @@ public class ComponentSampleModel extends SampleModel { throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ } - data.setElem(bankIndices[b], y * scanlineStride + x * pixelStride - + bandOffsets[b], s); + data.setElem(bankIndices[b], y * scanlineStride + x * pixelStride + bandOffsets[b], s); } @Override - public int[] getSamples(int x, int y, int w, int h, int b, int iArray[], - DataBuffer data) { + public int[] getSamples(int x, int y, int w, int h, int b, int iArray[], DataBuffer data) { if (x < 0 || y < 0 || x + w > this.width || y + h > this.height) { // awt.63=Coordinates are not in bounds throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ @@ -463,7 +481,7 @@ public class ComponentSampleModel extends SampleModel { } else { samples = iArray; } - + if (data == null) { // awt.295=data is null throw new NullPointerException(Messages.getString("awt.295")); //$NON-NLS-1$ @@ -479,8 +497,7 @@ public class ComponentSampleModel extends SampleModel { } @Override - public void setSamples(int x, int y, int w, int h, int b, int iArray[], - DataBuffer data) { + public void setSamples(int x, int y, int w, int h, int b, int iArray[], DataBuffer data) { if (x < 0 || y < 0 || x + w > this.width || y + h > this.height) { // awt.63=Coordinates are not in bounds throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ @@ -500,8 +517,7 @@ public class ComponentSampleModel extends SampleModel { throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ } - data.setElemFloat(bankIndices[b], y * scanlineStride + - x * pixelStride + bandOffsets[b], s); + data.setElemFloat(bankIndices[b], y * scanlineStride + x * pixelStride + bandOffsets[b], s); } @Override @@ -511,8 +527,9 @@ public class ComponentSampleModel extends SampleModel { throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ } - data.setElemDouble(bankIndices[b], y * scanlineStride + - x * pixelStride + bandOffsets[b], s); + data + .setElemDouble(bankIndices[b], y * scanlineStride + x * pixelStride + + bandOffsets[b], s); } @Override @@ -525,28 +542,27 @@ public class ComponentSampleModel extends SampleModel { maxOffset = bandOffsets[i]; } } - int size = (height - 1) * scanlineStride + - (width - 1) * pixelStride + maxOffset + 1; + int size = (height - 1) * scanlineStride + (width - 1) * pixelStride + maxOffset + 1; switch (dataType) { - case DataBuffer.TYPE_BYTE: - data = new DataBufferByte(size, numBanks); - break; - case DataBuffer.TYPE_SHORT: - data = new DataBufferShort(size, numBanks); - break; - case DataBuffer.TYPE_USHORT: - data = new DataBufferUShort(size, numBanks); - break; - case DataBuffer.TYPE_INT: - data = new DataBufferInt(size, numBanks); - break; - case DataBuffer.TYPE_FLOAT: - data = new DataBufferFloat(size, numBanks); - break; - case DataBuffer.TYPE_DOUBLE: - data = new DataBufferDouble(size, numBanks); - break; + case DataBuffer.TYPE_BYTE: + data = new DataBufferByte(size, numBanks); + break; + case DataBuffer.TYPE_SHORT: + data = new DataBufferShort(size, numBanks); + break; + case DataBuffer.TYPE_USHORT: + data = new DataBufferUShort(size, numBanks); + break; + case DataBuffer.TYPE_INT: + data = new DataBufferInt(size, numBanks); + break; + case DataBuffer.TYPE_FLOAT: + data = new DataBufferFloat(size, numBanks); + break; + case DataBuffer.TYPE_DOUBLE: + data = new DataBufferDouble(size, numBanks); + break; } return data; @@ -556,10 +572,12 @@ public class ComponentSampleModel extends SampleModel { /** * Gets the offset of the specified band of the specified pixel. * - * @param x the X coordinate of the pixel. - * @param y the Y coordinate of the pixel. - * @param b the band. - * + * @param x + * the X coordinate of the pixel. + * @param y + * the Y coordinate of the pixel. + * @param b + * the band. * @return the offset of the specified band of the specified pixel. */ public int getOffset(int x, int y, int b) { @@ -569,9 +587,10 @@ public class ComponentSampleModel extends SampleModel { /** * Gets the offset of the first band of the specified pixel. * - * @param x the X coordinate of pixel. - * @param y the Y coordinate of pixel. - * + * @param x + * the X coordinate of pixel. + * @param y + * the Y coordinate of pixel. * @return the offset of the first band of the specified pixel. */ public int getOffset(int x, int y) { @@ -595,8 +614,7 @@ public class ComponentSampleModel extends SampleModel { } /** - * Gets an array of bank indices corresponding to this - * ComponentSampleModel. + * Gets an array of bank indices corresponding to this ComponentSampleModel. * * @return the array of bank indices. */ @@ -605,7 +623,7 @@ public class ComponentSampleModel extends SampleModel { } /** - * Gets an array of the band offsets corresponding to this + * Gets an array of the band offsets corresponding to this * ComponentSampleModel. * * @return the array of band offsets. @@ -673,7 +691,7 @@ public class ComponentSampleModel extends SampleModel { /** * Gets the pixel stride. * - * @return the pixel stride + * @return the pixel stride. */ public final int getPixelStride() { return pixelStride; @@ -685,6 +703,3 @@ public class ComponentSampleModel extends SampleModel { } } - - - diff --git a/awt/java/awt/image/ConvolveOp.java b/awt/java/awt/image/ConvolveOp.java index bb588bcdbbb24d5c1bde6982f82024b9ca8601c4..6eb8909b81057cf6abe577bc693ec2a7bf2fc53d 100644 --- a/awt/java/awt/image/ConvolveOp.java +++ b/awt/java/awt/image/ConvolveOp.java @@ -32,47 +32,57 @@ import org.apache.harmony.awt.gl.AwtImageBackdoorAccessor; import org.apache.harmony.awt.internal.nls.Messages; /** - * The ConvolveOp class convolves from the source data - * to the destination using a convolution kernel. - * Each output pixel is represented as the result of multiplying - * the kernel and the surround of the input pixel. + * The ConvolveOp class convolves from the source data to the destination using + * a convolution kernel. Each output pixel is represented as the result of + * multiplying the kernel and the surround of the input pixel. + * + * @since Android 1.0 */ public class ConvolveOp implements BufferedImageOp, RasterOp { - /** - * The Constant EDGE_ZERO_FILL indicates that pixels at the edge of - * the destination image are set to zero. + /** + * The Constant EDGE_ZERO_FILL indicates that pixels at the edge of the + * destination image are set to zero. */ public static final int EDGE_ZERO_FILL = 0; - /** - * The Constant EDGE_NO_OP indicates that pixels at the edge of - * the source image are converted to the edge pixels in the - * destination without modification. + /** + * The Constant EDGE_NO_OP indicates that pixels at the edge of the source + * image are converted to the edge pixels in the destination without + * modification. */ public static final int EDGE_NO_OP = 1; - /** The kernel. */ + /** + * The kernel. + */ private Kernel kernel; - - /** The edge cond. */ + + /** + * The edge cond. + */ private int edgeCond; - - /** The rhs. */ + + /** + * The rhs. + */ private RenderingHints rhs = null; static { // TODO - //System.loadLibrary("imageops"); + // System.loadLibrary("imageops"); } /** - * Instantiates a new ConvolveOp object with the specified Kernel - * and specified edges condition. + * Instantiates a new ConvolveOp object with the specified Kernel and + * specified edges condition. * - * @param kernel the specified Kernel. - * @param edgeCondition the specified edge condition. - * @param hints the RenderingHints object, or null. + * @param kernel + * the specified Kernel. + * @param edgeCondition + * the specified edge condition. + * @param hints + * the RenderingHints object, or null. */ public ConvolveOp(Kernel kernel, int edgeCondition, RenderingHints hints) { this.kernel = kernel; @@ -81,10 +91,11 @@ public class ConvolveOp implements BufferedImageOp, RasterOp { } /** - * Instantiates a new ConvolveOp object with the specified Kernel - * and EDGE_ZERO_FILL edge condition. + * Instantiates a new ConvolveOp object with the specified Kernel and + * EDGE_ZERO_FILL edge condition. * - * @param kernel the specified Kernel. + * @param kernel + * the specified Kernel. */ public ConvolveOp(Kernel kernel) { this.kernel = kernel; @@ -97,7 +108,7 @@ public class ConvolveOp implements BufferedImageOp, RasterOp { * @return the Kernel object of this ConvolveOp. */ public final Kernel getKernel() { - return (Kernel) kernel.clone(); + return (Kernel)kernel.clone(); } public final RenderingHints getRenderingHints() { @@ -143,17 +154,11 @@ public class ConvolveOp implements BufferedImageOp, RasterOp { dstCM = ColorModel.getRGBdefault(); } - WritableRaster r = - dstCM.isCompatibleSampleModel(src.getSampleModel()) ? - src.getRaster().createCompatibleWritableRaster(src.getWidth(), src.getHeight()) : - dstCM.createCompatibleWritableRaster(src.getWidth(), src.getHeight()); - - return new BufferedImage( - dstCM, - r, - dstCM.isAlphaPremultiplied(), - null - ); + WritableRaster r = dstCM.isCompatibleSampleModel(src.getSampleModel()) ? src.getRaster() + .createCompatibleWritableRaster(src.getWidth(), src.getHeight()) : dstCM + .createCompatibleWritableRaster(src.getWidth(), src.getHeight()); + + return new BufferedImage(dstCM, r, dstCM.isAlphaPremultiplied(), null); } public final WritableRaster filter(Raster src, WritableRaster dst) { @@ -162,7 +167,7 @@ public class ConvolveOp implements BufferedImageOp, RasterOp { throw new NullPointerException(Messages.getString("awt.256")); //$NON-NLS-1$ } - if (src == dst){ + if (src == dst) { // awt.257=Source raster is equal to destination throw new IllegalArgumentException(Messages.getString("awt.257")); //$NON-NLS-1$ } @@ -170,17 +175,18 @@ public class ConvolveOp implements BufferedImageOp, RasterOp { if (dst == null) { dst = createCompatibleDestRaster(src); } else if (src.getNumBands() != dst.getNumBands()) { - // awt.258=Number of source bands ({0}) is not equal to number of destination bands ({1}) - throw new IllegalArgumentException( - Messages.getString("awt.258", src.getNumBands(), dst.getNumBands())); //$NON-NLS-1$ + // awt.258=Number of source bands ({0}) is not equal to number of + // destination bands ({1}) + throw new IllegalArgumentException(Messages.getString( + "awt.258", src.getNumBands(), dst.getNumBands())); //$NON-NLS-1$ } // TODO - //if (ippFilter(src, dst, BufferedImage.TYPE_CUSTOM) != 0) - if (slowFilter(src, dst) != 0) { - // awt.21F=Unable to transform source - throw new ImagingOpException (Messages.getString("awt.21F")); //$NON-NLS-1$ - } + // if (ippFilter(src, dst, BufferedImage.TYPE_CUSTOM) != 0) + if (slowFilter(src, dst) != 0) { + // awt.21F=Unable to transform source + throw new ImagingOpException(Messages.getString("awt.21F")); //$NON-NLS-1$ + } return dst; } @@ -188,10 +194,11 @@ public class ConvolveOp implements BufferedImageOp, RasterOp { /** * Slow filter. * - * @param src the src - * @param dst the dst - * - * @return the int + * @param src + * the src. + * @param dst + * the dst. + * @return the int. */ private int slowFilter(Raster src, WritableRaster dst) { try { @@ -219,7 +226,7 @@ public class ConvolveOp implements BufferedImageOp, RasterOp { int[] masks = new int[numBands]; int[] sampleSizes = sm.getSampleSize(); - for (int i=0; i < numBands; i++){ + for (int i = 0; i < numBands; i++) { maxValues[i] = (1 << sampleSizes[i]) - 1; masks[i] = ~(maxValues[i]); } @@ -228,61 +235,56 @@ public class ConvolveOp implements BufferedImageOp, RasterOp { float[] pixels = null; pixels = src.getPixels(srcMinX, srcMinY, srcWidth, srcHeight, pixels); float[] newPixels = new float[pixels.length]; - int rowLength = srcWidth*numBands; - if (this.edgeCond == ConvolveOp.EDGE_NO_OP){ + int rowLength = srcWidth * numBands; + if (this.edgeCond == ConvolveOp.EDGE_NO_OP) { // top int start = 0; - int length = yOrigin*rowLength; + int length = yOrigin * rowLength; System.arraycopy(pixels, start, newPixels, start, length); // bottom - start = (srcHeight - (kHeight - yOrigin - 1))*rowLength; - length = (kHeight - yOrigin - 1)*rowLength; + start = (srcHeight - (kHeight - yOrigin - 1)) * rowLength; + length = (kHeight - yOrigin - 1) * rowLength; System.arraycopy(pixels, start, newPixels, start, length); // middle - length = xOrigin*numBands; - int length1 = (kWidth - xOrigin - 1)*numBands; - start = yOrigin*rowLength; - int start1 = (yOrigin+1)*rowLength - length1; - for (int i = yOrigin; i < (srcHeight - (kHeight - yOrigin - 1)); i ++) { + length = xOrigin * numBands; + int length1 = (kWidth - xOrigin - 1) * numBands; + start = yOrigin * rowLength; + int start1 = (yOrigin + 1) * rowLength - length1; + for (int i = yOrigin; i < (srcHeight - (kHeight - yOrigin - 1)); i++) { System.arraycopy(pixels, start, newPixels, start, length); System.arraycopy(pixels, start1, newPixels, start1, length1); - start +=rowLength; - start1 +=rowLength; + start += rowLength; + start1 += rowLength; } } // Cycle over pixels to be calculated - for (int i = yOrigin; i < srcConvMaxY; i++){ - for (int j = xOrigin; j < srcConvMaxX; j++){ + for (int i = yOrigin; i < srcConvMaxY; i++) { + for (int j = xOrigin; j < srcConvMaxX; j++) { // Take kernel data in backward direction, convolution int kernelIdx = data.length - 1; int pixelIndex = i * rowLength + j * numBands; - for (int hIdx = 0, rasterHIdx = i - yOrigin; - hIdx < kHeight; - hIdx++, rasterHIdx++ - ){ - for (int wIdx = 0, rasterWIdx = j - xOrigin; - wIdx < kWidth; - wIdx++, rasterWIdx++ - ){ + for (int hIdx = 0, rasterHIdx = i - yOrigin; hIdx < kHeight; hIdx++, rasterHIdx++) { + for (int wIdx = 0, rasterWIdx = j - xOrigin; wIdx < kWidth; wIdx++, rasterWIdx++) { int curIndex = rasterHIdx * rowLength + rasterWIdx * numBands; - for (int idx=0; idx < numBands; idx++){ - newPixels[pixelIndex+idx] += data[kernelIdx] * pixels[curIndex+idx]; + for (int idx = 0; idx < numBands; idx++) { + newPixels[pixelIndex + idx] += data[kernelIdx] + * pixels[curIndex + idx]; } kernelIdx--; } } // Check for overflow now - for (int idx=0; idx < numBands; idx++){ - if (((int)newPixels[pixelIndex+idx] & masks[idx]) != 0) { - if (newPixels[pixelIndex+idx] < 0) { - newPixels[pixelIndex+idx] = 0; + for (int idx = 0; idx < numBands; idx++) { + if (((int)newPixels[pixelIndex + idx] & masks[idx]) != 0) { + if (newPixels[pixelIndex + idx] < 0) { + newPixels[pixelIndex + idx] = 0; } else { - newPixels[pixelIndex+idx] = maxValues[idx]; + newPixels[pixelIndex + idx] = maxValues[idx]; } } } @@ -302,7 +304,7 @@ public class ConvolveOp implements BufferedImageOp, RasterOp { throw new NullPointerException(Messages.getString("awt.259")); //$NON-NLS-1$ } - if (src == dst){ + if (src == dst) { // awt.25A=Source equals to destination throw new IllegalArgumentException(Messages.getString("awt.25A")); //$NON-NLS-1$ } @@ -319,13 +321,10 @@ public class ConvolveOp implements BufferedImageOp, RasterOp { dst = createCompatibleDestImage(src, srcCM); } else { if (!srcCM.equals(dst.getColorModel())) { - // Treat BufferedImage.TYPE_INT_RGB and BufferedImage.TYPE_INT_ARGB as same - if ( - !((src.getType() == BufferedImage.TYPE_INT_RGB || - src.getType() == BufferedImage.TYPE_INT_ARGB) && - (dst.getType() == BufferedImage.TYPE_INT_RGB || - dst.getType() == BufferedImage.TYPE_INT_ARGB)) - ) { + // Treat BufferedImage.TYPE_INT_RGB and + // BufferedImage.TYPE_INT_ARGB as same + if (!((src.getType() == BufferedImage.TYPE_INT_RGB || src.getType() == BufferedImage.TYPE_INT_ARGB) && (dst + .getType() == BufferedImage.TYPE_INT_RGB || dst.getType() == BufferedImage.TYPE_INT_ARGB))) { finalDst = dst; dst = createCompatibleDestImage(src, srcCM); } @@ -334,11 +333,11 @@ public class ConvolveOp implements BufferedImageOp, RasterOp { // Skip alpha channel for TYPE_INT_RGB images // TODO - //if (ippFilter(src.getRaster(), dst.getRaster(), src.getType()) != 0) - if (slowFilter(src.getRaster(), dst.getRaster()) != 0) { - // awt.21F=Unable to transform source - throw new ImagingOpException (Messages.getString("awt.21F")); //$NON-NLS-1$ - } + // if (ippFilter(src.getRaster(), dst.getRaster(), src.getType()) != 0) + if (slowFilter(src.getRaster(), dst.getRaster()) != 0) { + // awt.21F=Unable to transform source + throw new ImagingOpException(Messages.getString("awt.21F")); //$NON-NLS-1$ + } if (finalDst != null) { Graphics2D g = finalDst.createGraphics(); @@ -355,11 +354,13 @@ public class ConvolveOp implements BufferedImageOp, RasterOp { /** * Ipp filter. * - * @param src the src - * @param dst the dst - * @param imageType the image type - * - * @return the int + * @param src + * the src. + * @param dst + * the dst. + * @param imageType + * the image type. + * @return the int. */ @SuppressWarnings("unused") private int ippFilter(Raster src, WritableRaster dst, int imageType) { @@ -372,8 +373,8 @@ public class ConvolveOp implements BufferedImageOp, RasterOp { case BufferedImage.TYPE_INT_RGB: case BufferedImage.TYPE_INT_BGR: { channels = 4; - srcStride = src.getWidth()*4; - dstStride = dst.getWidth()*4; + srcStride = src.getWidth() * 4; + dstStride = dst.getWidth() * 4; skipChannel = true; break; } @@ -383,8 +384,8 @@ public class ConvolveOp implements BufferedImageOp, RasterOp { case BufferedImage.TYPE_4BYTE_ABGR: case BufferedImage.TYPE_4BYTE_ABGR_PRE: { channels = 4; - srcStride = src.getWidth()*4; - dstStride = dst.getWidth()*4; + srcStride = src.getWidth() * 4; + dstStride = dst.getWidth() * 4; break; } @@ -397,12 +398,13 @@ public class ConvolveOp implements BufferedImageOp, RasterOp { case BufferedImage.TYPE_3BYTE_BGR: { channels = 3; - srcStride = src.getWidth()*3; - dstStride = dst.getWidth()*3; + srcStride = src.getWidth() * 3; + dstStride = dst.getWidth() * 3; break; } - case BufferedImage.TYPE_USHORT_GRAY: // TODO - could be done in native code? + case BufferedImage.TYPE_USHORT_GRAY: // TODO - could be done in + // native code? case BufferedImage.TYPE_USHORT_565_RGB: case BufferedImage.TYPE_USHORT_555_RGB: case BufferedImage.TYPE_BYTE_BINARY: { @@ -413,59 +415,51 @@ public class ConvolveOp implements BufferedImageOp, RasterOp { SampleModel srcSM = src.getSampleModel(); SampleModel dstSM = dst.getSampleModel(); - if ( - srcSM instanceof PixelInterleavedSampleModel && - dstSM instanceof PixelInterleavedSampleModel - ) { + if (srcSM instanceof PixelInterleavedSampleModel + && dstSM instanceof PixelInterleavedSampleModel) { // Check PixelInterleavedSampleModel - if ( - srcSM.getDataType() != DataBuffer.TYPE_BYTE || - dstSM.getDataType() != DataBuffer.TYPE_BYTE - ) { + if (srcSM.getDataType() != DataBuffer.TYPE_BYTE + || dstSM.getDataType() != DataBuffer.TYPE_BYTE) { return slowFilter(src, dst); } - channels = srcSM.getNumBands(); // Have IPP functions for 1, 3 and 4 channels + channels = srcSM.getNumBands(); // Have IPP functions for 1, + // 3 and 4 channels if (!(channels == 1 || channels == 3 || channels == 4)) { return slowFilter(src, dst); } - srcStride = ((ComponentSampleModel) srcSM).getScanlineStride(); - dstStride = ((ComponentSampleModel) dstSM).getScanlineStride(); - } else if ( - srcSM instanceof SinglePixelPackedSampleModel && - dstSM instanceof SinglePixelPackedSampleModel - ) { + srcStride = ((ComponentSampleModel)srcSM).getScanlineStride(); + dstStride = ((ComponentSampleModel)dstSM).getScanlineStride(); + } else if (srcSM instanceof SinglePixelPackedSampleModel + && dstSM instanceof SinglePixelPackedSampleModel) { // Check SinglePixelPackedSampleModel - SinglePixelPackedSampleModel sppsm1 = (SinglePixelPackedSampleModel) srcSM; - SinglePixelPackedSampleModel sppsm2 = (SinglePixelPackedSampleModel) dstSM; + SinglePixelPackedSampleModel sppsm1 = (SinglePixelPackedSampleModel)srcSM; + SinglePixelPackedSampleModel sppsm2 = (SinglePixelPackedSampleModel)dstSM; channels = sppsm1.getNumBands(); - // TYPE_INT_RGB, TYPE_INT_ARGB... - if ( - sppsm1.getDataType() != DataBuffer.TYPE_INT || - sppsm2.getDataType() != DataBuffer.TYPE_INT || - !(channels == 3 || channels == 4) - ) { + // TYPE_INT_RGB, TYPE_INT_ARGB... + if (sppsm1.getDataType() != DataBuffer.TYPE_INT + || sppsm2.getDataType() != DataBuffer.TYPE_INT + || !(channels == 3 || channels == 4)) { return slowFilter(src, dst); } // Check compatibility of sample models - if ( - !Arrays.equals(sppsm1.getBitOffsets(), sppsm2.getBitOffsets()) || - !Arrays.equals(sppsm1.getBitMasks(), sppsm2.getBitMasks()) - ) { + if (!Arrays.equals(sppsm1.getBitOffsets(), sppsm2.getBitOffsets()) + || !Arrays.equals(sppsm1.getBitMasks(), sppsm2.getBitMasks())) { return slowFilter(src, dst); } - for (int i=0; i props) { Hashtable fprops; - if(props == null) { + if (props == null) { fprops = new Hashtable(); } else { - fprops = (Hashtable) props.clone(); + fprops = (Hashtable)props.clone(); } String propName = "Crop Filters"; //$NON-NLS-1$ String prop = "x=" + X + "; y=" + Y + "; width=" + //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ - WIDTH + "; height=" + HEIGHT; //$NON-NLS-1$ + WIDTH + "; height=" + HEIGHT; //$NON-NLS-1$ Object o = fprops.get(propName); - if(o != null){ - if(o instanceof String){ + if (o != null) { + if (o instanceof String) { prop = (String)o + "; " + prop; //$NON-NLS-1$ - }else{ - prop = o.toString() + "; " + prop; //$NON-NLS-1$ + } else { + prop = o.toString() + "; " + prop; //$NON-NLS-1$ } } fprops.put(propName, prop); @@ -73,15 +81,14 @@ public class CropImageFilter extends ImageFilter { } @Override - public void setPixels(int x, int y, int w, int h, ColorModel model, int[] pixels, int off, int scansize) { + public void setPixels(int x, int y, int w, int h, ColorModel model, int[] pixels, int off, + int scansize) { - if(x + w < X || X + WIDTH < x || - y + h < Y || Y + HEIGHT < y) { + if (x + w < X || X + WIDTH < x || y + h < Y || Y + HEIGHT < y) { return; } - int destX, destY, destWidth, destHeight, endX, endY, - srcEndX, srcEndY; + int destX, destY, destWidth, destHeight, endX, endY, srcEndX, srcEndY; int newOffset = off; @@ -91,37 +98,36 @@ public class CropImageFilter extends ImageFilter { srcEndX = x + w; srcEndY = y + h; - if(x <= X){ + if (x <= X) { destX = 0; newOffset += X; - if(endX >= srcEndX){ + if (endX >= srcEndX) { destWidth = srcEndX - X; - }else{ + } else { destWidth = WIDTH; } - }else{ + } else { destX = x - X; - if(endX >= srcEndX){ + if (endX >= srcEndX) { destWidth = w; - }else{ + } else { destWidth = endX - x; } } - - if(y <= Y){ + if (y <= Y) { newOffset += scansize * (Y - y); destY = 0; - if(endY >= srcEndY){ + if (endY >= srcEndY) { destHeight = srcEndY - Y; - }else{ + } else { destHeight = HEIGHT; } - }else{ + } else { destY = y - Y; - if(endY >= srcEndY){ + if (endY >= srcEndY) { destHeight = h; - }else{ + } else { destHeight = endY - y; } } @@ -129,15 +135,14 @@ public class CropImageFilter extends ImageFilter { } @Override - public void setPixels(int x, int y, int w, int h, ColorModel model, byte[] pixels, int off, int scansize) { + public void setPixels(int x, int y, int w, int h, ColorModel model, byte[] pixels, int off, + int scansize) { - if(x + w < X || X + WIDTH < x || - y + h < Y || Y + HEIGHT < y) { + if (x + w < X || X + WIDTH < x || y + h < Y || Y + HEIGHT < y) { return; } - int destX, destY, destWidth, destHeight, endX, endY, - srcEndX, srcEndY; + int destX, destY, destWidth, destHeight, endX, endY, srcEndX, srcEndY; int newOffset = off; @@ -147,37 +152,36 @@ public class CropImageFilter extends ImageFilter { srcEndX = x + w; srcEndY = y + h; - if(x <= X){ + if (x <= X) { destX = 0; newOffset += X; - if(endX >= srcEndX){ + if (endX >= srcEndX) { destWidth = srcEndX - X; - }else{ + } else { destWidth = WIDTH; } - }else{ + } else { destX = x - X; - if(endX >= srcEndX){ + if (endX >= srcEndX) { destWidth = w; - }else{ + } else { destWidth = endX - x; } } - - if(y <= Y){ + if (y <= Y) { newOffset += scansize * (Y - y); destY = 0; - if(endY >= srcEndY){ + if (endY >= srcEndY) { destHeight = srcEndY - Y; - }else{ + } else { destHeight = HEIGHT; } - }else{ + } else { destY = y - Y; - if(endY >= srcEndY){ + if (endY >= srcEndY) { destHeight = h; - }else{ + } else { destHeight = endY - y; } } @@ -190,4 +194,3 @@ public class CropImageFilter extends ImageFilter { } } - diff --git a/awt/java/awt/image/DataBuffer.java b/awt/java/awt/image/DataBuffer.java index 6856aee0e795004db24dc68f8fa93e94cbfdea5e..92f900fd36b2a0ce4bc969c6e742985dba1a88c9 100644 --- a/awt/java/awt/image/DataBuffer.java +++ b/awt/java/awt/image/DataBuffer.java @@ -18,65 +18,97 @@ * @author Igor V. Stolyarov * @version $Revision$ */ + package java.awt.image; import org.apache.harmony.awt.gl.image.DataBufferListener; import org.apache.harmony.awt.internal.nls.Messages; /** - * The Class DataBuffer is a wrapper class for a data array - * to be used for the situation where a suite of functionality - * acts on a set of data in a consistent way even though the - * primitive type of the data may vary from one use to the next. + * The Class DataBuffer is a wrapper class for a data array to be used for the + * situation where a suite of functionality acts on a set of data in a + * consistent way even though the primitive type of the data may vary from one + * use to the next. + * + * @since Android 1.0 */ public abstract class DataBuffer { - /** The Constant TYPE_BYTE. */ + /** + * The Constant TYPE_BYTE. + */ public static final int TYPE_BYTE = 0; - /** The Constant TYPE_USHORT. */ + /** + * The Constant TYPE_USHORT. + */ public static final int TYPE_USHORT = 1; - /** The Constant TYPE_SHORT. */ + /** + * The Constant TYPE_SHORT. + */ public static final int TYPE_SHORT = 2; - /** The Constant TYPE_INT. */ + /** + * The Constant TYPE_INT. + */ public static final int TYPE_INT = 3; - /** The Constant TYPE_FLOAT. */ + /** + * The Constant TYPE_FLOAT. + */ public static final int TYPE_FLOAT = 4; - /** The Constant TYPE_DOUBLE. */ + /** + * The Constant TYPE_DOUBLE. + */ public static final int TYPE_DOUBLE = 5; - /** The Constant TYPE_UNDEFINED. */ + /** + * The Constant TYPE_UNDEFINED. + */ public static final int TYPE_UNDEFINED = 32; - /** The data type indicates the primitive type of the - * data in this DataBuffer. */ + /** + * The data type indicates the primitive type of the data in this + * DataBuffer. + */ protected int dataType; - /** The number of data arrays in this DataBuffer. */ + /** + * The number of data arrays in this DataBuffer. + */ protected int banks; - /** The starting index for reading the - * data from the first (or only) internal data array. */ + /** + * The starting index for reading the data from the first (or only) internal + * data array. + */ protected int offset; - /** The length (number of elements) of the data arrays. */ + /** + * The length (number of elements) of the data arrays. + */ protected int size; - /** The starting indices for reading the - * data from the internal data arrays. */ + /** + * The starting indices for reading the data from the internal data arrays. + */ protected int offsets[]; - - /** The data changed. */ + + /** + * The data changed. + */ boolean dataChanged = true; - - /** The data taken. */ + + /** + * The data taken. + */ boolean dataTaken = false; - - /** The listener. */ + + /** + * The listener. + */ DataBufferListener listener; static { @@ -86,11 +118,15 @@ public abstract class DataBuffer { /** * Instantiates a new data buffer. * - * @param dataType the data type - * @param size the length (number of elements) of the data arrays - * @param numBanks the number of data arrays to create - * @param offsets the starting indices for reading the - * data from the internal data arrays + * @param dataType + * the data type. + * @param size + * the length (number of elements) of the data arrays. + * @param numBanks + * the number of data arrays to create. + * @param offsets + * the starting indices for reading the data from the internal + * data arrays. */ protected DataBuffer(int dataType, int size, int numBanks, int[] offsets) { this.dataType = dataType; @@ -101,13 +137,17 @@ public abstract class DataBuffer { } /** - * Instantiates a new data buffer with all of the - * data arrays starting at the same index. + * Instantiates a new data buffer with all of the data arrays starting at + * the same index. * - * @param dataType the data type - * @param size the length (number of elements) of the data arrays - * @param numBanks the number of data arrays to create - * @param offset the offset to use for all of the data arrays + * @param dataType + * the data type. + * @param size + * the length (number of elements) of the data arrays. + * @param numBanks + * the number of data arrays to create. + * @param offset + * the offset to use for all of the data arrays. */ protected DataBuffer(int dataType, int size, int numBanks, int offset) { this.dataType = dataType; @@ -122,12 +162,15 @@ public abstract class DataBuffer { } /** - * Instantiates a new data buffer with all of the - * data arrays read from the beginning (at offset zero). + * Instantiates a new data buffer with all of the data arrays read from the + * beginning (at offset zero). * - * @param dataType the data type - * @param size the length (number of elements) of the data arrays - * @param numBanks the number of data arrays to create + * @param dataType + * the data type. + * @param size + * the length (number of elements) of the data arrays. + * @param numBanks + * the number of data arrays to create. */ protected DataBuffer(int dataType, int size, int numBanks) { this.dataType = dataType; @@ -138,11 +181,13 @@ public abstract class DataBuffer { } /** - * Instantiates a new data buffer with one internal data array - * read from the beginning (at offset zero). + * Instantiates a new data buffer with one internal data array read from the + * beginning (at offset zero). * - * @param dataType the data type - * @param size the length (number of elements) of the data arrays + * @param dataType + * the data type. + * @param size + * the length (number of elements) of the data arrays. */ protected DataBuffer(int dataType, int size) { this.dataType = dataType; @@ -153,165 +198,161 @@ public abstract class DataBuffer { } /** - * Sets the data value in the specified array at the - * specified index. + * Sets the data value in the specified array at the specified index. * - * @param bank the internal array to the data to - * @param i the index within the array where the data - * should be written - * @param val the value to write into the array + * @param bank + * the internal array to the data to. + * @param i + * the index within the array where the data should be written. + * @param val + * the value to write into the array. */ public abstract void setElem(int bank, int i, int val); /** - * Sets the float data value in the specified array at the - * specified index. + * Sets the float data value in the specified array at the specified index. * - * @param bank the internal array to the data to - * @param i the index within the array where the data - * should be written - * @param val the value to write into the array + * @param bank + * the internal array to the data to. + * @param i + * the index within the array where the data should be written. + * @param val + * the value to write into the array. */ public void setElemFloat(int bank, int i, float val) { - setElem(bank, i, (int) val); + setElem(bank, i, (int)val); } /** - * Sets the double data value in the specified array at the - * specified index. + * Sets the double data value in the specified array at the specified index. * - * @param bank the internal array to the data to - * @param i the index within the array where the data - * should be written - * @param val the value to write into the array + * @param bank + * the internal array to the data to. + * @param i + * the index within the array where the data should be written. + * @param val + * the value to write into the array. */ public void setElemDouble(int bank, int i, double val) { - setElem(bank, i, (int) val); + setElem(bank, i, (int)val); } /** - * Sets the data value in the first array at the - * specified index. + * Sets the data value in the first array at the specified index. * - * @param i the index within the array where the data - * should be written - * @param val the value to write into the array + * @param i + * the index within the array where the data should be written. + * @param val + * the value to write into the array. */ public void setElem(int i, int val) { setElem(0, i, val); } /** - * Gets the data value from the specified data array at the - * specified index. - * - * @param bank the data array to read from - * @param i the index within the array where the data - * should be read + * Gets the data value from the specified data array at the specified index. * - * @return the data element + * @param bank + * the data array to read from. + * @param i + * the index within the array where the data should be read. + * @return the data element. */ public abstract int getElem(int bank, int i); /** - * Gets the float-type data value from the specified - * data array at the specified index. - * - * @param bank the data array to read from - * @param i the index within the array where the data - * should be read + * Gets the float-type data value from the specified data array at the + * specified index. * - * @return the data element + * @param bank + * the data array to read from. + * @param i + * the index within the array where the data should be read. + * @return the data element. */ public float getElemFloat(int bank, int i) { return getElem(bank, i); } /** - * Gets the double-type data value from the specified - * data array at the specified index. - * - * @param bank the data array to read from - * @param i the index within the array where the data - * should be read + * Gets the double-type data value from the specified data array at the + * specified index. * - * @return the data element + * @param bank + * the data array to read from. + * @param i + * the index within the array where the data should be read. + * @return the data element. */ public double getElemDouble(int bank, int i) { return getElem(bank, i); } /** - * Sets the float data value in the first array at the - * specified index. + * Sets the float data value in the first array at the specified index. * - * @param i the index within the array where the data - * should be written - * @param val the value to write into the array + * @param i + * the index within the array where the data should be written. + * @param val + * the value to write into the array. */ public void setElemFloat(int i, float val) { setElemFloat(0, i, val); } /** - * Sets the double data value in the first array at the - * specified index. + * Sets the double data value in the first array at the specified index. * - * @param i the index within the array where the data - * should be written - * @param val the value to write into the array + * @param i + * the index within the array where the data should be written. + * @param val + * the value to write into the array. */ public void setElemDouble(int i, double val) { setElemDouble(0, i, val); } /** - * Gets the data value from the first - * data array at the specified index and returns it - * as an int. - * - * @param i the index within the array where the data - * should be read + * Gets the data value from the first data array at the specified index and + * returns it as an integer. * - * @return the data element + * @param i + * the index within the array where the data should be read. + * @return the data element. */ public int getElem(int i) { return getElem(0, i); } /** - * Gets the data value from the first - * data array at the specified index and returns it - * as a float. + * Gets the data value from the first data array at the specified index and + * returns it as a float. * - * @param i the index within the array where the data - * should be read - * - * @return the data element + * @param i + * the index within the array where the data should be read. + * @return the data element. */ public float getElemFloat(int i) { return getElem(0, i); } /** - * Gets the data value from the first - * data array at the specified index and returns it - * as a double. - * - * @param i the index within the array where the data - * should be read + * Gets the data value from the first data array at the specified index and + * returns it as a double. * - * @return the data element + * @param i + * the index within the array where the data should be read. + * @return the data element. */ public double getElemDouble(int i) { return getElem(i); } /** - * Gets the array giving the offsets corresponding - * to the internal data arrays. + * Gets the array giving the offsets corresponding to the internal data + * arrays. * - * @return the array of offsets + * @return the array of offsets. */ public int[] getOffsets() { return offsets; @@ -320,18 +361,16 @@ public abstract class DataBuffer { /** * Gets the size in bits of the primitive data type. * - * @return the size in bits of the primitive data type - + * @return the size in bits of the primitive data type. */ public int getSize() { return size; } /** - * Gets the offset corresponding to the first internal - * data array. + * Gets the offset corresponding to the first internal data array. * - * @return the offset + * @return the offset. */ public int getOffset() { return offset; @@ -340,7 +379,7 @@ public abstract class DataBuffer { /** * Gets the number of data arrays in this DataBuffer. * - * @return the number of data arrays + * @return the number of data arrays. */ public int getNumBanks() { return banks; @@ -349,7 +388,7 @@ public abstract class DataBuffer { /** * Gets the primitive type of this buffer's data. * - * @return the data type + * @return the data type. */ public int getDataType() { return this.dataType; @@ -358,85 +397,85 @@ public abstract class DataBuffer { /** * Gets the size in bits of the primitive data type. * - * @param type the primitive type - * - * @return the size in bits of the primitive data type + * @param type + * the primitive type. + * @return the size in bits of the primitive data type. */ public static int getDataTypeSize(int type) { switch (type) { - case TYPE_BYTE: - return 8; + case TYPE_BYTE: + return 8; - case TYPE_USHORT: - case TYPE_SHORT: - return 16; + case TYPE_USHORT: + case TYPE_SHORT: + return 16; - case TYPE_INT: - case TYPE_FLOAT: - return 32; + case TYPE_INT: + case TYPE_FLOAT: + return 32; - case TYPE_DOUBLE: - return 64; + case TYPE_DOUBLE: + return 64; - default: - // awt.22C=Unknown data type {0} - throw new IllegalArgumentException(Messages.getString("awt.22C", type)); //$NON-NLS-1$ + default: + // awt.22C=Unknown data type {0} + throw new IllegalArgumentException(Messages.getString("awt.22C", type)); //$NON-NLS-1$ } } - + /** * Notifies the listener that the data has changed. */ - void notifyChanged(){ - if(listener != null && !dataChanged){ + void notifyChanged() { + if (listener != null && !dataChanged) { dataChanged = true; listener.dataChanged(); } } - + /** * Notifies the listener that the data has been released. */ - void notifyTaken(){ - if(listener != null && !dataTaken){ + void notifyTaken() { + if (listener != null && !dataTaken) { dataTaken = true; listener.dataTaken(); } } - + /** * Release the data. */ - void releaseData(){ - if(listener != null && dataTaken){ + void releaseData() { + if (listener != null && dataTaken) { dataTaken = false; listener.dataReleased(); } } - + /** * Adds the data buffer listener. * - * @param listener the listener + * @param listener + * the listener. */ - void addDataBufferListener(DataBufferListener listener){ + void addDataBufferListener(DataBufferListener listener) { this.listener = listener; } - + /** * Removes the data buffer listener. */ - void removeDataBufferListener(){ + void removeDataBufferListener() { listener = null; } - + /** * Validate. */ - void validate(){ + void validate() { dataChanged = false; } - -} +} diff --git a/awt/java/awt/image/DataBufferByte.java b/awt/java/awt/image/DataBufferByte.java index 4d29c9ca3dbccf636619c31ff4d1d9564f9e1138..3407de84dca8fa36c8cee911888ff00f739b89b7 100644 --- a/awt/java/awt/image/DataBufferByte.java +++ b/awt/java/awt/image/DataBufferByte.java @@ -18,25 +18,32 @@ * @author Igor V. Stolyarov * @version $Revision$ */ + package java.awt.image; /** - * The Class DataBufferByte is the subclass of DataBuffer - * for the case where the underlying data is of type byte. + * The Class DataBufferByte is the subclass of DataBuffer for the case where the + * underlying data is of type byte. + * + * @since Android 1.0 */ public final class DataBufferByte extends DataBuffer { - /** The data. */ + /** + * The data. + */ byte data[][]; /** * Instantiates a new data buffer of type unsigned short. * - * @param dataArrays the data arrays to copy the data from - * @param size the length (number of elements) to use - * from the data arrays - * @param offsets the starting indices for reading the - * data from the internal data arrays + * @param dataArrays + * the data arrays to copy the data from. + * @param size + * the length (number of elements) to use from the data arrays. + * @param offsets + * the starting indices for reading the data from the internal + * data arrays. */ public DataBufferByte(byte dataArrays[][], int size, int offsets[]) { super(TYPE_BYTE, size, dataArrays.length, offsets); @@ -46,9 +53,10 @@ public final class DataBufferByte extends DataBuffer { /** * Instantiates a new data buffer of type unsigned short. * - * @param dataArrays the data arrays to copy the data from - * @param size the length (number of elements) to use - * from the data arrays + * @param dataArrays + * the data arrays to copy the data from. + * @param size + * the length (number of elements) to use from the data arrays. */ public DataBufferByte(byte dataArrays[][], int size) { super(TYPE_BYTE, size, dataArrays.length); @@ -56,12 +64,15 @@ public final class DataBufferByte extends DataBuffer { } /** - * Instantiates a new data buffer of type unsigned short - * with a single underlying array of data. + * Instantiates a new data buffer of type unsigned short with a single + * underlying array of data. * - * @param dataArray the data array to copy the data from - * @param size the length (number of elements) to use - * @param offset the starting index to use when reading the data + * @param dataArray + * the data array to copy the data from. + * @param size + * the length (number of elements) to use. + * @param offset + * the starting index to use when reading the data. */ public DataBufferByte(byte dataArray[], int size, int offset) { super(TYPE_BYTE, size, 1, offset); @@ -70,12 +81,13 @@ public final class DataBufferByte extends DataBuffer { } /** - * Instantiates a new data buffer of type unsigned short - * with a single underlying array of data starting at - * index 0. + * Instantiates a new data buffer of type unsigned short with a single + * underlying array of data starting at index 0. * - * @param dataArray the data array to copy the data from - * @param size the length (number of elements) to use + * @param dataArray + * the data array to copy the data from. + * @param size + * the length (number of elements) to use. */ public DataBufferByte(byte dataArray[], int size) { super(TYPE_BYTE, size); @@ -84,12 +96,13 @@ public final class DataBufferByte extends DataBuffer { } /** - * Instantiates a new empty data buffer of type unsigned short - * with offsets equal to zero. + * Instantiates a new empty data buffer of type unsigned short with offsets + * equal to zero. * - * @param size the length (number of elements) to use - * from the data arrays - * @param numBanks the number of data arrays to create + * @param size + * the length (number of elements) to use from the data arrays. + * @param numBanks + * the number of data arrays to create. */ public DataBufferByte(int size, int numBanks) { super(TYPE_BYTE, size, numBanks); @@ -101,11 +114,11 @@ public final class DataBufferByte extends DataBuffer { } /** - * Instantiates a new empty data buffer of type unsigned short - * with a single underlying array of data starting at - * index 0. + * Instantiates a new empty data buffer of type unsigned short with a single + * underlying array of data starting at index 0. * - * @param size the length (number of elements) to use + * @param size + * the length (number of elements) to use. */ public DataBufferByte(int size) { super(TYPE_BYTE, size); @@ -115,13 +128,13 @@ public final class DataBufferByte extends DataBuffer { @Override public void setElem(int bank, int i, int val) { - data[bank][offsets[bank] + i] = (byte) val; + data[bank][offsets[bank] + i] = (byte)val; notifyChanged(); } @Override public void setElem(int i, int val) { - data[0][offset + i] = (byte) val; + data[0][offset + i] = (byte)val; notifyChanged(); } @@ -133,9 +146,9 @@ public final class DataBufferByte extends DataBuffer { /** * Gets the data of the specified internal data array. * - * @param bank the index of the desired data array - * - * @return the data + * @param bank + * the index of the desired data array. + * @return the data. */ public byte[] getData(int bank) { notifyTaken(); @@ -150,7 +163,7 @@ public final class DataBufferByte extends DataBuffer { /** * Gets the bank data. * - * @return the bank data + * @return the bank data. */ public byte[][] getBankData() { notifyTaken(); @@ -160,7 +173,7 @@ public final class DataBufferByte extends DataBuffer { /** * Gets the data of the first data array. * - * @return the data + * @return the data. */ public byte[] getData() { notifyTaken(); @@ -168,4 +181,3 @@ public final class DataBufferByte extends DataBuffer { } } - diff --git a/awt/java/awt/image/DataBufferDouble.java b/awt/java/awt/image/DataBufferDouble.java index fa3d324d7f47eb8eed48f439f869c0aea32f26bb..5d0a51688f034ca51cdd2846a1b64ab88e407333 100644 --- a/awt/java/awt/image/DataBufferDouble.java +++ b/awt/java/awt/image/DataBufferDouble.java @@ -18,26 +18,33 @@ * @author Igor V. Stolyarov * @version $Revision$ */ + package java.awt.image; /** - * The Class DataBufferDouble is the subclass of DataBuffer - * for the case where the underlying data is of type double. + * The Class DataBufferDouble is the subclass of DataBuffer for the case where + * the underlying data is of type double. + * + * @since Android 1.0 */ public final class DataBufferDouble extends DataBuffer { - /** The data. */ + /** + * The data. + */ double data[][]; /** * Instantiates a new data buffer of type double. * - * @param dataArrays the data arrays to copy the data from - * @param size the length (number of elements) to use - * from the data arrays - * @param offsets the starting indices for reading the - * data from the internal data arrays - */ + * @param dataArrays + * the data arrays to copy the data from. + * @param size + * the length (number of elements) to use from the data arrays. + * @param offsets + * the starting indices for reading the data from the internal + * data arrays. + */ public DataBufferDouble(double dataArrays[][], int size, int offsets[]) { super(TYPE_DOUBLE, size, dataArrays.length, offsets); data = dataArrays.clone(); @@ -46,9 +53,10 @@ public final class DataBufferDouble extends DataBuffer { /** * Instantiates a new data buffer of type double. * - * @param dataArrays the data arrays to copy the data from - * @param size the length (number of elements) to use - * from the data arrays + * @param dataArrays + * the data arrays to copy the data from. + * @param size + * the length (number of elements) to use from the data arrays. */ public DataBufferDouble(double dataArrays[][], int size) { super(TYPE_DOUBLE, size, dataArrays.length); @@ -56,12 +64,15 @@ public final class DataBufferDouble extends DataBuffer { } /** - * Instantiates a new data buffer of type double - * with a single underlying array of data. + * Instantiates a new data buffer of type double with a single underlying + * array of data. * - * @param dataArray the data array to copy the data from - * @param size the length (number of elements) to use - * @param offset the starting index to use when reading the data + * @param dataArray + * the data array to copy the data from. + * @param size + * the length (number of elements) to use. + * @param offset + * the starting index to use when reading the data. */ public DataBufferDouble(double dataArray[], int size, int offset) { super(TYPE_DOUBLE, size, 1, offset); @@ -70,12 +81,13 @@ public final class DataBufferDouble extends DataBuffer { } /** - * Instantiates a new data buffer of type double - * with a single underlying array of data starting at - * index 0. + * Instantiates a new data buffer of type double with a single underlying + * array of data starting at index 0. * - * @param dataArray the data array to copy the data from - * @param size the length (number of elements) to use + * @param dataArray + * the data array to copy the data from. + * @param size + * the length (number of elements) to use. */ public DataBufferDouble(double dataArray[], int size) { super(TYPE_DOUBLE, size); @@ -84,12 +96,13 @@ public final class DataBufferDouble extends DataBuffer { } /** - * Instantiates a new empty data buffer of type double - * with offsets equal to zero. + * Instantiates a new empty data buffer of type double with offsets equal to + * zero. * - * @param size the length (number of elements) to use - * from the data arrays - * @param numBanks the number of data arrays to create + * @param size + * the length (number of elements) to use from the data arrays. + * @param numBanks + * the number of data arrays to create. */ public DataBufferDouble(int size, int numBanks) { super(TYPE_DOUBLE, size, numBanks); @@ -101,11 +114,11 @@ public final class DataBufferDouble extends DataBuffer { } /** - * Instantiates a new empty data buffer of type double - * with a single underlying array of data starting at - * index 0. + * Instantiates a new empty data buffer of type double with a single + * underlying array of data starting at index 0. * - * @param size the length (number of elements) to use + * @param size + * the length (number of elements) to use. */ public DataBufferDouble(int size) { super(TYPE_DOUBLE, size); @@ -139,12 +152,12 @@ public final class DataBufferDouble extends DataBuffer { @Override public int getElem(int bank, int i) { - return (int) (data[bank][offsets[bank] + i]); + return (int)(data[bank][offsets[bank] + i]); } @Override public float getElemFloat(int bank, int i) { - return (float) (data[bank][offsets[bank] + i]); + return (float)(data[bank][offsets[bank] + i]); } @Override @@ -167,9 +180,9 @@ public final class DataBufferDouble extends DataBuffer { /** * Gets the data of the specified internal data array. * - * @param bank the index of the desired data array - * - * @return the data + * @param bank + * the index of the desired data array. + * @return the data. */ public double[] getData(int bank) { notifyTaken(); @@ -178,12 +191,12 @@ public final class DataBufferDouble extends DataBuffer { @Override public int getElem(int i) { - return (int) (data[0][offset + i]); + return (int)(data[0][offset + i]); } @Override public float getElemFloat(int i) { - return (float) (data[0][offset + i]); + return (float)(data[0][offset + i]); } @Override @@ -194,7 +207,7 @@ public final class DataBufferDouble extends DataBuffer { /** * Gets the bank data. * - * @return the bank data + * @return the bank data. */ public double[][] getBankData() { notifyTaken(); @@ -204,11 +217,10 @@ public final class DataBufferDouble extends DataBuffer { /** * Gets the data of the first data array. * - * @return the data + * @return the data. */ public double[] getData() { notifyTaken(); return data[0]; } } - diff --git a/awt/java/awt/image/DataBufferFloat.java b/awt/java/awt/image/DataBufferFloat.java index e34245c2c86e03bb1d0889ea6eb8fd97a6c832b2..9a4a6bfed23dc28d111f136dca708cf7f9fa43f6 100644 --- a/awt/java/awt/image/DataBufferFloat.java +++ b/awt/java/awt/image/DataBufferFloat.java @@ -18,25 +18,32 @@ * @author Igor V. Stolyarov * @version $Revision$ */ + package java.awt.image; /** - * The Class DataBufferFloat is the subclass of DataBuffer - * for the case where the underlying data is float. + * The Class DataBufferFloat is the subclass of DataBuffer for the case where + * the underlying data is float. + * + * @since Android 1.0 */ public final class DataBufferFloat extends DataBuffer { - /** The data. */ + /** + * The data. + */ float data[][]; /** * Instantiates a new data buffer of type float. * - * @param dataArrays the data arrays to copy the data from - * @param size the length (number of elements) to use - * from the data arrays - * @param offsets the starting indices for reading the - * data from the internal data arrays + * @param dataArrays + * the data arrays to copy the data from. + * @param size + * the length (number of elements) to use from the data arrays. + * @param offsets + * the starting indices for reading the data from the internal + * data arrays. */ public DataBufferFloat(float dataArrays[][], int size, int offsets[]) { super(TYPE_FLOAT, size, dataArrays.length, offsets); @@ -46,9 +53,10 @@ public final class DataBufferFloat extends DataBuffer { /** * Instantiates a new data buffer of type float. * - * @param dataArrays the data arrays to copy the data from - * @param size the length (number of elements) to use - * from the data arrays + * @param dataArrays + * the data arrays to copy the data from. + * @param size + * the length (number of elements) to use from the data arrays. */ public DataBufferFloat(float dataArrays[][], int size) { super(TYPE_FLOAT, size, dataArrays.length); @@ -56,12 +64,15 @@ public final class DataBufferFloat extends DataBuffer { } /** - * Instantiates a new data buffer of type float - * with a single underlying array of data. + * Instantiates a new data buffer of type float with a single underlying + * array of data. * - * @param dataArray the data array to copy the data from - * @param size the length (number of elements) to use - * @param offset the starting index to use when reading the data + * @param dataArray + * the data array to copy the data from. + * @param size + * the length (number of elements) to use. + * @param offset + * the starting index to use when reading the data. */ public DataBufferFloat(float dataArray[], int size, int offset) { super(TYPE_FLOAT, size, 1, offset); @@ -70,12 +81,13 @@ public final class DataBufferFloat extends DataBuffer { } /** - * Instantiates a new data buffer of type float - * with a single underlying array of data starting at - * index 0. + * Instantiates a new data buffer of type float with a single underlying + * array of data starting at index 0. * - * @param dataArray the data array to copy the data from - * @param size the length (number of elements) to use + * @param dataArray + * the data array to copy the data from. + * @param size + * the length (number of elements) to use. */ public DataBufferFloat(float dataArray[], int size) { super(TYPE_FLOAT, size); @@ -84,12 +96,13 @@ public final class DataBufferFloat extends DataBuffer { } /** - * Instantiates a new empty data buffer of type float - * with offsets equal to zero. + * Instantiates a new empty data buffer of type float with offsets equal to + * zero. * - * @param size the length (number of elements) to use - * from the data arrays - * @param numBanks the number of data arrays to create + * @param size + * the length (number of elements) to use from the data arrays. + * @param numBanks + * the number of data arrays to create. */ public DataBufferFloat(int size, int numBanks) { super(TYPE_FLOAT, size, numBanks); @@ -101,11 +114,11 @@ public final class DataBufferFloat extends DataBuffer { } /** - * Instantiates a new empty data buffer of type float - * with a single underlying array of data starting at - * index 0. + * Instantiates a new empty data buffer of type float with a single + * underlying array of data starting at index 0. * - * @param size the length (number of elements) to use + * @param size + * the length (number of elements) to use. */ public DataBufferFloat(int size) { super(TYPE_FLOAT, size); @@ -127,7 +140,7 @@ public final class DataBufferFloat extends DataBuffer { @Override public void setElemDouble(int bank, int i, double val) { - data[bank][offsets[bank] + i] = (float) val; + data[bank][offsets[bank] + i] = (float)val; notifyChanged(); } @@ -139,7 +152,7 @@ public final class DataBufferFloat extends DataBuffer { @Override public int getElem(int bank, int i) { - return (int) (data[bank][offsets[bank] + i]); + return (int)(data[bank][offsets[bank] + i]); } @Override @@ -160,16 +173,16 @@ public final class DataBufferFloat extends DataBuffer { @Override public void setElemDouble(int i, double val) { - data[0][offset + i] = (float) val; + data[0][offset + i] = (float)val; notifyChanged(); } /** * Gets the data of the specified internal data array. * - * @param bank the index of the desired array - * - * @return the data + * @param bank + * the index of the desired array. + * @return the data. */ public float[] getData(int bank) { notifyTaken(); @@ -178,7 +191,7 @@ public final class DataBufferFloat extends DataBuffer { @Override public int getElem(int i) { - return (int) (data[0][offset + i]); + return (int)(data[0][offset + i]); } @Override @@ -194,7 +207,7 @@ public final class DataBufferFloat extends DataBuffer { /** * Gets the bank data. * - * @return the bank data + * @return the bank data. */ public float[][] getBankData() { notifyTaken(); @@ -204,11 +217,10 @@ public final class DataBufferFloat extends DataBuffer { /** * Gets the data of the first data array. * - * @return the data + * @return the data. */ public float[] getData() { notifyTaken(); return data[0]; } } - diff --git a/awt/java/awt/image/DataBufferInt.java b/awt/java/awt/image/DataBufferInt.java index 43dc1880ad2718e7bbca89ecf4014a6248863fb0..380a1278d7a78ea040dcf080df1a912c26c09b80 100644 --- a/awt/java/awt/image/DataBufferInt.java +++ b/awt/java/awt/image/DataBufferInt.java @@ -18,25 +18,32 @@ * @author Igor V. Stolyarov * @version $Revision$ */ + package java.awt.image; /** - * The Class DataBufferInt is the subclass of DataBuffer - * for the case where the underlying data is of type int. + * The Class DataBufferInt is the subclass of DataBuffer for the case where the + * underlying data is of type integer. + * + * @since Android 1.0 */ public final class DataBufferInt extends DataBuffer { - /** The data. */ + /** + * The data. + */ int data[][]; /** - * Instantiates a new data buffer of type int. + * Instantiates a new data buffer of type integer. * - * @param dataArrays the data arrays to copy the data from - * @param size the length (number of elements) to use - * from the data arrays - * @param offsets the starting indices for reading the - * data from the internal data arrays + * @param dataArrays + * the data arrays to copy the data from. + * @param size + * the length (number of elements) to use from the data arrays. + * @param offsets + * the starting indices for reading the data from the internal + * data arrays. */ public DataBufferInt(int dataArrays[][], int size, int offsets[]) { super(TYPE_INT, size, dataArrays.length, offsets); @@ -44,11 +51,12 @@ public final class DataBufferInt extends DataBuffer { } /** - * Instantiates a new data buffer of type int. + * Instantiates a new data buffer of type integer. * - * @param dataArrays the data arrays to copy the data from - * @param size the length (number of elements) to use - * from the data arrays + * @param dataArrays + * the data arrays to copy the data from. + * @param size + * the length (number of elements) to use from the data arrays. */ public DataBufferInt(int dataArrays[][], int size) { super(TYPE_INT, size, dataArrays.length); @@ -56,12 +64,15 @@ public final class DataBufferInt extends DataBuffer { } /** - * Instantiates a new data buffer of type int - * with a single underlying array of data. + * Instantiates a new data buffer of type integer with a single underlying + * array of data. * - * @param dataArray the data array to copy the data from - * @param size the length (number of elements) to use - * @param offset the starting index to use when reading the data + * @param dataArray + * the data array to copy the data from. + * @param size + * the length (number of elements) to use. + * @param offset + * the starting index to use when reading the data. */ public DataBufferInt(int dataArray[], int size, int offset) { super(TYPE_INT, size, 1, offset); @@ -70,12 +81,13 @@ public final class DataBufferInt extends DataBuffer { } /** - * Instantiates a new data buffer of type int - * with a single underlying array of data starting at - * index 0. + * Instantiates a new data buffer of type integer with a single underlying + * array of data starting at index 0. * - * @param dataArray the data array to copy the data from - * @param size the length (number of elements) to use + * @param dataArray + * the data array to copy the data from. + * @param size + * the length (number of elements) to use. */ public DataBufferInt(int dataArray[], int size) { super(TYPE_INT, size); @@ -84,12 +96,13 @@ public final class DataBufferInt extends DataBuffer { } /** - * Instantiates a new empty data buffer of type int - * with offsets equal to zero. + * Instantiates a new empty data buffer of type integer with offsets equal + * to zero. * - * @param size the length (number of elements) to use - * from the data arrays - * @param numBanks the number of data arrays to create + * @param size + * the length (number of elements) to use from the data arrays. + * @param numBanks + * the number of data arrays to create. */ public DataBufferInt(int size, int numBanks) { super(TYPE_INT, size, numBanks); @@ -101,11 +114,11 @@ public final class DataBufferInt extends DataBuffer { } /** - * Instantiates a new empty data buffer of type int - * with a single underlying array of data starting at - * index 0. + * Instantiates a new empty data buffer of type integer with a single + * underlying array of data starting at index 0. * - * @param size the length (number of elements) to use + * @param size + * the length (number of elements) to use. */ public DataBufferInt(int size) { super(TYPE_INT, size); @@ -133,9 +146,9 @@ public final class DataBufferInt extends DataBuffer { /** * Gets the data of the specified internal data array. * - * @param bank the index of the desired data array - * - * @return the data + * @param bank + * the index of the desired data array. + * @return the data. */ public int[] getData(int bank) { notifyTaken(); @@ -150,7 +163,7 @@ public final class DataBufferInt extends DataBuffer { /** * Gets the bank data. * - * @return the bank data + * @return the bank data. */ public int[][] getBankData() { notifyTaken(); @@ -160,11 +173,10 @@ public final class DataBufferInt extends DataBuffer { /** * Gets the data of the first data array. * - * @return the data + * @return the data. */ public int[] getData() { notifyTaken(); return data[0]; } } - diff --git a/awt/java/awt/image/DataBufferShort.java b/awt/java/awt/image/DataBufferShort.java index 819ba4a46aece00cd6a85fb3a7bf104fbdb3cc53..1b11b29c3d92c2a3e5b3b59ddc2888ed58f2bcd7 100644 --- a/awt/java/awt/image/DataBufferShort.java +++ b/awt/java/awt/image/DataBufferShort.java @@ -18,25 +18,32 @@ * @author Igor V. Stolyarov * @version $Revision$ */ + package java.awt.image; /** - * The Class DataBufferShort is the subclass of DataBuffer - * for the case where the underlying data is short. + * The Class DataBufferShort is the subclass of DataBuffer for the case where + * the underlying data is short. + * + * @since Android 1.0 */ public final class DataBufferShort extends DataBuffer { - /** The data. */ + /** + * The data. + */ short data[][]; /** * Instantiates a new data buffer of type short. * - * @param dataArrays the data arrays to copy the data from - * @param size the length (number of elements) to use - * from the data arrays - * @param offsets the starting indices for reading the - * data from the internal data arrays + * @param dataArrays + * the data arrays to copy the data from. + * @param size + * the length (number of elements) to use from the data arrays. + * @param offsets + * the starting indices for reading the data from the internal + * data arrays. */ public DataBufferShort(short dataArrays[][], int size, int offsets[]) { super(TYPE_SHORT, size, dataArrays.length, offsets); @@ -46,9 +53,10 @@ public final class DataBufferShort extends DataBuffer { /** * Instantiates a new data buffer of type short. * - * @param dataArrays the data arrays to copy the data from - * @param size the length (number of elements) to use - * from the data arrays + * @param dataArrays + * the data arrays to copy the data from. + * @param size + * the length (number of elements) to use from the data arrays. */ public DataBufferShort(short dataArrays[][], int size) { super(TYPE_SHORT, size, dataArrays.length); @@ -56,13 +64,15 @@ public final class DataBufferShort extends DataBuffer { } /** - * Instantiates a new data buffer of type short - * with a single underlying array of data. + * Instantiates a new data buffer of type short with a single underlying + * array of data. * - * @param dataArray the data array to copy the data from - * @param size the length (number of elements) to use - * @param offset the starting index to use when reading the data - + * @param dataArray + * the data array to copy the data from. + * @param size + * the length (number of elements) to use. + * @param offset + * the starting index to use when reading the data. */ public DataBufferShort(short dataArray[], int size, int offset) { super(TYPE_SHORT, size, 1, offset); @@ -71,13 +81,13 @@ public final class DataBufferShort extends DataBuffer { } /** - * Instantiates a new data buffer of type short - * with a single underlying array of data starting at - * index 0. + * Instantiates a new data buffer of type short with a single underlying + * array of data starting at index 0. * - * @param dataArray the data array to copy the data from - * @param size the length (number of elements) to use - + * @param dataArray + * the data array to copy the data from. + * @param size + * the length (number of elements) to use. */ public DataBufferShort(short dataArray[], int size) { super(TYPE_SHORT, size); @@ -86,12 +96,12 @@ public final class DataBufferShort extends DataBuffer { } /** - * Instantiates a new data buffer of type short - * with offsets equal to zero. + * Instantiates a new data buffer of type short with offsets equal to zero. * - * @param size the length (number of elements) to use - * from the data arrays - * @param numBanks the number of data arrays to create + * @param size + * the length (number of elements) to use from the data arrays. + * @param numBanks + * the number of data arrays to create. */ public DataBufferShort(int size, int numBanks) { super(TYPE_SHORT, size, numBanks); @@ -103,11 +113,11 @@ public final class DataBufferShort extends DataBuffer { } /** - * Instantiates a new empty data buffer of type short - * with a single underlying array of data starting at - * index 0. + * Instantiates a new empty data buffer of type short with a single + * underlying array of data starting at index 0. * - * @param size the length (number of elements) to use + * @param size + * the length (number of elements) to use. */ public DataBufferShort(int size) { super(TYPE_SHORT, size); @@ -117,13 +127,13 @@ public final class DataBufferShort extends DataBuffer { @Override public void setElem(int bank, int i, int val) { - data[bank][offsets[bank] + i] = (short) val; + data[bank][offsets[bank] + i] = (short)val; notifyChanged(); } @Override public void setElem(int i, int val) { - data[0][offset + i] = (short) val; + data[0][offset + i] = (short)val; notifyChanged(); } @@ -135,9 +145,9 @@ public final class DataBufferShort extends DataBuffer { /** * Gets the data of the specified internal data array. * - * @param bank the index of the desired data array - * - * @return the data + * @param bank + * the index of the desired data array. + * @return the data. */ public short[] getData(int bank) { notifyTaken(); @@ -152,7 +162,7 @@ public final class DataBufferShort extends DataBuffer { /** * Gets the bank data. * - * @return the bank data + * @return the bank data. */ public short[][] getBankData() { notifyTaken(); @@ -162,11 +172,10 @@ public final class DataBufferShort extends DataBuffer { /** * Gets the data of the first data array. * - * @return the data + * @return the data. */ public short[] getData() { notifyTaken(); return data[0]; } } - diff --git a/awt/java/awt/image/DataBufferUShort.java b/awt/java/awt/image/DataBufferUShort.java index 79826784aa0c7f9e999be9e697d3da9ac88ba13b..58d9d8340bf64c1be80cd44d39c08ff104e510e2 100644 --- a/awt/java/awt/image/DataBufferUShort.java +++ b/awt/java/awt/image/DataBufferUShort.java @@ -18,34 +18,42 @@ * @author Igor V. Stolyarov * @version $Revision$ */ + package java.awt.image; import org.apache.harmony.awt.internal.nls.Messages; /** - * The Class DataBufferUShort is the subclass of DataBuffer - * for the case where the underlying data is unsigned short. + * The Class DataBufferUShort is the subclass of DataBuffer for the case where + * the underlying data is unsigned short. + * + * @since Android 1.0 */ public final class DataBufferUShort extends DataBuffer { - /** The data. */ + /** + * The data. + */ short data[][]; /** * Instantiates a new data buffer of type unsigned short. * - * @param dataArrays the data arrays to copy the data from - * @param size the length (number of elements) to use - * from the data arrays - * @param offsets the starting indices for reading the - * data from the internal data arrays + * @param dataArrays + * the data arrays to copy the data from. + * @param size + * the length (number of elements) to use from the data arrays. + * @param offsets + * the starting indices for reading the data from the internal + * data arrays. */ public DataBufferUShort(short dataArrays[][], int size, int offsets[]) { super(TYPE_USHORT, size, dataArrays.length, offsets); - for(int i = 0; i < dataArrays.length; i++){ - if(dataArrays[i].length < offsets[i] + size){ - // awt.28d=Length of dataArray[{0}] is less than size + offset[{1}] - throw new IllegalArgumentException(Messages.getString("awt.28D", i, i)); //$NON-NLS-1$ + for (int i = 0; i < dataArrays.length; i++) { + if (dataArrays[i].length < offsets[i] + size) { + // awt.28d=Length of dataArray[{0}] is less than size + + // offset[{1}] + throw new IllegalArgumentException(Messages.getString("awt.28D", i, i)); //$NON-NLS-1$ } } data = dataArrays.clone(); @@ -54,9 +62,10 @@ public final class DataBufferUShort extends DataBuffer { /** * Instantiates a new data buffer of type unsigned short. * - * @param dataArrays the data arrays to copy the data from - * @param size the length (number of elements) to use - * from the data arrays + * @param dataArrays + * the data arrays to copy the data from. + * @param size + * the length (number of elements) to use from the data arrays. */ public DataBufferUShort(short dataArrays[][], int size) { super(TYPE_USHORT, size, dataArrays.length); @@ -64,16 +73,19 @@ public final class DataBufferUShort extends DataBuffer { } /** - * Instantiates a new data buffer of type unsigned short - * with a single underlying array of data. + * Instantiates a new data buffer of type unsigned short with a single + * underlying array of data. * - * @param dataArray the data array to copy the data from - * @param size the length (number of elements) to use - * @param offset the starting index to use when reading the data + * @param dataArray + * the data array to copy the data from. + * @param size + * the length (number of elements) to use. + * @param offset + * the starting index to use when reading the data. */ public DataBufferUShort(short dataArray[], int size, int offset) { super(TYPE_USHORT, size, 1, offset); - if(dataArray.length < size + offset){ + if (dataArray.length < size + offset) { // awt.28E=Length of dataArray is less than size + offset throw new IllegalArgumentException(Messages.getString("awt.28E")); //$NON-NLS-1$ } @@ -82,12 +94,13 @@ public final class DataBufferUShort extends DataBuffer { } /** - * Instantiates a new data buffer of type unsigned short - * with a single underlying array of data starting at - * index 0. + * Instantiates a new data buffer of type unsigned short with a single + * underlying array of data starting at index 0. * - * @param dataArray the data array to copy the data from - * @param size the length (number of elements) to use + * @param dataArray + * the data array to copy the data from. + * @param size + * the length (number of elements) to use. */ public DataBufferUShort(short dataArray[], int size) { super(TYPE_USHORT, size); @@ -96,28 +109,29 @@ public final class DataBufferUShort extends DataBuffer { } /** - * Instantiates a new empty data buffer of type unsigned short - * with offsets equal to zero. + * Instantiates a new empty data buffer of type unsigned short with offsets + * equal to zero. * - * @param size the length (number of elements) to use - * from the data arrays - * @param numBanks the number of data arrays to create + * @param size + * the length (number of elements) to use from the data arrays. + * @param numBanks + * the number of data arrays to create. */ public DataBufferUShort(int size, int numBanks) { super(TYPE_USHORT, size, numBanks); data = new short[numBanks][]; - int i= 0; - while( i < numBanks) { + int i = 0; + while (i < numBanks) { data[i++] = new short[size]; } } /** - * Instantiates a new empty data buffer of type unsigned short - * with a single underlying array of data starting at - * index 0. + * Instantiates a new empty data buffer of type unsigned short with a single + * underlying array of data starting at index 0. * - * @param size the length (number of elements) to use + * @param size + * the length (number of elements) to use. */ public DataBufferUShort(int size) { super(TYPE_USHORT, size); @@ -145,9 +159,9 @@ public final class DataBufferUShort extends DataBuffer { /** * Gets the data of the specified internal data array. * - * @param bank the index of the desired data array - * - * @return the data + * @param bank + * the index of the desired data array. + * @return the data. */ public short[] getData(int bank) { notifyTaken(); @@ -162,7 +176,7 @@ public final class DataBufferUShort extends DataBuffer { /** * Gets the bank data. * - * @return the bank data + * @return the bank data. */ public short[][] getBankData() { notifyTaken(); @@ -172,11 +186,10 @@ public final class DataBufferUShort extends DataBuffer { /** * Gets the data of the first data array. * - * @return the data + * @return the data. */ public short[] getData() { notifyTaken(); return data[0]; } } - diff --git a/awt/java/awt/image/DirectColorModel.java b/awt/java/awt/image/DirectColorModel.java index 7a287c00e5b4958646680858c9b660e1d1e29761..700eb7a39e5e9a3ed65bef3a2e4d1a1d5addcdb1 100644 --- a/awt/java/awt/image/DirectColorModel.java +++ b/awt/java/awt/image/DirectColorModel.java @@ -18,6 +18,7 @@ * @author Igor V. Stolyarov * @version $Revision$ */ + package java.awt.image; import java.awt.color.ColorSpace; @@ -28,104 +29,141 @@ import org.apache.harmony.awt.gl.color.LUTColorConverter; import org.apache.harmony.awt.internal.nls.Messages; /** - * The Class DirectColorModel represents a standard (packed) RGB - * color model with additional support for converting between sRGB - * color space and 8 or 16 bit linear RGB color space using lookup tables. + * The Class DirectColorModel represents a standard (packed) RGB color model + * with additional support for converting between sRGB color space and 8 or 16 + * bit linear RGB color space using lookup tables. + * + * @since Android 1.0 */ public class DirectColorModel extends PackedColorModel { - /** The from_ linea r_ rg b_ lut. */ + /** + * The from_ linea r_ rg b_ lut. + */ private byte from_LINEAR_RGB_LUT[]; // Lookup table for conversion from - // Linear RGB Color Space into sRGB - /** The to_ linea r_8 rg b_ lut. */ - private byte to_LINEAR_8RGB_LUT[]; // Lookup table for conversion from - // sRGB Color Space into Linear RGB - // 8 bit + // Linear RGB Color Space into sRGB + + /** + * The to_ linea r_8 rg b_ lut. + */ + private byte to_LINEAR_8RGB_LUT[]; // Lookup table for conversion from - /** The to_ linea r_16 rg b_ lut. */ - private short to_LINEAR_16RGB_LUT[]; // Lookup table for conversion from - // sRGB Color Space into Linear RGB - // 16 bit + // sRGB Color Space into Linear RGB + // 8 bit - /** The alpha lut. */ - private byte alphaLUT[]; // Lookup table for scale alpha value + /** + * The to_ linea r_16 rg b_ lut. + */ + private short to_LINEAR_16RGB_LUT[]; // Lookup table for conversion from - /** The color lu ts. */ - private byte colorLUTs[][]; // Lookup tables for scale color values + // sRGB Color Space into Linear RGB + // 16 bit - /** The is_s rgb. */ - private boolean is_sRGB; // ColorModel has sRGB ColorSpace + /** + * The alpha lut. + */ + private byte alphaLUT[]; // Lookup table for scale alpha value + + /** + * The color lu ts. + */ + private byte colorLUTs[][]; // Lookup tables for scale color values + + /** + * The is_s rgb. + */ + private boolean is_sRGB; // ColorModel has sRGB ColorSpace + + /** + * The is_ linea r_ rgb. + */ + private boolean is_LINEAR_RGB; // Color Model has Linear RGB Color - /** The is_ linea r_ rgb. */ - private boolean is_LINEAR_RGB; // Color Model has Linear RGB Color - // Space + // Space - /** The LINEA r_ rg b_ length. */ - private int LINEAR_RGB_Length; // Linear RGB bit length + /** + * The LINEA r_ rg b_ length. + */ + private int LINEAR_RGB_Length; // Linear RGB bit length - /** The factor. */ - private float fFactor; // Scale factor + /** + * The factor. + */ + private float fFactor; // Scale factor /** * Instantiates a new direct color model. * - * @param space the color space - * @param bits the array of component masks - * @param rmask the bitmask corresponding to the red band - * @param gmask the bitmask corresponding to the green band - * @param bmask the bitmask corresponding to the blue band - * @param amask the bitmask corresponding to the alpha band - * @param isAlphaPremultiplied whether the alpha is premultiplied in this color model - * @param transferType the transfer type (primitive java type - * to use for the components) - * - * @throws IllegalArgumentException if the number of bits in the combined - * bitmasks for the color bands is less than one or greater than 32 + * @param space + * the color space. + * @param bits + * the array of component masks. + * @param rmask + * the bitmask corresponding to the red band. + * @param gmask + * the bitmask corresponding to the green band. + * @param bmask + * the bitmask corresponding to the blue band. + * @param amask + * the bitmask corresponding to the alpha band. + * @param isAlphaPremultiplied + * whether the alpha is pre-multiplied in this color model. + * @param transferType + * the transfer type (primitive java type to use for the + * components). + * @throws IllegalArgumentException + * if the number of bits in the combined bitmasks for the color + * bands is less than one or greater than 32. */ - public DirectColorModel(ColorSpace space, int bits, int rmask, int gmask, - int bmask, int amask, boolean isAlphaPremultiplied, - int transferType) { + public DirectColorModel(ColorSpace space, int bits, int rmask, int gmask, int bmask, int amask, + boolean isAlphaPremultiplied, int transferType) { super(space, bits, rmask, gmask, bmask, amask, isAlphaPremultiplied, - (amask == 0 ? Transparency.OPAQUE : Transparency.TRANSLUCENT), - transferType); + (amask == 0 ? Transparency.OPAQUE : Transparency.TRANSLUCENT), transferType); initLUTs(); } /** - * Instantiates a new direct color model, determining the transfer - * type from the bits array, the transparency from the alpha mask, - * and the default color space {@link ColorSpace#CS_sRGB}. + * Instantiates a new direct color model, determining the transfer type from + * the bits array, the transparency from the alpha mask, and the default + * color space {@link ColorSpace#CS_sRGB}. * - * @param bits the array of component masks - * @param rmask the bitmask corresponding to the red band - * @param gmask the bitmask corresponding to the green band - * @param bmask the bitmask corresponding to the blue band - * @param amask the bitmask corresponding to the alpha band + * @param bits + * the array of component masks. + * @param rmask + * the bitmask corresponding to the red band. + * @param gmask + * the bitmask corresponding to the green band. + * @param bmask + * the bitmask corresponding to the blue band. + * @param amask + * the bitmask corresponding to the alpha band. */ - public DirectColorModel(int bits, int rmask, int gmask, int bmask, - int amask) { + public DirectColorModel(int bits, int rmask, int gmask, int bmask, int amask) { - super(ColorSpace.getInstance(ColorSpace.CS_sRGB), bits, rmask, gmask, - bmask, amask, false, - (amask == 0 ? Transparency.OPAQUE : Transparency.TRANSLUCENT), - ColorModel.getTransferType(bits)); + super(ColorSpace.getInstance(ColorSpace.CS_sRGB), bits, rmask, gmask, bmask, amask, false, + (amask == 0 ? Transparency.OPAQUE : Transparency.TRANSLUCENT), ColorModel + .getTransferType(bits)); initLUTs(); } /** - * Instantiates a new direct color model with no alpha channel, - * determining the transfer type from the bits array, - * the default color space {@link ColorSpace#CS_sRGB}, - * and with the transparency set to {@link Transparency#OPAQUE}. + * Instantiates a new direct color model with no alpha channel, determining + * the transfer type from the bits array, the default color space + * {@link ColorSpace#CS_sRGB}, and with the transparency set to + * {@link Transparency#OPAQUE}. * - * @param bits the array of component masks - * @param rmask the bitmask corresponding to the red band - * @param gmask the bitmask corresponding to the green band - * @param bmask the bitmask corresponding to the blue band + * @param bits + * the array of component masks. + * @param rmask + * the bitmask corresponding to the red band. + * @param gmask + * the bitmask corresponding to the green band. + * @param bmask + * the bitmask corresponding to the blue band. */ public DirectColorModel(int bits, int rmask, int gmask, int bmask) { this(bits, rmask, gmask, bmask, 0); @@ -139,42 +177,42 @@ public class DirectColorModel extends PackedColorModel { } switch (transferType) { - case DataBuffer.TYPE_BYTE: - byte ba[]; - if (obj == null) { - ba = new byte[1]; - } else { - ba = (byte[]) obj; - } - ba[0] = (byte) pixel; - obj = ba; - break; - - case DataBuffer.TYPE_USHORT: - short sa[]; - if (obj == null) { - sa = new short[1]; - } else { - sa = (short[]) obj; - } - sa[0] = (short) pixel; - obj = sa; - break; + case DataBuffer.TYPE_BYTE: + byte ba[]; + if (obj == null) { + ba = new byte[1]; + } else { + ba = (byte[])obj; + } + ba[0] = (byte)pixel; + obj = ba; + break; - case DataBuffer.TYPE_INT: - int ia[]; - if (obj == null) { - ia = new int[1]; - } else { - ia = (int[]) obj; - } - ia[0] = pixel; - obj = ia; - break; + case DataBuffer.TYPE_USHORT: + short sa[]; + if (obj == null) { + sa = new short[1]; + } else { + sa = (short[])obj; + } + sa[0] = (short)pixel; + obj = sa; + break; + + case DataBuffer.TYPE_INT: + int ia[]; + if (obj == null) { + ia = new int[1]; + } else { + ia = (int[])obj; + } + ia[0] = pixel; + obj = ia; + break; - default: - // awt.214=This Color Model doesn't support this transferType - throw new UnsupportedOperationException(Messages.getString("awt.214")); //$NON-NLS-1$ + default: + // awt.214=This Color Model doesn't support this transferType + throw new UnsupportedOperationException(Messages.getString("awt.214")); //$NON-NLS-1$ } return obj; @@ -187,7 +225,7 @@ public class DirectColorModel extends PackedColorModel { if (pixel == null) { ia = new int[1]; } else { - ia = (int[]) pixel; + ia = (int[])pixel; } ia[0] = rgb; return ia; @@ -246,67 +284,66 @@ public class DirectColorModel extends PackedColorModel { int pxl = 0; if (hasAlpha) { float normAlpha = normComp[numColorComponents]; - alpha = (int) (normAlpha * maxValues[numColorComponents] + 0.5f); + alpha = (int)(normAlpha * maxValues[numColorComponents] + 0.5f); if (isAlphaPremultiplied) { - red = (int) (normComp[0] * normAlpha * maxValues[0] + 0.5f); - green = (int) (normComp[1] * normAlpha * maxValues[1] + 0.5f); - blue = (int) (normComp[2] * normAlpha * maxValues[2] + 0.5f); + red = (int)(normComp[0] * normAlpha * maxValues[0] + 0.5f); + green = (int)(normComp[1] * normAlpha * maxValues[1] + 0.5f); + blue = (int)(normComp[2] * normAlpha * maxValues[2] + 0.5f); } else { - red = (int) (normComp[0] * maxValues[0] + 0.5f); - green = (int) (normComp[1] * maxValues[1] + 0.5f); - blue = (int) (normComp[2] * maxValues[2] + 0.5f); + red = (int)(normComp[0] * maxValues[0] + 0.5f); + green = (int)(normComp[1] * maxValues[1] + 0.5f); + blue = (int)(normComp[2] * maxValues[2] + 0.5f); } pxl = (alpha << offsets[3]) & componentMasks[3]; } else { - red = (int) (normComp[0] * maxValues[0] + 0.5f); - green = (int) (normComp[1] * maxValues[1] + 0.5f); - blue = (int) (normComp[2] * maxValues[2] + 0.5f); + red = (int)(normComp[0] * maxValues[0] + 0.5f); + green = (int)(normComp[1] * maxValues[1] + 0.5f); + blue = (int)(normComp[2] * maxValues[2] + 0.5f); } - pxl |= ((red << offsets[0]) & componentMasks[0]) | - ((green << offsets[1]) & componentMasks[1]) | - ((blue << offsets[2]) & componentMasks[2]); + pxl |= ((red << offsets[0]) & componentMasks[0]) + | ((green << offsets[1]) & componentMasks[1]) + | ((blue << offsets[2]) & componentMasks[2]); switch (transferType) { - case DataBuffer.TYPE_BYTE: - byte ba[]; - if (pixel == null) { - ba = new byte[1]; - } else { - ba = (byte[]) pixel; - } - ba[0] = (byte) pxl; - return ba; + case DataBuffer.TYPE_BYTE: + byte ba[]; + if (pixel == null) { + ba = new byte[1]; + } else { + ba = (byte[])pixel; + } + ba[0] = (byte)pxl; + return ba; - case DataBuffer.TYPE_USHORT: - short sa[]; - if (pixel == null) { - sa = new short[1]; - } else { - sa = (short[]) pixel; - } - sa[0] = (short) pxl; - return sa; + case DataBuffer.TYPE_USHORT: + short sa[]; + if (pixel == null) { + sa = new short[1]; + } else { + sa = (short[])pixel; + } + sa[0] = (short)pxl; + return sa; - case DataBuffer.TYPE_INT: - int ia[]; - if (pixel == null) { - ia = new int[1]; - } else { - ia = (int[]) pixel; - } - ia[0] = pxl; - return ia; + case DataBuffer.TYPE_INT: + int ia[]; + if (pixel == null) { + ia = new int[1]; + } else { + ia = (int[])pixel; + } + ia[0] = pxl; + return ia; - default: - // awt.214=This Color Model doesn't support this transferType - throw new UnsupportedOperationException(Messages.getString("awt.214")); //$NON-NLS-1$ + default: + // awt.214=This Color Model doesn't support this transferType + throw new UnsupportedOperationException(Messages.getString("awt.214")); //$NON-NLS-1$ } } @Override - public final ColorModel coerceData(WritableRaster raster, - boolean isAlphaPremultiplied) { + public final ColorModel coerceData(WritableRaster raster, boolean isAlphaPremultiplied) { if (!hasAlpha || this.isAlphaPremultiplied == isAlphaPremultiplied) { return this; @@ -324,86 +361,82 @@ public class DirectColorModel extends PackedColorModel { if (isAlphaPremultiplied) { switch (transferType) { - case DataBuffer.TYPE_BYTE: - case DataBuffer.TYPE_USHORT: - case DataBuffer.TYPE_INT: - for (int i = 0; i < h; i++, minY++) { - for (int j = 0, x = minX; j < w; j++, x++) { - components = raster.getPixel(x, minY, components); - if (components[numColorComponents] == 0) { - raster.setPixel(x, minY, transparentComponents); - } else { - float alpha = - components[numColorComponents] / - alphaFactor; - for (int n = 0; n < numColorComponents; n++) { - components[n] = - (int) (alpha * components[n] + 0.5f); + case DataBuffer.TYPE_BYTE: + case DataBuffer.TYPE_USHORT: + case DataBuffer.TYPE_INT: + for (int i = 0; i < h; i++, minY++) { + for (int j = 0, x = minX; j < w; j++, x++) { + components = raster.getPixel(x, minY, components); + if (components[numColorComponents] == 0) { + raster.setPixel(x, minY, transparentComponents); + } else { + float alpha = components[numColorComponents] / alphaFactor; + for (int n = 0; n < numColorComponents; n++) { + components[n] = (int)(alpha * components[n] + 0.5f); + } + raster.setPixel(x, minY, components); } - raster.setPixel(x, minY, components); } - } - } - break; + } + break; - default: - // awt.214=This Color Model doesn't support this transferType - throw new UnsupportedOperationException(Messages.getString("awt.214")); //$NON-NLS-1$ + default: + // awt.214=This Color Model doesn't support this + // transferType + throw new UnsupportedOperationException(Messages.getString("awt.214")); //$NON-NLS-1$ } } else { switch (transferType) { - case DataBuffer.TYPE_BYTE: - case DataBuffer.TYPE_USHORT: - case DataBuffer.TYPE_INT: - for (int i = 0; i < h; i++, minY++) { - for (int j = 0, x = minX; j < w; j++, x++) { - components = raster.getPixel(x, minY, components); - if (components[numColorComponents] != 0) { - float alpha = - alphaFactor / components[numColorComponents]; - for (int n = 0; n < numColorComponents; n++) { - components[n] = - (int) (alpha * components[n] + 0.5f); + case DataBuffer.TYPE_BYTE: + case DataBuffer.TYPE_USHORT: + case DataBuffer.TYPE_INT: + for (int i = 0; i < h; i++, minY++) { + for (int j = 0, x = minX; j < w; j++, x++) { + components = raster.getPixel(x, minY, components); + if (components[numColorComponents] != 0) { + float alpha = alphaFactor / components[numColorComponents]; + for (int n = 0; n < numColorComponents; n++) { + components[n] = (int)(alpha * components[n] + 0.5f); + } + raster.setPixel(x, minY, components); } - raster.setPixel(x, minY, components); } - } - } - break; + } + break; - default: - // awt.214=This Color Model doesn't support this transferType - throw new UnsupportedOperationException(Messages.getString("awt.214")); //$NON-NLS-1$ + default: + // awt.214=This Color Model doesn't support this + // transferType + throw new UnsupportedOperationException(Messages.getString("awt.214")); //$NON-NLS-1$ } } - return new DirectColorModel(cs, pixel_bits, componentMasks[0], - componentMasks[1], componentMasks[2], componentMasks[3], - isAlphaPremultiplied, transferType); + return new DirectColorModel(cs, pixel_bits, componentMasks[0], componentMasks[1], + componentMasks[2], componentMasks[3], isAlphaPremultiplied, transferType); } @Override public String toString() { - // The output format based on 1.5 release behaviour. + // The output format based on 1.5 release behaviour. // It could be reveled such way: - // BufferedImage bi = new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB); + // BufferedImage bi = new BufferedImage(1, 1, + // BufferedImage.TYPE_INT_ARGB); // ColorModel cm = bi.getColorModel(); // System.out.println(cm.toString()); String str = "DirectColorModel:" + " rmask = " + //$NON-NLS-1$ //$NON-NLS-2$ - Integer.toHexString(componentMasks[0]) + " gmask = " + //$NON-NLS-1$ - Integer.toHexString(componentMasks[1]) + " bmask = " + //$NON-NLS-1$ - Integer.toHexString(componentMasks[2]) + " amask = " + //$NON-NLS-1$ - (!hasAlpha ? "0" : Integer.toHexString(componentMasks[3])); //$NON-NLS-1$ + Integer.toHexString(componentMasks[0]) + " gmask = " + //$NON-NLS-1$ + Integer.toHexString(componentMasks[1]) + " bmask = " + //$NON-NLS-1$ + Integer.toHexString(componentMasks[2]) + " amask = " + //$NON-NLS-1$ + (!hasAlpha ? "0" : Integer.toHexString(componentMasks[3])); //$NON-NLS-1$ return str; } @Override - public final int[] getComponents(Object pixel, int components[], - int offset) { + public final int[] getComponents(Object pixel, int components[], int offset) { if (components == null) { components = new int[numComponents + offset]; @@ -412,25 +445,26 @@ public class DirectColorModel extends PackedColorModel { int intPixel = 0; switch (transferType) { - case DataBuffer.TYPE_BYTE: - byte ba[] = (byte[]) pixel; - intPixel = ba[0] & 0xff; - break; + case DataBuffer.TYPE_BYTE: + byte ba[] = (byte[])pixel; + intPixel = ba[0] & 0xff; + break; - case DataBuffer.TYPE_USHORT: - short sa[] = (short[]) pixel; - intPixel = sa[0] & 0xffff; - break; + case DataBuffer.TYPE_USHORT: + short sa[] = (short[])pixel; + intPixel = sa[0] & 0xffff; + break; - case DataBuffer.TYPE_INT: - int ia[] = (int[]) pixel; - intPixel = ia[0]; - break; + case DataBuffer.TYPE_INT: + int ia[] = (int[])pixel; + intPixel = ia[0]; + break; - default: - // awt.22D=This transferType ( {0} ) is not supported by this color model - throw new UnsupportedOperationException(Messages.getString("awt.22D", //$NON-NLS-1$ - transferType)); + default: + // awt.22D=This transferType ( {0} ) is not supported by this + // color model + throw new UnsupportedOperationException(Messages.getString("awt.22D", //$NON-NLS-1$ + transferType)); } return getComponents(intPixel, components, offset); @@ -440,24 +474,24 @@ public class DirectColorModel extends PackedColorModel { public int getRed(Object inData) { int pixel = 0; switch (transferType) { - case DataBuffer.TYPE_BYTE: - byte ba[] = (byte[]) inData; - pixel = ba[0] & 0xff; - break; + case DataBuffer.TYPE_BYTE: + byte ba[] = (byte[])inData; + pixel = ba[0] & 0xff; + break; - case DataBuffer.TYPE_USHORT: - short sa[] = (short[]) inData; - pixel = sa[0] & 0xffff; - break; + case DataBuffer.TYPE_USHORT: + short sa[] = (short[])inData; + pixel = sa[0] & 0xffff; + break; - case DataBuffer.TYPE_INT: - int ia[] = (int[]) inData; - pixel = ia[0]; - break; + case DataBuffer.TYPE_INT: + int ia[] = (int[])inData; + pixel = ia[0]; + break; - default: - // awt.214=This Color Model doesn't support this transferType - throw new UnsupportedOperationException(Messages.getString("awt.214")); //$NON-NLS-1$ + default: + // awt.214=This Color Model doesn't support this transferType + throw new UnsupportedOperationException(Messages.getString("awt.214")); //$NON-NLS-1$ } return getRed(pixel); } @@ -466,24 +500,24 @@ public class DirectColorModel extends PackedColorModel { public int getRGB(Object inData) { int pixel = 0; switch (transferType) { - case DataBuffer.TYPE_BYTE: - byte ba[] = (byte[]) inData; - pixel = ba[0] & 0xff; - break; + case DataBuffer.TYPE_BYTE: + byte ba[] = (byte[])inData; + pixel = ba[0] & 0xff; + break; - case DataBuffer.TYPE_USHORT: - short sa[] = (short[]) inData; - pixel = sa[0] & 0xffff; - break; + case DataBuffer.TYPE_USHORT: + short sa[] = (short[])inData; + pixel = sa[0] & 0xffff; + break; - case DataBuffer.TYPE_INT: - int ia[] = (int[]) inData; - pixel = ia[0]; - break; + case DataBuffer.TYPE_INT: + int ia[] = (int[])inData; + pixel = ia[0]; + break; - default: - // awt.214=This Color Model doesn't support this transferType - throw new UnsupportedOperationException(Messages.getString("awt.214")); //$NON-NLS-1$ + default: + // awt.214=This Color Model doesn't support this transferType + throw new UnsupportedOperationException(Messages.getString("awt.214")); //$NON-NLS-1$ } return getRGB(pixel); } @@ -492,24 +526,24 @@ public class DirectColorModel extends PackedColorModel { public int getGreen(Object inData) { int pixel = 0; switch (transferType) { - case DataBuffer.TYPE_BYTE: - byte ba[] = (byte[]) inData; - pixel = ba[0] & 0xff; - break; + case DataBuffer.TYPE_BYTE: + byte ba[] = (byte[])inData; + pixel = ba[0] & 0xff; + break; - case DataBuffer.TYPE_USHORT: - short sa[] = (short[]) inData; - pixel = sa[0] & 0xffff; - break; + case DataBuffer.TYPE_USHORT: + short sa[] = (short[])inData; + pixel = sa[0] & 0xffff; + break; - case DataBuffer.TYPE_INT: - int ia[] = (int[]) inData; - pixel = ia[0]; - break; + case DataBuffer.TYPE_INT: + int ia[] = (int[])inData; + pixel = ia[0]; + break; - default: - // awt.214=This Color Model doesn't support this transferType - throw new UnsupportedOperationException(Messages.getString("awt.214")); //$NON-NLS-1$ + default: + // awt.214=This Color Model doesn't support this transferType + throw new UnsupportedOperationException(Messages.getString("awt.214")); //$NON-NLS-1$ } return getGreen(pixel); } @@ -518,24 +552,24 @@ public class DirectColorModel extends PackedColorModel { public int getBlue(Object inData) { int pixel = 0; switch (transferType) { - case DataBuffer.TYPE_BYTE: - byte ba[] = (byte[]) inData; - pixel = ba[0] & 0xff; - break; + case DataBuffer.TYPE_BYTE: + byte ba[] = (byte[])inData; + pixel = ba[0] & 0xff; + break; - case DataBuffer.TYPE_USHORT: - short sa[] = (short[]) inData; - pixel = sa[0] & 0xffff; - break; + case DataBuffer.TYPE_USHORT: + short sa[] = (short[])inData; + pixel = sa[0] & 0xffff; + break; - case DataBuffer.TYPE_INT: - int ia[] = (int[]) inData; - pixel = ia[0]; - break; + case DataBuffer.TYPE_INT: + int ia[] = (int[])inData; + pixel = ia[0]; + break; - default: - // awt.214=This Color Model doesn't support this transferType - throw new UnsupportedOperationException(Messages.getString("awt.214")); //$NON-NLS-1$ + default: + // awt.214=This Color Model doesn't support this transferType + throw new UnsupportedOperationException(Messages.getString("awt.214")); //$NON-NLS-1$ } return getBlue(pixel); } @@ -544,24 +578,24 @@ public class DirectColorModel extends PackedColorModel { public int getAlpha(Object inData) { int pixel = 0; switch (transferType) { - case DataBuffer.TYPE_BYTE: - byte ba[] = (byte[]) inData; - pixel = ba[0] & 0xff; - break; + case DataBuffer.TYPE_BYTE: + byte ba[] = (byte[])inData; + pixel = ba[0] & 0xff; + break; - case DataBuffer.TYPE_USHORT: - short sa[] = (short[]) inData; - pixel = sa[0] & 0xffff; - break; + case DataBuffer.TYPE_USHORT: + short sa[] = (short[])inData; + pixel = sa[0] & 0xffff; + break; - case DataBuffer.TYPE_INT: - int ia[] = (int[]) inData; - pixel = ia[0]; - break; + case DataBuffer.TYPE_INT: + int ia[] = (int[])inData; + pixel = ia[0]; + break; - default: - // awt.214=This Color Model doesn't support this transferType - throw new UnsupportedOperationException(Messages.getString("awt.214")); //$NON-NLS-1$ + default: + // awt.214=This Color Model doesn't support this transferType + throw new UnsupportedOperationException(Messages.getString("awt.214")); //$NON-NLS-1$ } return getAlpha(pixel); } @@ -576,14 +610,11 @@ public class DirectColorModel extends PackedColorModel { int bandMasks[] = componentMasks.clone(); if (pixel_bits > 16) { - return Raster.createPackedRaster(DataBuffer.TYPE_INT, w, h, - bandMasks, null); + return Raster.createPackedRaster(DataBuffer.TYPE_INT, w, h, bandMasks, null); } else if (pixel_bits > 8) { - return Raster.createPackedRaster(DataBuffer.TYPE_USHORT, w, h, - bandMasks, null); + return Raster.createPackedRaster(DataBuffer.TYPE_USHORT, w, h, bandMasks, null); } else { - return Raster.createPackedRaster(DataBuffer.TYPE_BYTE, w, h, - bandMasks, null); + return Raster.createPackedRaster(DataBuffer.TYPE_BYTE, w, h, bandMasks, null); } } @@ -594,7 +625,7 @@ public class DirectColorModel extends PackedColorModel { return false; } - SinglePixelPackedSampleModel sppsm = (SinglePixelPackedSampleModel) sm; + SinglePixelPackedSampleModel sppsm = (SinglePixelPackedSampleModel)sm; if (sppsm.getNumBands() != numComponents) { return false; @@ -640,8 +671,8 @@ public class DirectColorModel extends PackedColorModel { @Override public final int getRGB(int pixel) { - return (getAlpha(pixel) << 24) | (getRed(pixel) << 16) | - (getGreen(pixel) << 8) | getBlue(pixel); + return (getAlpha(pixel) << 24) | (getRed(pixel) << 16) | (getGreen(pixel) << 8) + | getBlue(pixel); } @Override @@ -681,7 +712,7 @@ public class DirectColorModel extends PackedColorModel { /** * Gets the red mask. * - * @return the red mask + * @return the red mask. */ public final int getRedMask() { return componentMasks[0]; @@ -690,7 +721,7 @@ public class DirectColorModel extends PackedColorModel { /** * Gets the green mask. * - * @return the green mask + * @return the green mask. */ public final int getGreenMask() { return componentMasks[1]; @@ -699,7 +730,7 @@ public class DirectColorModel extends PackedColorModel { /** * Gets the blue mask. * - * @return the blue mask + * @return the blue mask. */ public final int getBlueMask() { return componentMasks[2]; @@ -708,7 +739,7 @@ public class DirectColorModel extends PackedColorModel { /** * Gets the alpha mask. * - * @return the alpha mask + * @return the alpha mask. */ public final int getAlphaMask() { if (hasAlpha) { @@ -727,16 +758,12 @@ public class DirectColorModel extends PackedColorModel { if (is_LINEAR_RGB) { if (maxBitLength > 8) { LINEAR_RGB_Length = 16; - from_LINEAR_RGB_LUT = - LUTColorConverter.getFrom16lRGBtosRGB_LUT(); - to_LINEAR_16RGB_LUT = - LUTColorConverter.getFromsRGBto16lRGB_LUT(); + from_LINEAR_RGB_LUT = LUTColorConverter.getFrom16lRGBtosRGB_LUT(); + to_LINEAR_16RGB_LUT = LUTColorConverter.getFromsRGBto16lRGB_LUT(); } else { LINEAR_RGB_Length = 8; - from_LINEAR_RGB_LUT = - LUTColorConverter.getFrom8lRGBtosRGB_LUT(); - to_LINEAR_8RGB_LUT = - LUTColorConverter.getFromsRGBto8lRGB_LUT(); + from_LINEAR_RGB_LUT = LUTColorConverter.getFrom8lRGBtosRGB_LUT(); + to_LINEAR_8RGB_LUT = LUTColorConverter.getFromsRGBto8lRGB_LUT(); } fFactor = ((1 << LINEAR_RGB_Length) - 1); } else { @@ -746,7 +773,7 @@ public class DirectColorModel extends PackedColorModel { if (hasAlpha && bits[3] != 8) { alphaLUT = new byte[maxValues[3] + 1]; for (int i = 0; i <= maxValues[3]; i++) { - alphaLUT[i] = (byte) (scales[3] * i + 0.5f); + alphaLUT[i] = (byte)(scales[3] * i + 0.5f); } } @@ -765,7 +792,7 @@ public class DirectColorModel extends PackedColorModel { } colorLUTs[i] = new byte[maxValues[i] + 1]; for (int j = 0; j <= maxValues[i]; j++) { - colorLUTs[i][j] = (byte) (scales[i] * j + 0.5f); + colorLUTs[i][j] = (byte)(scales[i] * j + 0.5f); } } } @@ -784,9 +811,9 @@ public class DirectColorModel extends PackedColorModel { for (int j = 0; j <= maxValues[0]; j++) { int idx; if (LINEAR_RGB_Length == 8) { - idx = (int) (scales[i] * j + 0.5f); + idx = (int)(scales[i] * j + 0.5f); } else { - idx = (int) (scales[i] * j * 257.0f + 0.5f); + idx = (int)(scales[i] * j * 257.0f + 0.5f); } colorLUTs[i][j] = from_LINEAR_RGB_LUT[idx]; } @@ -798,20 +825,20 @@ public class DirectColorModel extends PackedColorModel { } /** - * This method return RGB component value if Color Model has - * sRGB ColorSpace. + * This method return RGB component value if Color Model has sRGB + * ColorSpace. * - * @param pixel - INT representation of pixel - * @param idx - index of pixel component - * - * @return - value of the pixel component scaled fro 0 to 255 + * @param pixel + * the integer representation of the pixel. + * @param idx + * the index of the pixel component. + * @return the value of the pixel component scaled from 0 to 255. */ private int getComponentFrom_sRGB(int pixel, int idx) { int comp = (pixel & componentMasks[idx]) >> offsets[idx]; if (isAlphaPremultiplied) { int alpha = (pixel & componentMasks[3]) >>> offsets[3]; - comp = alpha == 0 ? 0 : (int) (scales[idx] * comp * 255.0f / - (scales[3] * alpha) + 0.5f); + comp = alpha == 0 ? 0 : (int)(scales[idx] * comp * 255.0f / (scales[3] * alpha) + 0.5f); } else if (bits[idx] != 8) { comp = colorLUTs[idx][comp] & 0xff; } @@ -819,21 +846,21 @@ public class DirectColorModel extends PackedColorModel { } /** - * This method return RGB component value if Color Model has - * Linear RGB ColorSpace. - * - * @param pixel - INT representation of pixel - * @param idx - index of pixel component + * This method return RGB component value if Color Model has Linear RGB + * ColorSpace. * - * @return - value of the pixel component scaled fro 0 to 255 + * @param pixel + * the integer representation of the pixel. + * @param idx + * the index of the pixel component. + * @return the value of the pixel component scaled from 0 to 255. */ private int getComponentFrom_LINEAR_RGB(int pixel, int idx) { int comp = (pixel & componentMasks[idx]) >> offsets[idx]; if (isAlphaPremultiplied) { float factor = ((1 << LINEAR_RGB_Length) - 1); int alpha = (pixel & componentMasks[3]) >> offsets[3]; - comp = alpha == 0 ? 0 : (int) (scales[idx] * comp * factor / - (scales[3] * alpha) + 0.5f); + comp = alpha == 0 ? 0 : (int)(scales[idx] * comp * factor / (scales[3] * alpha) + 0.5f); } else if (bits[idx] != LINEAR_RGB_Length) { comp = colorLUTs[idx][comp] & 0xff; } else { @@ -843,20 +870,20 @@ public class DirectColorModel extends PackedColorModel { } /** - * This method return RGB component value if Color Model has - * arbitrary RGB ColorSapce. + * This method return RGB component value if Color Model has arbitrary RGB + * ColorSapce. * - * @param pixel - INT representation of pixel - * @param idx - index of pixel component - * - * @return - value of the pixel component scaled fro 0 to 255 + * @param pixel + * the integer representation of the pixel. + * @param idx + * the index of the pixel component. + * @return the value of the pixel component scaled from 0 to 255. */ private int getComponentFrom_RGB(int pixel, int idx) { int components[] = getComponents(pixel, null, 0); float[] normComponents = getNormalizedComponents(components, 0, null, 0); float[] sRGBcomponents = cs.toRGB(normComponents); - return (int) (sRGBcomponents[idx] * 255.0f + 0.5f); + return (int)(sRGBcomponents[idx] * 255.0f + 0.5f); } } - diff --git a/awt/java/awt/image/FilteredImageSource.java b/awt/java/awt/image/FilteredImageSource.java index 6a41fa76a2ffe2f18aafa421d5397c8298ea85be..ed8558d3c5e5c1bda61738d9775582c3c01b4a5d 100644 --- a/awt/java/awt/image/FilteredImageSource.java +++ b/awt/java/awt/image/FilteredImageSource.java @@ -18,32 +18,42 @@ * @author Igor V. Stolyarov * @version $Revision$ */ + package java.awt.image; import java.util.Hashtable; - /** - * The FilteredImageSource class is used for producing image data for a new - * filtered version of the original image using the specified filter object. + * The FilteredImageSource class is used for producing image data for a new + * filtered version of the original image using the specified filter object. + * + * @since Android 1.0 */ public class FilteredImageSource implements ImageProducer { - /** The source. */ + /** + * The source. + */ private final ImageProducer source; - - /** The filter. */ + + /** + * The filter. + */ private final ImageFilter filter; - /** The cons table. */ + /** + * The cons table. + */ private final Hashtable consTable = new Hashtable(); /** - * Instantiates a new FilteredImageSource object with - * the specified ImageProducer and the ImageFilter objects. + * Instantiates a new FilteredImageSource object with the specified + * ImageProducer and the ImageFilter objects. * - * @param orig the specified ImageProducer. - * @param imgf the specified ImageFilter. + * @param orig + * the specified ImageProducer. + * @param imgf + * the specified ImageFilter. */ public FilteredImageSource(ImageProducer orig, ImageFilter imgf) { source = orig; @@ -51,7 +61,7 @@ public class FilteredImageSource implements ImageProducer { } public synchronized boolean isConsumer(ImageConsumer ic) { - if(ic != null) { + if (ic != null) { return consTable.containsKey(ic); } return false; @@ -64,14 +74,14 @@ public class FilteredImageSource implements ImageProducer { } public void requestTopDownLeftRightResend(ImageConsumer ic) { - if(ic != null && isConsumer(ic)){ - ImageFilter fic = (ImageFilter) consTable.get(ic); + if (ic != null && isConsumer(ic)) { + ImageFilter fic = (ImageFilter)consTable.get(ic); fic.resendTopDownLeftRight(source); } } public synchronized void removeConsumer(ImageConsumer ic) { - if(ic != null && isConsumer(ic)){ + if (ic != null && isConsumer(ic)) { ImageConsumer fic = consTable.get(ic); source.removeConsumer(fic); consTable.remove(ic); @@ -79,7 +89,7 @@ public class FilteredImageSource implements ImageProducer { } public synchronized void addConsumer(ImageConsumer ic) { - if(ic != null && !isConsumer(ic)){ + if (ic != null && !isConsumer(ic)) { ImageConsumer fic = filter.getFilterInstance(ic); source.addConsumer(fic); consTable.put(ic, fic); diff --git a/awt/java/awt/image/ImageConsumer.java b/awt/java/awt/image/ImageConsumer.java index 2eba290d54d39d26cd6e38fb9d71a41e3266aad6..caf87d108847d2f2dd190ce0d219fadfe24b3bdb 100644 --- a/awt/java/awt/image/ImageConsumer.java +++ b/awt/java/awt/image/ImageConsumer.java @@ -18,148 +18,168 @@ * @author Igor V. Stolyarov * @version $Revision$ */ + package java.awt.image; import java.util.Hashtable; /** - * The ImageConsumer interface provides the data about the image - * and about how its data is delivered. A ImageProducer provides - * all of the information about the image using - * the methods defined in this interface. + * The ImageConsumer interface provides the data about the image and about how + * its data is delivered. A ImageProducer provides all of the information about + * the image using the methods defined in this interface. + * + * @since Android 1.0 */ public interface ImageConsumer { - /** - * The Constant RANDOMPIXELORDER indicates that the pixels are - * delivered in a random order. + /** + * The Constant RANDOMPIXELORDER indicates that the pixels are delivered in + * a random order. */ public static final int RANDOMPIXELORDER = 1; - /** - * The Constant TOPDOWNLEFTRIGHT indicates that the pixels are - * delivered in top-down, left-to-right order. + /** + * The Constant TOPDOWNLEFTRIGHT indicates that the pixels are delivered in + * top-down, left-to-right order. */ public static final int TOPDOWNLEFTRIGHT = 2; - /** - * The Constant COMPLETESCANLINES indicates that the pixels are - * delivered in complete scanline. + /** + * The Constant COMPLETESCANLINES indicates that the pixels are delivered in + * complete scanline. */ public static final int COMPLETESCANLINES = 4; - /** - * The Constant SINGLEPASS indicates that pixels are delivered - * in a single pass. + /** + * The Constant SINGLEPASS indicates that pixels are delivered in a single + * pass. */ public static final int SINGLEPASS = 8; - /** - * The Constant SINGLEFRAME indicates that image consists of - * single frame. + /** + * The Constant SINGLEFRAME indicates that image consists of single frame. */ public static final int SINGLEFRAME = 16; - /** + /** * The Constant IMAGEERROR indicates an image error during image producing. */ public static final int IMAGEERROR = 1; - /** - * The Constant SINGLEFRAMEDONE indicates that only one of the - * image's frames is completed. + /** + * The Constant SINGLEFRAMEDONE indicates that only one of the image's + * frames is completed. */ public static final int SINGLEFRAMEDONE = 2; - /** - * The Constant STATICIMAGEDONE indicates that the image is completed. + /** + * The Constant STATICIMAGEDONE indicates that the image is completed. */ public static final int STATICIMAGEDONE = 3; - /** - * The Constant IMAGEABORTED indicates that the image producing - * process is aborted. + /** + * The Constant IMAGEABORTED indicates that the image producing process is + * aborted. */ public static final int IMAGEABORTED = 4; /** * Sets the properties for the image associated with this ImageConsumer. * - * @param props the properties for the image associated with - * this ImageConsumer. + * @param props + * the properties for the image associated with this + * ImageConsumer. */ public void setProperties(Hashtable props); /** * Sets the ColorModel object. * - * @param model the new ColorModel. + * @param model + * the new ColorModel. */ public void setColorModel(ColorModel model); /** * Sets the pixels for the specified rectangular area of the image. * - * @param x the X coordinate of rectangular area. - * @param y the Y coordinate of rectangular area. - * @param w the width of rectangular area. - * @param h the height of rectangular area. - * @param model the specified ColorModel to be used for pixels - * converting. - * @param pixels the array of pixels. - * @param off the offset of pixels array. - * @param scansize the distance from the one row of pixels - * to the next row in the specified array. - */ - public void setPixels(int x, int y, int w, int h, ColorModel model, - int[] pixels, int off, int scansize); + * @param x + * the X coordinate of rectangular area. + * @param y + * the Y coordinate of rectangular area. + * @param w + * the width of rectangular area. + * @param h + * the height of rectangular area. + * @param model + * the specified ColorModel to be used for pixels converting. + * @param pixels + * the array of pixels. + * @param off + * the offset of pixels array. + * @param scansize + * the distance from the one row of pixels to the next row in the + * specified array. + */ + public void setPixels(int x, int y, int w, int h, ColorModel model, int[] pixels, int off, + int scansize); /** * Sets the pixels for the specified rectangular area of the image. * - * @param x the X coordinate of rectangular area. - * @param y the Y coordinate of rectangular area. - * @param w the width of rectangular area. - * @param h the height of rectangular area. - * @param model the specified ColorModel to be used for pixels - * converting. - * @param pixels the array of pixels. - * @param off the offset of pixels array. - * @param scansize the distance from the one row of pixels - * to the next row in the specified array. - */ - public void setPixels(int x, int y, int w, int h, ColorModel model, - byte[] pixels, int off, int scansize); + * @param x + * the X coordinate of rectangular area. + * @param y + * the Y coordinate of rectangular area. + * @param w + * the width of rectangular area. + * @param h + * the height of rectangular area. + * @param model + * the specified ColorModel to be used for pixels converting. + * @param pixels + * the array of pixels. + * @param off + * the offset of pixels array. + * @param scansize + * the distance from the one row of pixels to the next row in the + * specified array. + */ + public void setPixels(int x, int y, int w, int h, ColorModel model, byte[] pixels, int off, + int scansize); /** * Sets the dimensions of a source image. * - * @param width the width of the image. - * @param height the height of the image. + * @param width + * the width of the image. + * @param height + * the height of the image. */ public void setDimensions(int width, int height); /** - * Sets the hint flags of pixels order, which is used by - * the ImageConsumer for obtaining pixels from the ImageProducer - * for which this ImageConsumer is added. + * Sets the hint flags of pixels order, which is used by the ImageConsumer + * for obtaining pixels from the ImageProducer for which this ImageConsumer + * is added. * - * @param hintflags the mask of hint flags. + * @param hintflags + * the mask of hint flags. */ public void setHints(int hintflags); /** * THis method is called in the one of the following cases: *

      - *
    • The ImageProducer (for which this ImageConsumer is added) - * has been delivered all pixels of the source image.
    • - *
    • A one frame of an animation has been completed.
    • - *
    • An error while loading or producing of the image has occured. - *
    + *
  • The ImageProducer (for which this ImageConsumer is added) has been + * delivered all pixels of the source image.
  • + *
  • A one frame of an animation has been completed.
  • + *
  • An error while loading or producing of the image has occurred. + * * - * @param status the status of image producing. + * @param status + * the status of image producing. */ public void imageComplete(int status); } - diff --git a/awt/java/awt/image/ImageFilter.java b/awt/java/awt/image/ImageFilter.java index e386d657a82e2752944bd5a6b8a3ef5f8466c10a..d2c9f502482385deafce7dc561ff7c1b8b6be4b1 100644 --- a/awt/java/awt/image/ImageFilter.java +++ b/awt/java/awt/image/ImageFilter.java @@ -18,17 +18,22 @@ * @author Igor V. Stolyarov * @version $Revision$ */ + package java.awt.image; import java.util.Hashtable; /** - * The ImageFilter class provides a filter for delivering image data - * from an ImageProducer to an ImageConsumer. + * The ImageFilter class provides a filter for delivering image data from an + * ImageProducer to an ImageConsumer. + * + * @since Android 1.0 */ public class ImageFilter implements ImageConsumer, Cloneable { - /** The consumer. */ + /** + * The consumer. + */ protected ImageConsumer consumer; /** @@ -39,16 +44,16 @@ public class ImageFilter implements ImageConsumer, Cloneable { } /** - * Gets an instance of an ImageFilter object which performs - * the filtering for the specified ImageConsumer. - * - * @param ic the specified ImageConsumer. + * Gets an instance of an ImageFilter object which performs the filtering + * for the specified ImageConsumer. * - * @return an ImageFilter used to perform the filtering for - * the specified ImageConsumer. + * @param ic + * the specified ImageConsumer. + * @return an ImageFilter used to perform the filtering for the specified + * ImageConsumer. */ public ImageFilter getFilterInstance(ImageConsumer ic) { - ImageFilter filter = (ImageFilter) clone(); + ImageFilter filter = (ImageFilter)clone(); filter.consumer = ic; return filter; } @@ -59,14 +64,14 @@ public class ImageFilter implements ImageConsumer, Cloneable { if (props == null) { fprops = new Hashtable(); } else { - fprops = (Hashtable) props.clone(); + fprops = (Hashtable)props.clone(); } String propName = "Filters"; //$NON-NLS-1$ String prop = "Null filter"; //$NON-NLS-1$ Object o = fprops.get(propName); if (o != null) { if (o instanceof String) { - prop = (String) o + "; " + prop; //$NON-NLS-1$ + prop = (String)o + "; " + prop; //$NON-NLS-1$ } else { prop = o.toString() + "; " + prop; //$NON-NLS-1$ } @@ -90,11 +95,11 @@ public class ImageFilter implements ImageConsumer, Cloneable { } /** - * Responds to a request for a Top-Down-Left-Right ordered - * resend of the pixel data from an ImageConsumer. + * Responds to a request for a Top-Down-Left-Right ordered resend of the + * pixel data from an ImageConsumer. * - * @param ip the ImageProducer that provides this instance of - * the filter. + * @param ip + * the ImageProducer that provides this instance of the filter. */ public void resendTopDownLeftRight(ImageProducer ip) { ip.requestTopDownLeftRightResend(this); diff --git a/awt/java/awt/image/ImageObserver.java b/awt/java/awt/image/ImageObserver.java index 418bd0766bbcb6760cef928aa65538de73d8dfcf..21ec41bf2582843aa9cf44f938fa6349472fe7f2 100644 --- a/awt/java/awt/image/ImageObserver.java +++ b/awt/java/awt/image/ImageObserver.java @@ -18,82 +18,84 @@ * @author Igor V. Stolyarov * @version $Revision$ */ + package java.awt.image; import java.awt.Image; /** - * the ImageObserver interface is an asynchronous update interface - * for receiving notifications about Image construction status. + * the ImageObserver interface is an asynchronous update interface for receiving + * notifications about Image construction status. + * + * @since Android 1.0 */ public interface ImageObserver { - /** - * The Constant WIDTH indicates that the width of the image is - * available. + /** + * The Constant WIDTH indicates that the width of the image is available. */ public static final int WIDTH = 1; - /** - * The Constant HEIGHT indicates that the width of the image is - * available. + /** + * The Constant HEIGHT indicates that the width of the image is available. */ public static final int HEIGHT = 2; - /** - * The Constant PROPERTIES indicates that the properties of the image - * are available. + /** + * The Constant PROPERTIES indicates that the properties of the image are + * available. */ public static final int PROPERTIES = 4; /** - * The Constant SOMEBITS indicates that more bits needed for - * drawing a scaled variation of the image pixels are available. + * The Constant SOMEBITS indicates that more bits needed for drawing a + * scaled variation of the image pixels are available. */ public static final int SOMEBITS = 8; - /** - * The Constant FRAMEBITS indicates that complete frame of - * a image which was previously drawn is now available - * for drawing again. + /** + * The Constant FRAMEBITS indicates that complete frame of a image which was + * previously drawn is now available for drawing again. */ public static final int FRAMEBITS = 16; - /** - * The Constant ALLBITS indicates that an image which - * was previously drawn is now complete and can be drawn again. + /** + * The Constant ALLBITS indicates that an image which was previously drawn + * is now complete and can be drawn again. */ public static final int ALLBITS = 32; - /** - * The Constant ERROR indicates that error occured. + /** + * The Constant ERROR indicates that error occurred. */ public static final int ERROR = 64; - /** - * The Constant ABORT indicates that the image producing is - * aborted. + /** + * The Constant ABORT indicates that the image producing is aborted. */ public static final int ABORT = 128; /** - * This method is called when information about an Image - * interface becomes available. This method returns true - * if further updates are needed, false if not. - * - * @param img the image to be observed. - * @param infoflags the bitwise OR combination of information flags: - * ABORT, ALLBITS, ERROR, FRAMEBITS, HEIGHT, PROPERTIES, SOMEBITS, - * WIDTH. - * @param x the X coordinate. - * @param y the Y coordinate. - * @param width the width. - * @param height the height. + * This method is called when information about an Image interface becomes + * available. This method returns true if further updates are needed, false + * if not. * + * @param img + * the image to be observed. + * @param infoflags + * the bitwise OR combination of information flags: ABORT, + * ALLBITS, ERROR, FRAMEBITS, HEIGHT, PROPERTIES, SOMEBITS, + * WIDTH. + * @param x + * the X coordinate. + * @param y + * the Y coordinate. + * @param width + * the width. + * @param height + * the height. * @return true if further updates are needed, false if not. */ - public boolean imageUpdate(Image img, int infoflags, int x, int y, - int width, int height); + public boolean imageUpdate(Image img, int infoflags, int x, int y, int width, int height); } - diff --git a/awt/java/awt/image/ImageProducer.java b/awt/java/awt/image/ImageProducer.java index 557ae085a43978d789d56f797a38fdc83ab62b8a..9138be27118f12c32cf802119c4ded6abf899217 100644 --- a/awt/java/awt/image/ImageProducer.java +++ b/awt/java/awt/image/ImageProducer.java @@ -18,57 +18,62 @@ * @author Igor V. Stolyarov * @version $Revision$ */ -package java.awt.image; +package java.awt.image; /** - * The ImageProducer provides an interface for objects which produce - * the image data. ImageProducer is used for reconstructing the - * image. Each image contains an ImageProducer. + * The ImageProducer provides an interface for objects which produce the image + * data. ImageProducer is used for reconstructing the image. Each image contains + * an ImageProducer. + * + * @since Android 1.0 */ public interface ImageProducer { /** - * Checks if the specified ImageConsumer is registered with this + * Checks if the specified ImageConsumer is registered with this * ImageProvider or not. * - * @param ic the ImageConsumer to be checked. - * - * @return true, if the specified ImageConsumer is registered with this - * ImageProvider, false otherwise. + * @param ic + * the ImageConsumer to be checked. + * @return true, if the specified ImageConsumer is registered with this + * ImageProvider, false otherwise. */ public boolean isConsumer(ImageConsumer ic); /** - * Starts a reconstruction of the image data which will - * be delivered to this consumer. This method addes the - * specified ImageConsumer before reconstructing the image. + * Starts a reconstruction of the image data which will be delivered to this + * consumer. This method adds the specified ImageConsumer before + * reconstructing the image. * - * @param ic the specified ImageConsumer. + * @param ic + * the specified ImageConsumer. */ public void startProduction(ImageConsumer ic); /** - * Requests the ImageProducer to resend the image data - * in ImageConsumer.TOPDOWNLEFTRIGHT order. + * Requests the ImageProducer to resend the image data in + * ImageConsumer.TOPDOWNLEFTRIGHT order. * - * @param ic the specified ImageConsumer. + * @param ic + * the specified ImageConsumer. */ public void requestTopDownLeftRightResend(ImageConsumer ic); /** * Deregisters the specified ImageConsumer. * - * @param ic the specified ImageConsumer. + * @param ic + * the specified ImageConsumer. */ public void removeConsumer(ImageConsumer ic); /** * Adds the specified ImageConsumer object to this ImageProducer. * - * @param ic the specified ImageConsumer. + * @param ic + * the specified ImageConsumer. */ public void addConsumer(ImageConsumer ic); } - diff --git a/awt/java/awt/image/ImagingOpException.java b/awt/java/awt/image/ImagingOpException.java index ebcaba42503a3daaace0fa5980ac3c426fb76273..e0c0127f4a1f61accebf52b1ff9c030717c8e064 100644 --- a/awt/java/awt/image/ImagingOpException.java +++ b/awt/java/awt/image/ImagingOpException.java @@ -24,19 +24,24 @@ package java.awt.image; /** - * The ImagingOpException class provides error notification when - * the BufferedImageOp or RasterOp filter methods can not perform - * the desired filter operation. + * The ImagingOpException class provides error notification when the + * BufferedImageOp or RasterOp filter methods can not perform the desired filter + * operation. + * + * @since Android 1.0 */ public class ImagingOpException extends RuntimeException { - - /** The Constant serialVersionUID. */ + + /** + * The Constant serialVersionUID. + */ private static final long serialVersionUID = 8026288481846276658L; /** * Instantiates a new ImagingOpException with a detail message. * - * @param s the detail message. + * @param s + * the detail message. */ public ImagingOpException(String s) { super(s); diff --git a/awt/java/awt/image/IndexColorModel.java b/awt/java/awt/image/IndexColorModel.java index a7043f491c7284f8ad24704a9d8cc8c73e321afe..0b06acda61047f4faa8fb97d63bf706a801d1fc3 100644 --- a/awt/java/awt/image/IndexColorModel.java +++ b/awt/java/awt/image/IndexColorModel.java @@ -18,6 +18,7 @@ * @author Igor V. Stolyarov * @version $Revision$ */ + package java.awt.image; import java.awt.Transparency; @@ -27,64 +28,92 @@ import java.math.BigInteger; import org.apache.harmony.awt.internal.nls.Messages; /** - * The Class IndexColorModel represents a color model in which the - * color values of the pixels are read from a palette. + * The Class IndexColorModel represents a color model in which the color values + * of the pixels are read from a palette. + * + * @since Android 1.0 */ public class IndexColorModel extends ColorModel { - /** The color map. */ - private int colorMap[]; // Color Map + /** + * The color map. + */ + private int colorMap[]; // Color Map + + /** + * The map size. + */ + private int mapSize; // Color Map size + + /** + * The transparent index. + */ + private int transparentIndex; // Index of fully transparent pixel + + /** + * The gray palette. + */ + private boolean grayPalette; // Color Model has Color Map with Gray Pallete - /** The map size. */ - private int mapSize; // Color Map size + /** + * The valid bits. + */ + private BigInteger validBits; // Specify valid Color Map values - /** The transparent index. */ - private int transparentIndex; // Index of fully transparent pixel + /** + * The Constant CACHESIZE. + */ + private static final int CACHESIZE = 20; // Cache size. Cache used for - /** The gray palette. */ - private boolean grayPalette; // Color Model has Color Map with Gray Pallete + // improving performace of selection + // nearest color in Color Map - /** The valid bits. */ - private BigInteger validBits; // Specify valid Color Map values + /** + * The cachetable. + */ + private final int cachetable[] = new int[CACHESIZE * 2]; // Cache table - - /** The Constant CACHESIZE. */ - private static final int CACHESIZE = 20; // Cache size. Cache used for - // improving performace of selection - // nearest color in Color Map + // used for - /** The cachetable. */ - private final int cachetable[] = new int[CACHESIZE * 2]; // Cache table - used for - // storing RGB values and that appropriate indices - // in the Color Map - + // storing RGB values and that appropriate indices + // in the Color Map - /** The next insert idx. */ - private int nextInsertIdx = 0; // Next index for insertion into Cache table + /** + * The next insert idx. + */ + private int nextInsertIdx = 0; // Next index for insertion into Cache table - /** The total inserted. */ - private int totalInserted = 0; // Number of inserted values into Cache table + /** + * The total inserted. + */ + private int totalInserted = 0; // Number of inserted values into Cache table /** * Instantiates a new index color model. * - * @param bits the array of component masks - * @param size the size of the color map - * @param cmap the array that gives the color mapping - * @param start the start index of the color mapping data within the cmap array - * @param transferType the transfer type (primitive java type - * to use for the components) - * @param validBits a list of which bits represent valid colormap - * values, or null if all are valid - * - * @throws IllegalArgumentException if the size of the color map is - * less than one + * @param bits + * the array of component masks. + * @param size + * the size of the color map. + * @param cmap + * the array that gives the color mapping. + * @param start + * the start index of the color mapping data within the cmap + * array. + * @param transferType + * the transfer type (primitive java type to use for the + * components). + * @param validBits + * a list of which bits represent valid colormap values, or null + * if all are valid. + * @throws IllegalArgumentException + * if the size of the color map is less than one. */ - public IndexColorModel(int bits, int size, int cmap[], int start, - int transferType, BigInteger validBits) { + public IndexColorModel(int bits, int size, int cmap[], int start, int transferType, + BigInteger validBits) { - super(bits, IndexColorModel.createBits(true), - ColorSpace.getInstance(ColorSpace.CS_sRGB), true, false, - Transparency.OPAQUE, validateTransferType(transferType)); + super(bits, IndexColorModel.createBits(true), ColorSpace.getInstance(ColorSpace.CS_sRGB), + true, false, Transparency.OPAQUE, validateTransferType(transferType)); if (size < 1) { // awt.264=Size of the color map is less than 1 @@ -122,8 +151,7 @@ public class IndexColorModel extends ColorModel { if (transparency == Transparency.OPAQUE) { transparency = Transparency.BITMASK; } - } else if (alpha != alphaMask && - transparency != Transparency.TRANSLUCENT) { + } else if (alpha != alphaMask && transparency != Transparency.TRANSLUCENT) { transparency = Transparency.TRANSLUCENT; } @@ -135,25 +163,31 @@ public class IndexColorModel extends ColorModel { /** * Instantiates a new index color model. * - * @param bits the array of component masks - * @param size the size of the color map - * @param cmap the array that gives the color mapping - * @param start the start index of the color mapping data within the cmap array - * @param hasalpha whether this color model uses alpha - * @param trans the transparency supported, @see java.awt.Transparency - * @param transferType the transfer type (primitive java type - * to use for the components) - * - * @throws IllegalArgumentException if the size of the color map is - * less than one + * @param bits + * the array of component masks. + * @param size + * the size of the color map. + * @param cmap + * the array that gives the color mapping. + * @param start + * the start index of the color mapping data within the cmap + * array. + * @param hasalpha + * whether this color model uses alpha. + * @param trans + * the transparency supported, @see java.awt.Transparency. + * @param transferType + * the transfer type (primitive java type to use for the + * components). + * @throws IllegalArgumentException + * if the size of the color map is less than one. */ - public IndexColorModel(int bits, int size, int cmap[], int start, - boolean hasalpha, int trans, int transferType) { + public IndexColorModel(int bits, int size, int cmap[], int start, boolean hasalpha, int trans, + int transferType) { - super(bits, IndexColorModel.createBits(hasalpha || (trans >= 0)), - ColorSpace.getInstance(ColorSpace.CS_sRGB), - (hasalpha || (trans >= 0)), false, Transparency.OPAQUE, - validateTransferType(transferType)); + super(bits, IndexColorModel.createBits(hasalpha || (trans >= 0)), ColorSpace + .getInstance(ColorSpace.CS_sRGB), (hasalpha || (trans >= 0)), false, + Transparency.OPAQUE, validateTransferType(transferType)); if (size < 1) { // awt.264=Size of the color map is less than 1 @@ -192,8 +226,7 @@ public class IndexColorModel extends ColorModel { if (transparency == Transparency.OPAQUE) { transparency = Transparency.BITMASK; } - } else if (alpha != 0 - && transparency != Transparency.TRANSLUCENT) { + } else if (alpha != 0 && transparency != Transparency.TRANSLUCENT) { transparency = Transparency.TRANSLUCENT; } } else { @@ -205,55 +238,70 @@ public class IndexColorModel extends ColorModel { } /** - * Instantiates a new index color model by building the color map - * from arrays of red, green, blue, and alpha values. + * Instantiates a new index color model by building the color map from + * arrays of red, green, blue, and alpha values. * - * @param bits the array of component masks - * @param size the size of the color map - * @param r the array giving the red components of the entries in the color map - * @param g the array giving the green components of the entries in the color map - * @param b the array giving the blue components of the entries in the color map - * @param a the array giving the alpha components of the entries in the color map - * - * @throws IllegalArgumentException if the size of the color map is - * less than one - * @throws ArrayIndexOutOfBoundsException if the size of one of the - * component arrays is less than the size of the color map + * @param bits + * the array of component masks. + * @param size + * the size of the color map. + * @param r + * the array giving the red components of the entries in the + * color map. + * @param g + * the array giving the green components of the entries in the + * color map. + * @param b + * the array giving the blue components of the entries in the + * color map. + * @param a + * the array giving the alpha components of the entries in the + * color map. + * @throws IllegalArgumentException + * if the size of the color map is less than one. + * @throws ArrayIndexOutOfBoundsException + * if the size of one of the component arrays is less than the + * size of the color map. */ - public IndexColorModel(int bits, int size, byte r[], byte g[], byte b[], - byte a[]) { + public IndexColorModel(int bits, int size, byte r[], byte g[], byte b[], byte a[]) { - super(bits, IndexColorModel.createBits(true), - ColorSpace.getInstance(ColorSpace.CS_sRGB), true, false, - Transparency.OPAQUE, - validateTransferType(ColorModel.getTransferType(bits))); + super(bits, IndexColorModel.createBits(true), ColorSpace.getInstance(ColorSpace.CS_sRGB), + true, false, Transparency.OPAQUE, validateTransferType(ColorModel + .getTransferType(bits))); createColorMap(size, r, g, b, a, -1); checkPalette(); } /** - * Instantiates a new index color model by building the color map - * from arrays of red, green, and blue values. + * Instantiates a new index color model by building the color map from + * arrays of red, green, and blue values. * - * @param bits the array of component masks - * @param size the size of the color map - * @param r the array giving the red components of the entries in the color map - * @param g the array giving the green components of the entries in the color map - * @param b the array giving the blue components of the entries in the color map - * @param trans the transparency supported, @see java.awt.Transparency - * - * @throws IllegalArgumentException if the size of the color map is - * less than one - * @throws ArrayIndexOutOfBoundsException if the size of one of the - * component arrays is less than the size of the color map + * @param bits + * the array of component masks. + * @param size + * the size of the color map. + * @param r + * the array giving the red components of the entries in the + * color map. + * @param g + * the array giving the green components of the entries in the + * color map. + * @param b + * the array giving the blue components of the entries in the + * color map. + * @param trans + * the transparency supported, @see java.awt.Transparency. + * @throws IllegalArgumentException + * if the size of the color map is less than one. + * @throws ArrayIndexOutOfBoundsException + * if the size of one of the component arrays is less than the + * size of the color map. */ - public IndexColorModel(int bits, int size, byte r[], byte g[], byte b[], - int trans) { + public IndexColorModel(int bits, int size, byte r[], byte g[], byte b[], int trans) { - super(bits, IndexColorModel.createBits((trans >= 0)), - ColorSpace.getInstance(ColorSpace.CS_sRGB), (trans >= 0), false, - Transparency.OPAQUE, + super(bits, IndexColorModel.createBits((trans >= 0)), ColorSpace + .getInstance(ColorSpace.CS_sRGB), (trans >= 0), false, Transparency.OPAQUE, validateTransferType(ColorModel.getTransferType(bits))); createColorMap(size, r, g, b, null, trans); @@ -261,25 +309,32 @@ public class IndexColorModel extends ColorModel { } /** - * Instantiates a new index color model by building the color map - * from arrays of red, green, and blue values. - * - * @param bits the array of component masks - * @param size the size of the color map - * @param r the array giving the red components of the entries in the color map - * @param g the array giving the green components of the entries in the color map - * @param b the array giving the blue components of the entries in the color map + * Instantiates a new index color model by building the color map from + * arrays of red, green, and blue values. * - * @throws IllegalArgumentException if the size of the color map is - * less than one - * @throws ArrayIndexOutOfBoundsException if the size of one of the - * component arrays is less than the size of the color map + * @param bits + * the array of component masks. + * @param size + * the size of the color map. + * @param r + * the array giving the red components of the entries in the + * color map. + * @param g + * the array giving the green components of the entries in the + * color map. + * @param b + * the array giving the blue components of the entries in the + * color map. + * @throws IllegalArgumentException + * if the size of the color map is less than one. + * @throws ArrayIndexOutOfBoundsException + * if the size of one of the component arrays is less than the + * size of the color map. */ public IndexColorModel(int bits, int size, byte r[], byte g[], byte b[]) { - super(bits, IndexColorModel.createBits(false), - ColorSpace.getInstance(ColorSpace.CS_sRGB), false, false, - Transparency.OPAQUE, - validateTransferType(ColorModel.getTransferType(bits))); + super(bits, IndexColorModel.createBits(false), ColorSpace.getInstance(ColorSpace.CS_sRGB), + false, false, Transparency.OPAQUE, validateTransferType(ColorModel + .getTransferType(bits))); createColorMap(size, r, g, b, null, -1); checkPalette(); @@ -288,23 +343,27 @@ public class IndexColorModel extends ColorModel { /** * Instantiates a new index color model. * - * @param bits the array of component masks - * @param size the size of the color map - * @param cmap the array that gives the color mapping - * @param start the start index of the color mapping data within the cmap array - * @param hasalpha whether this color model uses alpha - * @param trans the transparency supported, @see java.awt.Transparency - * - * @throws IllegalArgumentException if the size of the color map is - * less than one + * @param bits + * the array of component masks. + * @param size + * the size of the color map. + * @param cmap + * the array that gives the color mapping. + * @param start + * the start index of the color mapping data within the cmap + * array. + * @param hasalpha + * whether this color model uses alpha. + * @param trans + * the transparency supported, @see java.awt.Transparency. + * @throws IllegalArgumentException + * if the size of the color map is less than one. */ - public IndexColorModel(int bits, int size, byte cmap[], int start, - boolean hasalpha, int trans) { + public IndexColorModel(int bits, int size, byte cmap[], int start, boolean hasalpha, int trans) { - super(bits, IndexColorModel.createBits(hasalpha || (trans >= 0)), - ColorSpace.getInstance(ColorSpace.CS_sRGB), - (hasalpha || (trans >= 0)), false, Transparency.OPAQUE, - validateTransferType(ColorModel.getTransferType(bits))); + super(bits, IndexColorModel.createBits(hasalpha || (trans >= 0)), ColorSpace + .getInstance(ColorSpace.CS_sRGB), (hasalpha || (trans >= 0)), false, + Transparency.OPAQUE, validateTransferType(ColorModel.getTransferType(bits))); if (size < 1) { // awt.264=Size of the color map is less than 1 @@ -319,13 +378,13 @@ public class IndexColorModel extends ColorModel { int alpha = 0xff000000; for (int i = 0; i < mapSize; i++) { - colorMap[i] = (cmap[start++] & 0xff) << 16 | - (cmap[start++] & 0xff) << 8 | (cmap[start++] & 0xff); + colorMap[i] = (cmap[start++] & 0xff) << 16 | (cmap[start++] & 0xff) << 8 + | (cmap[start++] & 0xff); if (trans == i) { if (transparency == Transparency.OPAQUE) { transparency = Transparency.BITMASK; } - if(hasalpha) { + if (hasalpha) { start++; } continue; @@ -340,8 +399,7 @@ public class IndexColorModel extends ColorModel { } } } else { - if (alpha != 0xff && - transparency != Transparency.TRANSLUCENT) { + if (alpha != 0xff && transparency != Transparency.TRANSLUCENT) { transparency = Transparency.TRANSLUCENT; } } @@ -360,25 +418,29 @@ public class IndexColorModel extends ColorModel { /** * Instantiates a new index color model. * - * @param bits the array of component masks - * @param size the size of the color map - * @param cmap the array that gives the color mapping - * @param start the start index of the color mapping data within the cmap array - * @param hasalpha whether this color model uses alpha - * - * @throws IllegalArgumentException if the size of the color map is - * less than one + * @param bits + * the array of component masks. + * @param size + * the size of the color map. + * @param cmap + * the array that gives the color mapping. + * @param start + * the start index of the color mapping data within the cmap + * array. + * @param hasalpha + * whether this color model uses alpha. + * @throws IllegalArgumentException + * if the size of the color map is less than one. */ - public IndexColorModel(int bits, int size, byte cmap[], int start, - boolean hasalpha) { + public IndexColorModel(int bits, int size, byte cmap[], int start, boolean hasalpha) { this(bits, size, cmap, start, hasalpha, -1); } @Override public Object getDataElements(int[] components, int offset, Object pixel) { - int rgb = (components[offset] << 16) | (components[offset + 1]) << 8 | - components[offset + 2]; + int rgb = (components[offset] << 16) | (components[offset + 1]) << 8 + | components[offset + 2]; if (hasAlpha) { rgb |= components[offset + 3] << 24; } else { @@ -419,7 +481,7 @@ public class IndexColorModel extends ColorModel { } } else if (alpha == 0 && transparentIndex > -1) { pixIdx = transparentIndex; - } else { + } else { int minAlphaError = 255; int minError = 195075; // 255^2 + 255^2 + 255^2 int alphaError; @@ -470,19 +532,19 @@ public class IndexColorModel extends ColorModel { /** * Converts an image from indexed to RGB format. * - * @param raster the raster containing the source image - * @param forceARGB whether to use the default RGB color model - * - * @return the buffered image - * - * @throws IllegalArgumentException if the raster is not compatible with - * this color model + * @param raster + * the raster containing the source image. + * @param forceARGB + * whether to use the default RGB color model. + * @return the buffered image. + * @throws IllegalArgumentException + * if the raster is not compatible with this color model. */ - public BufferedImage convertToIntDiscrete(Raster raster, - boolean forceARGB) { + public BufferedImage convertToIntDiscrete(Raster raster, boolean forceARGB) { if (!isCompatibleRaster(raster)) { - // awt.265=The raster argument is not compatible with this IndexColorModel + // awt.265=The raster argument is not compatible with this + // IndexColorModel throw new IllegalArgumentException(Messages.getString("awt.265")); //$NON-NLS-1$ } @@ -490,8 +552,7 @@ public class IndexColorModel extends ColorModel { if (forceARGB || transparency == Transparency.TRANSLUCENT) { model = ColorModel.getRGBdefault(); } else if (transparency == Transparency.BITMASK) { - model = new DirectColorModel(25, 0x00ff0000, 0x0000ff00, - 0x000000ff, 0x01000000); + model = new DirectColorModel(25, 0x00ff0000, 0x0000ff00, 0x000000ff, 0x01000000); } else { model = new DirectColorModel(24, 0x00ff0000, 0x0000ff00, 0x000000ff); } @@ -510,7 +571,7 @@ public class IndexColorModel extends ColorModel { for (int i = 0; i < h; i++, minY++) { obj = raster.getDataElements(minX, minY, w, 1, obj); if (obj instanceof byte[]) { - byte ba[] = (byte[]) obj; + byte ba[] = (byte[])obj; if (pixels == null) { pixels = new int[ba.length]; } @@ -518,7 +579,7 @@ public class IndexColorModel extends ColorModel { pixels[j] = colorMap[ba[j] & 0xff]; } } else if (obj instanceof short[]) { - short sa[] = (short[]) obj; + short sa[] = (short[])obj; if (pixels == null) { pixels = new int[sa.length]; } @@ -527,7 +588,7 @@ public class IndexColorModel extends ColorModel { } } if (obj instanceof int[]) { - int ia[] = (int[]) obj; + int ia[] = (int[])obj; if (pixels == null) { pixels = new int[ia.length]; } @@ -545,7 +606,7 @@ public class IndexColorModel extends ColorModel { /** * Gets the valid pixels. * - * @return the valid pixels + * @return the valid pixels. */ public BigInteger getValidPixels() { return validBits; @@ -553,14 +614,15 @@ public class IndexColorModel extends ColorModel { @Override public String toString() { - // The output format based on 1.5 release behaviour. + // The output format based on 1.5 release behaviour. // It could be reveled such way: - // BufferedImage bi = new BufferedImage(1, 1, BufferedImage.TYPE_BYTE_INDEXED); + // BufferedImage bi = new BufferedImage(1, 1, + // BufferedImage.TYPE_BYTE_INDEXED); // ColorModel cm = bi.getColorModel(); // System.out.println(cm.toString()); String str = "IndexColorModel: #pixel_bits = " + pixel_bits + //$NON-NLS-1$ - " numComponents = " + numComponents + " color space = " + cs + //$NON-NLS-1$ //$NON-NLS-2$ - " transparency = "; //$NON-NLS-1$ + " numComponents = " + numComponents + " color space = " + cs + //$NON-NLS-1$ //$NON-NLS-2$ + " transparency = "; //$NON-NLS-1$ if (transparency == Transparency.OPAQUE) { str = str + "Transparency.OPAQUE"; //$NON-NLS-1$ @@ -571,7 +633,7 @@ public class IndexColorModel extends ColorModel { } str = str + " transIndex = " + transparentIndex + " has alpha = " + //$NON-NLS-1$ //$NON-NLS-2$ - hasAlpha + " isAlphaPre = " + isAlphaPremultiplied; //$NON-NLS-1$ + hasAlpha + " isAlphaPre = " + isAlphaPremultiplied; //$NON-NLS-1$ return str; } @@ -580,13 +642,13 @@ public class IndexColorModel extends ColorModel { public int[] getComponents(Object pixel, int components[], int offset) { int pixIdx = -1; if (pixel instanceof byte[]) { - byte ba[] = (byte[]) pixel; + byte ba[] = (byte[])pixel; pixIdx = ba[0] & 0xff; } else if (pixel instanceof short[]) { - short sa[] = (short[]) pixel; + short sa[] = (short[])pixel; pixIdx = sa[0] & 0xffff; } else if (pixel instanceof int[]) { - int ia[] = (int[]) pixel; + int ia[] = (int[])pixel; pixIdx = ia[0]; } else { // awt.219=This transferType is not supported by this color model @@ -600,14 +662,11 @@ public class IndexColorModel extends ColorModel { public WritableRaster createCompatibleWritableRaster(int w, int h) { WritableRaster raster; if (pixel_bits == 1 || pixel_bits == 2 || pixel_bits == 4) { - raster = Raster.createPackedRaster(DataBuffer.TYPE_BYTE, w, h, 1, - pixel_bits, null); + raster = Raster.createPackedRaster(DataBuffer.TYPE_BYTE, w, h, 1, pixel_bits, null); } else if (pixel_bits <= 8) { - raster = Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE, w, h, - 1, null); + raster = Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE, w, h, 1, null); } else if (pixel_bits <= 16) { - raster = Raster.createInterleavedRaster(DataBuffer.TYPE_USHORT, w, - h, 1, null); + raster = Raster.createInterleavedRaster(DataBuffer.TYPE_USHORT, w, h, 1, null); } else { // awt.266=The number of bits in a pixel is greater than 16 throw new UnsupportedOperationException(Messages.getString("awt.266")); //$NON-NLS-1$ @@ -622,8 +681,7 @@ public class IndexColorModel extends ColorModel { return false; } - if (!(sm instanceof MultiPixelPackedSampleModel) - && !(sm instanceof ComponentSampleModel)) { + if (!(sm instanceof MultiPixelPackedSampleModel) && !(sm instanceof ComponentSampleModel)) { return false; } @@ -640,48 +698,45 @@ public class IndexColorModel extends ColorModel { @Override public SampleModel createCompatibleSampleModel(int w, int h) { if (pixel_bits == 1 || pixel_bits == 2 || pixel_bits == 4) { - return new MultiPixelPackedSampleModel(DataBuffer.TYPE_BYTE, w, h, - pixel_bits); + return new MultiPixelPackedSampleModel(DataBuffer.TYPE_BYTE, w, h, pixel_bits); } int bandOffsets[] = new int[1]; bandOffsets[0] = 0; - return new ComponentSampleModel(transferType, w, h, 1, w, - bandOffsets); + return new ComponentSampleModel(transferType, w, h, 1, w, bandOffsets); } @Override public boolean isCompatibleRaster(Raster raster) { int sampleSize = raster.getSampleModel().getSampleSize(0); - return (raster.getTransferType() == transferType && - raster.getNumBands() == 1 && (1 << sampleSize) >= mapSize); + return (raster.getTransferType() == transferType && raster.getNumBands() == 1 && (1 << sampleSize) >= mapSize); } @Override public int getDataElement(int components[], int offset) { int rgb = (components[offset] << 16) | (components[offset + 1]) << 8 | components[offset + 2]; - + if (hasAlpha) { rgb |= components[offset + 3] << 24; } else { rgb |= 0xff000000; } - + int pixel; switch (transferType) { - case DataBuffer.TYPE_BYTE: - byte ba[] = (byte[]) getDataElements(rgb, null); - pixel = ba[0] & 0xff; - break; - case DataBuffer.TYPE_USHORT: - short sa[] = (short[]) getDataElements(rgb, null); - pixel = sa[0] & 0xffff; - break; - default: - // awt.267=The transferType is invalid - throw new UnsupportedOperationException(Messages.getString("awt.267")); //$NON-NLS-1$ + case DataBuffer.TYPE_BYTE: + byte ba[] = (byte[])getDataElements(rgb, null); + pixel = ba[0] & 0xff; + break; + case DataBuffer.TYPE_USHORT: + short sa[] = (short[])getDataElements(rgb, null); + pixel = sa[0] & 0xffff; + break; + default: + // awt.267=The transferType is invalid + throw new UnsupportedOperationException(Messages.getString("awt.267")); //$NON-NLS-1$ } return pixel; @@ -690,7 +745,8 @@ public class IndexColorModel extends ColorModel { /** * Gets the color map. * - * @param rgb the destination array where the color map is written + * @param rgb + * the destination array where the color map is written. */ public final void getRGBs(int rgb[]) { System.arraycopy(colorMap, 0, rgb, 0, mapSize); @@ -699,44 +755,48 @@ public class IndexColorModel extends ColorModel { /** * Gets the red component of the color map. * - * @param r the destination array + * @param r + * the destination array. */ public final void getReds(byte r[]) { for (int i = 0; i < mapSize; i++) { - r[i] = (byte) (colorMap[i] >> 16); + r[i] = (byte)(colorMap[i] >> 16); } } /** * Gets the green component of the color map. * - * @param g the destination array + * @param g + * the destination array. */ public final void getGreens(byte g[]) { for (int i = 0; i < mapSize; i++) { - g[i] = (byte) (colorMap[i] >> 8); + g[i] = (byte)(colorMap[i] >> 8); } } /** * Gets the blue component of the color map. * - * @param b the destination array + * @param b + * the destination array. */ public final void getBlues(byte b[]) { for (int i = 0; i < mapSize; i++) { - b[i] = (byte) colorMap[i]; + b[i] = (byte)colorMap[i]; } } /** * Gets the alpha component of the color map. * - * @param a the destination array + * @param a + * the destination array. */ public final void getAlphas(byte a[]) { for (int i = 0; i < mapSize; i++) { - a[i] = (byte) (colorMap[i] >> 24); + a[i] = (byte)(colorMap[i] >> 24); } } @@ -759,9 +819,9 @@ public class IndexColorModel extends ColorModel { /** * Checks if the specified pixel is valid for this color model. * - * @param pixel the pixel - * - * @return true, if the pixel is valid + * @param pixel + * the pixel. + * @return true, if the pixel is valid. */ public boolean isValid(int pixel) { if (validBits == null) { @@ -803,7 +863,7 @@ public class IndexColorModel extends ColorModel { /** * Checks if this color model validates pixels. * - * @return true, if all pixels are valid, otherwise false + * @return true, if all pixels are valid, otherwise false. */ public boolean isValid() { return (validBits == null); @@ -818,7 +878,7 @@ public class IndexColorModel extends ColorModel { /** * Gets the index that represents the transparent pixel. * - * @return the index that represents the transparent pixel + * @return the index that represents the transparent pixel. */ public final int getTransparentPixel() { return transparentIndex; @@ -832,7 +892,7 @@ public class IndexColorModel extends ColorModel { /** * Gets the size of the color map. * - * @return the map size + * @return the map size. */ public final int getMapSize() { return mapSize; @@ -841,15 +901,20 @@ public class IndexColorModel extends ColorModel { /** * Creates the color map. * - * @param size the size - * @param r the r - * @param g the g - * @param b the b - * @param a the a - * @param trans the trans - */ - private void createColorMap(int size, byte r[], byte g[], byte b[], - byte a[], int trans) { + * @param size + * the size. + * @param r + * the r. + * @param g + * the g. + * @param b + * the b. + * @param a + * the a. + * @param trans + * the trans. + */ + private void createColorMap(int size, byte r[], byte g[], byte b[], byte a[], int trans) { if (size < 1) { // awt.264=Size of the color map is less than 1 throw new IllegalArgumentException(Messages.getString("awt.264")); //$NON-NLS-1$ @@ -867,8 +932,7 @@ public class IndexColorModel extends ColorModel { int alpha = 0; for (int i = 0; i < mapSize; i++) { - colorMap[i] = ((r[i] & 0xff) << 16) | ((g[i] & 0xff) << 8) | - (b[i] & 0xff); + colorMap[i] = ((r[i] & 0xff) << 16) | ((g[i] & 0xff) << 8) | (b[i] & 0xff); if (trans == i) { continue; @@ -900,7 +964,7 @@ public class IndexColorModel extends ColorModel { } /** - * This method checking, if Color Map has Gray Palette. + * This method checking, if Color Map has Gray palette. */ private void checkPalette() { grayPalette = false; @@ -911,8 +975,7 @@ public class IndexColorModel extends ColorModel { for (int i = 0; i < mapSize; i++) { rgb = colorMap[i]; - if (((rgb >> 16) & 0xff) != ((rgb >> 8) & 0xff) || - ((rgb >> 8) & 0xff) != (rgb & 0xff)) { + if (((rgb >> 16) & 0xff) != ((rgb >> 8) & 0xff) || ((rgb >> 8) & 0xff) != (rgb & 0xff)) { return; } } @@ -922,40 +985,39 @@ public class IndexColorModel extends ColorModel { /** * Construction an array pixel representation. * - * @param colorMapIdx - index into Color Map - * @param pixel - pixel - * - * @return - an array pixel representation + * @param colorMapIdx + * the index into Color Map. + * @param pixel + * the pixel + * @return the pixel representation array. */ private Object createDataObject(int colorMapIdx, Object pixel) { if (pixel == null) { switch (transferType) { - case DataBuffer.TYPE_BYTE: - byte[] ba = new byte[1]; - ba[0] = (byte) colorMapIdx; - pixel = ba; - break; - case DataBuffer.TYPE_USHORT: - short[] sa = new short[1]; - sa[0] = (short) colorMapIdx; - pixel = sa; - break; - default: - // awt.267=The transferType is invalid - throw new UnsupportedOperationException(Messages.getString("awt.267")); //$NON-NLS-1$ + case DataBuffer.TYPE_BYTE: + byte[] ba = new byte[1]; + ba[0] = (byte)colorMapIdx; + pixel = ba; + break; + case DataBuffer.TYPE_USHORT: + short[] sa = new short[1]; + sa[0] = (short)colorMapIdx; + pixel = sa; + break; + default: + // awt.267=The transferType is invalid + throw new UnsupportedOperationException(Messages.getString("awt.267")); //$NON-NLS-1$ } - } else if (pixel instanceof byte[] - && transferType == DataBuffer.TYPE_BYTE) { - byte ba[] = (byte[]) pixel; - ba[0] = (byte) colorMapIdx; + } else if (pixel instanceof byte[] && transferType == DataBuffer.TYPE_BYTE) { + byte ba[] = (byte[])pixel; + ba[0] = (byte)colorMapIdx; pixel = ba; - } else if (pixel instanceof short[]&& - transferType == DataBuffer.TYPE_USHORT) { - short[] sa = (short[]) pixel; - sa[0] = (short) colorMapIdx; + } else if (pixel instanceof short[] && transferType == DataBuffer.TYPE_USHORT) { + short[] sa = (short[])pixel; + sa[0] = (short)colorMapIdx; pixel = sa; } else if (pixel instanceof int[]) { - int ia[] = (int[]) pixel; + int ia[] = (int[])pixel; ia[0] = colorMapIdx; pixel = ia; } else { @@ -968,9 +1030,9 @@ public class IndexColorModel extends ColorModel { /** * Creates the bits. * - * @param hasAlpha the has alpha - * - * @return the int[] + * @param hasAlpha + * the has alpha. + * @return the int[]. */ private static int[] createBits(boolean hasAlpha) { @@ -993,28 +1055,26 @@ public class IndexColorModel extends ColorModel { /** * Validate transfer type. * - * @param transferType the transfer type - * - * @return the int + * @param transferType + * the transfer type. + * @return the int. */ private static int validateTransferType(int transferType) { - if (transferType != DataBuffer.TYPE_BYTE && - transferType != DataBuffer.TYPE_USHORT) { - // awt.269=The transferType is not one of DataBuffer.TYPE_BYTE or DataBuffer.TYPE_USHORT + if (transferType != DataBuffer.TYPE_BYTE && transferType != DataBuffer.TYPE_USHORT) { + // awt.269=The transferType is not one of DataBuffer.TYPE_BYTE or + // DataBuffer.TYPE_USHORT throw new IllegalArgumentException(Messages.getString("awt.269")); //$NON-NLS-1$ } return transferType; } /** - * Checks if is gray pallete. + * Checks if is gray palette. * - * @return true, if is gray pallete + * @return true, if is gray palette. */ - boolean isGrayPallete(){ + boolean isGrayPallete() { return grayPalette; } } - - diff --git a/awt/java/awt/image/Kernel.java b/awt/java/awt/image/Kernel.java index c6f00e2b8b5eec67e7b47029da97759bc44ace9a..a59d27a11423a4b9238e36babec736d6fe28237a 100644 --- a/awt/java/awt/image/Kernel.java +++ b/awt/java/awt/image/Kernel.java @@ -27,38 +27,53 @@ import org.apache.harmony.awt.internal.nls.Messages; /** * The Kernel class provides a matrix. This matrix is stored as a float array - * which describes how a specified pixel affects the value calculated for - * the pixel's position in the output image of a filtering operation. - * The X, Y origins indicate the kernel matrix element which corresponds to - * the pixel position for which an output value is being calculated. + * which describes how a specified pixel affects the value calculated for the + * pixel's position in the output image of a filtering operation. The X, Y + * origins indicate the kernel matrix element which corresponds to the pixel + * position for which an output value is being calculated. + * + * @since Android 1.0 */ public class Kernel implements Cloneable { - - /** The x origin. */ + + /** + * The x origin. + */ private final int xOrigin; - - /** The y origin. */ + + /** + * The y origin. + */ private final int yOrigin; - - /** The width. */ + + /** + * The width. + */ private int width; - - /** The height. */ + + /** + * The height. + */ private int height; - - /** The data. */ + + /** + * The data. + */ float data[]; /** - * Instantiates a new Kernel with the specified float array. - * The width*height elements of the data array are copied. + * Instantiates a new Kernel with the specified float array. The + * width*height elements of the data array are copied. * - * @param width the width of the Kernel. - * @param height the height of the Kernel. - * @param data the data of Kernel. + * @param width + * the width of the Kernel. + * @param height + * the height of the Kernel. + * @param data + * the data of Kernel. */ public Kernel(int width, int height, float[] data) { - int dataLength = width*height; + int dataLength = width * height; if (data.length < dataLength) { // awt.22B=Length of data should not be less than width*height throw new IllegalArgumentException(Messages.getString("awt.22B")); //$NON-NLS-1$ @@ -70,8 +85,8 @@ public class Kernel implements Cloneable { this.data = new float[dataLength]; System.arraycopy(data, 0, this.data, 0, dataLength); - xOrigin = (width-1)/2; - yOrigin = (height-1)/2; + xOrigin = (width - 1) / 2; + yOrigin = (height - 1) / 2; } /** @@ -95,8 +110,8 @@ public class Kernel implements Cloneable { /** * Gets the float data array of this Kernel. * - * @param data the float array where the resulted data will be stored. - * + * @param data + * the float array where the resulted data will be stored. * @return the float data array of this Kernel. */ public final float[] getKernelData(float[] data) { diff --git a/awt/java/awt/image/LookupOp.java b/awt/java/awt/image/LookupOp.java index f9bd2c7b20d7cd8f29d782740d4fc2adeb491b8b..3362c5cf792599f756889c1be4aad6e10949a652 100644 --- a/awt/java/awt/image/LookupOp.java +++ b/awt/java/awt/image/LookupOp.java @@ -32,56 +32,76 @@ import org.apache.harmony.awt.gl.AwtImageBackdoorAccessor; import org.apache.harmony.awt.internal.nls.Messages; /** - * The LookupOp class perfoms a lookup operation which transforms a - * source image by filtering each band using a table of data. - * The table may contain a single array or it may contain a - * different data array for each band of the image. + * The LookupOp class performs a lookup operation which transforms a source + * image by filtering each band using a table of data. The table may contain a + * single array or it may contain a different data array for each band of the + * image. + * + * @since Android 1.0 */ public class LookupOp implements BufferedImageOp, RasterOp { - - /** The lut. */ + + /** + * The lut. + */ private final LookupTable lut; - - /** The hints. */ + + /** + * The hints. + */ private RenderingHints hints; - + // TODO remove when this field is used - /** The can use ipp. */ + /** + * The can use ipp. + */ @SuppressWarnings("unused") private final boolean canUseIpp; // We don't create levels/values when it is possible to reuse old - /** The cached levels. */ + /** + * The cached levels. + */ private int cachedLevels[]; - - /** The cached values. */ + + /** + * The cached values. + */ private int cachedValues[]; + // Number of channels for which cache is valid. - // If negative number of channels is same as positive but skipAlpha was specified - /** The valid for channels. */ + // If negative number of channels is same as positive but skipAlpha was + // specified + /** + * The valid for channels. + */ private int validForChannels; - /** The level initializer. */ + /** + * The level initializer. + */ static int levelInitializer[] = new int[0x10000]; static { // TODO // System.loadLibrary("imageops"); - for (int i=1; i<=0x10000; i++) { - levelInitializer[i-1] = i; + for (int i = 1; i <= 0x10000; i++) { + levelInitializer[i - 1] = i; } } /** - * Instantiates a new LookupOp object from the specified - * LookupTable object and a RenderingHints object. + * Instantiates a new LookupOp object from the specified LookupTable object + * and a RenderingHints object. * - * @param lookup the specified LookupTable object. - * @param hints the RenderingHints object or null. + * @param lookup + * the specified LookupTable object. + * @param hints + * the RenderingHints object or null. */ public LookupOp(LookupTable lookup, RenderingHints hints) { - if (lookup == null){ + if (lookup == null) { throw new NullPointerException(Messages.getString("awt.01", "lookup")); //$NON-NLS-1$ //$NON-NLS-2$ } lut = lookup; @@ -136,27 +156,16 @@ public class LookupOp implements BufferedImageOp, RasterOp { transferType = DataBuffer.TYPE_SHORT; } - dstCM = new ComponentColorModel( - dstCM.cs, - dstCM.hasAlpha(), - dstCM.isAlphaPremultiplied, - dstCM.transparency, - transferType - ); + dstCM = new ComponentColorModel(dstCM.cs, dstCM.hasAlpha(), + dstCM.isAlphaPremultiplied, dstCM.transparency, transferType); } } - WritableRaster r = - dstCM.isCompatibleSampleModel(src.getSampleModel()) ? - src.getRaster().createCompatibleWritableRaster(src.getWidth(), src.getHeight()) : - dstCM.createCompatibleWritableRaster(src.getWidth(), src.getHeight()); - - return new BufferedImage( - dstCM, - r, - dstCM.isAlphaPremultiplied(), - null - ); + WritableRaster r = dstCM.isCompatibleSampleModel(src.getSampleModel()) ? src.getRaster() + .createCompatibleWritableRaster(src.getWidth(), src.getHeight()) : dstCM + .createCompatibleWritableRaster(src.getWidth(), src.getHeight()); + + return new BufferedImage(dstCM, r, dstCM.isAlphaPremultiplied(), null); } public final WritableRaster filter(Raster src, WritableRaster dst) { @@ -166,25 +175,27 @@ public class LookupOp implements BufferedImageOp, RasterOp { if (src.getNumBands() != dst.getNumBands()) { throw new IllegalArgumentException(Messages.getString("awt.237")); //$NON-NLS-1$ } } - if (src.getWidth() != dst.getWidth()){ + if (src.getWidth() != dst.getWidth()) { throw new IllegalArgumentException(Messages.getString("awt.28F")); //$NON-NLS-1$ } } - if (src.getHeight() != dst.getHeight()){ + if (src.getHeight() != dst.getHeight()) { throw new IllegalArgumentException(Messages.getString("awt.290")); //$NON-NLS-1$ } } } if (lut.getNumComponents() != 1 && lut.getNumComponents() != src.getNumBands()) { - // awt.238=The number of arrays in the LookupTable does not meet the restrictions + // awt.238=The number of arrays in the LookupTable does not meet the + // restrictions throw new IllegalArgumentException(Messages.getString("awt.238")); //$NON-NLS-1$ } // TODO - // if (!canUseIpp || ippFilter(src, dst, BufferedImage.TYPE_CUSTOM, false) != 0) - if (slowFilter(src, dst, false) != 0) { - // awt.21F=Unable to transform source - throw new ImagingOpException (Messages.getString("awt.21F")); //$NON-NLS-1$ - } + // if (!canUseIpp || ippFilter(src, dst, BufferedImage.TYPE_CUSTOM, + // false) != 0) + if (slowFilter(src, dst, false) != 0) { + // awt.21F=Unable to transform source + throw new ImagingOpException(Messages.getString("awt.21F")); //$NON-NLS-1$ + } return dst; } @@ -202,18 +213,20 @@ public class LookupOp implements BufferedImageOp, RasterOp { int nLUTComponents = lut.getNumComponents(); boolean skipAlpha; if (srcCM.hasAlpha()) { - if (nLUTComponents == 1 || nLUTComponents == nComponents-1) { + if (nLUTComponents == 1 || nLUTComponents == nComponents - 1) { skipAlpha = true; } else if (nLUTComponents == nComponents) { skipAlpha = false; } else { - // awt.229=Number of components in the LUT does not match the number of bands + // awt.229=Number of components in the LUT does not match the + // number of bands throw new IllegalArgumentException(Messages.getString("awt.229")); //$NON-NLS-1$ } } else if (nLUTComponents == 1 || nLUTComponents == nComponents) { skipAlpha = false; } else { - // awt.229=Number of components in the LUT does not match the number of bands + // awt.229=Number of components in the LUT does not match the number + // of bands throw new IllegalArgumentException(Messages.getString("awt.229")); //$NON-NLS-1$ } @@ -222,21 +235,19 @@ public class LookupOp implements BufferedImageOp, RasterOp { finalDst = dst; dst = createCompatibleDestImage(src, null); } else { - if (src.getWidth() != dst.getWidth()){ + if (src.getWidth() != dst.getWidth()) { throw new IllegalArgumentException(Messages.getString("awt.291")); //$NON-NLS-1$ } - if (src.getHeight() != dst.getHeight()){ + if (src.getHeight() != dst.getHeight()) { throw new IllegalArgumentException(Messages.getString("awt.292")); //$NON-NLS-1$ } if (!srcCM.equals(dst.getColorModel())) { // Treat BufferedImage.TYPE_INT_RGB and // BufferedImage.TYPE_INT_ARGB as same - if (!((src.getType() == BufferedImage.TYPE_INT_RGB || src - .getType() == BufferedImage.TYPE_INT_ARGB) && (dst - .getType() == BufferedImage.TYPE_INT_RGB || dst - .getType() == BufferedImage.TYPE_INT_ARGB))) { + if (!((src.getType() == BufferedImage.TYPE_INT_RGB || src.getType() == BufferedImage.TYPE_INT_ARGB) && (dst + .getType() == BufferedImage.TYPE_INT_RGB || dst.getType() == BufferedImage.TYPE_INT_ARGB))) { finalDst = dst; dst = createCompatibleDestImage(src, null); } @@ -244,11 +255,12 @@ public class LookupOp implements BufferedImageOp, RasterOp { } // TODO - //if (!canUseIpp || ippFilter(src.getRaster(), dst.getRaster(), src.getType(), skipAlpha) != 0) - if (slowFilter(src.getRaster(), dst.getRaster(), skipAlpha) != 0) { - // awt.21F=Unable to transform source - throw new ImagingOpException (Messages.getString("awt.21F")); //$NON-NLS-1$ - } + // if (!canUseIpp || ippFilter(src.getRaster(), dst.getRaster(), + // src.getType(), skipAlpha) != 0) + if (slowFilter(src.getRaster(), dst.getRaster(), skipAlpha) != 0) { + // awt.21F=Unable to transform source + throw new ImagingOpException(Messages.getString("awt.21F")); //$NON-NLS-1$ + } if (finalDst != null) { Graphics2D g = finalDst.createGraphics(); @@ -264,11 +276,13 @@ public class LookupOp implements BufferedImageOp, RasterOp { /** * Slow filter. * - * @param src the src - * @param dst the dst - * @param skipAlpha the skip alpha - * - * @return the int + * @param src + * the src. + * @param dst + * the dst. + * @param skipAlpha + * the skip alpha. + * @return the int. */ private final int slowFilter(Raster src, WritableRaster dst, boolean skipAlpha) { int minSrcX = src.getMinX(); @@ -286,39 +300,39 @@ public class LookupOp implements BufferedImageOp, RasterOp { int[] pixels = null; int offset = lut.getOffset(); - if (lut instanceof ByteLookupTable){ + if (lut instanceof ByteLookupTable) { byte[][] byteData = ((ByteLookupTable)lut).getTable(); pixels = src.getPixels(minSrcX, minSrcY, srcWidth, srcHeight, pixels); - if (lut.getNumComponents() != 1){ - for (int i=0; i < pixels.length; i+= numBands){ - for (int b = 0; b < numBands2Process; b++){ - pixels[i+b] = byteData[b][pixels[i+b]-offset] & 0xFF; + if (lut.getNumComponents() != 1) { + for (int i = 0; i < pixels.length; i += numBands) { + for (int b = 0; b < numBands2Process; b++) { + pixels[i + b] = byteData[b][pixels[i + b] - offset] & 0xFF; } } } else { - for (int i=0; i < pixels.length; i+= numBands){ - for (int b = 0; b < numBands2Process; b++){ - pixels[i+b] = byteData[0][pixels[i+b]-offset] & 0xFF; + for (int i = 0; i < pixels.length; i += numBands) { + for (int b = 0; b < numBands2Process; b++) { + pixels[i + b] = byteData[0][pixels[i + b] - offset] & 0xFF; } } } dst.setPixels(minDstX, minDstY, srcWidth, srcHeight, pixels); - } else if (lut instanceof ShortLookupTable){ - short[][] shortData = ((ShortLookupTable)lut).getTable(); + } else if (lut instanceof ShortLookupTable) { + short[][] shortData = ((ShortLookupTable)lut).getTable(); pixels = src.getPixels(minSrcX, minSrcY, srcWidth, srcHeight, pixels); - if (lut.getNumComponents() != 1){ - for (int i=0; i < pixels.length; i+= numBands){ - for (int b = 0; b < numBands2Process; b++){ - pixels[i+b] = shortData[b][pixels[i+b]-offset] & 0xFFFF; + if (lut.getNumComponents() != 1) { + for (int i = 0; i < pixels.length; i += numBands) { + for (int b = 0; b < numBands2Process; b++) { + pixels[i + b] = shortData[b][pixels[i + b] - offset] & 0xFFFF; } } } else { - for (int i=0; i < pixels.length; i+= numBands){ - for (int b = 0; b < numBands2Process; b++){ - pixels[i+b] = shortData[0][pixels[i+b]-offset] & 0xFFFF; + for (int i = 0; i < pixels.length; i += numBands) { + for (int b = 0; b < numBands2Process; b++) { + pixels[i + b] = shortData[0][pixels[i + b] - offset] & 0xFFFF; } } } @@ -328,8 +342,8 @@ public class LookupOp implements BufferedImageOp, RasterOp { int pixel[] = new int[src.getNumBands()]; int maxY = minSrcY + srcHeight; int maxX = minSrcX + srcWidth; - for (int srcY=minSrcY, dstY = minDstY; srcY < maxY; srcY++, dstY++){ - for (int srcX=minSrcX, dstX = minDstX; srcX < maxX; srcX++, dstX++){ + for (int srcY = minSrcY, dstY = minDstY; srcY < maxY; srcY++, dstY++) { + for (int srcX = minSrcX, dstX = minDstX; srcX < maxX; srcX++, dstX++) { src.getPixel(srcX, srcY, pixel); lut.lookupPixel(pixel, pixel); dst.setPixel(dstX, dstY, pixel); @@ -343,16 +357,19 @@ public class LookupOp implements BufferedImageOp, RasterOp { /** * Creates the byte levels. * - * @param channels the channels - * @param skipAlpha the skip alpha - * @param levels the levels - * @param values the values - * @param channelsOrder the channels order + * @param channels + * the channels. + * @param skipAlpha + * the skip alpha. + * @param levels + * the levels. + * @param values + * the values. + * @param channelsOrder + * the channels order. */ - private final void createByteLevels( - int channels, boolean skipAlpha, - int levels[], int values[], int channelsOrder[] - ) { + private final void createByteLevels(int channels, boolean skipAlpha, int levels[], + int values[], int channelsOrder[]) { byte data[][] = ((ByteLookupTable)lut).getTable(); int nLevels = data[0].length; int offset = lut.getOffset(); @@ -360,18 +377,18 @@ public class LookupOp implements BufferedImageOp, RasterOp { // Use one data array for all channels or use several data arrays int dataIncrement = data.length > 1 ? 1 : 0; - for (int ch = 0, dataIdx = 0; ch= data.length)) { + if ((channelOffset == channels - 1 && skipAlpha) || (dataIdx >= data.length)) { continue; } System.arraycopy(levelInitializer, offset, levels, channelBase, nLevels); - for (int from=0, to=channelBase; from 1 ? 1 : 0; - for (int ch = 0, dataIdx = 0; ch= data.length)) { + if ((channelOffset == channels - 1 && skipAlpha) || (dataIdx >= data.length)) { continue; } int channelBase = nLevels * channelOffset; System.arraycopy(levelInitializer, offset, levels, channelBase, nLevels); - for (int from=0, to=channelBase; from properties; - - /** The consumers. */ + + /** + * The consumers. + */ Vector consumers; - - /** The animated. */ + + /** + * The animated. + */ boolean animated; - - /** The fullbuffers. */ + + /** + * The fullbuffers. + */ boolean fullbuffers; - - /** The data type. */ + + /** + * The data type. + */ int dataType; - /** The Constant DATA_TYPE_BYTE. */ + /** + * The Constant DATA_TYPE_BYTE. + */ static final int DATA_TYPE_BYTE = 0; - - /** The Constant DATA_TYPE_INT. */ + + /** + * The Constant DATA_TYPE_INT. + */ static final int DATA_TYPE_INT = 1; /** - * Instantiates a new MemoryImageSource with the specified - * parameters. + * Instantiates a new MemoryImageSource with the specified parameters. * - * @param w the width of the rectangular area of pixels. - * @param h the height of the rectangular area of pixels. - * @param cm the specified ColorModel. - * @param pix the pixel array. - * @param off the offset in the pixel array. - * @param scan the distance from one pixel's row to the next - * in the pixel array. - * @param props the set of properties to be used for image - * processing. + * @param w + * the width of the rectangular area of pixels. + * @param h + * the height of the rectangular area of pixels. + * @param cm + * the specified ColorModel. + * @param pix + * the pixel array. + * @param off + * the offset in the pixel array. + * @param scan + * the distance from one pixel's row to the next in the pixel + * array. + * @param props + * the set of properties to be used for image processing. */ - public MemoryImageSource(int w, int h, ColorModel cm, int pix[], - int off, int scan, Hashtable props) { + public MemoryImageSource(int w, int h, ColorModel cm, int pix[], int off, int scan, + Hashtable props) { init(w, h, cm, pix, off, scan, props); } /** - * Instantiates a new MemoryImageSource with the specified - * parameters. + * Instantiates a new MemoryImageSource with the specified parameters. * - * @param w the width of the rectangular area of pixels. - * @param h the height of the rectangular area of pixels. - * @param cm the specified ColorModel. - * @param pix the pixel array. - * @param off the offset in the pixel array. - * @param scan the distance from one pixel's row to the next - * in the pixel array. - * @param props the set of properties to be used for image - * processing. + * @param w + * the width of the rectangular area of pixels. + * @param h + * the height of the rectangular area of pixels. + * @param cm + * the specified ColorModel. + * @param pix + * the pixel array. + * @param off + * the offset in the pixel array. + * @param scan + * the distance from one pixel's row to the next in the pixel + * array. + * @param props + * the set of properties to be used for image processing. */ - public MemoryImageSource(int w, int h, ColorModel cm, byte pix[], - int off, int scan, Hashtable props) { + public MemoryImageSource(int w, int h, ColorModel cm, byte pix[], int off, int scan, + Hashtable props) { init(w, h, cm, pix, off, scan, props); } /** - * Instantiates a new MemoryImageSource with the specified - * parameters and default RGB ColorModel. + * Instantiates a new MemoryImageSource with the specified parameters and + * default RGB ColorModel. * - * @param w the width of the rectangular area of pixels. - * @param h the height of the rectangular area of pixels. - * @param pix the pixel array. - * @param off the offset in the pixel array. - * @param scan the distance from one pixel's row to the next - * in the pixel array. - * @param props the set of properties to be used for image - * processing. + * @param w + * the width of the rectangular area of pixels. + * @param h + * the height of the rectangular area of pixels. + * @param pix + * the pixel array. + * @param off + * the offset in the pixel array. + * @param scan + * the distance from one pixel's row to the next in the pixel + * array. + * @param props + * the set of properties to be used for image processing. */ - public MemoryImageSource(int w, int h, int pix[], int off, int scan, - Hashtable props) { + public MemoryImageSource(int w, int h, int pix[], int off, int scan, Hashtable props) { init(w, h, ColorModel.getRGBdefault(), pix, off, scan, props); } /** - * Instantiates a new MemoryImageSource with the specified - * parameters. + * Instantiates a new MemoryImageSource with the specified parameters. * - * @param w the width of the rectangular area of pixels. - * @param h the height of the rectangular area of pixels. - * @param cm the specified ColorModel. - * @param pix the pixel array. - * @param off the offset in the pixel array. - * @param scan the distance from one pixel's row to the next - * in the pixel array. + * @param w + * the width of the rectangular area of pixels. + * @param h + * the height of the rectangular area of pixels. + * @param cm + * the specified ColorModel. + * @param pix + * the pixel array. + * @param off + * the offset in the pixel array. + * @param scan + * the distance from one pixel's row to the next in the pixel + * array. */ - public MemoryImageSource(int w, int h, ColorModel cm, int pix[], - int off, int scan) { + public MemoryImageSource(int w, int h, ColorModel cm, int pix[], int off, int scan) { init(w, h, cm, pix, off, scan, null); } /** - * Instantiates a new MemoryImageSource with the specified - * parameters. + * Instantiates a new MemoryImageSource with the specified parameters. * - * @param w the width of the rectangular area of pixels. - * @param h the height of the rectangular area of pixels. - * @param cm the specified ColorModel. - * @param pix the pixel array. - * @param off the offset in the pixel array. - * @param scan the distance from one pixel's row to the next - * in the pixel array. + * @param w + * the width of the rectangular area of pixels. + * @param h + * the height of the rectangular area of pixels. + * @param cm + * the specified ColorModel. + * @param pix + * the pixel array. + * @param off + * the offset in the pixel array. + * @param scan + * the distance from one pixel's row to the next in the pixel + * array. */ - public MemoryImageSource(int w, int h, ColorModel cm, byte pix[], - int off, int scan) { + public MemoryImageSource(int w, int h, ColorModel cm, byte pix[], int off, int scan) { init(w, h, cm, pix, off, scan, null); } /** - * Instantiates a new MemoryImageSource with the specified - * parameters and default RGB ColorModel. + * Instantiates a new MemoryImageSource with the specified parameters and + * default RGB ColorModel. * - * @param w the width of the rectangular area of pixels. - * @param h the height of the rectangular area of pixels. - * @param pix the pixels array. - * @param off the offset in the pixel array. - * @param scan the distance from one pixel's row to the next - * in the pixel array. + * @param w + * the width of the rectangular area of pixels. + * @param h + * the height of the rectangular area of pixels. + * @param pix + * the pixels array. + * @param off + * the offset in the pixel array. + * @param scan + * the distance from one pixel's row to the next in the pixel + * array. */ public MemoryImageSource(int w, int h, int pix[], int off, int scan) { init(w, h, ColorModel.getRGBdefault(), pix, off, scan, null); @@ -184,25 +242,25 @@ public class MemoryImageSource implements ImageProducer { } public void startProduction(ImageConsumer ic) { - if(!isConsumer(ic) && ic != null) { + if (!isConsumer(ic) && ic != null) { consumers.addElement(ic); } - try{ + try { setHeader(ic); setPixels(ic, 0, 0, width, height); - if(animated){ + if (animated) { ic.imageComplete(ImageConsumer.SINGLEFRAMEDONE); - }else{ + } else { ic.imageComplete(ImageConsumer.STATICIMAGEDONE); - if(isConsumer(ic)) { + if (isConsumer(ic)) { removeConsumer(ic); } } - }catch(Exception e){ - if(isConsumer(ic)) { + } catch (Exception e) { + if (isConsumer(ic)) { ic.imageComplete(ImageConsumer.IMAGEERROR); } - if(isConsumer(ic)) { + if (isConsumer(ic)) { removeConsumer(ic); } } @@ -216,26 +274,29 @@ public class MemoryImageSource implements ImageProducer { } public synchronized void addConsumer(ImageConsumer ic) { - if(ic == null || consumers.contains(ic)) { + if (ic == null || consumers.contains(ic)) { return; } consumers.addElement(ic); } /** - * Replaces the pixel data with a new pixel array for holding - * the pixels for this image. If an animation - * flag is set to true value by the setAnimated() method, - * the new pixels will be immediately delivered to the ImageConsumers. + * Replaces the pixel data with a new pixel array for holding the pixels for + * this image. If an animation flag is set to true value by the + * setAnimated() method, the new pixels will be immediately delivered to the + * ImageConsumers. * - * @param newpix the new pixel array. - * @param newmodel the new ColorModel. - * @param offset the offset in the array. - * @param scansize the distance from one row of pixels to the next row - * in the pixel array + * @param newpix + * the new pixel array. + * @param newmodel + * the new ColorModel. + * @param offset + * the offset in the array. + * @param scansize + * the distance from one row of pixels to the next row in the + * pixel array. */ - public synchronized void newPixels(int newpix[], ColorModel newmodel, - int offset, int scansize) { + public synchronized void newPixels(int newpix[], ColorModel newmodel, int offset, int scansize) { this.dataType = DATA_TYPE_INT; this.iData = newpix; this.cm = newmodel; @@ -245,19 +306,22 @@ public class MemoryImageSource implements ImageProducer { } /** - * Replaces the pixel data with a new pixel array for holding - * the pixels for this image. If an animation - * flag is set to true value by the setAnimated() method, - * the new pixels will be immediately delivered to the ImageConsumers. + * Replaces the pixel data with a new pixel array for holding the pixels for + * this image. If an animation flag is set to true value by the + * setAnimated() method, the new pixels will be immediately delivered to the + * ImageConsumers. * - * @param newpix the new pixel array. - * @param newmodel the new ColorModel. - * @param offset the offset in the array. - * @param scansize the distance from one row of pixels to the next row - * in the pixel array + * @param newpix + * the new pixel array. + * @param newmodel + * the new ColorModel. + * @param offset + * the offset in the array. + * @param scansize + * the distance from one row of pixels to the next row in the + * pixel array. */ - public synchronized void newPixels(byte newpix[], ColorModel newmodel, - int offset, int scansize) { + public synchronized void newPixels(byte newpix[], ColorModel newmodel, int offset, int scansize) { this.dataType = DATA_TYPE_BYTE; this.bData = newpix; this.cm = newmodel; @@ -267,33 +331,33 @@ public class MemoryImageSource implements ImageProducer { } /** - * Sets the full buffer updates flag to true. If this is an - * animated image, the image consumers hints are updated - * accordingly. + * Sets the full buffer updates flag to true. If this is an animated image, + * the image consumers hints are updated accordingly. * - * @param fullbuffers the true if the pixel buffer should be sent always. + * @param fullbuffers + * the true if the pixel buffer should be sent always. */ public synchronized void setFullBufferUpdates(boolean fullbuffers) { - if(this.fullbuffers == fullbuffers) { + if (this.fullbuffers == fullbuffers) { return; } this.fullbuffers = fullbuffers; - if(animated){ + if (animated) { Object consAr[] = consumers.toArray(); for (Object element : consAr) { ImageConsumer con = (ImageConsumer)element; - try{ - if(fullbuffers){ - con.setHints(ImageConsumer.TOPDOWNLEFTRIGHT | - ImageConsumer.COMPLETESCANLINES); - }else{ + try { + if (fullbuffers) { + con.setHints(ImageConsumer.TOPDOWNLEFTRIGHT + | ImageConsumer.COMPLETESCANLINES); + } else { con.setHints(ImageConsumer.RANDOMPIXELORDER); } - }catch(Exception e){ - if(isConsumer(con)) { + } catch (Exception e) { + if (isConsumer(con)) { con.imageComplete(ImageConsumer.IMAGEERROR); } - if(isConsumer(con)) { + if (isConsumer(con)) { removeConsumer(con); } } @@ -302,27 +366,28 @@ public class MemoryImageSource implements ImageProducer { } /** - * Sets the flag that tells whether this memory image has more - * than one frame (for animation): true for multiple frames, - * false if this class represents a single frame image. - * - * @param animated whether this image represents an animation. + * Sets the flag that tells whether this memory image has more than one + * frame (for animation): true for multiple frames, false if this class + * represents a single frame image. + * + * @param animated + * whether this image represents an animation. */ public synchronized void setAnimated(boolean animated) { - if(this.animated == animated) { + if (this.animated == animated) { return; } Object consAr[] = consumers.toArray(); for (Object element : consAr) { ImageConsumer con = (ImageConsumer)element; - try{ + try { con.imageComplete(ImageConsumer.STATICIMAGEDONE); - }catch(Exception e){ - if(isConsumer(con)) { + } catch (Exception e) { + if (isConsumer(con)) { con.imageComplete(ImageConsumer.IMAGEERROR); } } - if(isConsumer(con)){ + if (isConsumer(con)) { removeConsumer(con); } } @@ -330,60 +395,63 @@ public class MemoryImageSource implements ImageProducer { } /** - * Sends the specified rectangular area of the buffer to - * ImageConsumers and notifies them that an animation frame - * is completed only if framenotify parameter is true. - * That works only if the animated flag has been set to true - * by the setAnimated() method. If the full buffer update flag - * has been set to true by the setFullBufferUpdates() method, - * then the entire buffer will always be sent ignoring parameters. + * Sends the specified rectangular area of the buffer to ImageConsumers and + * notifies them that an animation frame is completed only if the {@code + * framenotify} parameter is true. That works only if the animated flag has + * been set to true by the setAnimated() method. If the full buffer update + * flag has been set to true by the setFullBufferUpdates() method, then the + * entire buffer will always be sent ignoring parameters. * - * @param x the X coordinate of the rectangular area. - * @param y the Y coordinate of rthe ectangular area. - * @param w the width of the rectangular area. - * @param h the height of the rectangular area. - * @param framenotify true if a SINGLEFRAMEDONE notification - * should be sent to the registered consumers, false otherwise. + * @param x + * the X coordinate of the rectangular area. + * @param y + * the Y coordinate of the rectangular area. + * @param w + * the width of the rectangular area. + * @param h + * the height of the rectangular area. + * @param framenotify + * true if a SINGLEFRAMEDONE notification should be sent to the + * registered consumers, false otherwise. */ - public synchronized void newPixels(int x, int y, int w, int h, - boolean framenotify) { - if(animated){ - if(fullbuffers){ + public synchronized void newPixels(int x, int y, int w, int h, boolean framenotify) { + if (animated) { + if (fullbuffers) { x = 0; y = 0; w = width; h = height; - }else{ - if(x < 0){ + } else { + if (x < 0) { w += x; x = 0; } - if(w > width) { + if (w > width) { w = width - x; } - if(y < 0){ + if (y < 0) { h += y; y = 0; } } - if(h > height) { + if (h > height) { h = height - y; } Object consAr[] = consumers.toArray(); for (Object element : consAr) { ImageConsumer con = (ImageConsumer)element; - try{ - if(w > 0 && h > 0) { + try { + if (w > 0 && h > 0) { setPixels(con, x, y, w, h); } - if(framenotify) { + if (framenotify) { con.imageComplete(ImageConsumer.SINGLEFRAMEDONE); } - }catch(Exception ex){ - if(isConsumer(con)) { + } catch (Exception ex) { + if (isConsumer(con)) { con.imageComplete(ImageConsumer.IMAGEERROR); } - if(isConsumer(con)) { + if (isConsumer(con)) { removeConsumer(con); } } @@ -392,26 +460,29 @@ public class MemoryImageSource implements ImageProducer { } /** - * Sends the specified rectangular area of the buffer to - * the ImageConsumers and notifies them that an animation frame - * is completed if the animated flag has been set to true - * by the setAnimated() method. If the full buffer update flag - * has been set to true by the setFullBufferUpdates() method, + * Sends the specified rectangular area of the buffer to the ImageConsumers + * and notifies them that an animation frame is completed if the animated + * flag has been set to true by the setAnimated() method. If the full buffer + * update flag has been set to true by the setFullBufferUpdates() method, * then the entire buffer will always be sent ignoring parameters. * - * @param x the X coordinate of the rectangular area. - * @param y the Y coordinate of the rectangular area. - * @param w the width of the rectangular area. - * @param h the height of the rectangular area. + * @param x + * the X coordinate of the rectangular area. + * @param y + * the Y coordinate of the rectangular area. + * @param w + * the width of the rectangular area. + * @param h + * the height of the rectangular area. */ public synchronized void newPixels(int x, int y, int w, int h) { newPixels(x, y, w, h, true); } /** - * Sends a new buffer of pixels to the ImageConsumers - * and notifies them that an animation frame is completed if - * the animated flag has been set to true by the setAnimated() method. + * Sends a new buffer of pixels to the ImageConsumers and notifies them that + * an animation frame is completed if the animated flag has been set to true + * by the setAnimated() method. */ public void newPixels() { newPixels(0, 0, width, height, true); @@ -420,16 +491,23 @@ public class MemoryImageSource implements ImageProducer { /** * Inits the. * - * @param width the width - * @param height the height - * @param model the model - * @param pixels the pixels - * @param off the off - * @param scan the scan - * @param prop the prop + * @param width + * the width. + * @param height + * the height. + * @param model + * the model. + * @param pixels + * the pixels. + * @param off + * the off. + * @param scan + * the scan. + * @param prop + * the prop. */ - private void init(int width, int height, ColorModel model, byte pixels[], - int off, int scan, Hashtable prop){ + private void init(int width, int height, ColorModel model, byte pixels[], int off, int scan, + Hashtable prop) { this.width = width; this.height = height; @@ -446,16 +524,23 @@ public class MemoryImageSource implements ImageProducer { /** * Inits the. * - * @param width the width - * @param height the height - * @param model the model - * @param pixels the pixels - * @param off the off - * @param scan the scan - * @param prop the prop + * @param width + * the width. + * @param height + * the height. + * @param model + * the model. + * @param pixels + * the pixels. + * @param off + * the off. + * @param scan + * the scan. + * @param prop + * the prop. */ - private void init(int width, int height, ColorModel model, int pixels[], - int off, int scan, Hashtable prop){ + private void init(int width, int height, ColorModel model, int pixels[], int off, int scan, + Hashtable prop) { this.width = width; this.height = height; @@ -471,42 +556,48 @@ public class MemoryImageSource implements ImageProducer { /** * Sets the pixels. * - * @param con the con - * @param x the x - * @param y the y - * @param w the w - * @param h the h + * @param con + * the con. + * @param x + * the x. + * @param y + * the y. + * @param w + * the w. + * @param h + * the h. */ - private void setPixels(ImageConsumer con, int x, int y, int w, int h){ + private void setPixels(ImageConsumer con, int x, int y, int w, int h) { int pixelOff = scanline * y + offset + x; - switch(dataType){ - case DATA_TYPE_BYTE: - con.setPixels(x, y, w, h, cm, bData, pixelOff, scanline); - break; - case DATA_TYPE_INT: - con.setPixels(x, y, w, h, cm, iData, pixelOff, scanline); - break; - default: - // awt.22A=Wrong type of pixels array - throw new IllegalArgumentException(Messages.getString("awt.22A")); //$NON-NLS-1$ + switch (dataType) { + case DATA_TYPE_BYTE: + con.setPixels(x, y, w, h, cm, bData, pixelOff, scanline); + break; + case DATA_TYPE_INT: + con.setPixels(x, y, w, h, cm, iData, pixelOff, scanline); + break; + default: + // awt.22A=Wrong type of pixels array + throw new IllegalArgumentException(Messages.getString("awt.22A")); //$NON-NLS-1$ } } /** * Sets the header. * - * @param con the new header + * @param con + * the new header. */ - private synchronized void setHeader(ImageConsumer con){ + private synchronized void setHeader(ImageConsumer con) { con.setDimensions(width, height); con.setProperties(properties); con.setColorModel(cm); - con.setHints(animated ? (fullbuffers ? (ImageConsumer.TOPDOWNLEFTRIGHT | - ImageConsumer.COMPLETESCANLINES) : ImageConsumer.RANDOMPIXELORDER) : - (ImageConsumer.TOPDOWNLEFTRIGHT | ImageConsumer.COMPLETESCANLINES | - ImageConsumer.SINGLEPASS | ImageConsumer.SINGLEFRAME)); + con + .setHints(animated ? (fullbuffers ? (ImageConsumer.TOPDOWNLEFTRIGHT | ImageConsumer.COMPLETESCANLINES) + : ImageConsumer.RANDOMPIXELORDER) + : (ImageConsumer.TOPDOWNLEFTRIGHT | ImageConsumer.COMPLETESCANLINES + | ImageConsumer.SINGLEPASS | ImageConsumer.SINGLEFRAME)); } } - diff --git a/awt/java/awt/image/MultiPixelPackedSampleModel.java b/awt/java/awt/image/MultiPixelPackedSampleModel.java index dd44b49ec41dc9b3ad7ae55edfc98c58306cb5d6..3dc13d8f4df3da4a13174ab4a8d38f5468804426 100644 --- a/awt/java/awt/image/MultiPixelPackedSampleModel.java +++ b/awt/java/awt/image/MultiPixelPackedSampleModel.java @@ -18,72 +18,93 @@ * @author Igor V. Stolyarov * @version $Revision$ */ + package java.awt.image; import org.apache.harmony.awt.internal.nls.Messages; /** - * The MultiPixelPackedSampleModel class represents image data with one - * band. This class packs multiple pixels with one sample in one data - * element and supports the following data types: DataBuffer.TYPE_BYTE, - * DataBuffer.TYPE_USHORT, or DataBuffer.TYPE_INT. + * The MultiPixelPackedSampleModel class represents image data with one band. + * This class packs multiple pixels with one sample in one data element and + * supports the following data types: DataBuffer.TYPE_BYTE, + * DataBuffer.TYPE_USHORT, or DataBuffer.TYPE_INT. + * + * @since Android 1.0 */ public class MultiPixelPackedSampleModel extends SampleModel { - /** The pixel bit stride. */ + /** + * The pixel bit stride. + */ private int pixelBitStride; - /** The scanline stride. */ + /** + * The scanline stride. + */ private int scanlineStride; - /** The data bit offset. */ + /** + * The data bit offset. + */ private int dataBitOffset; - /** The bit mask. */ + /** + * The bit mask. + */ private int bitMask; - /** The data element size. */ + /** + * The data element size. + */ private int dataElementSize; - /** The pixels per data element. */ + /** + * The pixels per data element. + */ private int pixelsPerDataElement; /** * Instantiates a new MultiPixelPackedSampleModel with the specified * parameters. * - * @param dataType the data type of the samples. - * @param w the width of the image data. - * @param h the height of the image data. - * @param numberOfBits the number of bits per pixel. - * @param scanlineStride the scanline stride of the of the image data. - * @param dataBitOffset the array of the band offsets. + * @param dataType + * the data type of the samples. + * @param w + * the width of the image data. + * @param h + * the height of the image data. + * @param numberOfBits + * the number of bits per pixel. + * @param scanlineStride + * the scanline stride of the of the image data. + * @param dataBitOffset + * the array of the band offsets. */ - public MultiPixelPackedSampleModel(int dataType, int w, int h, - int numberOfBits, int scanlineStride, int dataBitOffset) { + public MultiPixelPackedSampleModel(int dataType, int w, int h, int numberOfBits, + int scanlineStride, int dataBitOffset) { super(dataType, w, h, 1); - if (dataType != DataBuffer.TYPE_BYTE && - dataType != DataBuffer.TYPE_USHORT && - dataType != DataBuffer.TYPE_INT) { + if (dataType != DataBuffer.TYPE_BYTE && dataType != DataBuffer.TYPE_USHORT + && dataType != DataBuffer.TYPE_INT) { // awt.61=Unsupported data type: {0} throw new IllegalArgumentException(Messages.getString("awt.61", //$NON-NLS-1$ dataType)); } this.scanlineStride = scanlineStride; - if(numberOfBits == 0) { + if (numberOfBits == 0) { // awt.20C=Number of Bits equals to zero throw new RasterFormatException(Messages.getString("awt.20C")); //$NON-NLS-1$ } this.pixelBitStride = numberOfBits; this.dataElementSize = DataBuffer.getDataTypeSize(dataType); - if(dataElementSize % pixelBitStride != 0) { - // awt.20D=The number of bits per pixel is not a power of 2 or pixels span data element boundaries + if (dataElementSize % pixelBitStride != 0) { + // awt.20D=The number of bits per pixel is not a power of 2 or + // pixels span data element boundaries throw new RasterFormatException(Messages.getString("awt.20D")); //$NON-NLS-1$ } - if(dataBitOffset % numberOfBits != 0) { + if (dataBitOffset % numberOfBits != 0) { // awt.20E=Data Bit offset is not a multiple of pixel bit stride throw new RasterFormatException(Messages.getString("awt.20E")); //$NON-NLS-1$ } @@ -97,17 +118,20 @@ public class MultiPixelPackedSampleModel extends SampleModel { * Instantiates a new MultiPixelPackedSampleModel with the specified * parameters. * - * @param dataType the data type of the samples. - * @param w the width of the image data. - * @param h the height of the image data. - * @param numberOfBits the number of bits per pixel. + * @param dataType + * the data type of the samples. + * @param w + * the width of the image data. + * @param h + * the height of the image data. + * @param numberOfBits + * the number of bits per pixel. */ - public MultiPixelPackedSampleModel(int dataType, int w, int h, - int numberOfBits) { + public MultiPixelPackedSampleModel(int dataType, int w, int h, int numberOfBits) { - this(dataType, w, h, numberOfBits, (numberOfBits * w + - DataBuffer.getDataTypeSize(dataType) - 1) / - DataBuffer.getDataTypeSize(dataType), 0); + this(dataType, w, h, numberOfBits, + (numberOfBits * w + DataBuffer.getDataTypeSize(dataType) - 1) + / DataBuffer.getDataTypeSize(dataType), 0); } @Override @@ -117,36 +141,36 @@ public class MultiPixelPackedSampleModel extends SampleModel { throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ } switch (getTransferType()) { - case DataBuffer.TYPE_BYTE: - byte bdata[]; - if (obj == null) { - bdata = new byte[1]; - } else { - bdata = (byte[]) obj; - } - bdata[0] = (byte) getSample(x, y, 0, data); - obj = bdata; - break; - case DataBuffer.TYPE_USHORT: - short sdata[]; - if (obj == null) { - sdata = new short[1]; - } else { - sdata = (short[]) obj; - } - sdata[0] = (short) getSample(x, y, 0, data); - obj = sdata; - break; - case DataBuffer.TYPE_INT: - int idata[]; - if (obj == null) { - idata = new int[1]; - } else { - idata = (int[]) obj; - } - idata[0] = getSample(x, y, 0, data); - obj = idata; - break; + case DataBuffer.TYPE_BYTE: + byte bdata[]; + if (obj == null) { + bdata = new byte[1]; + } else { + bdata = (byte[])obj; + } + bdata[0] = (byte)getSample(x, y, 0, data); + obj = bdata; + break; + case DataBuffer.TYPE_USHORT: + short sdata[]; + if (obj == null) { + sdata = new short[1]; + } else { + sdata = (short[])obj; + } + sdata[0] = (short)getSample(x, y, 0, data); + obj = sdata; + break; + case DataBuffer.TYPE_INT: + int idata[]; + if (obj == null) { + idata = new int[1]; + } else { + idata = (int[])obj; + } + idata[0] = getSample(x, y, 0, data); + obj = idata; + break; } return obj; @@ -158,14 +182,14 @@ public class MultiPixelPackedSampleModel extends SampleModel { } /** - * Compares this MultiPixelPackedSampleModel object with - * the specified object. - * - * @param o the Object to be compared. + * Compares this MultiPixelPackedSampleModel object with the specified + * object. * - * @return true, if the object is a MultiPixelPackedSampleModel - * with the same data parameter values as this MultiPixelPackedSampleModel, - * false otherwise. + * @param o + * the Object to be compared. + * @return true, if the object is a MultiPixelPackedSampleModel with the + * same data parameter values as this MultiPixelPackedSampleModel, + * false otherwise. */ @Override public boolean equals(Object o) { @@ -173,17 +197,14 @@ public class MultiPixelPackedSampleModel extends SampleModel { return false; } - MultiPixelPackedSampleModel model = (MultiPixelPackedSampleModel) o; - return this.width == model.width && - this.height == model.height && - this.numBands == model.numBands && - this.dataType == model.dataType && - this.pixelBitStride == model.pixelBitStride && - this.bitMask == model.bitMask && - this.pixelsPerDataElement == model.pixelsPerDataElement && - this.dataElementSize == model.dataElementSize && - this.dataBitOffset == model.dataBitOffset && - this.scanlineStride == model.scanlineStride; + MultiPixelPackedSampleModel model = (MultiPixelPackedSampleModel)o; + return this.width == model.width && this.height == model.height + && this.numBands == model.numBands && this.dataType == model.dataType + && this.pixelBitStride == model.pixelBitStride && this.bitMask == model.bitMask + && this.pixelsPerDataElement == model.pixelsPerDataElement + && this.dataElementSize == model.dataElementSize + && this.dataBitOffset == model.dataBitOffset + && this.scanlineStride == model.scanlineStride; } @Override @@ -231,8 +252,7 @@ public class MultiPixelPackedSampleModel extends SampleModel { int bitnum = dataBitOffset + x * pixelBitStride; int elem = data.getElem(y * scanlineStride + bitnum / dataElementSize); - int shift = dataElementSize - (bitnum & (dataElementSize - 1)) - - pixelBitStride; + int shift = dataElementSize - (bitnum & (dataElementSize - 1)) - pixelBitStride; return (elem >> shift) & bitMask; } @@ -253,15 +273,15 @@ public class MultiPixelPackedSampleModel extends SampleModel { int size = scanlineStride * height; switch (dataType) { - case DataBuffer.TYPE_BYTE: - dataBuffer = new DataBufferByte(size + (dataBitOffset + 7) / 8); - break; - case DataBuffer.TYPE_USHORT: - dataBuffer = new DataBufferUShort(size + (dataBitOffset + 15) / 16); - break; - case DataBuffer.TYPE_INT: - dataBuffer = new DataBufferInt(size + (dataBitOffset + 31) / 32); - break; + case DataBuffer.TYPE_BYTE: + dataBuffer = new DataBufferByte(size + (dataBitOffset + 7) / 8); + break; + case DataBuffer.TYPE_USHORT: + dataBuffer = new DataBufferUShort(size + (dataBitOffset + 15) / 16); + break; + case DataBuffer.TYPE_INT: + dataBuffer = new DataBufferInt(size + (dataBitOffset + 31) / 32); + break; } return dataBuffer; } @@ -269,14 +289,14 @@ public class MultiPixelPackedSampleModel extends SampleModel { /** * Gets the offset of the specified pixel in the data array. * - * @param x the X coordinate of the specified pixel. - * @param y the Y coordinate of the specified pixel. - * + * @param x + * the X coordinate of the specified pixel. + * @param y + * the Y coordinate of the specified pixel. * @return the offset of the specified pixel. */ public int getOffset(int x, int y) { - return y * scanlineStride + (x * pixelBitStride + dataBitOffset) / - dataElementSize; + return y * scanlineStride + (x * pixelBitStride + dataBitOffset) / dataElementSize; } @Override @@ -285,11 +305,11 @@ public class MultiPixelPackedSampleModel extends SampleModel { } /** - * Gets the bit offset in the data element which - * is stored for the specified pixel of a scanline. - * - * @param x the pixel. + * Gets the bit offset in the data element which is stored for the specified + * pixel of a scanline. * + * @param x + * the pixel. * @return the bit offset of the pixel in the data element. */ public int getBitOffset(int x) { @@ -298,7 +318,9 @@ public class MultiPixelPackedSampleModel extends SampleModel { @Override public int[] getSampleSize() { - int sampleSizes[] = { pixelBitStride }; + int sampleSizes[] = { + pixelBitStride + }; return sampleSizes; } @@ -396,54 +418,58 @@ public class MultiPixelPackedSampleModel extends SampleModel { } /** - * This method is used by other methods of this class. The behaviour of - * this method depends on the method which has been invoke this one. The - * argument methodId is used to choose valid behaviour in a particular case. - * If methodId is equal to 1 it means that this method has been invoked by - * the setDataElements() method, 2 - means setPixel(), and setSample() in - * any other cases. + * This method is used by other methods of this class. The behavior of this + * method depends on the method which has been invoke this one. The argument + * methodId is used to choose valid behavior in a particular case. If + * methodId is equal to 1 it means that this method has been invoked by the + * setDataElements() method, 2 - means setPixel(), and setSample() in any + * other cases. * - * @param x the x - * @param y the y - * @param obj the obj - * @param data the data - * @param methodId the method id - * @param s the s + * @param x + * the x. + * @param y + * the y. + * @param obj + * the obj. + * @param data + * the data. + * @param methodId + * the method id. + * @param s + * the s. */ - private void setSample(final int x, final int y, final Object obj, - final DataBuffer data, final int methodId, int s) { + private void setSample(final int x, final int y, final Object obj, final DataBuffer data, + final int methodId, int s) { if ((x < 0) || (y < 0) || (x >= this.width) || (y >= this.height)) { // awt.63=Coordinates are not in bounds - throw new ArrayIndexOutOfBoundsException(Messages - .getString("awt.63")); //$NON-NLS-1$ + throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ } final int bitnum = dataBitOffset + x * pixelBitStride; final int idx = y * scanlineStride + bitnum / dataElementSize; - final int shift = dataElementSize - (bitnum & (dataElementSize - 1)) - - pixelBitStride; + final int shift = dataElementSize - (bitnum & (dataElementSize - 1)) - pixelBitStride; final int mask = ~(bitMask << shift); int elem = data.getElem(idx); switch (methodId) { - case 1: { // Invoked from setDataElements() - switch (getTransferType()) { - case DataBuffer.TYPE_BYTE: - s = ((byte[]) obj)[0] & 0xff; - break; - case DataBuffer.TYPE_USHORT: - s = ((short[]) obj)[0] & 0xffff; + case 1: { // Invoked from setDataElements() + switch (getTransferType()) { + case DataBuffer.TYPE_BYTE: + s = ((byte[])obj)[0] & 0xff; + break; + case DataBuffer.TYPE_USHORT: + s = ((short[])obj)[0] & 0xffff; + break; + case DataBuffer.TYPE_INT: + s = ((int[])obj)[0]; + break; + } break; - case DataBuffer.TYPE_INT: - s = ((int[]) obj)[0]; + } + case 2: { // Invoked from setPixel() + s = ((int[])obj)[0]; break; } - break; - } - case 2: { // Invoked from setPixel() - s = ((int[]) obj)[0]; - break; - } } elem &= mask; @@ -451,4 +477,3 @@ public class MultiPixelPackedSampleModel extends SampleModel { data.setElem(idx, elem); } } - diff --git a/awt/java/awt/image/PackedColorModel.java b/awt/java/awt/image/PackedColorModel.java index 7aaefbfe5c576cbc10b9c8f62ae27ea8b370a8b2..4d1c2e5003d9c5706b530ab2b44bfe00514aaa7a 100644 --- a/awt/java/awt/image/PackedColorModel.java +++ b/awt/java/awt/image/PackedColorModel.java @@ -18,6 +18,7 @@ * @author Igor V. Stolyarov * @version $Revision$ */ + package java.awt.image; import java.awt.Transparency; @@ -27,44 +28,57 @@ import java.util.Arrays; import org.apache.harmony.awt.internal.nls.Messages; /** - * The Class PackedColorModel represents a color model where the - * components are just the red, green, and blue bands, plus an alpha - * band if alpha is supported. + * The class PackedColorModel represents a color model where the components are + * just the red, green, and blue bands, plus an alpha band if alpha is + * supported. + * + * @since Android 1.0 */ public abstract class PackedColorModel extends ColorModel { - /** The component masks. */ + /** + * The component masks. + */ int componentMasks[]; - /** The offsets. */ + /** + * The offsets. + */ int offsets[]; - /** The scales. */ + /** + * The scales. + */ float scales[]; /** * Instantiates a new packed color model. * - * @param space the color space - * @param bits the array of component masks - * @param colorMaskArray the array that gives the bitmask corresponding - * to each color band (red, green, and blue) - * @param alphaMask the bitmask corresponding to the alpha band - * @param isAlphaPremultiplied whether the alpha is premultiplied in this color model - * @param trans the transparency strategy, @see java.awt.Transparency - * @param transferType the transfer type (primitive java type - * to use for the components) - * - * @throws IllegalArgumentException if the number of bits in the combined - * bitmasks for the color bands is less than one or greater than 32 + * @param space + * the color space. + * @param bits + * the array of component masks. + * @param colorMaskArray + * the array that gives the bitmask corresponding to each color + * band (red, green, and blue). + * @param alphaMask + * the bitmask corresponding to the alpha band. + * @param isAlphaPremultiplied + * whether the alpha is pre-multiplied in this color model. + * @param trans + * the transparency strategy, @see java.awt.Transparency. + * @param transferType + * the transfer type (primitive java type to use for the + * components). + * @throws IllegalArgumentException + * if the number of bits in the combined bitmasks for the color + * bands is less than one or greater than 32. */ - public PackedColorModel(ColorSpace space, int bits, int colorMaskArray[], - int alphaMask, boolean isAlphaPremultiplied, int trans, - int transferType) { + public PackedColorModel(ColorSpace space, int bits, int colorMaskArray[], int alphaMask, + boolean isAlphaPremultiplied, int trans, int transferType) { - super(bits, createBits(colorMaskArray, alphaMask), space, - (alphaMask == 0 ? false : true), isAlphaPremultiplied, trans, - validateTransferType(transferType)); + super(bits, createBits(colorMaskArray, alphaMask), space, (alphaMask == 0 ? false : true), + isAlphaPremultiplied, trans, validateTransferType(transferType)); if (pixel_bits < 1 || pixel_bits > 32) { // awt.236=The bits is less than 1 or greater than 32 @@ -89,27 +103,34 @@ public abstract class PackedColorModel extends ColorModel { /** * Instantiates a new packed color model. * - * @param space the color space - * @param bits the array of component masks - * @param rmask the bitmask corresponding to the red band - * @param gmask the bitmask corresponding to the green band - * @param bmask the bitmask corresponding to the blue band - * @param amask the bitmask corresponding to the alpha band - * @param isAlphaPremultiplied whether the alpha is premultiplied in this color model - * @param trans the transparency strategy, @see java.awt.Transparency - * @param transferType the transfer type (primitive java type - * to use for the components) - * - * @throws IllegalArgumentException if the number of bits in the combined - * bitmasks for the color bands is less than one or greater than 32 + * @param space + * the color space. + * @param bits + * the array of component masks. + * @param rmask + * the bitmask corresponding to the red band. + * @param gmask + * the bitmask corresponding to the green band. + * @param bmask + * the bitmask corresponding to the blue band. + * @param amask + * the bitmask corresponding to the alpha band. + * @param isAlphaPremultiplied + * whether the alpha is pre-multiplied in this color model. + * @param trans + * the transparency strategy, @see java.awt.Transparency. + * @param transferType + * the transfer type (primitive java type to use for the + * components). + * @throws IllegalArgumentException + * if the number of bits in the combined bitmasks for the color + * bands is less than one or greater than 32. */ - public PackedColorModel(ColorSpace space, int bits, int rmask, int gmask, - int bmask, int amask, boolean isAlphaPremultiplied, int trans, - int transferType) { + public PackedColorModel(ColorSpace space, int bits, int rmask, int gmask, int bmask, int amask, + boolean isAlphaPremultiplied, int trans, int transferType) { - super(bits, createBits(rmask, gmask, bmask, amask), space, - (amask == 0 ? false : true), isAlphaPremultiplied, trans, - validateTransferType(transferType)); + super(bits, createBits(rmask, gmask, bmask, amask), space, (amask == 0 ? false : true), + isAlphaPremultiplied, trans, validateTransferType(transferType)); if (pixel_bits < 1 || pixel_bits > 32) { // awt.236=The bits is less than 1 or greater than 32 @@ -123,7 +144,8 @@ public abstract class PackedColorModel extends ColorModel { for (int i = 0; i < numColorComponents; i++) { if (cs.getMinValue(i) != 0.0f || cs.getMaxValue(i) != 1.0f) { - // awt.23A=The min/max normalized component values are not 0.0/1.0 + // awt.23A=The min/max normalized component values are not + // 0.0/1.0 throw new IllegalArgumentException(Messages.getString("awt.23A")); //$NON-NLS-1$ } } @@ -144,7 +166,7 @@ public abstract class PackedColorModel extends ColorModel { @Override public WritableRaster getAlphaRaster(WritableRaster raster) { - if(!hasAlpha) { + if (!hasAlpha) { return null; } @@ -165,18 +187,16 @@ public abstract class PackedColorModel extends ColorModel { if (!(obj instanceof PackedColorModel)) { return false; } - PackedColorModel cm = (PackedColorModel) obj; - - return (pixel_bits == cm.getPixelSize() && - transferType == cm.getTransferType() && - cs.getType() == cm.getColorSpace().getType() && - hasAlpha == cm.hasAlpha() && - isAlphaPremultiplied == cm.isAlphaPremultiplied() && - transparency == cm.getTransparency() && - numColorComponents == cm.getNumColorComponents()&& - numComponents == cm.getNumComponents() && - Arrays.equals(bits, cm.getComponentSize()) && - Arrays.equals(componentMasks, cm.getMasks())); + PackedColorModel cm = (PackedColorModel)obj; + + return (pixel_bits == cm.getPixelSize() && transferType == cm.getTransferType() + && cs.getType() == cm.getColorSpace().getType() && hasAlpha == cm.hasAlpha() + && isAlphaPremultiplied == cm.isAlphaPremultiplied() + && transparency == cm.getTransparency() + && numColorComponents == cm.getNumColorComponents() + && numComponents == cm.getNumComponents() + && Arrays.equals(bits, cm.getComponentSize()) && Arrays.equals(componentMasks, cm + .getMasks())); } @Override @@ -187,25 +207,23 @@ public abstract class PackedColorModel extends ColorModel { if (!(sm instanceof SinglePixelPackedSampleModel)) { return false; } - SinglePixelPackedSampleModel esm = (SinglePixelPackedSampleModel) sm; + SinglePixelPackedSampleModel esm = (SinglePixelPackedSampleModel)sm; - return ((esm.getNumBands() == numComponents) && - (esm.getTransferType() == transferType) && - Arrays.equals(esm.getBitMasks(), componentMasks)); + return ((esm.getNumBands() == numComponents) && (esm.getTransferType() == transferType) && Arrays + .equals(esm.getBitMasks(), componentMasks)); } @Override public SampleModel createCompatibleSampleModel(int w, int h) { - return new SinglePixelPackedSampleModel(transferType, w, h, - componentMasks); + return new SinglePixelPackedSampleModel(transferType, w, h, componentMasks); } /** * Gets the bitmask corresponding to the specified color component. * - * @param index the index of the desired color - * - * @return the mask + * @param index + * the index of the desired color. + * @return the mask. */ public final int getMask(int index) { return componentMasks[index]; @@ -214,7 +232,7 @@ public abstract class PackedColorModel extends ColorModel { /** * Gets the bitmasks of the components. * - * @return the masks + * @return the masks. */ public final int[] getMasks() { return (componentMasks.clone()); @@ -223,10 +241,11 @@ public abstract class PackedColorModel extends ColorModel { /** * Creates the bits. * - * @param colorMaskArray the color mask array - * @param alphaMask the alpha mask - * - * @return the int[] + * @param colorMaskArray + * the color mask array. + * @param alphaMask + * the alpha mask. + * @return the int[]. */ private static int[] createBits(int colorMaskArray[], int alphaMask) { int bits[]; @@ -262,15 +281,17 @@ public abstract class PackedColorModel extends ColorModel { /** * Creates the bits. * - * @param rmask the rmask - * @param gmask the gmask - * @param bmask the bmask - * @param amask the amask - * - * @return the int[] + * @param rmask + * the rmask. + * @param gmask + * the gmask. + * @param bmask + * the bmask. + * @param amask + * the amask. + * @return the int[]. */ - private static int[] createBits(int rmask, int gmask, int bmask, - int amask) { + private static int[] createBits(int rmask, int gmask, int bmask, int amask) { int numComp; if (amask == 0) { @@ -312,9 +333,9 @@ public abstract class PackedColorModel extends ColorModel { /** * Count comp bits. * - * @param compMask the comp mask - * - * @return the int + * @param compMask + * the comp mask. + * @return the int. */ private static int countCompBits(int compMask) { int bits = 0; @@ -340,20 +361,19 @@ public abstract class PackedColorModel extends ColorModel { /** * Validate transfer type. * - * @param transferType the transfer type - * - * @return the int + * @param transferType + * the transfer type. + * @return the int. */ private static int validateTransferType(int transferType) { - if (transferType != DataBuffer.TYPE_BYTE && - transferType != DataBuffer.TYPE_USHORT && - transferType != DataBuffer.TYPE_INT) { + if (transferType != DataBuffer.TYPE_BYTE && transferType != DataBuffer.TYPE_USHORT + && transferType != DataBuffer.TYPE_INT) { // awt.240=The transferType not is one of DataBuffer.TYPE_BYTE, - // DataBuffer.TYPE_USHORT or DataBuffer.TYPE_INT + // DataBuffer.TYPE_USHORT or DataBuffer.TYPE_INT throw new IllegalArgumentException(Messages.getString("awt.240")); //$NON-NLS-1$ } return transferType; -} + } /** * Parses the components. @@ -380,4 +400,3 @@ public abstract class PackedColorModel extends ColorModel { } } - diff --git a/awt/java/awt/image/PixelInterleavedSampleModel.java b/awt/java/awt/image/PixelInterleavedSampleModel.java index e41473ec93b176992d9975046cd40ecb79e7f506..8e646f80b9d769916f979bd6c1f90ca1d02f23ca 100644 --- a/awt/java/awt/image/PixelInterleavedSampleModel.java +++ b/awt/java/awt/image/PixelInterleavedSampleModel.java @@ -18,30 +18,39 @@ * @author Igor V. Stolyarov * @version $Revision$ */ + package java.awt.image; import org.apache.harmony.awt.internal.nls.Messages; /** - * The PixelInterleavedSampleModel class represents image data - * as represented as interleaved pixels and for which each sample of - * a pixel takes one data element of the DataBuffer. + * The PixelInterleavedSampleModel class represents image data as represented as + * interleaved pixels and for which each sample of a pixel takes one data + * element of the DataBuffer. + * + * @since Android 1.0 */ public class PixelInterleavedSampleModel extends ComponentSampleModel { /** - * Instantiates a new PixelInterleavedSampleModel with the - * specified parameters. + * Instantiates a new PixelInterleavedSampleModel with the specified + * parameters. * - * @param dataType the data type of the samples. - * @param w the width of the image data. - * @param h the height of the image data. - * @param pixelStride the pixel stride of the image data. - * @param scanlineStride the scanline stride of the of the image data. - * @param bandOffsets the array of the band offsets. + * @param dataType + * the data type of the samples. + * @param w + * the width of the image data. + * @param h + * the height of the image data. + * @param pixelStride + * the pixel stride of the image data. + * @param scanlineStride + * the scanline stride of the of the image data. + * @param bandOffsets + * the array of the band offsets. */ - public PixelInterleavedSampleModel(int dataType, int w, int h, - int pixelStride, int scanlineStride, int bandOffsets[]) { + public PixelInterleavedSampleModel(int dataType, int w, int h, int pixelStride, + int scanlineStride, int bandOffsets[]) { super(dataType, w, h, pixelStride, scanlineStride, bandOffsets); @@ -59,7 +68,8 @@ public class PixelInterleavedSampleModel extends ComponentSampleModel { maxOffset -= minOffset; if (maxOffset > scanlineStride) { - // awt.241=Any offset between bands is greater than the Scanline stride + // awt.241=Any offset between bands is greater than the Scanline + // stride throw new IllegalArgumentException(Messages.getString("awt.241")); //$NON-NLS-1$ } @@ -69,7 +79,8 @@ public class PixelInterleavedSampleModel extends ComponentSampleModel { } if (pixelStride * w > scanlineStride) { - // awt.243=Product of Pixel stride and w is greater than Scanline stride + // awt.243=Product of Pixel stride and w is greater than Scanline + // stride throw new IllegalArgumentException(Messages.getString("awt.243")); //$NON-NLS-1$ } @@ -82,8 +93,8 @@ public class PixelInterleavedSampleModel extends ComponentSampleModel { newOffsets[i] = bandOffsets[bands[i]]; } - return new PixelInterleavedSampleModel(dataType, width, height, - pixelStride, scanlineStride, newOffsets); + return new PixelInterleavedSampleModel(dataType, width, height, pixelStride, + scanlineStride, newOffsets); } @Override @@ -106,8 +117,8 @@ public class PixelInterleavedSampleModel extends ComponentSampleModel { newOffsets = bandOffsets; } - return new PixelInterleavedSampleModel(dataType, w, h, pixelStride, - pixelStride * w, newOffsets); + return new PixelInterleavedSampleModel(dataType, w, h, pixelStride, pixelStride * w, + newOffsets); } @Override @@ -121,4 +132,3 @@ public class PixelInterleavedSampleModel extends ComponentSampleModel { } } - diff --git a/awt/java/awt/image/RGBImageFilter.java b/awt/java/awt/image/RGBImageFilter.java index 9a7699793e23c0ac14760770518a2bd366038748..f5fe5d9ff9ab6fe33835589bbefc4e96e6e502a6 100644 --- a/awt/java/awt/image/RGBImageFilter.java +++ b/awt/java/awt/image/RGBImageFilter.java @@ -18,46 +18,48 @@ * @author Igor V. Stolyarov * @version $Revision$ */ -package java.awt.image; +package java.awt.image; /** - * The RGBImageFilter class represents a filter which modifies - * pixels of an image in the default RGB ColorModel. + * The RGBImageFilter class represents a filter which modifies pixels of an + * image in the default RGB ColorModel. + * + * @since Android 1.0 */ public abstract class RGBImageFilter extends ImageFilter { - /** - * The origmodel is the ColorModel to be replaced by newmodel - * when substituteColorModel is called. + /** + * The original model is the ColorModel to be replaced by the new model when + * substituteColorModel is called. */ protected ColorModel origmodel; - /** - * The newmodel is the ColorModel with which to replace origmodel - * when substituteColorModel is called. + /** + * The new model is the ColorModel with which to replace the original model + * when substituteColorModel is called. */ protected ColorModel newmodel; - /** - * The canFilterIndexColorModel indicates if it is - * acceptable to apply the color filtering of the filterRGB - * method to the color table entries of an IndexColorModel - * object. - * */ + /** + * The canFilterIndexColorModel indicates if it is acceptable to apply the + * color filtering of the filterRGB method to the color table entries of an + * IndexColorModel object. + */ protected boolean canFilterIndexColorModel; /** * Instantiates a new RGBImageFilter. */ - public RGBImageFilter() {} + public RGBImageFilter() { + } /** - * Filters an IndexColorModel object by calling filterRGB function for - * each entry of IndexColorModel. - * - * @param icm the IndexColorModel to be filtered. + * Filters an IndexColorModel object by calling filterRGB function for each + * entry of IndexColorModel. * + * @param icm + * the IndexColorModel to be filtered. * @return the IndexColorModel. */ public IndexColorModel filterIndexColorModel(IndexColorModel icm) { @@ -69,28 +71,30 @@ public abstract class RGBImageFilter extends ImageFilter { icm.getRGBs(colorMap); int trans = -1; boolean hasAlpha = false; - for(int i = 0; i < mapSize; i++){ + for (int i = 0; i < mapSize; i++) { filteredColorMap[i] = filterRGB(-1, -1, colorMap[i]); int alpha = filteredColorMap[i] >>> 24; - if(alpha != 0xff){ - if(!hasAlpha) { + if (alpha != 0xff) { + if (!hasAlpha) { hasAlpha = true; } - if(alpha == 0 && trans < 0) { + if (alpha == 0 && trans < 0) { trans = i; } } } - return new IndexColorModel(bits, mapSize, filteredColorMap, 0, - hasAlpha, trans, transferType); + return new IndexColorModel(bits, mapSize, filteredColorMap, 0, hasAlpha, trans, + transferType); } /** * Replaces the original color model and the new one. * - * @param oldcm the old ColorModel. - * @param newcm the new ColorModel. + * @param oldcm + * the old ColorModel. + * @param newcm + * the new ColorModel. */ public void substituteColorModel(ColorModel oldcm, ColorModel newcm) { origmodel = oldcm; @@ -99,29 +103,27 @@ public abstract class RGBImageFilter extends ImageFilter { @Override public void setColorModel(ColorModel model) { - if(model instanceof IndexColorModel && - canFilterIndexColorModel){ - IndexColorModel icm = (IndexColorModel) model; + if (model instanceof IndexColorModel && canFilterIndexColorModel) { + IndexColorModel icm = (IndexColorModel)model; ColorModel filteredModel = filterIndexColorModel(icm); substituteColorModel(model, filteredModel); consumer.setColorModel(filteredModel); - }else{ + } else { consumer.setColorModel(ColorModel.getRGBdefault()); } } @Override - public void setPixels(int x, int y, int w, int h, ColorModel model, - int[] pixels, int off, int scansize) { - - if(model == null || model == origmodel){ + public void setPixels(int x, int y, int w, int h, ColorModel model, int[] pixels, int off, + int scansize) { + + if (model == null || model == origmodel) { consumer.setPixels(x, y, w, h, newmodel, pixels, off, scansize); - }else{ + } else { int rgbPixels[] = new int[w]; - for(int sy = y, pixelsOff = off; sy < y + h; - sy++, pixelsOff += scansize){ - - for(int sx = x, idx = 0; sx < x + w; sx++, idx++){ + for (int sy = y, pixelsOff = off; sy < y + h; sy++, pixelsOff += scansize) { + + for (int sx = x, idx = 0; sx < x + w; sx++, idx++) { rgbPixels[idx] = model.getRGB(pixels[pixelsOff + idx]); } filterRGBPixels(x, sy, w, 1, rgbPixels, 0, w); @@ -130,19 +132,17 @@ public abstract class RGBImageFilter extends ImageFilter { } @Override - public void setPixels(int x, int y, int w, int h, ColorModel model, - byte[] pixels, int off, int scansize) { - - if(model == null || model == origmodel){ + public void setPixels(int x, int y, int w, int h, ColorModel model, byte[] pixels, int off, + int scansize) { + + if (model == null || model == origmodel) { consumer.setPixels(x, y, w, h, newmodel, pixels, off, scansize); - }else{ + } else { int rgbPixels[] = new int[w]; - for(int sy = y, pixelsOff = off; sy < y + h; - sy++, pixelsOff += scansize){ - - for(int sx = x, idx = 0; sx < x + w; sx++, idx++){ - rgbPixels[idx] = - model.getRGB(pixels[pixelsOff + idx] & 0xff); + for (int sy = y, pixelsOff = off; sy < y + h; sy++, pixelsOff += scansize) { + + for (int sx = x, idx = 0; sx < x + w; sx++, idx++) { + rgbPixels[idx] = model.getRGB(pixels[pixelsOff + idx] & 0xff); } filterRGBPixels(x, sy, w, 1, rgbPixels, 0, w); } @@ -150,41 +150,46 @@ public abstract class RGBImageFilter extends ImageFilter { } /** - * Filters a region of pixels in the default RGB ColorModel - * by calling the filterRGB method for them. + * Filters a region of pixels in the default RGB ColorModel by calling the + * filterRGB method for them. * - * @param x the X coordinate of region. - * @param y the Y coordinate of region. - * @param w the width ofregion. - * @param h the height of region. - * @param pixels the pixels array. - * @param off the offset of array. - * @param scansize the distance between rows of pixels in the array. + * @param x + * the X coordinate of region. + * @param y + * the Y coordinate of region. + * @param w + * the width of region. + * @param h + * the height of region. + * @param pixels + * the pixels array. + * @param off + * the offset of array. + * @param scansize + * the distance between rows of pixels in the array. */ - public void filterRGBPixels(int x, int y, int w, int h, - int[] pixels, int off, int scansize) { - - for(int sy = y, lineOff = off; sy < y + h; sy++, lineOff += scansize){ - for(int sx = x, idx = 0; sx < x + w; sx++, idx++){ - pixels[lineOff + idx] = - filterRGB(sx, sy, pixels[lineOff + idx]); + public void filterRGBPixels(int x, int y, int w, int h, int[] pixels, int off, int scansize) { + + for (int sy = y, lineOff = off; sy < y + h; sy++, lineOff += scansize) { + for (int sx = x, idx = 0; sx < x + w; sx++, idx++) { + pixels[lineOff + idx] = filterRGB(sx, sy, pixels[lineOff + idx]); } } - consumer.setPixels(x, y, w, h, ColorModel.getRGBdefault(), - pixels, off, scansize); + consumer.setPixels(x, y, w, h, ColorModel.getRGBdefault(), pixels, off, scansize); } /** - * Coverts a single input pixel in the default RGB ColorModel - * to a single output pixel. - * - * @param x the X pixel's coordinate. - * @param y the Y pixel's coordinate. - * @param rgb a pixel in the default RGB color model. + * Converts a single input pixel in the default RGB ColorModel to a single + * output pixel. * + * @param x + * the X pixel's coordinate. + * @param y + * the Y pixel's coordinate. + * @param rgb + * a pixel in the default RGB color model. * @return a filtered pixel in the default RGB color model. */ public abstract int filterRGB(int x, int y, int rgb); } - diff --git a/awt/java/awt/image/Raster.java b/awt/java/awt/image/Raster.java index 4b2426e51a40d3e85b83c93048e87d3b9710ee43..6749fde9e4b97247f08beea0a617616a292e6bb9 100644 --- a/awt/java/awt/image/Raster.java +++ b/awt/java/awt/image/Raster.java @@ -18,6 +18,7 @@ * @author Igor V. Stolyarov * @version $Revision$ */ + package java.awt.image; import java.awt.Point; @@ -27,70 +28,95 @@ import org.apache.harmony.awt.gl.image.OrdinaryWritableRaster; import org.apache.harmony.awt.internal.nls.Messages; /** - * The Raster class represents a rectangular area of pixels. - * This class is defined by DataBuffer and SampleModel objects. - * The DataBuffer object stores sample values and DSampleModel defines - * the location of sample in this DataBuffer. + * The Raster class represents a rectangular area of pixels. This class is + * defined by DataBuffer and SampleModel objects. The DataBuffer object stores + * sample values and DSampleModel defines the location of sample in this + * DataBuffer. + * + * @since Android 1.0 */ public class Raster { - /** The DataBuffer of this Raster. */ + /** + * The DataBuffer of this Raster. + */ protected DataBuffer dataBuffer; - /** The height of this Raster. */ + /** + * The height of this Raster. + */ protected int height; - /** The X coordinate of the upper left pixel in this Raster. */ + /** + * The X coordinate of the upper left pixel in this Raster. + */ protected int minX; - /** The Y coordinate of the upper left pixel in this Raster. */ + /** + * The Y coordinate of the upper left pixel in this Raster. + */ protected int minY; - /** The number of bands in this Raster. */ + /** + * The number of bands in this Raster. + */ protected int numBands; - /** The number of data elements. */ + /** + * The number of data elements. + */ protected int numDataElements; - /** The parent of this Raster. */ + /** + * The parent of this Raster. + */ protected Raster parent; - /** The SampleModel of this Raster. */ + /** + * The SampleModel of this Raster. + */ protected SampleModel sampleModel; - /** - * The X translation from the coordinate space of the - * SampleModel of this Raster. + /** + * The X translation from the coordinate space of the SampleModel of this + * Raster. */ protected int sampleModelTranslateX; - /** - * The Y translation from the coordinate space of the - * SampleModel of this Raster. + /** + * The Y translation from the coordinate space of the SampleModel of this + * Raster. */ protected int sampleModelTranslateY; - /** The width of this Raster. */ + /** + * The width of this Raster. + */ protected int width; /** - * Creates a Raster object with a BandedSampleModel and the specified + * Creates a Raster object with a BandedSampleModel and the specified * DataBuffer. The number of bands is defined by the length of bandOffsets * or bankIndices arrays. * - * @param dataBuffer the specified DataBuffer. - * @param w the width of the image data. - * @param h the height of the image data. - * @param bankIndices the bank indices of bands. - * @param bandOffsets the band offsets of bands. - * @param location the location which defines the upper left corner - * of Raster. - * + * @param dataBuffer + * the specified DataBuffer. + * @param w + * the width of the image data. + * @param h + * the height of the image data. + * @param scanlineStride + * the scanline stride of the image data. + * @param bankIndices + * the bank indices of bands. + * @param bandOffsets + * the band offsets of bands. + * @param location + * the location which defines the upper left corner of Raster. * @return the WritableRaster object. */ - public static WritableRaster createBandedRaster(DataBuffer dataBuffer, - int w, int h, int scanlineStride, int bankIndices[], - int bandOffsets[], Point location) { + public static WritableRaster createBandedRaster(DataBuffer dataBuffer, int w, int h, + int scanlineStride, int bankIndices[], int bandOffsets[], Point location) { if (w <= 0 || h <= 0) { // awt.22E=w or h is less than or equal to zero @@ -101,9 +127,9 @@ public class Raster { location = new Point(0, 0); } - if ((long) location.x + w > Integer.MAX_VALUE - || (long) location.y + h > Integer.MAX_VALUE) { - // awt.276=location.x + w or location.y + h results in integer overflow + if ((long)location.x + w > Integer.MAX_VALUE || (long)location.y + h > Integer.MAX_VALUE) { + // awt.276=location.x + w or location.y + h results in integer + // overflow throw new RasterFormatException(Messages.getString("awt.276")); //$NON-NLS-1$ } @@ -119,39 +145,43 @@ public class Raster { int dataType = dataBuffer.getDataType(); - if (dataType != DataBuffer.TYPE_BYTE - && dataType != DataBuffer.TYPE_USHORT + if (dataType != DataBuffer.TYPE_BYTE && dataType != DataBuffer.TYPE_USHORT && dataType != DataBuffer.TYPE_INT) { // awt.230=dataType is not one of the supported data types throw new IllegalArgumentException(Messages.getString("awt.230")); //$NON-NLS-1$ } - BandedSampleModel sampleModel = new BandedSampleModel(dataType, w, h, - scanlineStride, bankIndices, bandOffsets); + BandedSampleModel sampleModel = new BandedSampleModel(dataType, w, h, scanlineStride, + bankIndices, bandOffsets); return new OrdinaryWritableRaster(sampleModel, dataBuffer, location); } /** - * Creates a Raster object with a BandedSampleModel and the specified - * data type. The Data type can be one of the following values: - * TYPE_BYTE, TYPE_USHORT, or TYPE_INT. - * - * @param dataType the data type of the samples: - * TYPE_BYTE, TYPE_USHORT, or TYPE_INT. - * @param w the width of the image data. - * @param h the height of the image data. - * @param scanlineStride the scanline stride of the image data. - * @param bankIndices the bank indices of bands. - * @param bandOffsets the band offsets of bands. - * @param location the location which defines the upper left corner - * of the Raster. - * + * Creates a Raster object with a BandedSampleModel and the specified data + * type. The Data type can be one of the following values: TYPE_BYTE, + * TYPE_USHORT, or TYPE_INT. + * + * @param dataType + * the data type of the samples: TYPE_BYTE, TYPE_USHORT, or + * TYPE_INT. + * @param w + * the width of the image data. + * @param h + * the height of the image data. + * @param scanlineStride + * the scanline stride of the image data. + * @param bankIndices + * the bank indices of bands. + * @param bandOffsets + * the band offsets of bands. + * @param location + * the location which defines the upper left corner of the + * Raster. * @return the WritableRaster object. */ - public static WritableRaster createBandedRaster(int dataType, int w, int h, - int scanlineStride, int bankIndices[], int bandOffsets[], - Point location) { + public static WritableRaster createBandedRaster(int dataType, int w, int h, int scanlineStride, + int bankIndices[], int bandOffsets[], Point location) { if (w <= 0 || h <= 0) { // awt.22E=w or h is less than or equal to zero @@ -162,9 +192,9 @@ public class Raster { location = new Point(0, 0); } - if ((long) location.x + w > Integer.MAX_VALUE - || (long) location.y + h > Integer.MAX_VALUE) { - // awt.276=location.x + w or location.y + h results in integer overflow + if ((long)location.x + w > Integer.MAX_VALUE || (long)location.y + h > Integer.MAX_VALUE) { + // awt.276=location.x + w or location.y + h results in integer + // overflow throw new RasterFormatException(Messages.getString("awt.276")); //$NON-NLS-1$ } @@ -173,8 +203,7 @@ public class Raster { throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.277")); //$NON-NLS-1$ } - if (dataType != DataBuffer.TYPE_BYTE - && dataType != DataBuffer.TYPE_USHORT + if (dataType != DataBuffer.TYPE_BYTE && dataType != DataBuffer.TYPE_USHORT && dataType != DataBuffer.TYPE_INT) { // awt.230=dataType is not one of the supported data types throw new IllegalArgumentException(Messages.getString("awt.230")); //$NON-NLS-1$ @@ -198,37 +227,40 @@ public class Raster { DataBuffer data = null; switch (dataType) { - case DataBuffer.TYPE_BYTE: - data = new DataBufferByte(dataSize, numBanks); - break; - case DataBuffer.TYPE_USHORT: - data = new DataBufferUShort(dataSize, numBanks); - break; - case DataBuffer.TYPE_INT: - data = new DataBufferInt(dataSize, numBanks); - break; - } - return createBandedRaster(data, w, h, scanlineStride, bankIndices, - bandOffsets, location); + case DataBuffer.TYPE_BYTE: + data = new DataBufferByte(dataSize, numBanks); + break; + case DataBuffer.TYPE_USHORT: + data = new DataBufferUShort(dataSize, numBanks); + break; + case DataBuffer.TYPE_INT: + data = new DataBufferInt(dataSize, numBanks); + break; + } + return createBandedRaster(data, w, h, scanlineStride, bankIndices, bandOffsets, location); } /** - * Creates a Raster object with a BandedSampleModel and the specified - * data type. The Data type can be one of the following values: - * TYPE_BYTE, TYPE_USHORT, or TYPE_INT. - * - * @param dataType the data type of the samples: - * TYPE_BYTE, TYPE_USHORT, or TYPE_INT. - * @param w the width of the image data. - * @param h the height of the image data. - * @param bands the number of bands. - * @param location the location which defines the upper left corner - * of the Raster. - * + * Creates a Raster object with a BandedSampleModel and the specified data + * type. The Data type can be one of the following values: TYPE_BYTE, + * TYPE_USHORT, or TYPE_INT. + * + * @param dataType + * the data type of the samples: TYPE_BYTE, TYPE_USHORT, or + * TYPE_INT. + * @param w + * the width of the image data. + * @param h + * the height of the image data. + * @param bands + * the number of bands. + * @param location + * the location which defines the upper left corner of the + * Raster. * @return the WritableRaster object. */ - public static WritableRaster createBandedRaster(int dataType, int w, int h, - int bands, Point location) { + public static WritableRaster createBandedRaster(int dataType, int w, int h, int bands, + Point location) { if (w <= 0 || h <= 0) { // awt.22E=w or h is less than or equal to zero @@ -239,9 +271,9 @@ public class Raster { location = new Point(0, 0); } - if ((long) location.x + w > Integer.MAX_VALUE - || (long) location.y + h > Integer.MAX_VALUE) { - // awt.276=location.x + w or location.y + h results in integer overflow + if ((long)location.x + w > Integer.MAX_VALUE || (long)location.y + h > Integer.MAX_VALUE) { + // awt.276=location.x + w or location.y + h results in integer + // overflow throw new RasterFormatException(Messages.getString("awt.276")); //$NON-NLS-1$ } @@ -257,28 +289,32 @@ public class Raster { bandOffsets[i] = 0; bankIndices[i] = i; } - return createBandedRaster(dataType, w, h, w, bankIndices, bandOffsets, - location); + return createBandedRaster(dataType, w, h, w, bankIndices, bandOffsets, location); } /** - * Creates a Raster object with a PixelInterleavedSampleModel - * and the specified DataBuffer. - * - * @param dataBuffer the DataBuffer. - * @param w the width of image data. - * @param h the height of image data. - * @param scanlineStride the scanline stride of the image data. - * @param pixelStride the pixel stride of image data. - * @param bandOffsets the band offsets of bands. - * @param location the location which defines the upper left corner - * of the Raster. - * + * Creates a Raster object with a PixelInterleavedSampleModel and the + * specified DataBuffer. + * + * @param dataBuffer + * the DataBuffer. + * @param w + * the width of image data. + * @param h + * the height of image data. + * @param scanlineStride + * the scanline stride of the image data. + * @param pixelStride + * the pixel stride of image data. + * @param bandOffsets + * the band offsets of bands. + * @param location + * the location which defines the upper left corner of the + * Raster. * @return the WritableRaster object. */ - public static WritableRaster createInterleavedRaster(DataBuffer dataBuffer, - int w, int h, int scanlineStride, int pixelStride, - int bandOffsets[], Point location) { + public static WritableRaster createInterleavedRaster(DataBuffer dataBuffer, int w, int h, + int scanlineStride, int pixelStride, int bandOffsets[], Point location) { if (w <= 0 || h <= 0) { // awt.22E=w or h is less than or equal to zero @@ -289,9 +325,9 @@ public class Raster { location = new Point(0, 0); } - if ((long) location.x + w > Integer.MAX_VALUE - || (long) location.y + h > Integer.MAX_VALUE) { - // awt.276=location.x + w or location.y + h results in integer overflow + if ((long)location.x + w > Integer.MAX_VALUE || (long)location.y + h > Integer.MAX_VALUE) { + // awt.276=location.x + w or location.y + h results in integer + // overflow throw new RasterFormatException(Messages.getString("awt.276")); //$NON-NLS-1$ } @@ -301,8 +337,7 @@ public class Raster { } int dataType = dataBuffer.getDataType(); - if (dataType != DataBuffer.TYPE_BYTE - && dataType != DataBuffer.TYPE_USHORT) { + if (dataType != DataBuffer.TYPE_BYTE && dataType != DataBuffer.TYPE_USHORT) { // awt.230=dataType is not one of the supported data types throw new IllegalArgumentException(Messages.getString("awt.230")); //$NON-NLS-1$ } @@ -317,35 +352,38 @@ public class Raster { throw new NullPointerException(Messages.getString("awt.27B")); //$NON-NLS-1$ } - PixelInterleavedSampleModel sampleModel = - new PixelInterleavedSampleModel(dataType, w, h, - pixelStride, scanlineStride, bandOffsets); + PixelInterleavedSampleModel sampleModel = new PixelInterleavedSampleModel(dataType, w, h, + pixelStride, scanlineStride, bandOffsets); return new OrdinaryWritableRaster(sampleModel, dataBuffer, location); } /** - * Creates a Raster object with a PixelInterleavedSampleModel - * and the specified data type. The Data type can be one of the - * following values: - * TYPE_BYTE, TYPE_USHORT, or TYPE_INT. - * - * @param dataType the data type of the samples: - * TYPE_BYTE, TYPE_USHORT, or TYPE_INT. - * @param w the width of image data. - * @param h the height of image data. - * @param scanlineStride the scanline stride of the image data. - * @param pixelStride the pixel stride of image data. - * @param bandOffsets the band offsets of bands. - * @param location the location which defines the upper left corner - * of the Raster. - * + * Creates a Raster object with a PixelInterleavedSampleModel and the + * specified data type. The Data type can be one of the following values: + * TYPE_BYTE, TYPE_USHORT, or TYPE_INT. + * + * @param dataType + * the data type of the samples: TYPE_BYTE, TYPE_USHORT, or + * TYPE_INT. + * @param w + * the width of image data. + * @param h + * the height of image data. + * @param scanlineStride + * the scanline stride of the image data. + * @param pixelStride + * the pixel stride of image data. + * @param bandOffsets + * the band offsets of bands. + * @param location + * the location which defines the upper left corner of the + * Raster. * @return the WritableRaster object. */ - public static WritableRaster createInterleavedRaster(int dataType, int w, - int h, int scanlineStride, int pixelStride, int bandOffsets[], - Point location) { + public static WritableRaster createInterleavedRaster(int dataType, int w, int h, + int scanlineStride, int pixelStride, int bandOffsets[], Point location) { if (w <= 0 || h <= 0) { // awt.22E=w or h is less than or equal to zero @@ -356,14 +394,13 @@ public class Raster { location = new Point(0, 0); } - if ((long) location.x + w > Integer.MAX_VALUE - || (long) location.y + h > Integer.MAX_VALUE) { - // awt.276=location.x + w or location.y + h results in integer overflow + if ((long)location.x + w > Integer.MAX_VALUE || (long)location.y + h > Integer.MAX_VALUE) { + // awt.276=location.x + w or location.y + h results in integer + // overflow throw new RasterFormatException(Messages.getString("awt.276")); //$NON-NLS-1$ } - if (dataType != DataBuffer.TYPE_BYTE - && dataType != DataBuffer.TYPE_USHORT) { + if (dataType != DataBuffer.TYPE_BYTE && dataType != DataBuffer.TYPE_USHORT) { // awt.230=dataType is not one of the supported data types throw new IllegalArgumentException(Messages.getString("awt.230")); //$NON-NLS-1$ } @@ -383,36 +420,38 @@ public class Raster { DataBuffer data = null; switch (dataType) { - case DataBuffer.TYPE_BYTE: - data = new DataBufferByte(size); - break; - case DataBuffer.TYPE_USHORT: - data = new DataBufferUShort(size); - break; + case DataBuffer.TYPE_BYTE: + data = new DataBufferByte(size); + break; + case DataBuffer.TYPE_USHORT: + data = new DataBufferUShort(size); + break; } - return createInterleavedRaster(data, w, h, scanlineStride, pixelStride, - bandOffsets, location); + return createInterleavedRaster(data, w, h, scanlineStride, pixelStride, bandOffsets, + location); } /** - * Creates a Raster object with a PixelInterleavedSampleModel - * and the specified data type. The Data type can be one of the - * following values: - * TYPE_BYTE, TYPE_USHORT, or TYPE_INT. - * - * @param dataType the data type of samples: - * TYPE_BYTE, TYPE_USHORT, or TYPE_INT. - * @param w the width of image data. - * @param h the height of image data. - * @param bands the number of bands. - * @param location the location which defines the upper left corner - * of the Raster. - * + * Creates a Raster object with a PixelInterleavedSampleModel and the + * specified data type. The Data type can be one of the following values: + * TYPE_BYTE, TYPE_USHORT, or TYPE_INT. + * + * @param dataType + * the data type of samples: TYPE_BYTE, TYPE_USHORT, or TYPE_INT. + * @param w + * the width of image data. + * @param h + * the height of image data. + * @param bands + * the number of bands. + * @param location + * the location which defines the upper left corner of the + * Raster. * @return the WritableRaster. */ - public static WritableRaster createInterleavedRaster(int dataType, int w, - int h, int bands, Point location) { + public static WritableRaster createInterleavedRaster(int dataType, int w, int h, int bands, + Point location) { if (w <= 0 || h <= 0) { // awt.22E=w or h is less than or equal to zero @@ -423,14 +462,13 @@ public class Raster { location = new Point(0, 0); } - if ((long) location.x + w > Integer.MAX_VALUE - || (long) location.y + h > Integer.MAX_VALUE) { - // awt.276=location.x + w or location.y + h results in integer overflow + if ((long)location.x + w > Integer.MAX_VALUE || (long)location.y + h > Integer.MAX_VALUE) { + // awt.276=location.x + w or location.y + h results in integer + // overflow throw new RasterFormatException(Messages.getString("awt.276")); //$NON-NLS-1$ } - if (dataType != DataBuffer.TYPE_BYTE - && dataType != DataBuffer.TYPE_USHORT) { + if (dataType != DataBuffer.TYPE_BYTE && dataType != DataBuffer.TYPE_USHORT) { // awt.230=dataType is not one of the supported data types throw new IllegalArgumentException(Messages.getString("awt.230")); //$NON-NLS-1$ } @@ -440,26 +478,30 @@ public class Raster { bandOffsets[i] = i; } - return createInterleavedRaster(dataType, w, h, w * bands, bands, - bandOffsets, location); + return createInterleavedRaster(dataType, w, h, w * bands, bands, bandOffsets, location); } /** - * Creates a Raster object with a SinglePixelPackedSampleModel - * and the specified DataBuffer. - * - * @param dataBuffer the DataBuffer. - * @param w the width of the image data. - * @param h the height of the image data. - * @param scanlineStride the scanline stride of the image data. - * @param bandMasks the band masks. - * @param location the location which defines the upper left corner - * of the Raster. - * + * Creates a Raster object with a SinglePixelPackedSampleModel and the + * specified DataBuffer. + * + * @param dataBuffer + * the DataBuffer. + * @param w + * the width of the image data. + * @param h + * the height of the image data. + * @param scanlineStride + * the scanline stride of the image data. + * @param bandMasks + * the band masks. + * @param location + * the location which defines the upper left corner of the + * Raster. * @return the WritableRaster. */ - public static WritableRaster createPackedRaster(DataBuffer dataBuffer, - int w, int h, int scanlineStride, int bandMasks[], Point location) { + public static WritableRaster createPackedRaster(DataBuffer dataBuffer, int w, int h, + int scanlineStride, int bandMasks[], Point location) { if (dataBuffer == null) { // awt.278=dataBuffer is null throw new NullPointerException(Messages.getString("awt.278")); //$NON-NLS-1$ @@ -474,9 +516,9 @@ public class Raster { location = new Point(0, 0); } - if ((long) location.x + w > Integer.MAX_VALUE - || (long) location.y + h > Integer.MAX_VALUE) { - // awt.276=location.x + w or location.y + h results in integer overflow + if ((long)location.x + w > Integer.MAX_VALUE || (long)location.y + h > Integer.MAX_VALUE) { + // awt.276=location.x + w or location.y + h results in integer + // overflow throw new RasterFormatException(Messages.getString("awt.276")); //$NON-NLS-1$ } @@ -491,35 +533,37 @@ public class Raster { } int dataType = dataBuffer.getDataType(); - if (dataType != DataBuffer.TYPE_BYTE - && dataType != DataBuffer.TYPE_USHORT + if (dataType != DataBuffer.TYPE_BYTE && dataType != DataBuffer.TYPE_USHORT && dataType != DataBuffer.TYPE_INT) { // awt.230=dataType is not one of the supported data types throw new IllegalArgumentException(Messages.getString("awt.230")); //$NON-NLS-1$ } - SinglePixelPackedSampleModel sampleModel = - new SinglePixelPackedSampleModel(dataType, w, h, - scanlineStride, bandMasks); + SinglePixelPackedSampleModel sampleModel = new SinglePixelPackedSampleModel(dataType, w, h, + scanlineStride, bandMasks); return new OrdinaryWritableRaster(sampleModel, dataBuffer, location); } /** - * Creates a Raster object with a MultiPixelPackedSampleModel - * and the specified DataBuffer. - * - * @param dataBuffer the DataBuffer. - * @param w the width of the image data. - * @param h the height of the image data. - * @param bitsPerPixel the number of bits per pixel. - * @param location the location which defines the upper left corner - * of the Raster. - * + * Creates a Raster object with a MultiPixelPackedSampleModel and the + * specified DataBuffer. + * + * @param dataBuffer + * the DataBuffer. + * @param w + * the width of the image data. + * @param h + * the height of the image data. + * @param bitsPerPixel + * the number of bits per pixel. + * @param location + * the location which defines the upper left corner of the + * Raster. * @return the WritableRaster. */ - public static WritableRaster createPackedRaster(DataBuffer dataBuffer, - int w, int h, int bitsPerPixel, Point location) { + public static WritableRaster createPackedRaster(DataBuffer dataBuffer, int w, int h, + int bitsPerPixel, Point location) { if (w <= 0 || h <= 0) { // awt.22E=w or h is less than or equal to zero @@ -530,9 +574,9 @@ public class Raster { location = new Point(0, 0); } - if ((long) location.x + w > Integer.MAX_VALUE - || (long) location.y + h > Integer.MAX_VALUE) { - // awt.276=location.x + w or location.y + h results in integer overflow + if ((long)location.x + w > Integer.MAX_VALUE || (long)location.y + h > Integer.MAX_VALUE) { + // awt.276=location.x + w or location.y + h results in integer + // overflow throw new RasterFormatException(Messages.getString("awt.276")); //$NON-NLS-1$ } @@ -547,37 +591,40 @@ public class Raster { } int dataType = dataBuffer.getDataType(); - if (dataType != DataBuffer.TYPE_BYTE - && dataType != DataBuffer.TYPE_USHORT + if (dataType != DataBuffer.TYPE_BYTE && dataType != DataBuffer.TYPE_USHORT && dataType != DataBuffer.TYPE_INT) { // awt.230=dataType is not one of the supported data types throw new IllegalArgumentException(Messages.getString("awt.230")); //$NON-NLS-1$ } - MultiPixelPackedSampleModel sampleModel = - new MultiPixelPackedSampleModel(dataType, w, h, bitsPerPixel); + MultiPixelPackedSampleModel sampleModel = new MultiPixelPackedSampleModel(dataType, w, h, + bitsPerPixel); return new OrdinaryWritableRaster(sampleModel, dataBuffer, location); } /** - * Creates a Raster object with a MultiPixelPackedSampleModel - * and the specified DataBuffer. - * - * @param dataType the data type of samples: - * TYPE_BYTE, TYPE_USHORT, or TYPE_INT. - * @param w the width of the image data. - * @param h the height of the image data. - * @param bands the number of bands. - * @param bitsPerBand the number of bits per band. - * @param location the location which defines the upper left corner - * of the Raster. - * + * Creates a Raster object with a MultiPixelPackedSampleModel and the + * specified DataBuffer. + * + * @param dataType + * the data type of samples: TYPE_BYTE, TYPE_USHORT, or TYPE_INT. + * @param w + * the width of the image data. + * @param h + * the height of the image data. + * @param bands + * the number of bands. + * @param bitsPerBand + * the number of bits per band. + * @param location + * the location which defines the upper left corner of the + * Raster. * @return the WritableRaster. */ - public static WritableRaster createPackedRaster(int dataType, int w, int h, - int bands, int bitsPerBand, Point location) { + public static WritableRaster createPackedRaster(int dataType, int w, int h, int bands, + int bitsPerBand, Point location) { if (w <= 0 || h <= 0) { // awt.22E=w or h is less than or equal to zero @@ -588,9 +635,9 @@ public class Raster { location = new Point(0, 0); } - if ((long) location.x + w > Integer.MAX_VALUE - || (long) location.y + h > Integer.MAX_VALUE) { - // awt.276=location.x + w or location.y + h results in integer overflow + if ((long)location.x + w > Integer.MAX_VALUE || (long)location.y + h > Integer.MAX_VALUE) { + // awt.276=location.x + w or location.y + h results in integer + // overflow throw new RasterFormatException(Messages.getString("awt.276")); //$NON-NLS-1$ } @@ -599,15 +646,15 @@ public class Raster { throw new IllegalArgumentException(Messages.getString("awt.27D")); //$NON-NLS-1$ } - if (dataType != DataBuffer.TYPE_BYTE - && dataType != DataBuffer.TYPE_USHORT + if (dataType != DataBuffer.TYPE_BYTE && dataType != DataBuffer.TYPE_USHORT && dataType != DataBuffer.TYPE_INT) { // awt.230=dataType is not one of the supported data types throw new IllegalArgumentException(Messages.getString("awt.230")); //$NON-NLS-1$ } if (bitsPerBand * bands > DataBuffer.getDataTypeSize(dataType)) { - // awt.27E=The product of bitsPerBand and bands is greater than the number of bits held by dataType + // awt.27E=The product of bitsPerBand and bands is greater than the + // number of bits held by dataType throw new IllegalArgumentException(Messages.getString("awt.27E")); //$NON-NLS-1$ } @@ -623,43 +670,45 @@ public class Raster { return createPackedRaster(dataType, w, h, bandMasks, location); } DataBuffer data = null; - int size = ((bitsPerBand * w + - DataBuffer.getDataTypeSize(dataType) - 1) / - DataBuffer.getDataTypeSize(dataType)) * h; + int size = ((bitsPerBand * w + DataBuffer.getDataTypeSize(dataType) - 1) / DataBuffer + .getDataTypeSize(dataType)) + * h; switch (dataType) { - case DataBuffer.TYPE_BYTE: - data = new DataBufferByte(size); - break; - case DataBuffer.TYPE_USHORT: - data = new DataBufferUShort(size); - break; - case DataBuffer.TYPE_INT: - data = new DataBufferInt(size); - break; + case DataBuffer.TYPE_BYTE: + data = new DataBufferByte(size); + break; + case DataBuffer.TYPE_USHORT: + data = new DataBufferUShort(size); + break; + case DataBuffer.TYPE_INT: + data = new DataBufferInt(size); + break; } return createPackedRaster(data, w, h, bitsPerBand, location); } /** - * Creates a Raster object with a SinglePixelPackedSampleModel - * and the specified DataBuffer. - * - * @param dataType the data type of samples: - * TYPE_BYTE, TYPE_USHORT, or TYPE_INT. - * @param w the width of the image data. - * @param h the height of the image data. - * @param bandMasks the band masks. - * @param location the location which defines the upper left corner - * of the Raster. - * + * Creates a Raster object with a SinglePixelPackedSampleModel and the + * specified DataBuffer. + * + * @param dataType + * the data type of samples: TYPE_BYTE, TYPE_USHORT, or TYPE_INT. + * @param w + * the width of the image data. + * @param h + * the height of the image data. + * @param bandMasks + * the band masks. + * @param location + * the location which defines the upper left corner of the + * Raster. * @return the WritableRaster. */ - public static WritableRaster createPackedRaster(int dataType, int w, int h, - int bandMasks[], Point location) { - - if (dataType != DataBuffer.TYPE_BYTE - && dataType != DataBuffer.TYPE_USHORT + public static WritableRaster createPackedRaster(int dataType, int w, int h, int bandMasks[], + Point location) { + + if (dataType != DataBuffer.TYPE_BYTE && dataType != DataBuffer.TYPE_USHORT && dataType != DataBuffer.TYPE_INT) { // awt.230=dataType is not one of the supported data types throw new IllegalArgumentException(Messages.getString("awt.230")); //$NON-NLS-1$ @@ -674,9 +723,9 @@ public class Raster { location = new Point(0, 0); } - if ((long) location.x + w > Integer.MAX_VALUE - || (long) location.y + h > Integer.MAX_VALUE) { - // awt.276=location.x + w or location.y + h results in integer overflow + if ((long)location.x + w > Integer.MAX_VALUE || (long)location.y + h > Integer.MAX_VALUE) { + // awt.276=location.x + w or location.y + h results in integer + // overflow throw new RasterFormatException(Messages.getString("awt.276")); //$NON-NLS-1$ } @@ -688,15 +737,15 @@ public class Raster { DataBuffer data = null; switch (dataType) { - case DataBuffer.TYPE_BYTE: - data = new DataBufferByte(w * h); - break; - case DataBuffer.TYPE_USHORT: - data = new DataBufferUShort(w * h); - break; - case DataBuffer.TYPE_INT: - data = new DataBufferInt(w * h); - break; + case DataBuffer.TYPE_BYTE: + data = new DataBufferByte(w * h); + break; + case DataBuffer.TYPE_USHORT: + data = new DataBufferUShort(w * h); + break; + case DataBuffer.TYPE_INT: + data = new DataBufferInt(w * h); + break; } return createPackedRaster(data, w, h, w, bandMasks, location); @@ -705,15 +754,16 @@ public class Raster { /** * Creates a Raster object with the specified DataBuffer and SampleModel. * - * @param sm the specified SampleModel. - * @param db the specified DataBuffer. - * @param location the location which defines the upper left corner - * of the Raster. - * + * @param sm + * the specified SampleModel. + * @param db + * the specified DataBuffer. + * @param location + * the location which defines the upper left corner of the + * Raster. * @return the Raster. */ - public static Raster createRaster(SampleModel sm, DataBuffer db, - Point location) { + public static Raster createRaster(SampleModel sm, DataBuffer db, Point location) { if (sm == null || db == null) { // awt.27F=SampleModel or DataBuffer is null @@ -730,15 +780,16 @@ public class Raster { /** * Creates a WritableRaster with the specified SampleModel and DataBuffer. * - * @param sm the specified SampleModel. - * @param db the specified DataBuffer. - * @param location the location which defines the upper left corner - * of the Raster. - * + * @param sm + * the specified SampleModel. + * @param db + * the specified DataBuffer. + * @param location + * the location which defines the upper left corner of the + * Raster. * @return the WritableRaster. */ - public static WritableRaster createWritableRaster(SampleModel sm, - DataBuffer db, Point location) { + public static WritableRaster createWritableRaster(SampleModel sm, DataBuffer db, Point location) { if (sm == null || db == null) { // awt.27F=SampleModel or DataBuffer is null @@ -755,14 +806,14 @@ public class Raster { /** * Creates a WritableRaster with the specified SampleModel. * - * @param sm the specified SampleModel. - * @param location the location which defines the upper left corner - * of the Raster. - * + * @param sm + * the specified SampleModel. + * @param location + * the location which defines the upper left corner of the + * Raster. * @return the WritableRaster. */ - public static WritableRaster createWritableRaster(SampleModel sm, - Point location) { + public static WritableRaster createWritableRaster(SampleModel sm, Point location) { if (sm == null) { // awt.280=SampleModel is null @@ -780,34 +831,42 @@ public class Raster { * Instantiates a new Raster object with the specified SampleModel and * DataBuffer. * - * @param sampleModel the specified SampleModel. - * @param dataBuffer the specified DataBuffer. - * @param origin the specified origin. + * @param sampleModel + * the specified SampleModel. + * @param dataBuffer + * the specified DataBuffer. + * @param origin + * the specified origin. */ - protected Raster(SampleModel sampleModel, DataBuffer dataBuffer, - Point origin) { + protected Raster(SampleModel sampleModel, DataBuffer dataBuffer, Point origin) { - this(sampleModel, dataBuffer, new Rectangle(origin.x, origin.y, - sampleModel.getWidth(), sampleModel.getHeight()), origin, null); + this(sampleModel, dataBuffer, new Rectangle(origin.x, origin.y, sampleModel.getWidth(), + sampleModel.getHeight()), origin, null); } /** * Instantiates a new Raster object with the specified SampleModel, - * DataBuffer, rectangular region and parent Raster. - * - * @param sampleModel the specified SampleModel. - * @param dataBuffer the specified DataBuffer. - * @param aRegion the a rectangular region which defines the new image bounds. - * @param sampleModelTranslate this point defines the translation point - * from the SampleModel coordinates to the new Raster coordinates. - * @param parent the parent of this Raster. + * DataBuffer, rectangular region and parent Raster. + * + * @param sampleModel + * the specified SampleModel. + * @param dataBuffer + * the specified DataBuffer. + * @param aRegion + * the a rectangular region which defines the new image bounds. + * @param sampleModelTranslate + * this point defines the translation point from the SampleModel + * coordinates to the new Raster coordinates. + * @param parent + * the parent of this Raster. */ - protected Raster(SampleModel sampleModel, DataBuffer dataBuffer, - Rectangle aRegion, Point sampleModelTranslate, Raster parent) { + protected Raster(SampleModel sampleModel, DataBuffer dataBuffer, Rectangle aRegion, + Point sampleModelTranslate, Raster parent) { if (sampleModel == null || dataBuffer == null || aRegion == null || sampleModelTranslate == null) { - // awt.281=sampleModel, dataBuffer, aRegion or sampleModelTranslate is null + // awt.281=sampleModel, dataBuffer, aRegion or sampleModelTranslate + // is null throw new NullPointerException(Messages.getString("awt.281")); //$NON-NLS-1$ } @@ -816,27 +875,25 @@ public class Raster { throw new RasterFormatException(Messages.getString("awt.282")); //$NON-NLS-1$ } - if ((long) aRegion.x + (long) aRegion.width > Integer.MAX_VALUE) { + if ((long)aRegion.x + (long)aRegion.width > Integer.MAX_VALUE) { // awt.283=Overflow X coordinate of Raster throw new RasterFormatException(Messages.getString("awt.283")); //$NON-NLS-1$ } - if ((long) aRegion.y + (long) aRegion.height > Integer.MAX_VALUE) { + if ((long)aRegion.y + (long)aRegion.height > Integer.MAX_VALUE) { // awt.284=Overflow Y coordinate of Raster throw new RasterFormatException(Messages.getString("awt.284")); //$NON-NLS-1$ } - + if (sampleModel instanceof ComponentSampleModel) { validateDataBuffer(dataBuffer, aRegion.width, aRegion.height, - ((ComponentSampleModel) sampleModel).getScanlineStride()); + ((ComponentSampleModel)sampleModel).getScanlineStride()); } else if (sampleModel instanceof MultiPixelPackedSampleModel) { validateDataBuffer(dataBuffer, aRegion.width, aRegion.height, - ((MultiPixelPackedSampleModel) sampleModel) - .getScanlineStride()); + ((MultiPixelPackedSampleModel)sampleModel).getScanlineStride()); } else if (sampleModel instanceof SinglePixelPackedSampleModel) { validateDataBuffer(dataBuffer, aRegion.width, aRegion.height, - ((SinglePixelPackedSampleModel) sampleModel) - .getScanlineStride()); + ((SinglePixelPackedSampleModel)sampleModel).getScanlineStride()); } this.sampleModel = sampleModel; @@ -856,36 +913,44 @@ public class Raster { /** * Instantiates a new Raster with the specified SampleModel. * - * @param sampleModel the specified SampleModel. - * @param origin the origin. + * @param sampleModel + * the specified SampleModel. + * @param origin + * the origin. */ protected Raster(SampleModel sampleModel, Point origin) { - this(sampleModel, sampleModel.createDataBuffer(), new Rectangle( - origin.x, origin.y, sampleModel.getWidth(), sampleModel - .getHeight()), origin, null); + this(sampleModel, sampleModel.createDataBuffer(), new Rectangle(origin.x, origin.y, + sampleModel.getWidth(), sampleModel.getHeight()), origin, null); } /** * Creates the child of this Raster by sharing the specified rectangular - * area in this Raste. The parentX, parentY, width - * and height parameters specify the rectangular area to be shared. - * - * @param parentX the X coordinate of the upper left corner of this Raster. - * @param parentY the Y coordinate of the upper left corner of this Raster. - * @param width the width of the child area. - * @param height the height of the child area. - * @param childMinX the X coordinate of child area mapped to the parentX - * coordinate. - * @param childMinY the Y coordinate of child area mapped to the parentY - * coordinate. - * @param bandList the array of band indicies. - * + * area in this raster. The parentX, parentY, width and height parameters + * specify the rectangular area to be shared. + * + * @param parentX + * the X coordinate of the upper left corner of this Raster. + * @param parentY + * the Y coordinate of the upper left corner of this Raster. + * @param width + * the width of the child area. + * @param height + * the height of the child area. + * @param childMinX + * the X coordinate of child area mapped to the parentX + * coordinate. + * @param childMinY + * the Y coordinate of child area mapped to the parentY + * coordinate. + * @param bandList + * the array of band indices. * @return the Raster. */ - public Raster createChild(int parentX, int parentY, int width, int height, - int childMinX, int childMinY, int bandList[]) { + public Raster createChild(int parentX, int parentY, int width, int height, int childMinX, + int childMinY, int bandList[]) { if (width <= 0 || height <= 0) { - // awt.285=Width or Height of child Raster is less than or equal to zero + // awt.285=Width or Height of child Raster is less than or equal to + // zero throw new RasterFormatException(Messages.getString("awt.285")); //$NON-NLS-1$ } @@ -899,22 +964,22 @@ public class Raster { throw new RasterFormatException(Messages.getString("awt.287")); //$NON-NLS-1$ } - if ((long) parentX + width > Integer.MAX_VALUE) { + if ((long)parentX + width > Integer.MAX_VALUE) { // awt.288=parentX + width results in integer overflow throw new RasterFormatException(Messages.getString("awt.288")); //$NON-NLS-1$ } - if ((long) parentY + height > Integer.MAX_VALUE) { + if ((long)parentY + height > Integer.MAX_VALUE) { // awt.289=parentY + height results in integer overflow throw new RasterFormatException(Messages.getString("awt.289")); //$NON-NLS-1$ } - if ((long) childMinX + width > Integer.MAX_VALUE) { + if ((long)childMinX + width > Integer.MAX_VALUE) { // awt.28A=childMinX + width results in integer overflow throw new RasterFormatException(Messages.getString("awt.28A")); //$NON-NLS-1$ } - if ((long) childMinY + height > Integer.MAX_VALUE) { + if ((long)childMinY + height > Integer.MAX_VALUE) { // awt.28B=childMinY + height results in integer overflow throw new RasterFormatException(Messages.getString("awt.28B")); //$NON-NLS-1$ } @@ -930,15 +995,14 @@ public class Raster { int childTranslateX = childMinX - parentX; int childTranslateY = childMinY - parentY; - return new Raster(childModel, dataBuffer, new Rectangle(childMinX, - childMinY, width, height), new Point(childTranslateX - + sampleModelTranslateX, childTranslateY - + sampleModelTranslateY), this); + return new Raster(childModel, dataBuffer, + new Rectangle(childMinX, childMinY, width, height), new Point(childTranslateX + + sampleModelTranslateX, childTranslateY + sampleModelTranslateY), this); } /** - * Create a compatible WritableRaster with the same parameters - * as this Raster. + * Create a compatible WritableRaster with the same parameters as this + * Raster. * * @return the WritableRaster. */ @@ -947,12 +1011,13 @@ public class Raster { } /** - * Create a compatible WritableRaster with the same parameters - * as this Raster and the specified size. - * - * @param w the width of the new WritableRaster. - * @param h the height of the new WritableRaster. + * Create a compatible WritableRaster with the same parameters as this + * Raster and the specified size. * + * @param w + * the width of the new WritableRaster. + * @param h + * the height of the new WritableRaster. * @return the WritableRaster. */ public WritableRaster createCompatibleWritableRaster(int w, int h) { @@ -967,18 +1032,20 @@ public class Raster { } /** - * Create a compatible WritableRaster with the same parameters - * as this Raster and the specified size and location. - * - * @param x the X coordinate of the new WritableRaster. - * @param y the Y coordinate of the new WritableRaster. - * @param w the width of the new WritableRaster. - * @param h the height of the new WritableRaster. - * + * Create a compatible WritableRaster with the same parameters as this + * Raster and the specified size and location. + * + * @param x + * the X coordinate of the new WritableRaster. + * @param y + * the Y coordinate of the new WritableRaster. + * @param w + * the width of the new WritableRaster. + * @param h + * the height of the new WritableRaster. * @return the WritableRaster. */ - public WritableRaster createCompatibleWritableRaster(int x, int y, int w, - int h) { + public WritableRaster createCompatibleWritableRaster(int x, int y, int w, int h) { WritableRaster raster = createCompatibleWritableRaster(w, h); @@ -986,12 +1053,12 @@ public class Raster { } /** - * Create a compatible WritableRaster with the same parameters - * as this Raster and the specified rectangle which determines - * new WritableRaster's location and size. - * - * @param rect the specified Rectangle. + * Create a compatible WritableRaster with the same parameters as this + * Raster and the specified rectangle which determines new WritableRaster's + * location and size. * + * @param rect + * the specified Rectangle. * @return the WritableRaster. */ public WritableRaster createCompatibleWritableRaster(Rectangle rect) { @@ -1000,23 +1067,21 @@ public class Raster { throw new NullPointerException(Messages.getString("awt.28C")); //$NON-NLS-1$ } - return createCompatibleWritableRaster(rect.x, rect.y, rect.width, - rect.height); + return createCompatibleWritableRaster(rect.x, rect.y, rect.width, rect.height); } /** - * Creates the translated child of this Raster. The New Raster - * object is a reference to the this Raster with a - * different location. - * - * @param childMinX the X coordinate of the new Raster. - * @param childMinY the Y coordinate of the new Raster. + * Creates the translated child of this Raster. The New Raster object is a + * reference to the this Raster with a different location. * + * @param childMinX + * the X coordinate of the new Raster. + * @param childMinY + * the Y coordinate of the new Raster. * @return the Raster. */ public Raster createTranslatedChild(int childMinX, int childMinY) { - return createChild(minX, minY, width, height, childMinX, childMinY, - null); + return createChild(minX, minY, width, height, childMinX, childMinY, null); } /** @@ -1038,41 +1103,46 @@ public class Raster { } /** - * Gets the data elements which represent the pixel data of the specified - * rectangle area as a primitive array. The following image data types - * are supported: DataBuffer.TYPE_BYTE, DataBuffer.TYPE_USHORT, - * DataBuffer.TYPE_INT, DataBuffer.TYPE_SHORT, DataBuffer.TYPE_FLOAT, - * or DataBuffer.TYPE_DOUBLE. - * - * @param x the X coordinate of the area of pixels. - * @param y the Y coordinate of the area of pixels. - * @param w the width of the area of pixels. - * @param h the height of the area of pixels. - * @param outData the resulting array. - * + * Gets the data elements which represent the pixel data of the specified + * rectangle area as a primitive array. The following image data types are + * supported: DataBuffer.TYPE_BYTE, DataBuffer.TYPE_USHORT, + * DataBuffer.TYPE_INT, DataBuffer.TYPE_SHORT, DataBuffer.TYPE_FLOAT, or + * DataBuffer.TYPE_DOUBLE. + * + * @param x + * the X coordinate of the area of pixels. + * @param y + * the Y coordinate of the area of pixels. + * @param w + * the width of the area of pixels. + * @param h + * the height of the area of pixels. + * @param outData + * the resulting array. * @return the data elements of the specified area of this Raster. */ public Object getDataElements(int x, int y, int w, int h, Object outData) { - return sampleModel.getDataElements(x - sampleModelTranslateX, y - - sampleModelTranslateY, w, h, outData, dataBuffer); + return sampleModel.getDataElements(x - sampleModelTranslateX, y - sampleModelTranslateY, w, + h, outData, dataBuffer); } /** - * Gets the data elements which represent the specified pixel of - * this Raster as a primitive array. The following image data types - * are supported: DataBuffer.TYPE_BYTE, DataBuffer.TYPE_USHORT, - * DataBuffer.TYPE_INT, DataBuffer.TYPE_SHORT, DataBuffer.TYPE_FLOAT, - * or DataBuffer.TYPE_DOUBLE. - * - * @param x the X coordinate of the pixel. - * @param y the Y coordinate of the pixel. - * @param outData the resulting data. - * + * Gets the data elements which represent the specified pixel of this Raster + * as a primitive array. The following image data types are supported: + * DataBuffer.TYPE_BYTE, DataBuffer.TYPE_USHORT, DataBuffer.TYPE_INT, + * DataBuffer.TYPE_SHORT, DataBuffer.TYPE_FLOAT, or DataBuffer.TYPE_DOUBLE. + * + * @param x + * the X coordinate of the pixel. + * @param y + * the Y coordinate of the pixel. + * @param outData + * the resulting data. * @return the data elements of the specified pixel of this Raster. */ public Object getDataElements(int x, int y, Object outData) { - return sampleModel.getDataElements(x - sampleModelTranslateX, y - - sampleModelTranslateY, outData, dataBuffer); + return sampleModel.getDataElements(x - sampleModelTranslateX, y - sampleModelTranslateY, + outData, dataBuffer); } /** @@ -1121,7 +1191,7 @@ public class Raster { } /** - * Gets the parent Raster for this Raster object. + * Gets the parent Raster for this Raster object. * * @return the parent Raster for this Raster object. */ @@ -1130,150 +1200,173 @@ public class Raster { } /** - * Gets a double array of samples for the specified pixel in this Raster. - * - * @param x the pixel's X coordinate. - * @param y the pixel's Y coordinate. - * @param dArray the double array where result array will be stored. - * - * @return the double array of samples for the specified pixel in - * this Raster. + * Gets a double array of samples for the specified pixel in this Raster. + * + * @param x + * the pixel's X coordinate. + * @param y + * the pixel's Y coordinate. + * @param dArray + * the double array where result array will be stored. + * @return the double array of samples for the specified pixel in this + * Raster. */ public double[] getPixel(int x, int y, double dArray[]) { - return sampleModel.getPixel(x - sampleModelTranslateX, y - - sampleModelTranslateY, dArray, dataBuffer); + return sampleModel.getPixel(x - sampleModelTranslateX, y - sampleModelTranslateY, dArray, + dataBuffer); } /** - * Gets a float array of samples for the specified pixel in this Raster. - * - * @param x the pixel's X coordinate. - * @param y the pixel's Y coordinate. - * @param fArray the float array where the result array will be stored. - * - * @return the float array of samples for the specified pixel in - * this Raster. + * Gets a float array of samples for the specified pixel in this Raster. + * + * @param x + * the pixel's X coordinate. + * @param y + * the pixel's Y coordinate. + * @param fArray + * the float array where the result array will be stored. + * @return the float array of samples for the specified pixel in this + * Raster. */ public float[] getPixel(int x, int y, float fArray[]) { - return sampleModel.getPixel(x - sampleModelTranslateX, y - - sampleModelTranslateY, fArray, dataBuffer); + return sampleModel.getPixel(x - sampleModelTranslateX, y - sampleModelTranslateY, fArray, + dataBuffer); } /** - * Gets an int array of samples for the specified pixel in this Raster. - * - * @param x the pixel's X coordinate. - * @param y the pixel's Y coordinate. - * @param iArray the int array where the result array will be stored. - * - * @return the int array of samples for the specified pixel in - * this Raster. + * Gets an integer array of samples for the specified pixel in this Raster. + * + * @param x + * the pixel's X coordinate. + * @param y + * the pixel's Y coordinate. + * @param iArray + * the integer array where the result array will be stored. + * @return the integer array of samples for the specified pixel in this + * Raster. */ public int[] getPixel(int x, int y, int iArray[]) { - return sampleModel.getPixel(x - sampleModelTranslateX, y - - sampleModelTranslateY, iArray, dataBuffer); + return sampleModel.getPixel(x - sampleModelTranslateX, y - sampleModelTranslateY, iArray, + dataBuffer); } /** - * Gets an double array of samples for the specified rectangular - * area of pixels in this Raster. - * - * @param x the X coordinate of the area of pixels. - * @param y the Y coordinate of the area of pixels. - * @param w the width of the area of pixels. - * @param h the height of the area of pixels. - * @param dArray the resulting array. - * - * @return the double array of samples for the specified rectangular - * area of pixels in this Raster. + * Gets an double array of samples for the specified rectangular area of + * pixels in this Raster. + * + * @param x + * the X coordinate of the area of pixels. + * @param y + * the Y coordinate of the area of pixels. + * @param w + * the width of the area of pixels. + * @param h + * the height of the area of pixels. + * @param dArray + * the resulting array. + * @return the double array of samples for the specified rectangular area of + * pixels in this Raster. */ public double[] getPixels(int x, int y, int w, int h, double dArray[]) { - return sampleModel.getPixels(x - sampleModelTranslateX, y - - sampleModelTranslateY, w, h, dArray, dataBuffer); + return sampleModel.getPixels(x - sampleModelTranslateX, y - sampleModelTranslateY, w, h, + dArray, dataBuffer); } /** - * Gets an float array of samples for the specified rectangular - * area of pixels in this Raster. - * - * @param x the X coordinate of the area of pixels. - * @param y the Y coordinate of the area of pixels. - * @param w the width of the area of pixels. - * @param h the height of the area of pixels. - * @param fArray the resulting array. - * - * @return the float array of samples for the specified rectangular - * area of pixels in this Raster. + * Gets an float array of samples for the specified rectangular area of + * pixels in this Raster. + * + * @param x + * the X coordinate of the area of pixels. + * @param y + * the Y coordinate of the area of pixels. + * @param w + * the width of the area of pixels. + * @param h + * the height of the area of pixels. + * @param fArray + * the resulting array. + * @return the float array of samples for the specified rectangular area of + * pixels in this Raster. */ public float[] getPixels(int x, int y, int w, int h, float fArray[]) { - return sampleModel.getPixels(x - sampleModelTranslateX, y - - sampleModelTranslateY, w, h, fArray, dataBuffer); + return sampleModel.getPixels(x - sampleModelTranslateX, y - sampleModelTranslateY, w, h, + fArray, dataBuffer); } /** - * Gets an int array of samples for the specified rectangular - * area of pixels in this Raster. - * - * @param x the X coordinate of the area of pixels. - * @param y the Y coordinate of the area of pixels. - * @param w the width of pixel's the area of pixels. - * @param h the height of pixel's the area of pixels. - * @param iArray the resulting array. - * - * @return the int array of samples for the specified rectangular - * area of pixels in this Raster. + * Gets an integer array of samples for the specified rectangular area of + * pixels in this raster. + * + * @param x + * the X coordinate of the area of pixels. + * @param y + * the Y coordinate of the area of pixels. + * @param w + * the width of pixel's the area of pixels. + * @param h + * the height of pixel's the area of pixels. + * @param iArray + * the resulting array. + * @return the integer array of samples for the specified rectangular area + * of pixels in this Raster. */ public int[] getPixels(int x, int y, int w, int h, int iArray[]) { - return sampleModel.getPixels(x - sampleModelTranslateX, y - - sampleModelTranslateY, w, h, iArray, dataBuffer); + return sampleModel.getPixels(x - sampleModelTranslateX, y - sampleModelTranslateY, w, h, + iArray, dataBuffer); } /** - * Gets the sample for the specified band of the specified - * pixel as an int. - * - * @param x the X coordinate of the pixel. - * @param y the Y coordinate of the pixel. - * @param b the band. - * - * @return the sample for the specified band of the specified - * pixel as an int. + * Gets the sample for the specified band of the specified pixel as an + * integer. + * + * @param x + * the X coordinate of the pixel. + * @param y + * the Y coordinate of the pixel. + * @param b + * the band. + * @return the sample for the specified band of the specified pixel as an + * integer. */ public int getSample(int x, int y, int b) { - return sampleModel.getSample(x - sampleModelTranslateX, y - - sampleModelTranslateY, b, dataBuffer); + return sampleModel.getSample(x - sampleModelTranslateX, y - sampleModelTranslateY, b, + dataBuffer); } /** - * Gets the sample for the specified band of the specified - * pixel as a double. - * - * @param x the X coordinate of the pixel. - * @param y the Y coordinate of the pixel. - * @param b the band. - * - * @return the sample for the specified band of the specified - * pixel as a double. + * Gets the sample for the specified band of the specified pixel as a + * double. + * + * @param x + * the X coordinate of the pixel. + * @param y + * the Y coordinate of the pixel. + * @param b + * the band. + * @return the sample for the specified band of the specified pixel as a + * double. */ public double getSampleDouble(int x, int y, int b) { - return sampleModel.getSampleDouble(x - sampleModelTranslateX, y - - sampleModelTranslateY, b, dataBuffer); + return sampleModel.getSampleDouble(x - sampleModelTranslateX, y - sampleModelTranslateY, b, + dataBuffer); } /** - * Gets the sample for the specified band of the specified - * pixel as a float. - * - * @param x the X coordinate of the pixel. - * @param y the Y coordinate of the pixel. - * @param b the band. - * - * @return the sample for the specified band of the specified - * pixel as a float. + * Gets the sample for the specified band of the specified pixel as a float. + * + * @param x + * the X coordinate of the pixel. + * @param y + * the Y coordinate of the pixel. + * @param b + * the band. + * @return the sample for the specified band of the specified pixel as a + * float. */ public float getSampleFloat(int x, int y, int b) { - return sampleModel.getSampleFloat(x - sampleModelTranslateX, y - - sampleModelTranslateY, b, dataBuffer); + return sampleModel.getSampleFloat(x - sampleModelTranslateX, y - sampleModelTranslateY, b, + dataBuffer); } /** @@ -1286,97 +1379,105 @@ public class Raster { } /** - * Gets the translation of the X coordinate from the SampleModel - * coordinate system to the Rasters's coordinate system. + * Gets the translation of the X coordinate from the SampleModel coordinate + * system to the Rasters's coordinate system. * - * @return the value of the translation of the X coordinate from - * the SampleModel coordinate system to the Rasters's - * coordinate system. + * @return the value of the translation of the X coordinate from the + * SampleModel coordinate system to the Rasters's coordinate system. */ public final int getSampleModelTranslateX() { return sampleModelTranslateX; } /** - * Gets the translation of the Y coordinate from the SampleModel - * coordinate system to the Rasters's coordinate system. + * Gets the translation of the Y coordinate from the SampleModel coordinate + * system to the Rasters's coordinate system. * - * @return the value of the translation of the Y coordinate from - * the SampleModel coordinate system to the Rasters's - * coordinate system. - + * @return the value of the translation of the Y coordinate from the + * SampleModel coordinate system to the Rasters's coordinate system. */ public final int getSampleModelTranslateY() { return sampleModelTranslateY; } /** - * Gets the double array of samples for the specified band - * of the specified rectangular area of pixels in this Raster - * as a double array. - * - * @param x the X coordinate of the rectangular area of pixels. - * @param y the Y coordinate of the rectangular area of pixels. - * @param w the width of the rectangular area of pixels. - * @param h the height of the rectangular area of pixels. - * @param b the band. - * @param dArray the resulting double array. - * - * @return the double array of samples for the specified band - * of the specified rectangular area of pixels. + * Gets the double array of samples for the specified band of the specified + * rectangular area of pixels in this Raster as a double array. + * + * @param x + * the X coordinate of the rectangular area of pixels. + * @param y + * the Y coordinate of the rectangular area of pixels. + * @param w + * the width of the rectangular area of pixels. + * @param h + * the height of the rectangular area of pixels. + * @param b + * the band. + * @param dArray + * the resulting double array. + * @return the double array of samples for the specified band of the + * specified rectangular area of pixels. */ - public double[] getSamples(int x, int y, int w, int h, int b, - double dArray[]) { + public double[] getSamples(int x, int y, int w, int h, int b, double dArray[]) { - return sampleModel.getSamples(x - sampleModelTranslateX, y - - sampleModelTranslateY, w, h, b, dArray, dataBuffer); + return sampleModel.getSamples(x - sampleModelTranslateX, y - sampleModelTranslateY, w, h, + b, dArray, dataBuffer); } /** - * Gets the float array of samples for the specified band - * of the specified rectangular area of pixels in this Raster - * as a float array. - * - * @param x the X coordinate of the rectangular area of pixels. - * @param y the Y coordinate of the rectangular area of pixels. - * @param w the width of the rectangular area of pixels. - * @param h the height of the rectangular area of pixels. - * @param b the band. - * @param fArray the resulting float array. - * - * @return the float array of samples for the specified band - * of the specified rectangular area of pixels. + * Gets the float array of samples for the specified band of the specified + * rectangular area of pixels in this Raster as a float array. + * + * @param x + * the X coordinate of the rectangular area of pixels. + * @param y + * the Y coordinate of the rectangular area of pixels. + * @param w + * the width of the rectangular area of pixels. + * @param h + * the height of the rectangular area of pixels. + * @param b + * the band. + * @param fArray + * the resulting float array. + * @return the float array of samples for the specified band of the + * specified rectangular area of pixels. */ public float[] getSamples(int x, int y, int w, int h, int b, float fArray[]) { - return sampleModel.getSamples(x - sampleModelTranslateX, y - - sampleModelTranslateY, w, h, b, fArray, dataBuffer); + return sampleModel.getSamples(x - sampleModelTranslateX, y - sampleModelTranslateY, w, h, + b, fArray, dataBuffer); } /** - * Gets the int array of samples for the specified band - * of the specified rectangular area of pixels in this Raster - * as a int array. - * - * @param x the X coordinate of the rectangular area of pixels. - * @param y the Y coordinate of the rectangular area of pixels. - * @param w the width of the rectangular area of pixels. - * @param h the height of the rectangular area of pixels. - * @param b the band. - * @param iArray the resulting int array. - * - * @return the int array of samples for the specified band - * of the specified rectangular area of pixels. + * Gets the integer array of samples for the specified band of the specified + * rectangular area of pixels in this Raster as a integer array. + * + * @param x + * the X coordinate of the rectangular area of pixels. + * @param y + * the Y coordinate of the rectangular area of pixels. + * @param w + * the width of the rectangular area of pixels. + * @param h + * the height of the rectangular area of pixels. + * @param b + * the band. + * @param iArray + * the resulting integer array. + * @return the integer array of samples for the specified band of the + * specified rectangular area of pixels. */ public int[] getSamples(int x, int y, int w, int h, int b, int iArray[]) { - return sampleModel.getSamples(x - sampleModelTranslateX, y - - sampleModelTranslateY, w, h, b, iArray, dataBuffer); + return sampleModel.getSamples(x - sampleModelTranslateX, y - sampleModelTranslateY, w, h, + b, iArray, dataBuffer); } /** * Gets the transfer type for pixels of this Raster. - * @see SampleModel#getTransferType() * + * @see SampleModel#getTransferType() * @return the transfer type for pixels of this Raster. */ public final int getTransferType() { @@ -1395,18 +1496,20 @@ public class Raster { /** * Validate data buffer. * - * @param dataBuffer the data buffer - * @param w the w - * @param h the h - * @param scanlineStride the scanline stride + * @param dataBuffer + * the data buffer. + * @param w + * the w. + * @param h + * the h. + * @param scanlineStride + * the scanline stride. */ - private static void validateDataBuffer(final DataBuffer dataBuffer, final int w, - final int h, final int scanlineStride) { + private static void validateDataBuffer(final DataBuffer dataBuffer, final int w, final int h, + final int scanlineStride) { if (dataBuffer.getSize() < (scanlineStride * (h - 1) + w - 1)) { // awt.298=dataBuffer is too small throw new RasterFormatException(Messages.getString("awt.298")); //$NON-NLS-1$ } } } - - diff --git a/awt/java/awt/image/RasterFormatException.java b/awt/java/awt/image/RasterFormatException.java index 8577dad4b075d0d5ccb56d1fd6a903b587994bed..c667141ff52f4acb7c4c426a6323adfaa1b8976e 100644 --- a/awt/java/awt/image/RasterFormatException.java +++ b/awt/java/awt/image/RasterFormatException.java @@ -18,28 +18,31 @@ * @author Igor V. Stolyarov * @version $Revision$ */ -package java.awt.image; +package java.awt.image; /** - * The RasterFormatException class represents the exception - * that is thrown when there's an invalid layout - * in the Raster. + * The RasterFormatException class represents the exception that is thrown when + * there's an invalid layout in the Raster. + * + * @since Android 1.0 */ public class RasterFormatException extends RuntimeException { - /** The Constant serialVersionUID. */ + /** + * The Constant serialVersionUID. + */ private static final long serialVersionUID = 96598996116164315L; /** - * Instantiates a new RasterFormatException with the - * specified detail message. + * Instantiates a new RasterFormatException with the specified detail + * message. * - * @param s the detail message. + * @param s + * the detail message. */ public RasterFormatException(String s) { super(s); } } - diff --git a/awt/java/awt/image/RasterOp.java b/awt/java/awt/image/RasterOp.java index e8933ee4b670427bb5926250448491ea5f0b016d..19a84c9df0ed1ed99eac43db83750cefdef80890 100644 --- a/awt/java/awt/image/RasterOp.java +++ b/awt/java/awt/image/RasterOp.java @@ -18,6 +18,7 @@ * @author Alexey A. Petrenko * @version $Revision$ */ + package java.awt.image; import java.awt.RenderingHints; @@ -25,20 +26,22 @@ import java.awt.geom.Point2D; import java.awt.geom.Rectangle2D; /** - * The RasterOp interface provides methods for performing transformations - * from source data to destination data for Raster objects. The source and - * destination objects should contain the appropriate number of bands for - * the particular classes which implement this interface. + * The RasterOp interface provides methods for performing transformations from + * source data to destination data for Raster objects. The source and + * destination objects should contain the appropriate number of bands for the + * particular classes which implement this interface. + * + * @since Android 1.0 */ public interface RasterOp { - + /** - * Creates a destination WritableRaster with the specified Raster; - * this destination image data is empty and has the correct size - * and number of bands. - * - * @param src the source Raster. + * Creates a destination WritableRaster with the specified Raster; this + * destination image data is empty and has the correct size and number of + * bands. * + * @param src + * the source Raster. * @return the WritableRaster. */ public WritableRaster createCompatibleDestRaster(Raster src); @@ -47,9 +50,10 @@ public interface RasterOp { * Performs a filter operation on the source Raster and stores the resulting * image data to the destination WritableRaster. * - * @param src the source Raster. - * @param dst the destination WritableRaster, where the result is stored. - * + * @param src + * the source Raster. + * @param dst + * the destination WritableRaster, where the result is stored. * @return the filtered WritableRaster. */ public WritableRaster filter(Raster src, WritableRaster dst); @@ -57,19 +61,20 @@ public interface RasterOp { /** * Gets the bounds of the filtered Raster. * - * @param src the source Raster to be filtered. - * + * @param src + * the source Raster to be filtered. * @return the rectangle bounds of the filtered Raster. */ public Rectangle2D getBounds2D(Raster src); /** - * Gets the point of the destination image which corresponds - * to the specified point in the source raster. - * - * @param srcPoint the point of the source raster. - * @param dstPoint the point where the result will be stored. + * Gets the point of the destination image which corresponds to the + * specified point in the source raster. * + * @param srcPoint + * the point of the source raster. + * @param dstPoint + * the point where the result will be stored. * @return the destination point. */ public Point2D getPoint2D(Point2D srcPoint, Point2D dstPoint); diff --git a/awt/java/awt/image/RenderedImage.java b/awt/java/awt/image/RenderedImage.java index db3a4c842dd4eb8cdfbd430a409f22f885c46369..5eafa649a15985fc612819ec2b69b7b2debe61fd 100644 --- a/awt/java/awt/image/RenderedImage.java +++ b/awt/java/awt/image/RenderedImage.java @@ -18,35 +18,37 @@ * @author Igor V. Stolyarov * @version $Revision$ */ + package java.awt.image; import java.awt.Rectangle; import java.util.Vector; /** - * The RenderedImage interface should be implemented by all objects which - * contains image data. The image data is represented as a single tile or - * an array of tiles. + * The RenderedImage interface should be implemented by all objects which + * contains image data. The image data is represented as a single tile or an + * array of tiles. + * + * @since Android 1.0 */ public interface RenderedImage { /** - * Gets the property with the specified name from the property set - * of this RenderedImage. - * - * @param name the property's name. + * Gets the property with the specified name from the property set of this + * RenderedImage. * + * @param name + * the property's name. * @return the property value corresponded to this property's name. */ public Object getProperty(String name); /** - * Copies the region of this RenderedImage to the specified - * WritableRaster. The bounds of the region are the bounds of the - * WritableRaster. - * - * @param raster the WritableRaster. + * Copies the region of this RenderedImage to the specified WritableRaster. + * The bounds of the region are the bounds of the WritableRaster. * + * @param raster + * the WritableRaster. * @return the created WritableRaster. */ public WritableRaster copyData(WritableRaster raster); @@ -54,19 +56,19 @@ public interface RenderedImage { /** * Gets the image data of the image's region as one tile. * - * @param rect the rectangular region of RenderedImage. - * + * @param rect + * the rectangular region of RenderedImage. * @return the image data of the image's region as one tile. */ public Raster getData(Rectangle rect); /** - * Gets all RenderedImage objects which are the source of this - * RenderedImage object. + * Gets all RenderedImage objects which are the source of this RenderedImage + * object. * - * @return a Vector of RenderedImage objects which are the source - * of this RenderedImage object or null, if there is no information - * about them. + * @return a Vector of RenderedImage objects which are the source of this + * RenderedImage object or null, if there is no information about + * them. */ public Vector getSources(); @@ -85,14 +87,13 @@ public interface RenderedImage { public SampleModel getSampleModel(); /** - * Gets the tile corresponded to the specified indices in the tile - * array. - * - * @param tileX the X index of the tile. - * @param tileY the Y index of the tile. + * Gets the tile corresponded to the specified indices in the tile array. * - * @return the tile corresponded to the specified indices in the tile - * array. + * @param tileX + * the X index of the tile. + * @param tileY + * the Y index of the tile. + * @return the tile corresponded to the specified indices in the tile array. */ public Raster getTile(int tileX, int tileY); @@ -195,4 +196,3 @@ public interface RenderedImage { public int getHeight(); } - diff --git a/awt/java/awt/image/ReplicateScaleFilter.java b/awt/java/awt/image/ReplicateScaleFilter.java index 9298125e0de24c8aa99d54017d8943e8650580bf..51c0f4994200bb365634c2178debbc29b34ee1bd 100644 --- a/awt/java/awt/image/ReplicateScaleFilter.java +++ b/awt/java/awt/image/ReplicateScaleFilter.java @@ -18,53 +18,69 @@ * @author Igor V. Stolyarov * @version $Revision$ */ + package java.awt.image; import java.util.Hashtable; import org.apache.harmony.awt.internal.nls.Messages; - /** - * The ReplicateScaleFilter class scales an source image - * by replicating rows and columns of pixels to scale up or - * omitting rows and columns of pixels to scale down. + * The ReplicateScaleFilter class scales an source image by replicating rows and + * columns of pixels to scale up or omitting rows and columns of pixels to scale + * down. + * + * @since Android 1.0 */ public class ReplicateScaleFilter extends ImageFilter { - /** The width of a source image. */ + /** + * The width of a source image. + */ protected int srcWidth; - /** The height of a source image. */ + /** + * The height of a source image. + */ protected int srcHeight; - /** The width of a destination image. */ + /** + * The width of a destination image. + */ protected int destWidth; - /** The height of a destination image. */ + /** + * The height of a destination image. + */ protected int destHeight; - /** The int array of source rows. */ + /** + * The integer array of source rows. + */ protected int[] srcrows; - /** The int array of source columns. */ + /** + * The integer array of source columns. + */ protected int[] srccols; - /** - * An Object (byte array with a destination width) provides - * a row of pixel data to the ImageConsumer. + /** + * An Object (byte array with a destination width) provides a row of pixel + * data to the ImageConsumer. */ protected Object outpixbuf; /** - * Instantiates a new ReplicateScaleFilter that filters - * the image with the specified width and height. + * Instantiates a new ReplicateScaleFilter that filters the image with the + * specified width and height. * - * @param width the width of scaled image. - * @param height the height of scaled image. + * @param width + * the width of scaled image. + * @param height + * the height of scaled image. */ public ReplicateScaleFilter(int width, int height) { - if(width == 0 || height == 0) { + if (width == 0 || height == 0) { // awt.234=Width or Height equals zero throw new IllegalArgumentException(Messages.getString("awt.234")); //$NON-NLS-1$ } @@ -77,40 +93,40 @@ public class ReplicateScaleFilter extends ImageFilter { @Override public void setProperties(Hashtable props) { Hashtable fprops; - if(props == null) { + if (props == null) { fprops = new Hashtable(); } else { - fprops = (Hashtable) props.clone(); + fprops = (Hashtable)props.clone(); } String propName = "Rescale Filters"; //$NON-NLS-1$ - String prop = "destWidth=" + destWidth + "; " + //$NON-NLS-1$ //$NON-NLS-2$ - "destHeight=" + destHeight; //$NON-NLS-1$ + String prop = "destWidth=" + destWidth + "; " + //$NON-NLS-1$ //$NON-NLS-2$ + "destHeight=" + destHeight; //$NON-NLS-1$ Object o = fprops.get(propName); - if(o != null){ - if(o instanceof String){ + if (o != null) { + if (o instanceof String) { prop = (String)o + "; " + prop; //$NON-NLS-1$ - }else{ - prop = o.toString() + "; " + prop; //$NON-NLS-1$ + } else { + prop = o.toString() + "; " + prop; //$NON-NLS-1$ } } fprops.put(propName, prop); consumer.setProperties(fprops); - } + } // setPixels methods produce pixels according to Java API Spacification @Override - public void setPixels(int x, int y, int w, int h, - ColorModel model, int[] pixels, int off, int scansize) { - - if(srccols == null) { + public void setPixels(int x, int y, int w, int h, ColorModel model, int[] pixels, int off, + int scansize) { + + if (srccols == null) { initArrays(); } int buff[]; - if(outpixbuf == null || !(outpixbuf instanceof int[])){ + if (outpixbuf == null || !(outpixbuf instanceof int[])) { buff = new int[destWidth]; outpixbuf = buff; - }else{ + } else { buff = (int[])outpixbuf; } @@ -121,32 +137,31 @@ public class ReplicateScaleFilter extends ImageFilter { int sx, sy, dx, dy; dy = dstY; - while((dy < destHeight) && ((sy = srcrows[dy]) < y + h)){ + while ((dy < destHeight) && ((sy = srcrows[dy]) < y + h)) { dx = dstX; int srcOff = off + (sy - y) * scansize; - while((dx < destWidth) && ((sx = srccols[dx]) < x + w)){ + while ((dx < destWidth) && ((sx = srccols[dx]) < x + w)) { buff[dx] = pixels[srcOff + (sx - x)]; dx++; } - consumer.setPixels(dstX, dy, dx - dstX, 1, model, buff, - dstX, destWidth); + consumer.setPixels(dstX, dy, dx - dstX, 1, model, buff, dstX, destWidth); dy++; } } @Override - public void setPixels(int x, int y, int w, int h, - ColorModel model, byte[] pixels, int off, int scansize) { - - if(srccols == null) { + public void setPixels(int x, int y, int w, int h, ColorModel model, byte[] pixels, int off, + int scansize) { + + if (srccols == null) { initArrays(); } byte buff[]; - if(outpixbuf == null || !(outpixbuf instanceof byte[])){ + if (outpixbuf == null || !(outpixbuf instanceof byte[])) { buff = new byte[destWidth]; outpixbuf = buff; - }else{ + } else { buff = (byte[])outpixbuf; } @@ -157,16 +172,15 @@ public class ReplicateScaleFilter extends ImageFilter { int sx, sy, dx, dy; dy = dstY; - while((dy < destHeight) && ((sy = srcrows[dy]) < y + h)){ + while ((dy < destHeight) && ((sy = srcrows[dy]) < y + h)) { dx = dstX; int srcOff = off + (sy - y) * scansize; - while((dx < destWidth) && ((sx = srccols[dx]) < x + w)){ + while ((dx < destWidth) && ((sx = srccols[dx]) < x + w)) { buff[dx] = pixels[srcOff + (sx - x)]; dx++; } - consumer.setPixels(dstX, dy, dx - dstX, 1, model, buff, - dstX, destWidth); + consumer.setPixels(dstX, dy, dx - dstX, 1, model, buff, dstX, destWidth); dy++; } } @@ -176,12 +190,12 @@ public class ReplicateScaleFilter extends ImageFilter { srcWidth = w; srcHeight = h; - if(destWidth < 0 && destHeight < 0){ + if (destWidth < 0 && destHeight < 0) { destWidth = srcWidth; destHeight = srcHeight; - }else if(destWidth < 0){ + } else if (destWidth < 0) { destWidth = destHeight * srcWidth / srcHeight; - }else if(destHeight < 0){ + } else if (destHeight < 0) { destHeight = destWidth * srcHeight / srcWidth; } consumer.setDimensions(destWidth, destHeight); @@ -190,24 +204,22 @@ public class ReplicateScaleFilter extends ImageFilter { /** * Initialization of srccols and srcrows arrays. */ - private void initArrays(){ + private void initArrays() { if ((destWidth < 0) || (destHeight < 0)) { throw new IndexOutOfBoundsException(); } - + srccols = new int[destWidth]; int ca = srcWidth >>> 1; - for(int i = 0; i < destWidth; i++){ + for (int i = 0; i < destWidth; i++) { srccols[i] = (i * srcWidth + ca) / destWidth; } srcrows = new int[destHeight]; int ra = srcHeight >>> 1; - for(int i = 0; i < destHeight; i++){ + for (int i = 0; i < destHeight; i++) { srcrows[i] = (i * srcHeight + ra) / destHeight; } } } - - diff --git a/awt/java/awt/image/RescaleOp.java b/awt/java/awt/image/RescaleOp.java index 0e96031cd8971ef11da1d2080ddbea706030bf81..d7e2bd7684a9c4e69ee92286ae97fff5d336761a 100644 --- a/awt/java/awt/image/RescaleOp.java +++ b/awt/java/awt/image/RescaleOp.java @@ -32,33 +32,43 @@ import org.apache.harmony.awt.gl.AwtImageBackdoorAccessor; import org.apache.harmony.awt.internal.nls.Messages; /** - * The Class RescaleOp performs rescaling of the source image data - * by multiplying the pixel values with a scale factor - * and then adding an offset. + * The Class RescaleOp performs rescaling of the source image data by + * multiplying the pixel values with a scale factor and then adding an offset. + * + * @since Android 1.0 */ public class RescaleOp implements BufferedImageOp, RasterOp { - - /** The scale factors. */ + + /** + * The scale factors. + */ private float scaleFactors[]; - - /** The offsets. */ + + /** + * The offsets. + */ private float offsets[]; - - /** The hints. */ + + /** + * The hints. + */ private RenderingHints hints; static { // TODO - //System.loadLibrary("imageops"); + // System.loadLibrary("imageops"); } /** - * Instantiates a new RescaleOp object with the specified - * scale factors and offsets. + * Instantiates a new RescaleOp object with the specified scale factors and + * offsets. * - * @param scaleFactors the array of scale factor values. - * @param offsets the array of offset values. - * @param hints the RenderingHints or null. + * @param scaleFactors + * the array of scale factor values. + * @param offsets + * the array of offset values. + * @param hints + * the RenderingHints or null. */ public RescaleOp(float[] scaleFactors, float[] offsets, RenderingHints hints) { int numFactors = Math.min(scaleFactors.length, offsets.length); @@ -73,12 +83,15 @@ public class RescaleOp implements BufferedImageOp, RasterOp { } /** - * Instantiates a new RescaleOp object with the specified - * scale factor and offset. + * Instantiates a new RescaleOp object with the specified scale factor and + * offset. * - * @param scaleFactor the scale factor. - * @param offset the offset. - * @param hints the RenderingHints or null. + * @param scaleFactor + * the scale factor. + * @param offset + * the offset. + * @param hints + * the RenderingHints or null. */ public RescaleOp(float scaleFactor, float offset, RenderingHints hints) { scaleFactors = new float[1]; @@ -106,9 +119,8 @@ public class RescaleOp implements BufferedImageOp, RasterOp { /** * Gets the scale factors of this RescaleOp. * - * @param scaleFactors the desired scale factors array will be copied - * to this array. - * + * @param scaleFactors + * the desired scale factors array will be copied to this array. * @return the scale factors array. */ public final float[] getScaleFactors(float[] scaleFactors) { @@ -124,8 +136,8 @@ public class RescaleOp implements BufferedImageOp, RasterOp { /** * Gets the offsets array of this RescaleOp. * - * @param offsets the desired offsets array will be copied to this array. - * + * @param offsets + * the desired offsets array will be copied to this array. * @return the offsets array of this RescaleOp. */ public final float[] getOffsets(float[] offsets) { @@ -168,17 +180,11 @@ public class RescaleOp implements BufferedImageOp, RasterOp { dstCM = ColorModel.getRGBdefault(); } - WritableRaster r = - dstCM.isCompatibleSampleModel(src.getSampleModel()) ? - src.getRaster().createCompatibleWritableRaster(src.getWidth(), src.getHeight()) : - dstCM.createCompatibleWritableRaster(src.getWidth(), src.getHeight()); - - return new BufferedImage( - dstCM, - r, - dstCM.isAlphaPremultiplied(), - null - ); + WritableRaster r = dstCM.isCompatibleSampleModel(src.getSampleModel()) ? src.getRaster() + .createCompatibleWritableRaster(src.getWidth(), src.getHeight()) : dstCM + .createCompatibleWritableRaster(src.getWidth(), src.getHeight()); + + return new BufferedImage(dstCM, r, dstCM.isAlphaPremultiplied(), null); } public final WritableRaster filter(Raster src, WritableRaster dst) { @@ -186,26 +192,25 @@ public class RescaleOp implements BufferedImageOp, RasterOp { dst = createCompatibleDestRaster(src); } else { if (src.getNumBands() != dst.getNumBands()) { - // awt.21D=Number of src bands ({0}) does not match number of dst bands ({1}) + // awt.21D=Number of src bands ({0}) does not match number of + // dst bands ({1}) throw new IllegalArgumentException(Messages.getString("awt.21D", //$NON-NLS-1$ src.getNumBands(), dst.getNumBands())); } } - if ( - this.scaleFactors.length != 1 && - this.scaleFactors.length != src.getNumBands() - ) { - // awt.21E=Number of scaling constants is not equal to the number of bands + if (this.scaleFactors.length != 1 && this.scaleFactors.length != src.getNumBands()) { + // awt.21E=Number of scaling constants is not equal to the number of + // bands throw new IllegalArgumentException(Messages.getString("awt.21E")); //$NON-NLS-1$ } // TODO - //if (ippFilter(src, dst, BufferedImage.TYPE_CUSTOM, false) != 0) - if (slowFilter(src, dst, false) != 0) { - // awt.21F=Unable to transform source - throw new ImagingOpException (Messages.getString("awt.21F")); //$NON-NLS-1$ - } + // if (ippFilter(src, dst, BufferedImage.TYPE_CUSTOM, false) != 0) + if (slowFilter(src, dst, false) != 0) { + // awt.21F=Unable to transform source + throw new ImagingOpException(Messages.getString("awt.21F")); //$NON-NLS-1$ + } return dst; } @@ -213,11 +218,13 @@ public class RescaleOp implements BufferedImageOp, RasterOp { /** * Slow filter. * - * @param src the src - * @param dst the dst - * @param skipAlpha the skip alpha - * - * @return the int + * @param src + * the src. + * @param dst + * the dst. + * @param skipAlpha + * the skip alpha. + * @return the int. */ private final int slowFilter(Raster src, WritableRaster dst, boolean skipAlpha) { SampleModel sm = src.getSampleModel(); @@ -235,7 +242,7 @@ public class RescaleOp implements BufferedImageOp, RasterOp { int[] masks = new int[numBands]; int[] sampleSizes = sm.getSampleSize(); - for (int i=0; i < numBands; i++){ + for (int i = 0; i < numBands; i++) { maxValues[i] = (1 << sampleSizes[i]) - 1; masks[i] = ~(maxValues[i]); } @@ -247,8 +254,8 @@ public class RescaleOp implements BufferedImageOp, RasterOp { // Cycle over pixels to be calculated if (skipAlpha) { // Always suppose that alpha channel is the last band if (scaleFactors.length > 1) { - for (int i = 0; i < pixels.length; ){ - for (int bandIdx = 0; bandIdx < numBands-1; bandIdx++, i++){ + for (int i = 0; i < pixels.length;) { + for (int bandIdx = 0; bandIdx < numBands - 1; bandIdx++, i++) { pixels[i] = pixels[i] * scaleFactors[bandIdx] + offsets[bandIdx]; // Check for overflow now if (((int)pixels[i] & masks[bandIdx]) != 0) { @@ -263,8 +270,8 @@ public class RescaleOp implements BufferedImageOp, RasterOp { i++; } } else { - for (int i = 0; i < pixels.length; ){ - for (int bandIdx = 0; bandIdx < numBands-1; bandIdx++, i++){ + for (int i = 0; i < pixels.length;) { + for (int bandIdx = 0; bandIdx < numBands - 1; bandIdx++, i++) { pixels[i] = pixels[i] * scaleFactors[0] + offsets[0]; // Check for overflow now if (((int)pixels[i] & masks[bandIdx]) != 0) { @@ -281,8 +288,8 @@ public class RescaleOp implements BufferedImageOp, RasterOp { } } else { if (scaleFactors.length > 1) { - for (int i = 0; i < pixels.length; ){ - for (int bandIdx = 0; bandIdx < numBands; bandIdx++, i++){ + for (int i = 0; i < pixels.length;) { + for (int bandIdx = 0; bandIdx < numBands; bandIdx++, i++) { pixels[i] = pixels[i] * scaleFactors[bandIdx] + offsets[bandIdx]; // Check for overflow now if (((int)pixels[i] & masks[bandIdx]) != 0) { @@ -295,8 +302,8 @@ public class RescaleOp implements BufferedImageOp, RasterOp { } } } else { - for (int i = 0; i < pixels.length; ){ - for (int bandIdx = 0; bandIdx < numBands; bandIdx++, i++){ + for (int i = 0; i < pixels.length;) { + for (int bandIdx = 0; bandIdx < numBands; bandIdx++, i++) { pixels[i] = pixels[i] * scaleFactors[0] + offsets[0]; // Check for overflow now if (((int)pixels[i] & masks[bandIdx]) != 0) { @@ -328,18 +335,20 @@ public class RescaleOp implements BufferedImageOp, RasterOp { int nComponents = srcCM.getNumComponents(); boolean skipAlpha; if (srcCM.hasAlpha()) { - if (scaleFactors.length == 1 || scaleFactors.length == nComponents-1) { + if (scaleFactors.length == 1 || scaleFactors.length == nComponents - 1) { skipAlpha = true; } else if (scaleFactors.length == nComponents) { skipAlpha = false; } else { - // awt.21E=Number of scaling constants is not equal to the number of bands + // awt.21E=Number of scaling constants is not equal to the + // number of bands throw new IllegalArgumentException(Messages.getString("awt.21E")); //$NON-NLS-1$ } } else if (scaleFactors.length == 1 || scaleFactors.length == nComponents) { skipAlpha = false; } else { - // awt.21E=Number of scaling constants is not equal to the number of bands + // awt.21E=Number of scaling constants is not equal to the number of + // bands throw new IllegalArgumentException(Messages.getString("awt.21E")); //$NON-NLS-1$ } @@ -348,24 +357,22 @@ public class RescaleOp implements BufferedImageOp, RasterOp { finalDst = dst; dst = createCompatibleDestImage(src, srcCM); } else if (!srcCM.equals(dst.getColorModel())) { - // Treat BufferedImage.TYPE_INT_RGB and BufferedImage.TYPE_INT_ARGB as same - if ( - !((src.getType() == BufferedImage.TYPE_INT_RGB || - src.getType() == BufferedImage.TYPE_INT_ARGB) && - (dst.getType() == BufferedImage.TYPE_INT_RGB || - dst.getType() == BufferedImage.TYPE_INT_ARGB)) - ) { + // Treat BufferedImage.TYPE_INT_RGB and BufferedImage.TYPE_INT_ARGB + // as same + if (!((src.getType() == BufferedImage.TYPE_INT_RGB || src.getType() == BufferedImage.TYPE_INT_ARGB) && (dst + .getType() == BufferedImage.TYPE_INT_RGB || dst.getType() == BufferedImage.TYPE_INT_ARGB))) { finalDst = dst; dst = createCompatibleDestImage(src, srcCM); } } // TODO - //if (ippFilter(src.getRaster(), dst.getRaster(), src.getType(), skipAlpha) != 0) - if (slowFilter(src.getRaster(), dst.getRaster(), skipAlpha) != 0) { - // awt.21F=Unable to transform source - throw new ImagingOpException (Messages.getString("awt.21F")); //$NON-NLS-1$ - } + // if (ippFilter(src.getRaster(), dst.getRaster(), src.getType(), + // skipAlpha) != 0) + if (slowFilter(src.getRaster(), dst.getRaster(), skipAlpha) != 0) { + // awt.21F=Unable to transform source + throw new ImagingOpException(Messages.getString("awt.21F")); //$NON-NLS-1$ + } if (finalDst != null) { Graphics2D g = finalDst.createGraphics(); @@ -378,21 +385,26 @@ public class RescaleOp implements BufferedImageOp, RasterOp { return finalDst; } - // Don't forget to pass allocated arrays for levels and values, size should be numBands*4 + // Don't forget to pass allocated arrays for levels and values, size should + // be numBands*4 /** * Creates the levels. * - * @param sm the sm - * @param numBands the num bands - * @param skipAlpha the skip alpha - * @param levels the levels - * @param values the values - * @param channelsOrder the channels order + * @param sm + * the sm. + * @param numBands + * the num bands. + * @param skipAlpha + * the skip alpha. + * @param levels + * the levels. + * @param values + * the values. + * @param channelsOrder + * the channels order. */ - private final void createLevels( - SampleModel sm, int numBands, boolean skipAlpha, - int levels[], int values[], int channelsOrder[] - ) { + private final void createLevels(SampleModel sm, int numBands, boolean skipAlpha, int levels[], + int values[], int channelsOrder[]) { // Suppose same sample size for all channels, otherwise use slow filter int maxValue = (1 << sm.getSampleSize(0)) - 1; @@ -411,17 +423,17 @@ public class RescaleOp implements BufferedImageOp, RasterOp { } if (skipAlpha) { - extScaleFactors[numBands-1] = 1; - extOffsets[numBands-1] = 0; + extScaleFactors[numBands - 1] = 1; + extOffsets[numBands - 1] = 0; } // Create a levels - for (int i=0; i maxValue){ + } else if (minLevel > maxValue) { minLevel = maxValue; } if (maxLevel < 0) { maxLevel = 0; - } else if (maxLevel > maxValue){ + } else if (maxLevel > maxValue) { maxLevel = maxValue; } - levels[i*4] = 0; + levels[i * 4] = 0; if (minLevel > maxLevel) { - levels[i*4+1] = (int) maxLevel; - levels[i*4+2] = (int) minLevel; + levels[i * 4 + 1] = (int)maxLevel; + levels[i * 4 + 2] = (int)minLevel; } else { - levels[i*4+1] = (int) minLevel; - levels[i*4+2] = (int) maxLevel; + levels[i * 4 + 1] = (int)minLevel; + levels[i * 4 + 2] = (int)maxLevel; } - levels[i*4+3] = maxValue+1; + levels[i * 4 + 3] = maxValue + 1; // Fill values - for (int k=0; k<4; k++) { - int idx = i*4+k; - values[idx] = (int) (extScaleFactors[i] * levels[idx] + extOffsets[i]); + for (int k = 0; k < 4; k++) { + int idx = i * 4 + k; + values[idx] = (int)(extScaleFactors[i] * levels[idx] + extOffsets[i]); if (values[idx] < 0) { values[idx] = 0; - } else if (values[idx] > maxValue){ + } else if (values[idx] > maxValue) { values[idx] = maxValue; } } @@ -463,14 +475,14 @@ public class RescaleOp implements BufferedImageOp, RasterOp { // Reorder data if channels are stored in different order if (channelsOrder != null) { - int len = numBands*4; + int len = numBands * 4; int savedLevels[] = new int[len]; int savedValues[] = new int[len]; System.arraycopy(levels, 0, savedLevels, 0, len); System.arraycopy(values, 0, savedValues, 0, len); for (int i = 0; i < channelsOrder.length; i++) { - System.arraycopy(savedLevels, i*4, levels, channelsOrder[i]*4, 4); - System.arraycopy(savedValues, i*4, values, channelsOrder[i]*4, 4); + System.arraycopy(savedLevels, i * 4, levels, channelsOrder[i] * 4, 4); + System.arraycopy(savedValues, i * 4, values, channelsOrder[i] * 4, 4); } } } @@ -479,18 +491,18 @@ public class RescaleOp implements BufferedImageOp, RasterOp { /** * Ipp filter. * - * @param src the src - * @param dst the dst - * @param imageType the image type - * @param skipAlpha the skip alpha - * - * @return the int + * @param src + * the src. + * @param dst + * the dst. + * @param imageType + * the image type. + * @param skipAlpha + * the skip alpha. + * @return the int. */ @SuppressWarnings("unused") - private final int ippFilter( - Raster src, WritableRaster dst, - int imageType, boolean skipAlpha - ) { + private final int ippFilter(Raster src, WritableRaster dst, int imageType, boolean skipAlpha) { int res; int srcStride, dstStride; @@ -503,9 +515,11 @@ public class RescaleOp implements BufferedImageOp, RasterOp { case BufferedImage.TYPE_INT_ARGB_PRE: case BufferedImage.TYPE_INT_RGB: { channels = 4; - srcStride = src.getWidth()*4; - dstStride = dst.getWidth()*4; - channelsOrder = new int[] {2, 1, 0, 3}; + srcStride = src.getWidth() * 4; + dstStride = dst.getWidth() * 4; + channelsOrder = new int[] { + 2, 1, 0, 3 + }; break; } @@ -513,8 +527,8 @@ public class RescaleOp implements BufferedImageOp, RasterOp { case BufferedImage.TYPE_4BYTE_ABGR_PRE: case BufferedImage.TYPE_INT_BGR: { channels = 4; - srcStride = src.getWidth()*4; - dstStride = dst.getWidth()*4; + srcStride = src.getWidth() * 4; + dstStride = dst.getWidth() * 4; break; } @@ -527,9 +541,11 @@ public class RescaleOp implements BufferedImageOp, RasterOp { case BufferedImage.TYPE_3BYTE_BGR: { channels = 3; - srcStride = src.getWidth()*3; - dstStride = dst.getWidth()*3; - channelsOrder = new int[] {2, 1, 0}; + srcStride = src.getWidth() * 3; + dstStride = dst.getWidth() * 3; + channelsOrder = new int[] { + 2, 1, 0 + }; break; } @@ -544,55 +560,46 @@ public class RescaleOp implements BufferedImageOp, RasterOp { SampleModel srcSM = src.getSampleModel(); SampleModel dstSM = dst.getSampleModel(); - if ( - srcSM instanceof PixelInterleavedSampleModel && - dstSM instanceof PixelInterleavedSampleModel - ) { + if (srcSM instanceof PixelInterleavedSampleModel + && dstSM instanceof PixelInterleavedSampleModel) { // Check PixelInterleavedSampleModel - if ( - srcSM.getDataType() != DataBuffer.TYPE_BYTE || - dstSM.getDataType() != DataBuffer.TYPE_BYTE - ) { + if (srcSM.getDataType() != DataBuffer.TYPE_BYTE + || dstSM.getDataType() != DataBuffer.TYPE_BYTE) { return slowFilter(src, dst, skipAlpha); } - channels = srcSM.getNumBands(); // Have IPP functions for 1, 3 and 4 channels + channels = srcSM.getNumBands(); // Have IPP functions for 1, + // 3 and 4 channels if (!(channels == 1 || channels == 3 || channels == 4)) { return slowFilter(src, dst, skipAlpha); } - srcStride = ((ComponentSampleModel) srcSM).getScanlineStride(); - dstStride = ((ComponentSampleModel) dstSM).getScanlineStride(); + srcStride = ((ComponentSampleModel)srcSM).getScanlineStride(); + dstStride = ((ComponentSampleModel)dstSM).getScanlineStride(); - channelsOrder = ((ComponentSampleModel) srcSM).getBandOffsets(); - } else if ( - srcSM instanceof SinglePixelPackedSampleModel && - dstSM instanceof SinglePixelPackedSampleModel - ) { + channelsOrder = ((ComponentSampleModel)srcSM).getBandOffsets(); + } else if (srcSM instanceof SinglePixelPackedSampleModel + && dstSM instanceof SinglePixelPackedSampleModel) { // Check SinglePixelPackedSampleModel - SinglePixelPackedSampleModel sppsm1 = (SinglePixelPackedSampleModel) srcSM; - SinglePixelPackedSampleModel sppsm2 = (SinglePixelPackedSampleModel) dstSM; + SinglePixelPackedSampleModel sppsm1 = (SinglePixelPackedSampleModel)srcSM; + SinglePixelPackedSampleModel sppsm2 = (SinglePixelPackedSampleModel)dstSM; channels = sppsm1.getNumBands(); - // TYPE_INT_RGB, TYPE_INT_ARGB... - if ( - sppsm1.getDataType() != DataBuffer.TYPE_INT || - sppsm2.getDataType() != DataBuffer.TYPE_INT || - !(channels == 3 || channels == 4) - ) { + // TYPE_INT_RGB, TYPE_INT_ARGB... + if (sppsm1.getDataType() != DataBuffer.TYPE_INT + || sppsm2.getDataType() != DataBuffer.TYPE_INT + || !(channels == 3 || channels == 4)) { return slowFilter(src, dst, skipAlpha); } // Check compatibility of sample models - if ( - !Arrays.equals(sppsm1.getBitOffsets(), sppsm2.getBitOffsets()) || - !Arrays.equals(sppsm1.getBitMasks(), sppsm2.getBitMasks()) - ) { + if (!Arrays.equals(sppsm1.getBitOffsets(), sppsm2.getBitOffsets()) + || !Arrays.equals(sppsm1.getBitMasks(), sppsm2.getBitMasks())) { return slowFilter(src, dst, skipAlpha); } - for (int i=0; i - * The image data is represented as a Raster with a DataBuffer - * and a SampleModel. The SampleModel allows access to the samples in the - * DataBuffer. + * The SampleModel class is abstract class for retrieving pixel's samples in the + * data of an image. Each pixel contains several samples. A sample is the set of + * values of the bands for single pixel. For example, each pixel in the RGB + * model contains three samples and there are three corresponding bands in the + * image data of such pixels representing red, green and blue components. + *

    + * The image data is represented as a Raster with a DataBuffer and a + * SampleModel. The SampleModel allows access to the samples in the DataBuffer. + * + * @since Android 1.0 */ public abstract class SampleModel { - /** The width of the image data which this SampleModel describes. */ + /** + * The width of the image data which this SampleModel describes. + */ protected int width; - /** The height of the image data which this SampleModel describes. */ + /** + * The height of the image data which this SampleModel describes. + */ protected int height; - /** The number of bands of image data which this SampleModel describes. */ + /** + * The number of bands of image data which this SampleModel describes. + */ protected int numBands; - /** The data type of the image data which this SampleModel describes. */ + /** + * The data type of the image data which this SampleModel describes. + */ protected int dataType; /** - * Instantiates a new SampleModel with the specified data type, - * width, height and number of bands. + * Instantiates a new SampleModel with the specified data type, width, + * height and number of bands. * - * @param dataType the data type of the image data. - * @param w the width of the image data. - * @param h the height of the image data. - * @param numBands the number of bands of the image data. + * @param dataType + * the data type of the image data. + * @param w + * the width of the image data. + * @param h + * the height of the image data. + * @param numBands + * the number of bands of the image data. */ public SampleModel(int dataType, int w, int h, int numBands) { if (w <= 0 || h <= 0) { @@ -63,15 +76,14 @@ public abstract class SampleModel { throw new IllegalArgumentException(Messages.getString("awt.22E")); //$NON-NLS-1$ } - double squre = ((double) w) * ((double) h); + double squre = ((double)w) * ((double)h); if (squre >= Integer.MAX_VALUE) { // awt.22F=The product of w and h is greater than Integer.MAX_VALUE throw new IllegalArgumentException(Messages.getString("awt.22F")); //$NON-NLS-1$ } - if (dataType < DataBuffer.TYPE_BYTE || - dataType > DataBuffer.TYPE_DOUBLE && - dataType != DataBuffer.TYPE_UNDEFINED) { + if (dataType < DataBuffer.TYPE_BYTE || dataType > DataBuffer.TYPE_DOUBLE + && dataType != DataBuffer.TYPE_UNDEFINED) { // awt.230=dataType is not one of the supported data types throw new IllegalArgumentException(Messages.getString("awt.230")); //$NON-NLS-1$ } @@ -89,154 +101,156 @@ public abstract class SampleModel { } /** - * Gets the data array for the specified pixel of the specified - * DataBuffer with one of the following types: - * DataBuffer.TYPE_BYTE, DataBuffer.TYPE_USHORT, - * DataBuffer.TYPE_INT, DataBuffer.TYPE_SHORT, + * Gets the data array for the specified pixel of the specified DataBuffer + * with one of the following types: DataBuffer.TYPE_BYTE, + * DataBuffer.TYPE_USHORT, DataBuffer.TYPE_INT, DataBuffer.TYPE_SHORT, * DataBuffer.TYPE_FLOAT, or DataBuffer.TYPE_DOUBLE. * - * @param x the X coordinate of pixel. - * @param y the Y coordinate of pixel. - * @param obj the Object is a data where the result will be stored. - * @param data the image data. - * - * @return the data array for the specified pixel of the specified - * DataBuffer. + * @param x + * the X coordinate of pixel. + * @param y + * the Y coordinate of pixel. + * @param obj + * the Object is a data where the result will be stored. + * @param data + * the image data. + * @return the data array for the specified pixel of the specified + * DataBuffer. */ - public abstract Object getDataElements(int x, int y, Object obj, - DataBuffer data); + public abstract Object getDataElements(int x, int y, Object obj, DataBuffer data); /** - * Gets the array of pixel data for the specified rectangular - * area of pixels of the specified DataBuffer with one of - * the following types: - * DataBuffer.TYPE_BYTE, DataBuffer.TYPE_USHORT, - * DataBuffer.TYPE_INT, DataBuffer.TYPE_SHORT, - * DataBuffer.TYPE_FLOAT, or DataBuffer.TYPE_DOUBLE. + * Gets the array of pixel data for the specified rectangular area of pixels + * of the specified DataBuffer with one of the following types: + * DataBuffer.TYPE_BYTE, DataBuffer.TYPE_USHORT, DataBuffer.TYPE_INT, + * DataBuffer.TYPE_SHORT, DataBuffer.TYPE_FLOAT, or DataBuffer.TYPE_DOUBLE. * - * - * @param x the X coordinate of the rectangular pixel area. - * @param y the Y coordinate of the rectangular pixel area. - * @param w the width of the rectangular pixel area. - * @param h the height of the rectangular pixel area. - * @param obj the Object is an array with the primitive type, - * where the result array will be stored. - * @param data the image data. - * - * @return the array of pixel data for the specified rectangular - * area of pixels of the specified DataBuffer object. + * @param x + * the X coordinate of the rectangular pixel area. + * @param y + * the Y coordinate of the rectangular pixel area. + * @param w + * the width of the rectangular pixel area. + * @param h + * the height of the rectangular pixel area. + * @param obj + * the Object is an array with the primitive type, where the + * result array will be stored. + * @param data + * the image data. + * @return the array of pixel data for the specified rectangular area of + * pixels of the specified DataBuffer object. */ - public Object getDataElements(int x, int y, int w, int h, Object obj, - DataBuffer data) { + public Object getDataElements(int x, int y, int w, int h, Object obj, DataBuffer data) { int numDataElements = getNumDataElements(); int idx = 0; switch (getTransferType()) { - case DataBuffer.TYPE_BYTE: - byte bdata[]; - byte bbuf[] = null; - - if (obj == null) { - bdata = new byte[numDataElements * w * h]; - } else { - bdata = (byte[]) obj; - } + case DataBuffer.TYPE_BYTE: + byte bdata[]; + byte bbuf[] = null; + + if (obj == null) { + bdata = new byte[numDataElements * w * h]; + } else { + bdata = (byte[])obj; + } - for (int i = y; i < y + h; i++) { - for (int j = x; j < x + w; j++) { - bbuf = (byte[]) getDataElements(j, i, bbuf, data); - for (int n = 0; n < numDataElements; n++) { - bdata[idx++] = bbuf[n]; + for (int i = y; i < y + h; i++) { + for (int j = x; j < x + w; j++) { + bbuf = (byte[])getDataElements(j, i, bbuf, data); + for (int n = 0; n < numDataElements; n++) { + bdata[idx++] = bbuf[n]; + } } } - } - obj = bdata; - break; - - case DataBuffer.TYPE_SHORT: - case DataBuffer.TYPE_USHORT: - short sdata[]; - short sbuf[] = null; - - if (obj == null) { - sdata = new short[numDataElements * w * h]; - } else { - sdata = (short[]) obj; - } + obj = bdata; + break; + + case DataBuffer.TYPE_SHORT: + case DataBuffer.TYPE_USHORT: + short sdata[]; + short sbuf[] = null; + + if (obj == null) { + sdata = new short[numDataElements * w * h]; + } else { + sdata = (short[])obj; + } - for (int i = y; i < y + h; i++) { - for (int j = x; j < x + w; j++) { - sbuf = (short[]) getDataElements(j, i, sbuf, data); - for (int n = 0; n < numDataElements; n++) { - sdata[idx++] = sbuf[n]; + for (int i = y; i < y + h; i++) { + for (int j = x; j < x + w; j++) { + sbuf = (short[])getDataElements(j, i, sbuf, data); + for (int n = 0; n < numDataElements; n++) { + sdata[idx++] = sbuf[n]; + } } } - } - obj = sdata; - break; + obj = sdata; + break; - case DataBuffer.TYPE_INT: - int idata[]; - int ibuf[] = null; + case DataBuffer.TYPE_INT: + int idata[]; + int ibuf[] = null; - if (obj == null) { - idata = new int[numDataElements * w * h]; - } else { - idata = (int[]) obj; - } + if (obj == null) { + idata = new int[numDataElements * w * h]; + } else { + idata = (int[])obj; + } - for (int i = y; i < y + h; i++) { - for (int j = x; j < x + w; j++) { - ibuf = (int[]) getDataElements(j, i, ibuf, data); - for (int n = 0; n < numDataElements; n++) { - idata[idx++] = ibuf[n]; + for (int i = y; i < y + h; i++) { + for (int j = x; j < x + w; j++) { + ibuf = (int[])getDataElements(j, i, ibuf, data); + for (int n = 0; n < numDataElements; n++) { + idata[idx++] = ibuf[n]; + } } } - } - obj = idata; - break; + obj = idata; + break; - case DataBuffer.TYPE_FLOAT: - float fdata[]; - float fbuf[] = null; + case DataBuffer.TYPE_FLOAT: + float fdata[]; + float fbuf[] = null; - if (obj == null) { - fdata = new float[numDataElements * w * h]; - } else { - fdata = (float[]) obj; - } + if (obj == null) { + fdata = new float[numDataElements * w * h]; + } else { + fdata = (float[])obj; + } - for (int i = y; i < y + h; i++) { - for (int j = x; j < x + w; j++) { - fbuf = (float[]) getDataElements(j, i, fbuf, data); - for (int n = 0; n < numDataElements; n++) { - fdata[idx++] = fbuf[n]; + for (int i = y; i < y + h; i++) { + for (int j = x; j < x + w; j++) { + fbuf = (float[])getDataElements(j, i, fbuf, data); + for (int n = 0; n < numDataElements; n++) { + fdata[idx++] = fbuf[n]; + } } } - } - obj = fdata; - break; + obj = fdata; + break; - case DataBuffer.TYPE_DOUBLE: - double ddata[]; - double dbuf[] = null; + case DataBuffer.TYPE_DOUBLE: + double ddata[]; + double dbuf[] = null; - if (obj == null) { - ddata = new double[numDataElements * w * h]; - } else { - ddata = (double[]) obj; - } + if (obj == null) { + ddata = new double[numDataElements * w * h]; + } else { + ddata = (double[])obj; + } - for (int i = y; i < y + h; i++) { - for (int j = x; j < x + w; j++) { - dbuf = (double[]) getDataElements(j, i, dbuf, data); - for (int n = 0; n < numDataElements; n++) { - ddata[idx++] = dbuf[n]; + for (int i = y; i < y + h; i++) { + for (int j = x; j < x + w; j++) { + dbuf = (double[])getDataElements(j, i, dbuf, data); + for (int n = 0; n < numDataElements; n++) { + ddata[idx++] = dbuf[n]; + } } } - } - obj = ddata; - break; + obj = ddata; + break; } @@ -244,140 +258,145 @@ public abstract class SampleModel { } /** - * Sets the data for a single pixel in the specified DataBuffer - * from a primitive array with one of the following types: - * DataBuffer.TYPE_BYTE, DataBuffer.TYPE_USHORT, - * DataBuffer.TYPE_INT, DataBuffer.TYPE_SHORT, - * DataBuffer.TYPE_FLOAT, or DataBuffer.TYPE_DOUBLE. + * Sets the data for a single pixel in the specified DataBuffer from a + * primitive array with one of the following types: DataBuffer.TYPE_BYTE, + * DataBuffer.TYPE_USHORT, DataBuffer.TYPE_INT, DataBuffer.TYPE_SHORT, + * DataBuffer.TYPE_FLOAT, or DataBuffer.TYPE_DOUBLE. * - * @param x the X coordinate of pixel. - * @param y the Y coordinate of pixel. - * @param obj the Object - the array of primitive pixel data - * to be set. - * @param data the image data. + * @param x + * the X coordinate of pixel. + * @param y + * the Y coordinate of pixel. + * @param obj + * the Object - the array of primitive pixel data to be set. + * @param data + * the image data. */ - public abstract void setDataElements(int x, int y, Object obj, - DataBuffer data); + public abstract void setDataElements(int x, int y, Object obj, DataBuffer data); /** - * Sets the data elements for a rectangular area of pixels in - * the specified DataBuffer from a primitive array with one of - * the following types: DataBuffer.TYPE_BYTE, DataBuffer.TYPE_USHORT, - * DataBuffer.TYPE_INT, DataBuffer.TYPE_SHORT, - * DataBuffer.TYPE_FLOAT, or DataBuffer.TYPE_DOUBLE. + * Sets the data elements for a rectangular area of pixels in the specified + * DataBuffer from a primitive array with one of the following types: + * DataBuffer.TYPE_BYTE, DataBuffer.TYPE_USHORT, DataBuffer.TYPE_INT, + * DataBuffer.TYPE_SHORT, DataBuffer.TYPE_FLOAT, or DataBuffer.TYPE_DOUBLE. * - * @param x the X coordinate of the specified rectangular area. - * @param y the Y coordinate of the specified rectangular area. - * @param w the width of rectangle. - * @param h the height of rectangle. - * @param obj the Object - the array of primitive pixel data - * to be set. - * @param data the image data. + * @param x + * the X coordinate of the specified rectangular area. + * @param y + * the Y coordinate of the specified rectangular area. + * @param w + * the width of rectangle. + * @param h + * the height of rectangle. + * @param obj + * the Object - the array of primitive pixel data to be set. + * @param data + * the image data. */ - public void setDataElements(int x, int y, int w, int h, Object obj, - DataBuffer data) { + public void setDataElements(int x, int y, int w, int h, Object obj, DataBuffer data) { int numDataElements = getNumDataElements(); int idx = 0; switch (getTransferType()) { - case DataBuffer.TYPE_BYTE: - byte bbuf[] = new byte[numDataElements]; - for (int i = y; i < y + h; i++) { - for (int j = x; j < x + w; j++) { - for (int n = 0; n < numDataElements; n++) { - bbuf[n] = ((byte[]) obj)[idx++]; + case DataBuffer.TYPE_BYTE: + byte bbuf[] = new byte[numDataElements]; + for (int i = y; i < y + h; i++) { + for (int j = x; j < x + w; j++) { + for (int n = 0; n < numDataElements; n++) { + bbuf[n] = ((byte[])obj)[idx++]; + } + setDataElements(j, i, bbuf, data); } - setDataElements(j, i, bbuf, data); } - } - break; - - case DataBuffer.TYPE_SHORT: - case DataBuffer.TYPE_USHORT: - short sbuf[] = new short[numDataElements]; - for (int i = y; i < y + h; i++) { - for (int j = x; j < x + w; j++) { - for (int n = 0; n < numDataElements; n++) { - sbuf[n] = ((short[]) obj)[idx++]; + break; + + case DataBuffer.TYPE_SHORT: + case DataBuffer.TYPE_USHORT: + short sbuf[] = new short[numDataElements]; + for (int i = y; i < y + h; i++) { + for (int j = x; j < x + w; j++) { + for (int n = 0; n < numDataElements; n++) { + sbuf[n] = ((short[])obj)[idx++]; + } + setDataElements(j, i, sbuf, data); } - setDataElements(j, i, sbuf, data); } - } - break; - - case DataBuffer.TYPE_INT: - int ibuf[] = new int[numDataElements]; - for (int i = y; i < y + h; i++) { - for (int j = x; j < x + w; j++) { - for (int n = 0; n < numDataElements; n++) { - ibuf[n] = ((int[]) obj)[idx++]; + break; + + case DataBuffer.TYPE_INT: + int ibuf[] = new int[numDataElements]; + for (int i = y; i < y + h; i++) { + for (int j = x; j < x + w; j++) { + for (int n = 0; n < numDataElements; n++) { + ibuf[n] = ((int[])obj)[idx++]; + } + setDataElements(j, i, ibuf, data); } - setDataElements(j, i, ibuf, data); } - } - break; - - case DataBuffer.TYPE_FLOAT: - float fbuf[] = new float[numDataElements]; - for (int i = y; i < y + h; i++) { - for (int j = x; j < x + w; j++) { - for (int n = 0; n < numDataElements; n++) { - fbuf[n] = ((float[]) obj)[idx++]; + break; + + case DataBuffer.TYPE_FLOAT: + float fbuf[] = new float[numDataElements]; + for (int i = y; i < y + h; i++) { + for (int j = x; j < x + w; j++) { + for (int n = 0; n < numDataElements; n++) { + fbuf[n] = ((float[])obj)[idx++]; + } + setDataElements(j, i, fbuf, data); } - setDataElements(j, i, fbuf, data); } - } - break; - - case DataBuffer.TYPE_DOUBLE: - double dbuf[] = new double[numDataElements]; - for (int i = y; i < y + h; i++) { - for (int j = x; j < x + w; j++) { - for (int n = 0; n < numDataElements; n++) { - dbuf[n] = ((double[]) obj)[idx++]; + break; + + case DataBuffer.TYPE_DOUBLE: + double dbuf[] = new double[numDataElements]; + for (int i = y; i < y + h; i++) { + for (int j = x; j < x + w; j++) { + for (int n = 0; n < numDataElements; n++) { + dbuf[n] = ((double[])obj)[idx++]; + } + setDataElements(j, i, dbuf, data); } - setDataElements(j, i, dbuf, data); } - } - break; + break; } } /** - * Creates a new SampleModel with the specified bands of - * this SampleModel. + * Creates a new SampleModel with the specified bands of this SampleModel. * - * @param bands the array of bands from this SampleModel. - * - * @return the SampleModel with the specified bands of - * this SampleModel. + * @param bands + * the array of bands from this SampleModel. + * @return the SampleModel with the specified bands of this SampleModel. */ public abstract SampleModel createSubsetSampleModel(int bands[]); /** - * Creates the SampleModel which has the same data as in - * this SampleModel with a different width and height. - * - * @param a0 the width of the image data. - * @param a1 the height of the image data. + * Creates the SampleModel which has the same data as in this SampleModel + * with a different width and height. * - * @return the SampleModel which has the same data as in - * this SampleModel with a different width and height. + * @param a0 + * the width of the image data. + * @param a1 + * the height of the image data. + * @return the SampleModel which has the same data as in this SampleModel + * with a different width and height. */ public abstract SampleModel createCompatibleSampleModel(int a0, int a1); /** - * Gets the samples of the specified pixel as a int array. + * Gets the samples of the specified pixel as an integer array. * - * @param x the X coordinate of pixel. - * @param y the Y coordinate of pixel. - * @param iArray the int array where result will be stored. - * @param data the image data. - * - * @return the int array with the samples of the specified pixel. - + * @param x + * the X coordinate of pixel. + * @param y + * the Y coordinate of pixel. + * @param iArray + * the integer array where result will be stored. + * @param data + * the image data. + * @return the integer array with the samples of the specified pixel. */ public int[] getPixel(int x, int y, int iArray[], DataBuffer data) { if (x < 0 || y < 0 || x >= this.width || y >= this.height) { @@ -400,12 +419,16 @@ public abstract class SampleModel { } /** - * Sets a pixel of the DataBuffer from a int array of samples. + * Sets a pixel of the DataBuffer from a integer array of samples. * - * @param x the X coordinate of pixel. - * @param y the Y coordinate of pixel. - * @param iArray the int array. - * @param data the image data. + * @param x + * the X coordinate of pixel. + * @param y + * the Y coordinate of pixel. + * @param iArray + * the integer array. + * @param data + * the image data. */ public void setPixel(int x, int y, int iArray[], DataBuffer data) { if (x < 0 || y < 0 || x >= this.width || y >= this.height) { @@ -420,11 +443,14 @@ public abstract class SampleModel { /** * Gets the samples of the specified pixel as a float array. * - * @param x the X coordinate of pixel. - * @param y the Y coordinate of pixel. - * @param fArray the float array where result will be stored. - * @param data the image data. - * + * @param x + * the X coordinate of pixel. + * @param y + * the Y coordinate of pixel. + * @param fArray + * the float array where result will be stored. + * @param data + * the image data. * @return the float array with the samples of the specified pixel. */ public float[] getPixel(int x, int y, float fArray[], DataBuffer data) { @@ -448,12 +474,16 @@ public abstract class SampleModel { } /** - * Sets a pixel of the DataBuffer from a float array of samples. + * Sets a pixel of the DataBuffer from a float array of samples. * - * @param x the X coordinate of pixel. - * @param y the Y coordinate of pixel. - * @param fArray the float array. - * @param data the image data. + * @param x + * the X coordinate of pixel. + * @param y + * the Y coordinate of pixel. + * @param fArray + * the float array. + * @param data + * the image data. */ public void setPixel(int x, int y, float fArray[], DataBuffer data) { if (x < 0 || y < 0 || x >= this.width || y >= this.height) { @@ -468,11 +498,14 @@ public abstract class SampleModel { /** * Gets the samples of the specified pixel as a double array. * - * @param x the X coordinate of pixel. - * @param y the Y coordinate of pixel. - * @param dArray the double array where result will be stored. - * @param data the image data. - * + * @param x + * the X coordinate of pixel. + * @param y + * the Y coordinate of pixel. + * @param dArray + * the double array where result will be stored. + * @param data + * the image data. * @return the double array with the samples of the specified pixel. */ public double[] getPixel(int x, int y, double dArray[], DataBuffer data) { @@ -496,12 +529,16 @@ public abstract class SampleModel { } /** - * Sets a pixel of the DataBuffer from a double array of samples. + * Sets a pixel of the DataBuffer from a double array of samples. * - * @param x the X coordinate of pixel. - * @param y the Y coordinate of pixel. - * @param dArray the double array. - * @param data the image data. + * @param x + * the X coordinate of pixel. + * @param y + * the Y coordinate of pixel. + * @param dArray + * the double array. + * @param data + * the image data. */ public void setPixel(int x, int y, double dArray[], DataBuffer data) { if (x < 0 || y < 0 || x >= this.width || y >= this.height) { @@ -514,43 +551,49 @@ public abstract class SampleModel { } /** - * Gets the sample of a specified band for the specified pixel - * as an int. - * - * @param x the X coordinate of pixel. - * @param y the Y coordinate of pixel. - * @param b the specified band. - * @param data the image data. + * Gets the sample of a specified band for the specified pixel as an + * integer. * + * @param x + * the X coordinate of pixel. + * @param y + * the Y coordinate of pixel. + * @param b + * the specified band. + * @param data + * the image data. * @return the sample of a specified band for the specified pixel. */ public abstract int getSample(int x, int y, int b, DataBuffer data); /** - * Gets the sample of a specified band for the specified pixel - * as a float. - * - * @param x the X coordinate of pixel. - * @param y the Y coordinate of pixel. - * @param b the specified band. - * @param data the image data. + * Gets the sample of a specified band for the specified pixel as a float. * + * @param x + * the X coordinate of pixel. + * @param y + * the Y coordinate of pixel. + * @param b + * the specified band. + * @param data + * the image data. * @return the sample of a specified band for the specified pixel. - */ public float getSampleFloat(int x, int y, int b, DataBuffer data) { return getSample(x, y, b, data); } /** - * Gets the sample of a specified band for the specified pixel - * as a double. - * - * @param x the X coordinate of pixel. - * @param y the Y coordinate of pixel. - * @param b the specified band. - * @param data the image data. + * Gets the sample of a specified band for the specified pixel as a double. * + * @param x + * the X coordinate of pixel. + * @param y + * the Y coordinate of pixel. + * @param b + * the specified band. + * @param data + * the image data. * @return the sample of a specified band for the specified pixel. */ public double getSampleDouble(int x, int y, int b, DataBuffer data) { @@ -558,21 +601,25 @@ public abstract class SampleModel { } /** - * Gets the samples of the specified rectangular area of pixels - * as a int array. - * - * @param x the X coordinate of the rectangle of pixels. - * @param y the Y coordinate of the rectangle of pixels. - * @param w the width of the rectangle of pixels. - * @param h the height of the rectangle of pixels. - * @param iArray the int array where result will be stored. - * @param data the image data. + * Gets the samples of the specified rectangular area of pixels as an + * integer array. * - * @return the int array with the samples of the specified - * rectangular area of pixels. + * @param x + * the X coordinate of the rectangle of pixels. + * @param y + * the Y coordinate of the rectangle of pixels. + * @param w + * the width of the rectangle of pixels. + * @param h + * the height of the rectangle of pixels. + * @param iArray + * the integer array where result will be stored. + * @param data + * the image data. + * @return the integer array with the samples of the specified rectangular + * area of pixels. */ - public int[] getPixels(int x, int y, int w, int h, int iArray[], - DataBuffer data) { + public int[] getPixels(int x, int y, int w, int h, int iArray[], DataBuffer data) { if (x < 0 || y < 0 || x + w > this.width || y + h > this.height) { // awt.63=Coordinates are not in bounds throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ @@ -597,18 +644,23 @@ public abstract class SampleModel { } /** - * Sets all of the samples for a rectangular area of pixels of the DataBuffer - * from an int array. + * Sets all of the samples for a rectangular area of pixels of the + * DataBuffer from an integer array. * - * @param x the X coordinate of the rectangle of pixels. - * @param y the Y coordinate of the rectangle of pixels. - * @param w the width of the rectangle of pixels. - * @param h the height of the rectangle of pixels. - * @param iArray the int array. - * @param data the image data. + * @param x + * the X coordinate of the rectangle of pixels. + * @param y + * the Y coordinate of the rectangle of pixels. + * @param w + * the width of the rectangle of pixels. + * @param h + * the height of the rectangle of pixels. + * @param iArray + * the integer array. + * @param data + * the image data. */ - public void setPixels(int x, int y, int w, int h, int iArray[], - DataBuffer data) { + public void setPixels(int x, int y, int w, int h, int iArray[], DataBuffer data) { if (x < 0 || y < 0 || x + w > this.width || y + h > this.height) { // awt.63=Coordinates are not in bounds throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ @@ -624,21 +676,25 @@ public abstract class SampleModel { } /** - * Gets the samples of the specified rectangular area of pixels - * as a float array. + * Gets the samples of the specified rectangular area of pixels as a float + * array. * - * @param x the X coordinate of the rectangle of pixels. - * @param y the Y coordinate of the rectangle of pixels. - * @param w the width of the rectangle of pixels. - * @param h the height of the rectangle of pixels. - * @param fArray the float array where result will be stored. - * @param data the image data. - * - * @return the float array with the samples of the specified - * rectangular area of pixels. + * @param x + * the X coordinate of the rectangle of pixels. + * @param y + * the Y coordinate of the rectangle of pixels. + * @param w + * the width of the rectangle of pixels. + * @param h + * the height of the rectangle of pixels. + * @param fArray + * the float array where result will be stored. + * @param data + * the image data. + * @return the float array with the samples of the specified rectangular + * area of pixels. */ - public float[] getPixels(int x, int y, int w, int h, float fArray[], - DataBuffer data) { + public float[] getPixels(int x, int y, int w, int h, float fArray[], DataBuffer data) { if (x < 0 || y < 0 || x + w > this.width || y + h > this.height) { // awt.63=Coordinates are not in bounds throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ @@ -663,18 +719,23 @@ public abstract class SampleModel { } /** - * Sets all of the samples for a rectangular area of pixels of the DataBuffer - * from a float array. + * Sets all of the samples for a rectangular area of pixels of the + * DataBuffer from a float array. * - * @param x the X coordinate of the rectangle of pixels. - * @param y the Y coordinate of the rectangle of pixels. - * @param w the width of the rectangle of pixels. - * @param h the height of the rectangle of pixels. - * @param fArray the float array. - * @param data the image data. + * @param x + * the X coordinate of the rectangle of pixels. + * @param y + * the Y coordinate of the rectangle of pixels. + * @param w + * the width of the rectangle of pixels. + * @param h + * the height of the rectangle of pixels. + * @param fArray + * the float array. + * @param data + * the image data. */ - public void setPixels(int x, int y, int w, int h, float fArray[], - DataBuffer data) { + public void setPixels(int x, int y, int w, int h, float fArray[], DataBuffer data) { if (x < 0 || y < 0 || x + w > this.width || y + h > this.height) { // awt.63=Coordinates are not in bounds throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ @@ -690,21 +751,25 @@ public abstract class SampleModel { } /** - * Gets the samples of the specified rectangular area of pixels - * as a double array. - * - * @param x the X coordinate of the rectangle of pixels. - * @param y the Y coordinate of the rectangle of pixels. - * @param w the width of the rectangle of pixels. - * @param h the height of the rectangle of pixels. - * @param dArray the double array where result will be stored. - * @param data the image data. + * Gets the samples of the specified rectangular area of pixels as a double + * array. * - * @return the double array with the samples of the specified - * rectangular area of pixels. + * @param x + * the X coordinate of the rectangle of pixels. + * @param y + * the Y coordinate of the rectangle of pixels. + * @param w + * the width of the rectangle of pixels. + * @param h + * the height of the rectangle of pixels. + * @param dArray + * the double array where result will be stored. + * @param data + * the image data. + * @return the double array with the samples of the specified rectangular + * area of pixels. */ - public double[] getPixels(int x, int y, int w, int h, double dArray[], - DataBuffer data) { + public double[] getPixels(int x, int y, int w, int h, double dArray[], DataBuffer data) { if (x < 0 || y < 0 || x + w > this.width || y + h > this.height) { // awt.63=Coordinates are not in bounds throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ @@ -729,18 +794,23 @@ public abstract class SampleModel { } /** - * Sets all of the samples for a rectangular area of pixels of the DataBuffer - * from a double array. + * Sets all of the samples for a rectangular area of pixels of the + * DataBuffer from a double array. * - * @param x the X coordinate of the rectangle of pixels. - * @param y the Y coordinate of the rectangle of pixels. - * @param w the width of the rectangle of pixels. - * @param h the height of the rectangle of pixels. - * @param dArray the double array. - * @param data the image data. + * @param x + * the X coordinate of the rectangle of pixels. + * @param y + * the Y coordinate of the rectangle of pixels. + * @param w + * the width of the rectangle of pixels. + * @param h + * the height of the rectangle of pixels. + * @param dArray + * the double array. + * @param data + * the image data. */ - public void setPixels(int x, int y, int w, int h, double dArray[], - DataBuffer data) { + public void setPixels(int x, int y, int w, int h, double dArray[], DataBuffer data) { if (x < 0 || y < 0 || x + w > this.width || y + h > this.height) { // awt.63=Coordinates are not in bounds throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ @@ -756,34 +826,44 @@ public abstract class SampleModel { } /** - * Sets a sample of the specified band for the specified pixel - * in the DataBuffer as int value. + * Sets a sample of the specified band for the specified pixel in the + * DataBuffer as integer value. * - * @param x the X coordinate of the pixel. - * @param y the Y coordinate of the pixel. - * @param b the specified band. - * @param s the sample as an int value. - * @param data the image data. + * @param x + * the X coordinate of the pixel. + * @param y + * the Y coordinate of the pixel. + * @param b + * the specified band. + * @param s + * the sample as an integer value. + * @param data + * the image data. */ public abstract void setSample(int x, int y, int b, int s, DataBuffer data); /** - * Gets the samples of a specified band for a specified rectangular - * area of pixels as a int array. - * - * @param x the X coordinate of the rectangle. - * @param y the Y coordinate of the rectangle. - * @param w the width of the rectangle. - * @param h the height of the rectangle. - * @param b the specified band. - * @param iArray the int array where result will be stored. - * @param data the image data. + * Gets the samples of a specified band for a specified rectangular area of + * pixels as a integer array. * - * @return the samples of a specified band for a specified rectangular - * area of pixels. + * @param x + * the X coordinate of the rectangle. + * @param y + * the Y coordinate of the rectangle. + * @param w + * the width of the rectangle. + * @param h + * the height of the rectangle. + * @param b + * the specified band. + * @param iArray + * the integer array where result will be stored. + * @param data + * the image data. + * @return the samples of a specified band for a specified rectangular area + * of pixels. */ - public int[] getSamples(int x, int y, int w, int h, int b, int iArray[], - DataBuffer data) { + public int[] getSamples(int x, int y, int w, int h, int b, int iArray[], DataBuffer data) { int samples[]; int idx = 0; @@ -803,19 +883,25 @@ public abstract class SampleModel { } /** - * Sets the samples from an int array in the specified band for - * the specified rectangle of pixels. + * Sets the samples from an integer array in the specified band for the + * specified rectangle of pixels. * - * @param x the X coordinate of the rectangle. - * @param y the Y coordinate of the rectangle. - * @param w the width of the rectangle. - * @param h the height of the rectangle. - * @param b the specified band. - * @param iArray the int array. - * @param data the image data. + * @param x + * the X coordinate of the rectangle. + * @param y + * the Y coordinate of the rectangle. + * @param w + * the width of the rectangle. + * @param h + * the height of the rectangle. + * @param b + * the specified band. + * @param iArray + * the integer array. + * @param data + * the image data. */ - public void setSamples(int x, int y, int w, int h, int b, int iArray[], - DataBuffer data) { + public void setSamples(int x, int y, int w, int h, int b, int iArray[], DataBuffer data) { int idx = 0; for (int i = y; i < y + h; i++) { for (int j = x; j < x + w; j++) { @@ -825,22 +911,27 @@ public abstract class SampleModel { } /** - * Gets the samples of a specified band for a specified rectangular - * area of pixels as a float array. + * Gets the samples of a specified band for a specified rectangular area of + * pixels as a float array. * - * @param x the X coordinate of the rectangle. - * @param y the Y coordinate of the rectangle. - * @param w the width of the rectangle. - * @param h the height of the rectangle. - * @param b the specified band. - * @param fArray the float array where result will be stored. - * @param data the image data. - * - * @return the samples of a specified band for a specified rectangular - * area of pixels. + * @param x + * the X coordinate of the rectangle. + * @param y + * the Y coordinate of the rectangle. + * @param w + * the width of the rectangle. + * @param h + * the height of the rectangle. + * @param b + * the specified band. + * @param fArray + * the float array where result will be stored. + * @param data + * the image data. + * @return the samples of a specified band for a specified rectangular area + * of pixels. */ - public float[] getSamples(int x, int y, int w, int h, int b, - float fArray[], DataBuffer data) { + public float[] getSamples(int x, int y, int w, int h, int b, float fArray[], DataBuffer data) { float samples[]; int idx = 0; @@ -860,19 +951,25 @@ public abstract class SampleModel { } /** - * Sets the samples from an float array in the specified band for - * the specified rectangle of pixels. + * Sets the samples from an float array in the specified band for the + * specified rectangle of pixels. * - * @param x the X coordinate of the rectangle. - * @param y the Y coordinate of the rectangle. - * @param w the width of the rectangle. - * @param h the height of the rectangle. - * @param b the specified band. - * @param fArray the float array - * @param data the image data. + * @param x + * the X coordinate of the rectangle. + * @param y + * the Y coordinate of the rectangle. + * @param w + * the width of the rectangle. + * @param h + * the height of the rectangle. + * @param b + * the specified band. + * @param fArray + * the float array. + * @param data + * the image data. */ - public void setSamples(int x, int y, int w, int h, int b, float fArray[], - DataBuffer data) { + public void setSamples(int x, int y, int w, int h, int b, float fArray[], DataBuffer data) { int idx = 0; for (int i = y; i < y + h; i++) { for (int j = x; j < x + w; j++) { @@ -882,22 +979,27 @@ public abstract class SampleModel { } /** - * Gets the samples of a specified band for a specified rectangular - * area of pixels as a double array. - * - * @param x the X coordinate of the rectangle. - * @param y the Y coordinate of the rectangle. - * @param w the width of the rectangle. - * @param h the height of the rectangle. - * @param b the specified band. - * @param dArray the double array where result will be stored. - * @param data the image data. + * Gets the samples of a specified band for a specified rectangular area of + * pixels as a double array. * - * @return the samples of a specified band for a specified rectangular - * area of pixels. + * @param x + * the X coordinate of the rectangle. + * @param y + * the Y coordinate of the rectangle. + * @param w + * the width of the rectangle. + * @param h + * the height of the rectangle. + * @param b + * the specified band. + * @param dArray + * the double array where result will be stored. + * @param data + * the image data. + * @return the samples of a specified band for a specified rectangular area + * of pixels. */ - public double[] getSamples(int x, int y, int w, int h, int b, - double dArray[], DataBuffer data) { + public double[] getSamples(int x, int y, int w, int h, int b, double dArray[], DataBuffer data) { double samples[]; int idx = 0; @@ -917,19 +1019,25 @@ public abstract class SampleModel { } /** - * Sets the samples from an double array in the specified band for - * the specified rectangle of pixels. + * Sets the samples from an double array in the specified band for the + * specified rectangle of pixels. * - * @param x the X coordinate of the rectangle. - * @param y the Y coordinate of the rectangle. - * @param w the width of the rectangle. - * @param h the height of the rectangle. - * @param b the specified band. - * @param dArray the double array - * @param data the image data. + * @param x + * the X coordinate of the rectangle. + * @param y + * the Y coordinate of the rectangle. + * @param w + * the width of the rectangle. + * @param h + * the height of the rectangle. + * @param b + * the specified band. + * @param dArray + * the double array. + * @param data + * the image data. */ - public void setSamples(int x, int y, int w, int h, int b, double dArray[], - DataBuffer data) { + public void setSamples(int x, int y, int w, int h, int b, double dArray[], DataBuffer data) { int idx = 0; for (int i = y; i < y + h; i++) { for (int j = x; j < x + w; j++) { @@ -939,53 +1047,62 @@ public abstract class SampleModel { } /** - * Sets a sample of the specified band for the specified pixel - * in the DataBuffer as float value. + * Sets a sample of the specified band for the specified pixel in the + * DataBuffer as float value. * - * @param x the X coordinate of the pixel. - * @param y the Y coordinate of the pixel. - * @param b the specified band. - * @param s the sample as float value. - * @param data the image data. + * @param x + * the X coordinate of the pixel. + * @param y + * the Y coordinate of the pixel. + * @param b + * the specified band. + * @param s + * the sample as float value. + * @param data + * the image data. */ public void setSample(int x, int y, int b, float s, DataBuffer data) { - setSample(x, y, b, (int) s, data); + setSample(x, y, b, (int)s, data); } /** - * Sets a sample of the specified band for the specified pixel - * in the DataBuffer as double value. + * Sets a sample of the specified band for the specified pixel in the + * DataBuffer as double value. * - * @param x the X coordinate of the pixel. - * @param y the Y coordinate of the pixel. - * @param b the specified band. - * @param s the sample as double value. - * @param data the image data. + * @param x + * the X coordinate of the pixel. + * @param y + * the Y coordinate of the pixel. + * @param b + * the specified band. + * @param s + * the sample as double value. + * @param data + * the image data. */ public void setSample(int x, int y, int b, double s, DataBuffer data) { - setSample(x, y, b, (int) s, data); + setSample(x, y, b, (int)s, data); } /** - * Creates a DataBuffer object which corresponds to the SampleModel. - * - * @return the DataBuffer object which corresponds to - * the SampleModel. + * Creates a DataBuffer object which corresponds to the SampleModel. + * + * @return the DataBuffer object which corresponds to the SampleModel. */ public abstract DataBuffer createDataBuffer(); /** * Gets the sample size in bits for the specified band. * - * @param band the specified band. - * + * @param band + * the specified band. * @return the sample size in bits for the specified band. */ public abstract int getSampleSize(int band); /** * Gets an array of the sample size in bits for all bands. - * + * * @return an array of the sample size in bits for all bands. */ public abstract int[] getSampleSize(); @@ -1000,10 +1117,9 @@ public abstract class SampleModel { } /** - * Gets the transfer type used to transfer pixels via - * the getDataElements and setDataElements methods. - * Transfer type value can be one of the predefined type - * from DataBuffer class or not. + * Gets the transfer type used to transfer pixels via the getDataElements + * and setDataElements methods. Transfer type value can be one of the + * predefined type from DataBuffer class or not. * * @return the transfer type. */ @@ -1012,20 +1128,18 @@ public abstract class SampleModel { } /** - * Returns the number of data elements for pixel transfering - * via the getDataElements and setDataElements methods. + * Returns the number of data elements for pixel transferring via the + * getDataElements and setDataElements methods. * - * @return the number of data elements for pixel transfering - * via the getDataElements and setDataElements methods. + * @return the number of data elements for pixel transferring via the + * getDataElements and setDataElements methods. */ public abstract int getNumDataElements(); /** - * Gets the number of bands in the image data of this - * SampleModel object. + * Gets the number of bands in the image data of this SampleModel object. * - * @return the number of bands in the image data of this - * SampleModel object. + * @return the number of bands in the image data of this SampleModel object. */ public final int getNumBands() { return numBands; @@ -1050,4 +1164,3 @@ public abstract class SampleModel { } } - diff --git a/awt/java/awt/image/ShortLookupTable.java b/awt/java/awt/image/ShortLookupTable.java index 77c9c457223b8bd7c068b27338402dae556e3044..4319d58056a3b63efd2c0826c3f557d6f5fb8f17 100644 --- a/awt/java/awt/image/ShortLookupTable.java +++ b/awt/java/awt/image/ShortLookupTable.java @@ -23,27 +23,30 @@ package java.awt.image; - /** - * The ShortLookupTable class provides provides functionality for - * lookup operations, and is defined by an input short array for - * bands or components of image and an offset value. - * The offset value will be subtracted from the input values before - * indexing the input arrays. The output of a lookup operation is + * The ShortLookupTable class provides provides functionality for lookup + * operations, and is defined by an input short array for bands or components of + * image and an offset value. The offset value will be subtracted from the input + * values before indexing the input arrays. The output of a lookup operation is * represented as an unsigned short array. + * + * @since Android 1.0 */ public class ShortLookupTable extends LookupTable { - - /** The data. */ + + /** + * The data. + */ private short data[][]; /** - * Instantiates a new ShortLookupTable with the specified offset value - * and the specified short array which represents lookup table for - * all bands. + * Instantiates a new ShortLookupTable with the specified offset value and + * the specified short array which represents lookup table for all bands. * - * @param offset the offset value. - * @param data the data array. + * @param offset + * the offset value. + * @param data + * the data array. */ public ShortLookupTable(int offset, short[] data) { super(offset, 1); @@ -53,12 +56,14 @@ public class ShortLookupTable extends LookupTable { } /** - * Instantiates a new ShortLookupTable with the specified offset value - * and the specified short array of arrays which represents lookup table - * for each band. + * Instantiates a new ShortLookupTable with the specified offset value and + * the specified short array of arrays which represents lookup table for + * each band. * - * @param offset the offset value. - * @param data the data array of arrays for each band. + * @param offset + * the offset value. + * @param data + * the data array of arrays for each band. */ public ShortLookupTable(int offset, short[][] data) { super(offset, data.length); @@ -70,9 +75,9 @@ public class ShortLookupTable extends LookupTable { } /** - * Gets the lookup table of this ShortLookupTable object. If - * this ShortLookupTable object has one short array for all bands, - * the returned array length is one. + * Gets the lookup table of this ShortLookupTable object. If this + * ShortLookupTable object has one short array for all bands, the returned + * array length is one. * * @return the lookup table of this ShortLookupTable object. */ @@ -81,14 +86,14 @@ public class ShortLookupTable extends LookupTable { } /** - * Returns a short array which contains samples of the specified - * pixel which is translated with the lookup table of this - * ShortLookupTable object. The resulted array is stored to - * the dst array. - * - * @param src the source array. - * @param dst the destination array where the result can be stored. + * Returns a short array which contains samples of the specified pixel which + * is translated with the lookup table of this ShortLookupTable object. The + * resulted array is stored to the dst array. * + * @param src + * the source array. + * @param dst + * the destination array where the result can be stored. * @return the short array of translated samples of a pixel. */ public short[] lookupPixel(short[] src, short[] dst) { @@ -99,11 +104,11 @@ public class ShortLookupTable extends LookupTable { int offset = getOffset(); if (getNumComponents() == 1) { for (int i = 0; i < src.length; i++) { - dst[i] = data[0][src[i]-offset]; + dst[i] = data[0][src[i] - offset]; } } else { for (int i = 0; i < getNumComponents(); i++) { - dst[i] = data[i][src[i]-offset]; + dst[i] = data[i][src[i] - offset]; } } @@ -119,11 +124,11 @@ public class ShortLookupTable extends LookupTable { int offset = getOffset(); if (getNumComponents() == 1) { for (int i = 0; i < src.length; i++) { - dst[i] = data[0][src[i]-offset]; + dst[i] = data[0][src[i] - offset]; } } else { for (int i = 0; i < getNumComponents(); i++) { - dst[i] = data[i][src[i]-offset]; + dst[i] = data[i][src[i] - offset]; } } diff --git a/awt/java/awt/image/SinglePixelPackedSampleModel.java b/awt/java/awt/image/SinglePixelPackedSampleModel.java index 311395a1d63fbcfee4107780517ee8b8a83661b1..69f3353b3af8826656e0456d7a7e5af8af12a253 100644 --- a/awt/java/awt/image/SinglePixelPackedSampleModel.java +++ b/awt/java/awt/image/SinglePixelPackedSampleModel.java @@ -18,6 +18,7 @@ * @author Igor V. Stolyarov * @version $Revision$ */ + package java.awt.image; import java.util.Arrays; @@ -25,39 +26,54 @@ import java.util.Arrays; import org.apache.harmony.awt.internal.nls.Messages; /** - * The SinglePixelPackedSampleModel class represents pixel data - * where several samples combine to create a single pixel and - * are stored in a single data array element. This class - * supports TYPE_BYTE, TYPE_USHORT, TYPE_INT data types. + * The SinglePixelPackedSampleModel class represents pixel data where several + * samples combine to create a single pixel and are stored in a single data + * array element. This class supports TYPE_BYTE, TYPE_USHORT, TYPE_INT data + * types. + * + * @since Android 1.0 */ public class SinglePixelPackedSampleModel extends SampleModel { - /** The bit masks. */ + /** + * The bit masks. + */ private int bitMasks[]; - /** The bit offsets. */ + /** + * The bit offsets. + */ private int bitOffsets[]; - /** The bit sizes. */ + /** + * The bit sizes. + */ private int bitSizes[]; - /** The scanline stride. */ + /** + * The scanline stride. + */ private int scanlineStride; - /** The max bit size. */ + /** + * The max bit size. + */ private int maxBitSize; /** * Instantiates a new SinglePixelPackedSampleModel with the specified * parameters. * - * @param dataType the data type of samples. - * @param w the width of the image data. - * @param h the height of the image data. - * @param bitMasks the bit masks for all the bands. + * @param dataType + * the data type of samples. + * @param w + * the width of the image data. + * @param h + * the height of the image data. + * @param bitMasks + * the bit masks for all the bands. */ - public SinglePixelPackedSampleModel(int dataType, int w, int h, - int bitMasks[]) { + public SinglePixelPackedSampleModel(int dataType, int w, int h, int bitMasks[]) { this(dataType, w, h, w, bitMasks); } @@ -65,20 +81,24 @@ public class SinglePixelPackedSampleModel extends SampleModel { * Instantiates a new SinglePixelPackedSampleModel with the specified * parameters. * - * @param dataType the data type of the samples. - * @param w the width of the image data. - * @param h the height of the image data. - * @param scanlineStride The scanline stride of the image data. - * @param bitMasks the bit masks for all the bands. + * @param dataType + * the data type of the samples. + * @param w + * the width of the image data. + * @param h + * the height of the image data. + * @param scanlineStride + * the scanline stride of the image data. + * @param bitMasks + * the bit masks for all the bands. */ - public SinglePixelPackedSampleModel(int dataType, int w, int h, - int scanlineStride, int bitMasks[]) { + public SinglePixelPackedSampleModel(int dataType, int w, int h, int scanlineStride, + int bitMasks[]) { super(dataType, w, h, bitMasks.length); - if (dataType != DataBuffer.TYPE_BYTE && - dataType != DataBuffer.TYPE_USHORT && - dataType != DataBuffer.TYPE_INT) { + if (dataType != DataBuffer.TYPE_BYTE && dataType != DataBuffer.TYPE_USHORT + && dataType != DataBuffer.TYPE_INT) { // awt.61=Unsupported data type: {0} throw new IllegalArgumentException(Messages.getString("awt.61", //$NON-NLS-1$ dataType)); @@ -109,8 +129,7 @@ public class SinglePixelPackedSampleModel extends SampleModel { if (mask != 0) { // awt.62=Wrong mask : {0} - throw new IllegalArgumentException(Messages.getString( - "awt.62", bitMasks[i])); //$NON-NLS-1$ + throw new IllegalArgumentException(Messages.getString("awt.62", bitMasks[i])); //$NON-NLS-1$ } } @@ -132,39 +151,39 @@ public class SinglePixelPackedSampleModel extends SampleModel { throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ } switch (getTransferType()) { - case DataBuffer.TYPE_BYTE: - byte bdata[]; - if (obj == null) { - bdata = new byte[1]; - } else { - bdata = (byte[]) obj; - } + case DataBuffer.TYPE_BYTE: + byte bdata[]; + if (obj == null) { + bdata = new byte[1]; + } else { + bdata = (byte[])obj; + } - bdata[0] = (byte) data.getElem(y * scanlineStride + x); - obj = bdata; - break; - case DataBuffer.TYPE_USHORT: - short sdata[]; - if (obj == null) { - sdata = new short[1]; - } else { - sdata = (short[]) obj; - } + bdata[0] = (byte)data.getElem(y * scanlineStride + x); + obj = bdata; + break; + case DataBuffer.TYPE_USHORT: + short sdata[]; + if (obj == null) { + sdata = new short[1]; + } else { + sdata = (short[])obj; + } - sdata[0] = (short) data.getElem(y * scanlineStride + x); - obj = sdata; - break; - case DataBuffer.TYPE_INT: - int idata[]; - if (obj == null) { - idata = new int[1]; - } else { - idata = (int[]) obj; - } + sdata[0] = (short)data.getElem(y * scanlineStride + x); + obj = sdata; + break; + case DataBuffer.TYPE_INT: + int idata[]; + if (obj == null) { + idata = new int[1]; + } else { + idata = (int[])obj; + } - idata[0] = data.getElem(y * scanlineStride + x); - obj = idata; - break; + idata[0] = data.getElem(y * scanlineStride + x); + obj = idata; + break; } return obj; } @@ -176,26 +195,26 @@ public class SinglePixelPackedSampleModel extends SampleModel { throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ } switch (getTransferType()) { - case DataBuffer.TYPE_BYTE: - data.setElem(y * scanlineStride + x, ((byte[]) obj)[0] & 0xff); - break; - case DataBuffer.TYPE_USHORT: - data.setElem(y * scanlineStride + x, ((short[]) obj)[0] & 0xffff); - break; - case DataBuffer.TYPE_INT: - data.setElem(y * scanlineStride + x, ((int[]) obj)[0]); - break; + case DataBuffer.TYPE_BYTE: + data.setElem(y * scanlineStride + x, ((byte[])obj)[0] & 0xff); + break; + case DataBuffer.TYPE_USHORT: + data.setElem(y * scanlineStride + x, ((short[])obj)[0] & 0xffff); + break; + case DataBuffer.TYPE_INT: + data.setElem(y * scanlineStride + x, ((int[])obj)[0]); + break; } } /** - * Compares this SinglePixelPackedSampleModel object with - * the specified object. - * - * @param o the Object to be compared. + * Compares this SinglePixelPackedSampleModel object with the specified + * object. * - * @return true, if this SinglePixelPackedSampleModel object is - * equal to the specified object, false otherwise. + * @param o + * the Object to be compared. + * @return true, if this SinglePixelPackedSampleModel object is equal to the + * specified object, false otherwise. */ @Override public boolean equals(Object o) { @@ -203,21 +222,20 @@ public class SinglePixelPackedSampleModel extends SampleModel { return false; } - SinglePixelPackedSampleModel model = (SinglePixelPackedSampleModel) o; - return this.width == model.width && - this.height == model.height && - this.numBands == model.numBands && - this.dataType == model.dataType && - Arrays.equals(this.bitMasks, model.bitMasks) && - Arrays.equals(this.bitOffsets, model.bitOffsets) && - Arrays.equals(this.bitSizes, model.bitSizes) && - this.scanlineStride == model.scanlineStride; + SinglePixelPackedSampleModel model = (SinglePixelPackedSampleModel)o; + return this.width == model.width && this.height == model.height + && this.numBands == model.numBands && this.dataType == model.dataType + && Arrays.equals(this.bitMasks, model.bitMasks) + && Arrays.equals(this.bitOffsets, model.bitOffsets) + && Arrays.equals(this.bitSizes, model.bitSizes) + && this.scanlineStride == model.scanlineStride; } @Override public SampleModel createSubsetSampleModel(int bands[]) { if (bands.length > this.numBands) { - // awt.64=The number of the bands in the subset is greater than the number of bands in the sample model + // awt.64=The number of the bands in the subset is greater than the + // number of bands in the sample model throw new RasterFormatException(Messages.getString("awt.64")); //$NON-NLS-1$ } @@ -225,14 +243,13 @@ public class SinglePixelPackedSampleModel extends SampleModel { for (int i = 0; i < bands.length; i++) { masks[i] = this.bitMasks[bands[i]]; } - return new SinglePixelPackedSampleModel(this.dataType, this.width, - this.height, this.scanlineStride, masks); + return new SinglePixelPackedSampleModel(this.dataType, this.width, this.height, + this.scanlineStride, masks); } @Override public SampleModel createCompatibleSampleModel(int w, int h) { - return new SinglePixelPackedSampleModel(this.dataType, w, h, - this.bitMasks); + return new SinglePixelPackedSampleModel(this.dataType, w, h, this.bitMasks); } @Override @@ -277,10 +294,9 @@ public class SinglePixelPackedSampleModel extends SampleModel { } @Override - public int[] getPixels(int x, int y, int w, int h, int iArray[], - DataBuffer data) { - if ((x < 0) || (y < 0) || ((long) x + (long) w > this.width) - || ((long) y + (long) h > this.height)) { + public int[] getPixels(int x, int y, int w, int h, int iArray[], DataBuffer data) { + if ((x < 0) || (y < 0) || ((long)x + (long)w > this.width) + || ((long)y + (long)h > this.height)) { // awt.63=Coordinates are not in bounds throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ } @@ -306,13 +322,11 @@ public class SinglePixelPackedSampleModel extends SampleModel { } @Override - public void setPixels(int x, int y, int w, int h, int iArray[], - DataBuffer data) { - if ((x < 0) || (y < 0) || ((long) x + (long) w > this.width) - || ((long) y + (long) h > this.height)) { + public void setPixels(int x, int y, int w, int h, int iArray[], DataBuffer data) { + if ((x < 0) || (y < 0) || ((long)x + (long)w > this.width) + || ((long)y + (long)h > this.height)) { // awt.63=Coordinates are not in bounds - throw new ArrayIndexOutOfBoundsException(Messages - .getString("awt.63")); //$NON-NLS-1$ + throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ } int idx = 0; @@ -339,13 +353,11 @@ public class SinglePixelPackedSampleModel extends SampleModel { } @Override - public int[] getSamples(int x, int y, int w, int h, int b, int iArray[], - DataBuffer data) { - if ((x < 0) || (y < 0) || ((long) x + (long) w > this.width) - || ((long) y + (long) h > this.height)) { + public int[] getSamples(int x, int y, int w, int h, int b, int iArray[], DataBuffer data) { + if ((x < 0) || (y < 0) || ((long)x + (long)w > this.width) + || ((long)y + (long)h > this.height)) { // awt.63=Coordinates are not in bounds - throw new ArrayIndexOutOfBoundsException(Messages - .getString("awt.63")); //$NON-NLS-1$ + throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ } int samples[]; @@ -367,10 +379,9 @@ public class SinglePixelPackedSampleModel extends SampleModel { } @Override - public void setSamples(int x, int y, int w, int h, int b, int iArray[], - DataBuffer data) { - if ((x < 0) || (y < 0) || ((long) x + (long) w > this.width) - || ((long) y + (long) h > this.height)) { + public void setSamples(int x, int y, int w, int h, int b, int iArray[], DataBuffer data) { + if ((x < 0) || (y < 0) || ((long)x + (long)w > this.width) + || ((long)y + (long)h > this.height)) { // awt.63=Coordinates are not in bounds throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ } @@ -389,15 +400,15 @@ public class SinglePixelPackedSampleModel extends SampleModel { int size = (this.height - 1) * scanlineStride + width; switch (this.dataType) { - case DataBuffer.TYPE_BYTE: - data = new DataBufferByte(size); - break; - case DataBuffer.TYPE_USHORT: - data = new DataBufferUShort(size); - break; - case DataBuffer.TYPE_INT: - data = new DataBufferInt(size); - break; + case DataBuffer.TYPE_BYTE: + data = new DataBufferByte(size); + break; + case DataBuffer.TYPE_USHORT: + data = new DataBufferUShort(size); + break; + case DataBuffer.TYPE_INT: + data = new DataBufferInt(size); + break; } return data; } @@ -405,9 +416,10 @@ public class SinglePixelPackedSampleModel extends SampleModel { /** * Gets the offset of the specified pixel in the data array. * - * @param x the X coordinate of the specified pixel. - * @param y the Y coordinate of the specified pixel. - * + * @param x + * the X coordinate of the specified pixel. + * @param y + * the Y coordinate of the specified pixel. * @return the offset of the specified pixel. */ public int getOffset(int x, int y) { @@ -425,7 +437,7 @@ public class SinglePixelPackedSampleModel extends SampleModel { } /** - * Gets an array of the bit offsets of the data array elements. + * Gets an array of the bit offsets of the data array elements. * * @return an array of the bit offsets. */ @@ -505,4 +517,3 @@ public class SinglePixelPackedSampleModel extends SampleModel { } } - diff --git a/awt/java/awt/image/TileObserver.java b/awt/java/awt/image/TileObserver.java index 39ded02ef42aa121d87611e5d87b094dcf4afade..7dd97e29b5cafff56337976114915cbb44efe07e 100644 --- a/awt/java/awt/image/TileObserver.java +++ b/awt/java/awt/image/TileObserver.java @@ -18,27 +18,32 @@ * @author Igor V. Stolyarov * @version $Revision$ */ -package java.awt.image; +package java.awt.image; /** - * An asynchronous update interface for receiving notifications - * about tile information when tiles of a WritableRenderedImage - * become modifiable or unmodifiable. + * An asynchronous update interface for receiving notifications about tile + * information when tiles of a WritableRenderedImage become modifiable or + * unmodifiable. + * + * @since Android 1.0 */ public interface TileObserver { /** - * This method is called when information about a tile - * update is available. + * This method is called when information about a tile update is available. * - * @param source the source image. - * @param tileX the X index of the tile. - * @param tileY the Y index of the tile. - * @param willBeWritable parameter which indicates whether - * the tile will be grabbed for writing or be released. + * @param source + * the source image. + * @param tileX + * the X index of the tile. + * @param tileY + * the Y index of the tile. + * @param willBeWritable + * parameter which indicates whether the tile will be grabbed for + * writing or be released. */ - public void tileUpdate(WritableRenderedImage source, int tileX, int tileY, boolean willBeWritable); + public void tileUpdate(WritableRenderedImage source, int tileX, int tileY, + boolean willBeWritable); } - diff --git a/awt/java/awt/image/VolatileImage.java b/awt/java/awt/image/VolatileImage.java index 3b0cfb2d37f7f0f26803eea59cf100e19cc89c69..f24e866bdb13512bf4f01da9b890293d152417ee 100644 --- a/awt/java/awt/image/VolatileImage.java +++ b/awt/java/awt/image/VolatileImage.java @@ -18,6 +18,7 @@ * @author Alexey A. Petrenko * @version $Revision$ */ + package java.awt.image; import java.awt.Graphics; @@ -28,35 +29,36 @@ import java.awt.ImageCapabilities; import java.awt.Transparency; /** - * The VolatileImage abstract class represents an image which can lose - * its contents at any point. VolatileImage objects are device specific. - * This class provies methods for checking if operation of this image - * are compatible for the GraphicsConfiguration. + * The VolatileImage abstract class represents an image which can lose its + * contents at any point. VolatileImage objects are device specific. This class + * provides methods for checking if operation of this image are compatible for + * the GraphicsConfiguration. + * + * @since Android 1.0 */ public abstract class VolatileImage extends Image - // Volatile image implements Transparency since 1.5 - implements Transparency { - - /** - * The Constant IMAGE_INCOMPATIBLE indicates that this VolatileImage - * is not applicable for the GraphicsConfiguration object. +// Volatile image implements Transparency since 1.5 + implements Transparency { + + /** + * The Constant IMAGE_INCOMPATIBLE indicates that this VolatileImage is not + * applicable for the GraphicsConfiguration object. */ public static final int IMAGE_INCOMPATIBLE = 2; - /** - * The Constant IMAGE_OK indicates that VolatileImage is ready - * for using. + /** + * The Constant IMAGE_OK indicates that VolatileImage is ready for using. */ public static final int IMAGE_OK = 0; - /** - * The Constant IMAGE_RESTORED indicates that VolatileImage - * will be ready to use after restoring. + /** + * The Constant IMAGE_RESTORED indicates that VolatileImage will be ready to + * use after restoring. */ public static final int IMAGE_RESTORED = 1; - /** - * The transparency value of this image. + /** + * The transparency value of this image. */ protected int transparency = OPAQUE; @@ -68,8 +70,8 @@ public abstract class VolatileImage extends Image } /** - * Returns true if rendering data is lost during validating. - * This method should be called after rendering operation of image. + * Returns true if rendering data is lost during validating. This method + * should be called after rendering operation of image. * * @return true, if contents lost during validating, false otherwise. */ @@ -98,8 +100,8 @@ public abstract class VolatileImage extends Image public abstract int getHeight(); /** - * Gets a BufferedImage representation of current VolatileImage that - * won't be affected by any changes to this VolatileImage. + * Gets a BufferedImage representation of current VolatileImage that won't + * be affected by any changes to this VolatileImage. * * @return a BufferedImage representation of current VolatileImage. */ @@ -113,14 +115,14 @@ public abstract class VolatileImage extends Image public abstract int getWidth(); /** - * Validates the drawing surface of the image if the surface had been - * lost and if the spacified GraphicsConfiguration object is - * applicable to this image. - * - * @param gc GraphicsConfiguration object. + * Validates the drawing surface of the image if the surface had been lost + * and if the specified GraphicsConfiguration object is applicable to this + * image. * + * @param gc + * the GraphicsConfiguration object. * @return one of the image status constants: IMAGE_OK, IMAGE_RESTORED or - * IMAGE_INCOMPATIBLE. + * IMAGE_INCOMPATIBLE. */ public abstract int validate(GraphicsConfiguration gc); diff --git a/awt/java/awt/image/WritableRaster.java b/awt/java/awt/image/WritableRaster.java index 0893915ea42587a87953e8fbbd3787e6dfbcb67c..51366ee64c13c63a68f72860ef528ea486090203 100644 --- a/awt/java/awt/image/WritableRaster.java +++ b/awt/java/awt/image/WritableRaster.java @@ -18,6 +18,7 @@ * @author Igor V. Stolyarov * @version $Revision$ */ + package java.awt.image; import java.awt.Point; @@ -26,114 +27,136 @@ import java.awt.Rectangle; import org.apache.harmony.awt.internal.nls.Messages; /** - * The WritableRaster class provides functionality for - * writing samples and pixel capabilities to the Raster. + * The WritableRaster class provides functionality for writing samples and pixel + * capabilities to the Raster. + * + * @since Android 1.0 */ public class WritableRaster extends Raster { /** - * Instantiates a new WritableRaster object with the specified - * SampleModel, DataBuffer, rectangular region and parent - * WritableRaster. + * Instantiates a new WritableRaster object with the specified SampleModel, + * DataBuffer, rectangular region and parent WritableRaster. * - * @param sampleModel the specified SampleModel. - * @param dataBuffer the specified DataBuffer. - * @param aRegion the rectangular region which defines the new image bounds. - * @param sampleModelTranslate this point defines the translation point - * from the SampleModel to the new WritableRaster coordinates. - * @param parent the parent of this WritableRaster. + * @param sampleModel + * the specified SampleModel. + * @param dataBuffer + * the specified DataBuffer. + * @param aRegion + * the rectangular region which defines the new image bounds. + * @param sampleModelTranslate + * this point defines the translation point from the SampleModel + * to the new WritableRaster coordinates. + * @param parent + * the parent of this WritableRaster. */ - protected WritableRaster(SampleModel sampleModel, DataBuffer dataBuffer, - Rectangle aRegion, Point sampleModelTranslate, - WritableRaster parent) { + protected WritableRaster(SampleModel sampleModel, DataBuffer dataBuffer, Rectangle aRegion, + Point sampleModelTranslate, WritableRaster parent) { super(sampleModel, dataBuffer, aRegion, sampleModelTranslate, parent); } /** - * Instantiates a new WritableRaster object with the specified - * SampleModel which defines a layout of this WritableRaster and - * DataBuffer objects which defines the image data. + * Instantiates a new WritableRaster object with the specified SampleModel + * which defines a layout of this WritableRaster and DataBuffer objects + * which defines the image data. * - * @param sampleModel the specified SampleModel. - * @param dataBuffer the specified DataBuffer. - * @param origin the point of origin. + * @param sampleModel + * the specified SampleModel. + * @param dataBuffer + * the specified DataBuffer. + * @param origin + * the point of origin. */ - protected WritableRaster(SampleModel sampleModel, DataBuffer dataBuffer, - Point origin) { - this(sampleModel, dataBuffer, new Rectangle(origin.x, origin.y, - sampleModel.width, sampleModel.height), origin, null); + protected WritableRaster(SampleModel sampleModel, DataBuffer dataBuffer, Point origin) { + this(sampleModel, dataBuffer, new Rectangle(origin.x, origin.y, sampleModel.width, + sampleModel.height), origin, null); } /** * Instantiates a new WritableRaster with the specified SampleModel. * - * @param sampleModel the specified SampleModel. - * @param origin the origin. + * @param sampleModel + * the specified SampleModel. + * @param origin + * the origin. */ protected WritableRaster(SampleModel sampleModel, Point origin) { - this(sampleModel, sampleModel.createDataBuffer(), new Rectangle( - origin.x, origin.y, sampleModel.width, sampleModel.height), - origin, null); + this(sampleModel, sampleModel.createDataBuffer(), new Rectangle(origin.x, origin.y, + sampleModel.width, sampleModel.height), origin, null); } /** - * Sets the data for a single pixel from an input Object which - * represents an array of primitive types: DataBuffer.TYPE_BYTE, - * DataBuffer.TYPE_USHORT, DataBuffer.TYPE_INT, DataBuffer.TYPE_SHORT, - * DataBuffer.TYPE_FLOAT, or DataBuffer.TYPE_DOUBLE. + * Sets the data for a single pixel from an input Object which represents an + * array of primitive types: DataBuffer.TYPE_BYTE, DataBuffer.TYPE_USHORT, + * DataBuffer.TYPE_INT, DataBuffer.TYPE_SHORT, DataBuffer.TYPE_FLOAT, or + * DataBuffer.TYPE_DOUBLE. * - * @param x the X coordinate of the pixel. - * @param y the Y coordinate of the pixel. - * @param inData the input data. + * @param x + * the X coordinate of the pixel. + * @param y + * the Y coordinate of the pixel. + * @param inData + * the input data. */ public void setDataElements(int x, int y, Object inData) { - sampleModel.setDataElements(x - sampleModelTranslateX, - y - sampleModelTranslateY, inData, dataBuffer); + sampleModel.setDataElements(x - sampleModelTranslateX, y - sampleModelTranslateY, inData, + dataBuffer); } /** - * Sets the data elements which represent pixel data to the specified - * rectangle area as a primitive array. The following image data types - * are supported: DataBuffer.TYPE_BYTE, DataBuffer.TYPE_USHORT, - * DataBuffer.TYPE_INT, DataBuffer.TYPE_SHORT, DataBuffer.TYPE_FLOAT, - * or DataBuffer.TYPE_DOUBLE. + * Sets the data elements which represent pixel data to the specified + * rectangle area as a primitive array. The following image data types are + * supported: DataBuffer.TYPE_BYTE, DataBuffer.TYPE_USHORT, + * DataBuffer.TYPE_INT, DataBuffer.TYPE_SHORT, DataBuffer.TYPE_FLOAT, or + * DataBuffer.TYPE_DOUBLE. * - * @param x the X coordinate of the rectangle of pixels. - * @param y the Y coordinate of the rectangle of pixels. - * @param w the width of the rectangle of pixels. - * @param h the height of the rectangle of pixels. - * @param inData the array of primitive type data to be set to the - * specified area. + * @param x + * the X coordinate of the rectangle of pixels. + * @param y + * the Y coordinate of the rectangle of pixels. + * @param w + * the width of the rectangle of pixels. + * @param h + * the height of the rectangle of pixels. + * @param inData + * the array of primitive type data to be set to the specified + * area. */ public void setDataElements(int x, int y, int w, int h, Object inData) { - sampleModel.setDataElements(x - sampleModelTranslateX, - y - sampleModelTranslateY, w, h, inData, dataBuffer); + sampleModel.setDataElements(x - sampleModelTranslateX, y - sampleModelTranslateY, w, h, + inData, dataBuffer); } /** - * Creates the child of this WritableRaster by sharing the specified - * rectangular area in this WritableRaster. - * The parentX, parentY, width and height parameters specify rectangular - * area to be shared. - * - * @param parentX the X coordinate of the upper left corner of - * the shared rectangle with respect to this WritableRaster' coordinates. - * @param parentY the Y coordinate of the upper left corner of - * the shared rectangle with respect to this WritableRaster' coordinates. - * @param w the width of the child area. - * @param h the height of the child area. - * @param childMinX the X coordinate of child area mapped to the parentX - * coordinate. - * @param childMinY the Y coordinate of child area mapped to the parentY - * coordinate. - * @param bandList the array of band indicies. + * Creates the child of this WritableRaster by sharing the specified + * rectangular area in this WritableRaster. The parentX, parentY, width and + * height parameters specify rectangular area to be shared. * + * @param parentX + * the X coordinate of the upper left corner of the shared + * rectangle with respect to this WritableRaster' coordinates. + * @param parentY + * the Y coordinate of the upper left corner of the shared + * rectangle with respect to this WritableRaster' coordinates. + * @param w + * the width of the child area. + * @param h + * the height of the child area. + * @param childMinX + * the X coordinate of child area mapped to the parentX + * coordinate. + * @param childMinY + * the Y coordinate of child area mapped to the parentY + * coordinate. + * @param bandList + * the array of band indices. * @return the child WritableRaster. */ - public WritableRaster createWritableChild(int parentX, int parentY, int w, - int h, int childMinX, int childMinY, int bandList[]) { + public WritableRaster createWritableChild(int parentX, int parentY, int w, int h, + int childMinX, int childMinY, int bandList[]) { if (w <= 0 || h <= 0) { - // awt.244=Width or Height of child Raster is less than or equal to zero + // awt.244=Width or Height of child Raster is less than or equal to + // zero throw new RasterFormatException(Messages.getString("awt.244")); //$NON-NLS-1$ } @@ -147,22 +170,22 @@ public class WritableRaster extends Raster { throw new RasterFormatException(Messages.getString("awt.246")); //$NON-NLS-1$ } - if ((long) parentX + w > Integer.MAX_VALUE) { + if ((long)parentX + w > Integer.MAX_VALUE) { // awt.247=parentX + w results in integer overflow throw new RasterFormatException(Messages.getString("awt.247")); //$NON-NLS-1$ } - if ((long) parentY + h > Integer.MAX_VALUE) { + if ((long)parentY + h > Integer.MAX_VALUE) { // awt.248=parentY + h results in integer overflow throw new RasterFormatException(Messages.getString("awt.248")); //$NON-NLS-1$ } - if ((long) childMinX + w > Integer.MAX_VALUE) { + if ((long)childMinX + w > Integer.MAX_VALUE) { // awt.249=childMinX + w results in integer overflow throw new RasterFormatException(Messages.getString("awt.249")); //$NON-NLS-1$ } - if ((long) childMinY + h > Integer.MAX_VALUE) { + if ((long)childMinY + h > Integer.MAX_VALUE) { // awt.24A=childMinY + h results in integer overflow throw new RasterFormatException(Messages.getString("awt.24A")); //$NON-NLS-1$ } @@ -179,59 +202,60 @@ public class WritableRaster extends Raster { int childTranslateY = childMinY - parentY; return new WritableRaster(childModel, dataBuffer, - new Rectangle(childMinX, childMinY, w, h), - new Point(childTranslateX + sampleModelTranslateX, - childTranslateY + sampleModelTranslateY), - this); + new Rectangle(childMinX, childMinY, w, h), new Point(childTranslateX + + sampleModelTranslateX, childTranslateY + sampleModelTranslateY), this); } /** - * Creates the translated child of this WritableRaster. - * New WritableRaster object is a reference to the this - * WritableRaster and with different location. - * - * @param childMinX the X coordinate of the new WritableRaster. - * @param childMinY the Y coordinate of the new WritableRaster. + * Creates the translated child of this WritableRaster. New WritableRaster + * object is a reference to the this WritableRaster and with different + * location. * + * @param childMinX + * the X coordinate of the new WritableRaster. + * @param childMinY + * the Y coordinate of the new WritableRaster. * @return the WritableRaster. */ - public WritableRaster createWritableTranslatedChild(int childMinX, - int childMinY) { - return createWritableChild(minX, minY, width, height, childMinX, - childMinY, null); + public WritableRaster createWritableTranslatedChild(int childMinX, int childMinY) { + return createWritableChild(minX, minY, width, height, childMinX, childMinY, null); } /** - * Gets the parent WritableRaster for this WritableRaster object. + * Gets the parent WritableRaster for this WritableRaster object. * * @return the parent WritableRaster for this WritableRaster object. */ public WritableRaster getWritableParent() { - return (WritableRaster) parent; + return (WritableRaster)parent; } /** - * Sets pixels from the specified source Raster srcRaster to this + * Sets pixels from the specified source Raster srcRaster to this * WritableRaster. * - * @param srcRaster the source Raster. + * @param srcRaster + * the source Raster. */ public void setRect(Raster srcRaster) { setRect(0, 0, srcRaster); } /** - * Sets pixels from the specified source Raster srcRaster to this - * WritableRaster. Each pixel with (x, y) coordinates from the source - * Raster is copied to pixel with (x+dx, y+dy) coordinates in this - * WritableRaster. The pixels with (x+dx, y+dy) coordinates which - * are out the bounds of this raster are ignored. - * - * @param dx the distance the pixel's X coordinate in the source - * Raster is translated when writtien to this WritableRaster. - * @param dy the distance the pixel's Y coordinate in the source - * Raster is translated when writtien to this WritableRaster. - * @param srcRaster the source Raster. + * Sets pixels from the specified source Raster srcRaster to this + * WritableRaster. Each pixel with (x, y) coordinates from the source Raster + * is copied to pixel with (x+dx, y+dy) coordinates in this WritableRaster. + * The pixels with (x+dx, y+dy) coordinates which are out the bounds of this + * raster are ignored. + * + * @param dx + * the distance the pixel's X coordinate in the source Raster is + * translated when writtien to this WritableRaster. + * @param dy + * the distance the pixel's Y coordinate in the source Raster is + * translated when writtien to this WritableRaster. + * @param srcRaster + * the source Raster. */ public void setRect(int dx, int dy, Raster srcRaster) { int w = srcRaster.getWidth(); @@ -272,47 +296,47 @@ public class WritableRaster extends Raster { } switch (sampleModel.getDataType()) { - case DataBuffer.TYPE_BYTE: - case DataBuffer.TYPE_SHORT: - case DataBuffer.TYPE_USHORT: - case DataBuffer.TYPE_INT: - int iPixelsLine[] = null; - for (int i = 0; i < h; i++) { - iPixelsLine = srcRaster.getPixels(srcX, srcY + i, w, 1, - iPixelsLine); - setPixels(dstX, dstY + i, w, 1, iPixelsLine); - } - break; - - case DataBuffer.TYPE_FLOAT: - float fPixelsLine[] = null; - for (int i = 0; i < h; i++) { - fPixelsLine = srcRaster.getPixels(srcX, srcY + i, w, 1, - fPixelsLine); - setPixels(dstX, dstY + i, w, 1, fPixelsLine); - } - break; - - case DataBuffer.TYPE_DOUBLE: - double dPixelsLine[] = null; - for (int i = 0; i < h; i++) { - dPixelsLine = srcRaster.getPixels(srcX, srcY + i, w, 1, - dPixelsLine); - setPixels(dstX, dstY + i, w, 1, dPixelsLine); - } - break; + case DataBuffer.TYPE_BYTE: + case DataBuffer.TYPE_SHORT: + case DataBuffer.TYPE_USHORT: + case DataBuffer.TYPE_INT: + int iPixelsLine[] = null; + for (int i = 0; i < h; i++) { + iPixelsLine = srcRaster.getPixels(srcX, srcY + i, w, 1, iPixelsLine); + setPixels(dstX, dstY + i, w, 1, iPixelsLine); + } + break; + + case DataBuffer.TYPE_FLOAT: + float fPixelsLine[] = null; + for (int i = 0; i < h; i++) { + fPixelsLine = srcRaster.getPixels(srcX, srcY + i, w, 1, fPixelsLine); + setPixels(dstX, dstY + i, w, 1, fPixelsLine); + } + break; + + case DataBuffer.TYPE_DOUBLE: + double dPixelsLine[] = null; + for (int i = 0; i < h; i++) { + dPixelsLine = srcRaster.getPixels(srcX, srcY + i, w, 1, dPixelsLine); + setPixels(dstX, dstY + i, w, 1, dPixelsLine); + } + break; } } /** - * Sets the data for a rectangle of pixels from an input Raster to - * this WritableRaster. + * Sets the data for a rectangle of pixels from an input Raster to this + * WritableRaster. * - * @param x the X coordinate of the point where the data of - * the input Raster is to be written. - * @param y the Y coordinate of the point where the data of - * the input Raster is to be written. - * @param inRaster the input Raster. + * @param x + * the X coordinate of the point where the data of the input + * Raster is to be written. + * @param y + * the Y coordinate of the point where the data of the input + * Raster is to be written. + * @param inRaster + * the input Raster. */ public void setDataElements(int x, int y, Raster inRaster) { int dstX = x + inRaster.getMinX(); @@ -321,8 +345,8 @@ public class WritableRaster extends Raster { int w = inRaster.getWidth(); int h = inRaster.getHeight(); - if (dstX < this.minX || dstX + w > this.minX + this.width || - dstY < this.minY || dstY + h > this.minY + this.height) { + if (dstX < this.minX || dstX + w > this.minX + this.width || dstY < this.minY + || dstY + h > this.minY + this.height) { // awt.63=Coordinates are not in bounds throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ } @@ -338,179 +362,231 @@ public class WritableRaster extends Raster { } /** - * Sets a int array of samples for the specified pixel - * in this WritableRaster. + * Sets an integer array of samples for the specified pixel in this + * WritableRaster. * - * @param x the pixel's X coordinate. - * @param y the pixel's Y coordinate. - * @param iArray the int array of samples. + * @param x + * the pixel's X coordinate. + * @param y + * the pixel's Y coordinate. + * @param iArray + * the integer array of samples. */ public void setPixel(int x, int y, int iArray[]) { - sampleModel.setPixel(x - sampleModelTranslateX, - y - sampleModelTranslateY, iArray, dataBuffer); + sampleModel.setPixel(x - sampleModelTranslateX, y - sampleModelTranslateY, iArray, + dataBuffer); } /** - * Sets a float array of samples for the specified pixel - * in this WritableRaster. + * Sets a float array of samples for the specified pixel in this + * WritableRaster. * - * @param x the pixel's X coordinate. - * @param y the pixel's Y coordinate. - * @param fArray the float array of samples. + * @param x + * the pixel's X coordinate. + * @param y + * the pixel's Y coordinate. + * @param fArray + * the float array of samples. */ public void setPixel(int x, int y, float fArray[]) { - sampleModel.setPixel(x - sampleModelTranslateX, - y - sampleModelTranslateY, fArray, dataBuffer); + sampleModel.setPixel(x - sampleModelTranslateX, y - sampleModelTranslateY, fArray, + dataBuffer); } /** - * Sets a double array of samples for the specified pixel - * in this WritableRaster. + * Sets a double array of samples for the specified pixel in this + * WritableRaster. * - * @param x the pixel's X coordinate. - * @param y the pixel's Y coordinate. - * @param dArray the double array of samples. + * @param x + * the pixel's X coordinate. + * @param y + * the pixel's Y coordinate. + * @param dArray + * the double array of samples. */ public void setPixel(int x, int y, double dArray[]) { - sampleModel.setPixel(x - sampleModelTranslateX, - y - sampleModelTranslateY, dArray, dataBuffer); + sampleModel.setPixel(x - sampleModelTranslateX, y - sampleModelTranslateY, dArray, + dataBuffer); } /** - * Sets a int array of samples for the specified rectangular area - * of pixels in this WritableRaster. + * Sets a integer array of samples for the specified rectangular area of + * pixels in this WritableRaster. * - * @param x the X coordinate of rectangular area. - * @param y the Y coordinate of rectangular area. - * @param w the width of rectangular area. - * @param h the height of rectangular area. - * @param iArray the int array of samples. + * @param x + * the X coordinate of rectangular area. + * @param y + * the Y coordinate of rectangular area. + * @param w + * the width of rectangular area. + * @param h + * the height of rectangular area. + * @param iArray + * the integer array of samples. */ public void setPixels(int x, int y, int w, int h, int iArray[]) { - sampleModel.setPixels(x - sampleModelTranslateX, - y - sampleModelTranslateY, w, h, iArray, dataBuffer); + sampleModel.setPixels(x - sampleModelTranslateX, y - sampleModelTranslateY, w, h, iArray, + dataBuffer); } /** - * Sets a float array of samples for the specified rectangular area - * of pixels in this WritableRaster. + * Sets a float array of samples for the specified rectangular area of + * pixels in this WritableRaster. * - * @param x the X coordinate of rectangular area. - * @param y the Y coordinate of rectangular area. - * @param w the width of rectangular area. - * @param h the height of rectangular area. - * @param fArray the float array of samples. + * @param x + * the X coordinate of rectangular area. + * @param y + * the Y coordinate of rectangular area. + * @param w + * the width of rectangular area. + * @param h + * the height of rectangular area. + * @param fArray + * the float array of samples. */ public void setPixels(int x, int y, int w, int h, float fArray[]) { - sampleModel.setPixels(x - sampleModelTranslateX, - y - sampleModelTranslateY, w, h, fArray, dataBuffer); + sampleModel.setPixels(x - sampleModelTranslateX, y - sampleModelTranslateY, w, h, fArray, + dataBuffer); } /** - * Sets a double array of samples for the specified rectangular area - * of pixels in this WritableRaster. + * Sets a double array of samples for the specified rectangular area of + * pixels in this WritableRaster. * - * @param x the X coordinate of rectangular area. - * @param y the Y coordinate of rectangular area. - * @param w the width of rectangular area. - * @param h the height of rectangular area. - * @param dArray the double array of samples. + * @param x + * the X coordinate of rectangular area. + * @param y + * the Y coordinate of rectangular area. + * @param w + * the width of rectangular area. + * @param h + * the height of rectangular area. + * @param dArray + * the double array of samples. */ public void setPixels(int x, int y, int w, int h, double dArray[]) { - sampleModel.setPixels(x - sampleModelTranslateX, - y - sampleModelTranslateY, w, h, dArray, dataBuffer); + sampleModel.setPixels(x - sampleModelTranslateX, y - sampleModelTranslateY, w, h, dArray, + dataBuffer); } /** - * Sets the samples for the specified band and the specified - * rectangular area of pixels with an int array of samples. + * Sets the samples for the specified band and the specified rectangular + * area of pixels with an integer array of samples. * - * @param x the X coordinate of the area of pixels. - * @param y the Y coordinate of the area of pixels. - * @param w the width of the area of pixels. - * @param h the height of the area of pixels. - * @param b the specified band. - * @param iArray the int array of samples. - + * @param x + * the X coordinate of the area of pixels. + * @param y + * the Y coordinate of the area of pixels. + * @param w + * the width of the area of pixels. + * @param h + * the height of the area of pixels. + * @param b + * the specified band. + * @param iArray + * the integer array of samples. */ public void setSamples(int x, int y, int w, int h, int b, int iArray[]) { - sampleModel.setSamples(x - sampleModelTranslateX, - y - sampleModelTranslateY, w, h, b, iArray, dataBuffer); + sampleModel.setSamples(x - sampleModelTranslateX, y - sampleModelTranslateY, w, h, b, + iArray, dataBuffer); } /** - * Sets the samples for the specified band and the specified - * rectangular area of pixels with a float array of samples. + * Sets the samples for the specified band and the specified rectangular + * area of pixels with a float array of samples. * - * @param x the X coordinate of the area of pixels. - * @param y the Y coordinate of the area of pixels. - * @param w the width of the area of pixels. - * @param h the height of the area of pixels. - * @param b the specified band. - * @param fArray the float array of samples. + * @param x + * the X coordinate of the area of pixels. + * @param y + * the Y coordinate of the area of pixels. + * @param w + * the width of the area of pixels. + * @param h + * the height of the area of pixels. + * @param b + * the specified band. + * @param fArray + * the float array of samples. */ public void setSamples(int x, int y, int w, int h, int b, float fArray[]) { - sampleModel.setSamples(x - sampleModelTranslateX, - y - sampleModelTranslateY, w, h, b, fArray, dataBuffer); + sampleModel.setSamples(x - sampleModelTranslateX, y - sampleModelTranslateY, w, h, b, + fArray, dataBuffer); } /** - * Sets the samples for the specified band and the specified - * rectangular area of pixels with a double array of samples. + * Sets the samples for the specified band and the specified rectangular + * area of pixels with a double array of samples. * - * @param x the X coordinate of the area of pixels. - * @param y the Y coordinate of the area of pixels. - * @param w the width of the area of pixels. - * @param h the height of the area of pixels. - * @param b the specified band. - * @param dArray the double array of samples. + * @param x + * the X coordinate of the area of pixels. + * @param y + * the Y coordinate of the area of pixels. + * @param w + * the width of the area of pixels. + * @param h + * the height of the area of pixels. + * @param b + * the specified band. + * @param dArray + * the double array of samples. */ public void setSamples(int x, int y, int w, int h, int b, double dArray[]) { - sampleModel.setSamples(x - sampleModelTranslateX, - y - sampleModelTranslateY, w, h, b, dArray, dataBuffer); + sampleModel.setSamples(x - sampleModelTranslateX, y - sampleModelTranslateY, w, h, b, + dArray, dataBuffer); } /** - * Sets the sample for the specified band and the specified - * pixel with an int sample. + * Sets the sample for the specified band and the specified pixel with an + * integer sample. * - * @param x the X coordinate of the pixel. - * @param y the Y coordinate of the pixel. - * @param b the specified band. - * @param s the sample to be set. + * @param x + * the X coordinate of the pixel. + * @param y + * the Y coordinate of the pixel. + * @param b + * the specified band. + * @param s + * the sample to be set. */ public void setSample(int x, int y, int b, int s) { - sampleModel.setSample(x - sampleModelTranslateX, - y - sampleModelTranslateY, b, s, dataBuffer); + sampleModel.setSample(x - sampleModelTranslateX, y - sampleModelTranslateY, b, s, + dataBuffer); } /** - * Sets the sample for the specified band and the specified - * pixel with a float sample. + * Sets the sample for the specified band and the specified pixel with a + * float sample. * - * @param x the X coordinate of the pixel. - * @param y the Y coordinate of the pixel. - * @param b the specified band. - * @param s the sample to be set. + * @param x + * the X coordinate of the pixel. + * @param y + * the Y coordinate of the pixel. + * @param b + * the specified band. + * @param s + * the sample to be set. */ public void setSample(int x, int y, int b, float s) { - sampleModel.setSample(x - sampleModelTranslateX, - y - sampleModelTranslateY, b, s, dataBuffer); + sampleModel.setSample(x - sampleModelTranslateX, y - sampleModelTranslateY, b, s, + dataBuffer); } /** - * Sets the sample for the specified band and the specified - * pixel with a int sample. + * Sets the sample for the specified band and the specified pixel with an + * integer sample. * - * @param x the X coordinate of the pixel. - * @param y the Y coordinate of the pixel. - * @param b the specified band. - * @param s the sample to be set. + * @param x + * the X coordinate of the pixel. + * @param y + * the Y coordinate of the pixel. + * @param b + * the specified band. + * @param s + * the sample to be set. */ public void setSample(int x, int y, int b, double s) { - sampleModel.setSample(x - sampleModelTranslateX, - y - sampleModelTranslateY, b, s, dataBuffer); + sampleModel.setSample(x - sampleModelTranslateX, y - sampleModelTranslateY, b, s, + dataBuffer); } } - diff --git a/awt/java/awt/image/WritableRenderedImage.java b/awt/java/awt/image/WritableRenderedImage.java index ee1cb9e25a1eebae71f9e3612ba052fa7e7ccde8..052353b60ff3b151311e5fa7c7cefbc22860c8d8 100644 --- a/awt/java/awt/image/WritableRenderedImage.java +++ b/awt/java/awt/image/WritableRenderedImage.java @@ -18,23 +18,27 @@ * @author Igor V. Stolyarov * @version $Revision$ */ + package java.awt.image; import java.awt.Point; /** - * The WriteableRenderedImage interface is interface for objects which - * contains Raster data of one or several tiles. This interface provides - * notification mehanism for obtaining tile's writing status. + * The WriteableRenderedImage interface is interface for objects which contains + * Raster data of one or several tiles. This interface provides notification + * mechanism for obtaining tile's writing status. + * + * @since Android 1.0 */ public interface WritableRenderedImage extends RenderedImage { /** - * Gets and checks out the writable tile for writing. - * - * @param tileX the X index of the tile. - * @param tileY the Y index of the tile. + * Gets and checks out the writable tile for writing. * + * @param tileX + * the X index of the tile. + * @param tileY + * the Y index of the tile. * @return the WritableRaster. */ public WritableRaster getWritableTile(int tileX, int tileY); @@ -42,60 +46,64 @@ public interface WritableRenderedImage extends RenderedImage { /** * Removes the registered TileObserver. * - * @param to the TileObserver which is registered for this - * WritableRenderedImage. + * @param to + * the TileObserver which is registered for this + * WritableRenderedImage. */ public void removeTileObserver(TileObserver to); /** * Adds the specified TileObserver to this WritableRenderedImage. * - * @param to the TileObserver object to be added. + * @param to + * the TileObserver object to be added. */ public void addTileObserver(TileObserver to); /** - * Sets this image to the contents of the specified Raster. + * Sets this image to the contents of the specified Raster. * - * @param r the specified Raster. + * @param r + * the specified Raster. */ public void setData(Raster r); /** - * Gets the array of points wich represent indices of tiles which - * are check out for writing. + * Gets the array of points which represent indices of tiles which are check + * out for writing. * - * @return the array of Points. + * @return the array of points. */ public Point[] getWritableTileIndices(); /** * Checks if the specified tile is writable or not. * - * @param tileX the X index of tile. - * @param tileY the Y index of tile. - * - * @return true, if the specified tile is writable, - * false otherwise. + * @param tileX + * the X index of tile. + * @param tileY + * the Y index of tile. + * @return true, if the specified tile is writable, false otherwise. */ public boolean isTileWritable(int tileX, int tileY); /** - * Release the specified writable tile. This method removes the writer - * from the tile. + * Release the specified writable tile. This method removes the writer from + * the tile. * - * @param tileX the X index of the tile. - * @param tileY the Y index of the tile. + * @param tileX + * the X index of the tile. + * @param tileY + * the Y index of the tile. */ public void releaseWritableTile(int tileX, int tileY); /** * Checks if there is a tile which is checked out for writing. * - * @return true, if any tile is checked out for writing, false if there - * is no such tile. + * @return true, if any tile is checked out for writing, false if there is + * no such tile. */ public boolean hasTileWriters(); } - diff --git a/awt/java/awt/image/package.html b/awt/java/awt/image/package.html new file mode 100644 index 0000000000000000000000000000000000000000..b4d6ef0a8d087b92f319698ef98c678c85491bfa --- /dev/null +++ b/awt/java/awt/image/package.html @@ -0,0 +1,8 @@ + + +

    + This package contains classes and interfaces that allow to modify existing images or to create a new image rather than loading it from a file. +

    + @since Android 1.0 + + diff --git a/awt/java/awt/image/renderable/ContextualRenderedImageFactory.java b/awt/java/awt/image/renderable/ContextualRenderedImageFactory.java index 3e966379e2ca1783428b58a5f3ba77cab70dca78..1881a0c276f58e9402ec4c555f9b065d03164c67 100644 --- a/awt/java/awt/image/renderable/ContextualRenderedImageFactory.java +++ b/awt/java/awt/image/renderable/ContextualRenderedImageFactory.java @@ -18,72 +18,80 @@ * @author Igor V. Stolyarov * @version $Revision$ */ + package java.awt.image.renderable; import java.awt.geom.Rectangle2D; import java.awt.image.RenderedImage; /** - * A factory for creating ContextualRenderedImage objects with utilities - * for manipulating the properties in the parameter block. + * A factory for creating ContextualRenderedImage objects with utilities for + * manipulating the properties in the parameter block. + * + * @since Android 1.0 */ public interface ContextualRenderedImageFactory extends RenderedImageFactory { /** * Maps a render context to a parameter block and a renderable image. * - * @param a0 the index - * @param a1 the RenderContext - * @param a2 the ParameterBlock - * @param a3 the RenderableImage - * - * @return the render context + * @param a0 + * the index. + * @param a1 + * the RenderContext. + * @param a2 + * the ParameterBlock. + * @param a3 + * the RenderableImage. + * @return the render context. */ - public RenderContext mapRenderContext(int a0, RenderContext a1, ParameterBlock a2, RenderableImage a3); + public RenderContext mapRenderContext(int a0, RenderContext a1, ParameterBlock a2, + RenderableImage a3); /** * Gets the value of the property from the parameter block. * - * @param a0 the parameter block to examine to find the property - * @param a1 the name of the property - * - * @return the value of the property + * @param a0 + * the parameter block to examine to find the property. + * @param a1 + * the name of the property. + * @return the value of the property. */ public Object getProperty(ParameterBlock a0, String a1); /** - * Creates the rendered image determined by the render context and - * parameter block. + * Creates the rendered image determined by the render context and parameter + * block. * - * @param a0 the RenderContext - * @param a1 the ParameterBlock - * - * @return the rendered image + * @param a0 + * the RenderContext. + * @param a1 + * the ParameterBlock. + * @return the rendered image. */ public RenderedImage create(RenderContext a0, ParameterBlock a1); /** * Gets the bounding rectangle from the parameter block. * - * @param a0 the parameter block to read the bounds from - * - * @return the bounding rectangle + * @param a0 + * the parameter block to read the bounds from. + * @return the bounding rectangle. */ public Rectangle2D getBounds2D(ParameterBlock a0); /** * Gets the names of all of the supported properties. * - * @return the property names + * @return the property names. */ public String[] getPropertyNames(); /** * Checks if this image factory is dynamic. * - * @return true, if this image factory is dynamic + * @return true, if this image factory is dynamic. */ public boolean isDynamic(); } - diff --git a/awt/java/awt/image/renderable/ParameterBlock.java b/awt/java/awt/image/renderable/ParameterBlock.java index 1555f45b7831af9600461f208b2c07f7be04c7f4..7dde73a945b687cc5aed7e938845a4fb42264436 100644 --- a/awt/java/awt/image/renderable/ParameterBlock.java +++ b/awt/java/awt/image/renderable/ParameterBlock.java @@ -18,6 +18,7 @@ * @author Igor V. Stolyarov * @version $Revision$ */ + package java.awt.image.renderable; import java.awt.image.RenderedImage; @@ -25,28 +26,36 @@ import java.io.Serializable; import java.util.Vector; /** - * The Class ParameterBlock groups an indexed set of parameter data - * with a set of renderable (source) images. The mapping between - * the indexed parameters and their property names is provided - * by a {@link ContextualRenderedImageFactory} + * The class ParameterBlock groups an indexed set of parameter data with a set + * of renderable (source) images. The mapping between the indexed parameters and + * their property names is provided by a {@link ContextualRenderedImageFactory}. + * + * @since Android 1.0 */ public class ParameterBlock implements Cloneable, Serializable { - - /** The Constant serialVersionUID. */ + /** + * The Constant serialVersionUID. + */ private static final long serialVersionUID = -7577115551785240750L; - /** The sources (renderable images). */ + /** + * The sources (renderable images). + */ protected Vector sources = new Vector(); - /** The parameters. */ + /** + * The parameters. + */ protected Vector parameters = new Vector(); /** * Instantiates a new parameter block. * - * @param sources the vector of source images - * @param parameters the vector of parameters + * @param sources + * the vector of source images. + * @param parameters + * the vector of parameters. */ public ParameterBlock(Vector sources, Vector parameters) { setSources(sources); @@ -56,7 +65,8 @@ public class ParameterBlock implements Cloneable, Serializable { /** * Instantiates a new parameter block with no parameters. * - * @param sources the vector of source images + * @param sources + * the vector of source images. */ public ParameterBlock(Vector sources) { setSources(sources); @@ -65,18 +75,20 @@ public class ParameterBlock implements Cloneable, Serializable { /** * Instantiates a new parameter block with no image or parameter vectors. */ - public ParameterBlock() {} + public ParameterBlock() { + } /** * Sets the source image at the specified index. * - * @param source the source image - * @param index the index where the source will be placed - * - * @return this parameter block + * @param source + * the source image. + * @param index + * the index where the source will be placed. + * @return this parameter block. */ public ParameterBlock setSource(Object source, int index) { - if(sources.size() < index + 1){ + if (sources.size() < index + 1) { sources.setSize(index + 1); } sources.setElementAt(source, index); @@ -86,14 +98,15 @@ public class ParameterBlock implements Cloneable, Serializable { /** * Sets the parameter value object at the specified index. * - * @param obj the parameter value to place at the desired index - * @param index the index where the object is to be placed in the - * vector of parameters - * - * @return this parameter block + * @param obj + * the parameter value to place at the desired index. + * @param index + * the index where the object is to be placed in the vector of + * parameters. + * @return this parameter block. */ public ParameterBlock set(Object obj, int index) { - if(parameters.size() < index + 1){ + if (parameters.size() < index + 1) { parameters.setSize(index + 1); } parameters.setElementAt(obj, index); @@ -103,9 +116,9 @@ public class ParameterBlock implements Cloneable, Serializable { /** * Adds a source to the vector of sources. * - * @param source the source to add - * - * @return this parameter block + * @param source + * the source to add. + * @return this parameter block. */ public ParameterBlock addSource(Object source) { sources.addElement(source); @@ -115,9 +128,9 @@ public class ParameterBlock implements Cloneable, Serializable { /** * Adds the object to the vector of parameter values * - * @param obj the obj to add - * - * @return this parameter block + * @param obj + * the obj to add. + * @return this parameter block. */ public ParameterBlock add(Object obj) { parameters.addElement(obj); @@ -125,20 +138,22 @@ public class ParameterBlock implements Cloneable, Serializable { } /** - * Sets the vector of sources, replacing the existing - * vector of sources, if any. + * Sets the vector of sources, replacing the existing vector of sources, if + * any. * - * @param sources the new sources + * @param sources + * the new sources. */ public void setSources(Vector sources) { this.sources = sources; } /** - * Sets the vector of parameters, replacing the existing - * vector of parameters, if any. + * Sets the vector of parameters, replacing the existing vector of + * parameters, if any. * - * @param parameters the new parameters + * @param parameters + * the new parameters. */ public void setParameters(Vector parameters) { this.parameters = parameters; @@ -147,7 +162,7 @@ public class ParameterBlock implements Cloneable, Serializable { /** * Gets the vector of sources. * - * @return the sources + * @return the sources. */ public Vector getSources() { return sources; @@ -156,7 +171,7 @@ public class ParameterBlock implements Cloneable, Serializable { /** * Gets the vector of parameters. * - * @return the parameters + * @return the parameters. */ public Vector getParameters() { return parameters; @@ -165,9 +180,9 @@ public class ParameterBlock implements Cloneable, Serializable { /** * Gets the source at the specified index. * - * @param index the index - * - * @return the source object found at the specified index + * @param index + * the index. + * @return the source object found at the specified index. */ public Object getSource(int index) { return sources.elementAt(index); @@ -176,9 +191,9 @@ public class ParameterBlock implements Cloneable, Serializable { /** * Gets the object parameter found at the specified index. * - * @param index the index - * - * @return the parameter object found at the specified index + * @param index + * the index. + * @return the parameter object found at the specified index. */ public Object getObjectParameter(int index) { return parameters.elementAt(index); @@ -187,328 +202,333 @@ public class ParameterBlock implements Cloneable, Serializable { /** * Shallow clone (clones using the superclass clone method). * - * @return the clone of this object + * @return the clone of this object. */ public Object shallowClone() { - try{ + try { return super.clone(); - }catch(Exception e){ + } catch (Exception e) { return null; } } + /** + * Returns a copy of this ParameterBlock instance. + * + * @return the identical copy of this instance. + */ @SuppressWarnings("unchecked") @Override public Object clone() { ParameterBlock replica; - try{ + try { replica = (ParameterBlock)super.clone(); - }catch(Exception e){ + } catch (Exception e) { return null; } - if(sources != null){ + if (sources != null) { replica.setSources((Vector)(sources.clone())); } - if(parameters != null){ + if (parameters != null) { replica.setParameters((Vector)(parameters.clone())); } return replica; } /** - * Gets an array of classes corresponding to all of the parameter - * values found in the array of parameters, in order. + * Gets an array of classes corresponding to all of the parameter values + * found in the array of parameters, in order. * - * @return the parameter classes + * @return the parameter classes. */ public Class[] getParamClasses() { int count = parameters.size(); Class paramClasses[] = new Class[count]; - for(int i = 0; i < count; i++){ + for (int i = 0; i < count; i++) { paramClasses[i] = parameters.elementAt(i).getClass(); } return paramClasses; } /** - * Gets the renderable source image found at the specified index - * in the source array. - * - * @param index the index + * Gets the renderable source image found at the specified index in the + * source array. * - * @return the renderable source image + * @param index + * the index. + * @return the renderable source image. */ public RenderableImage getRenderableSource(int index) { return (RenderableImage)sources.elementAt(index); } /** - * Wraps the short value in a Short and places it in the - * parameter block at the specified index. + * Wraps the short value in a Short and places it in the parameter block at + * the specified index. * - * @param s the short value of the parameter - * @param index the index - * - * @return this parameter block + * @param s + * the short value of the parameter. + * @param index + * the index. + * @return this parameter block. */ public ParameterBlock set(short s, int index) { return set(new Short(s), index); } /** - * Wraps the short value in a Short and adds it to the - * parameter block. - * - * @param s the short value of the parameter + * Wraps the short value in a Short and adds it to the parameter block. * - * @return this parameter block + * @param s + * the short value of the parameter. + * @return this parameter block. */ public ParameterBlock add(short s) { return add(new Short(s)); } /** - * Wraps the long value in a Long and places it in the - * parameter block at the specified index. + * Wraps the long value in a Long and places it in the parameter block at + * the specified index. * - * @param l the long value of the parameter - * @param index the index - * - * @return this parameter block + * @param l + * the long value of the parameter. + * @param index + * the index. + * @return this parameter block. */ public ParameterBlock set(long l, int index) { return set(new Long(l), index); } /** - * Wraps the long value in a Long and adds it to the - * parameter block. - * - * @param l the long value of the parameter + * Wraps the long value in a Long and adds it to the parameter block. * - * @return this parameter block + * @param l + * the long value of the parameter. + * @return this parameter block. */ public ParameterBlock add(long l) { return add(new Long(l)); } /** - * Wraps the int value in an Integer and places it in the - * parameter block at the specified index. - * - * @param i the int value of the parameter - * @param index the index + * Wraps the integer value in an Integer and places it in the parameter + * block at the specified index. * - * @return this parameter block + * @param i + * the integer value of the parameter. + * @param index + * the index. + * @return this parameter block. */ public ParameterBlock set(int i, int index) { return set(new Integer(i), index); } /** - * Wraps the int value in an Integer and adds it to the - * parameter block. + * Wraps the integer value in an Integer and adds it to the parameter block. * - * @param i the int value of the parameter - * - * @return this parameter block + * @param i + * the integer value of the parameter. + * @return this parameter block. */ public ParameterBlock add(int i) { return add(new Integer(i)); } /** - * Wraps the float value in a Float and places it in the - * parameter block at the specified index. - * - * @param f the float value of the parameter - * @param index the index + * Wraps the float value in a Float and places it in the parameter block at + * the specified index. * - * @return this parameter block + * @param f + * the float value of the parameter. + * @param index + * the index. + * @return this parameter block. */ public ParameterBlock set(float f, int index) { return set(new Float(f), index); } /** - * Wraps the float value in a Float and adds it to the - * parameter block. + * Wraps the float value in a Float and adds it to the parameter block. * - * @param f the float value of the parameter - * - * @return this parameter block + * @param f + * the float value of the parameter. + * @return this parameter block. */ public ParameterBlock add(float f) { return add(new Float(f)); } /** - * Wraps the double value in a Double and places it in the - * parameter block at the specified index. - * - * @param d the double value of the parameter - * @param index the index + * Wraps the double value in a Double and places it in the parameter block + * at the specified index. * - * @return this parameter block + * @param d + * the double value of the parameter. + * @param index + * the index. + * @return this parameter block. */ public ParameterBlock set(double d, int index) { return set(new Double(d), index); } /** - * Wraps the double value in a Double and adds it to the - * parameter block. - * - * @param d the double value of the parameter + * Wraps the double value in a Double and adds it to the parameter block. * - * @return this parameter block + * @param d + * the double value of the parameter. + * @return this parameter block. */ public ParameterBlock add(double d) { return add(new Double(d)); } /** - * Wraps the char value in a Character and places it in the - * parameter block at the specified index. + * Wraps the char value in a Character and places it in the parameter block + * at the specified index. * - * @param c the char value of the parameter - * @param index the index - * - * @return this parameter block + * @param c + * the char value of the parameter. + * @param index + * the index. + * @return this parameter block. */ public ParameterBlock set(char c, int index) { return set(new Character(c), index); } /** - * Wraps the char value in a Character and adds it to the - * parameter block. - * - * @param c the char value of the parameter + * Wraps the char value in a Character and adds it to the parameter block. * - * @return this parameter block + * @param c + * the char value of the parameter. + * @return this parameter block. */ public ParameterBlock add(char c) { return add(new Character(c)); } /** - * Wraps the byte value in a Byte and places it in the - * parameter block at the specified index. + * Wraps the byte value in a Byte and places it in the parameter block at + * the specified index. * - * @param b the byte value of the parameter - * @param index the index - * - * @return this parameter block + * @param b + * the byte value of the parameter. + * @param index + * the index. + * @return this parameter block. */ public ParameterBlock set(byte b, int index) { return set(new Byte(b), index); } /** - * Wraps the byte value in a Byte and adds it to the - * parameter block. - * - * @param b the byte value of the parameter + * Wraps the byte value in a Byte and adds it to the parameter block. * - * @return the parameter block + * @param b + * the byte value of the parameter. + * @return the parameter block. */ public ParameterBlock add(byte b) { return add(new Byte(b)); } /** - * Gets the RenderedImage at the specified index from the - * vector of source images. - * - * @param index the index + * Gets the RenderedImage at the specified index from the vector of source + * images. * - * @return the rendered image + * @param index + * the index. + * @return the rendered image. */ public RenderedImage getRenderedSource(int index) { return (RenderedImage)sources.elementAt(index); } /** - * Gets the short-valued parameter found at the desired index - * in the vector of parameter values. + * Gets the short-valued parameter found at the desired index in the vector + * of parameter values. * - * @param index the index - * - * @return the short parameter + * @param index + * the index. + * @return the short parameter. */ public short getShortParameter(int index) { return ((Short)parameters.elementAt(index)).shortValue(); } /** - * Gets the long-valued parameter found at the desired index - * in the vector of parameter values. - * - * @param index the index + * Gets the long-valued parameter found at the desired index in the vector + * of parameter values. * - * @return the long parameter + * @param index + * the index. + * @return the long parameter. */ public long getLongParameter(int index) { return ((Long)parameters.elementAt(index)).longValue(); } /** - * Gets the int-valued parameter found at the desired index - * in the vector of parameter values. + * Gets the integer-valued parameter found at the desired index in the + * vector of parameter values. * - * @param index the index - * - * @return the int parameter + * @param index + * the index. + * @return the integer parameter. */ public int getIntParameter(int index) { return ((Integer)parameters.elementAt(index)).intValue(); } /** - * Gets the float-valued parameter found at the desired index - * in the vector of parameter values. - * - * @param index the index + * Gets the float-valued parameter found at the desired index in the vector + * of parameter values. * - * @return the float parameter + * @param index + * the index. + * @return the float parameter. */ public float getFloatParameter(int index) { return ((Float)parameters.elementAt(index)).floatValue(); } /** - * Gets the double-valued parameter found at the desired index - * in the vector of parameter values. - * - * @param index the index + * Gets the double-valued parameter found at the desired index in the vector + * of parameter values. * - * @return the double parameter + * @param index + * the index. + * @return the double parameter. */ public double getDoubleParameter(int index) { return ((Double)parameters.elementAt(index)).doubleValue(); } /** - * Gets the char-valued parameter found at the desired index - * in the vector of parameter values. + * Gets the char-valued parameter found at the desired index in the vector + * of parameter values. * - * @param index the index - * - * @return the char parameter + * @param index + * the index. + * @return the char parameter. */ public char getCharParameter(int index) { return ((Character)parameters.elementAt(index)).charValue(); } /** - * Gets the byte-valued parameter found at the desired index - * in the vector of parameter values. - * - * @param index the index + * Gets the byte-valued parameter found at the desired index in the vector + * of parameter values. * - * @return the byte parameter + * @param index + * the index. + * @return the byte parameter. */ public byte getByteParameter(int index) { return ((Byte)parameters.elementAt(index)).byteValue(); @@ -531,7 +551,7 @@ public class ParameterBlock implements Cloneable, Serializable { /** * Gets the number of elements in the vector of sources. * - * @return the number of elements in the vector of sources + * @return the number of elements in the vector of sources. */ public int getNumSources() { return sources.size(); @@ -540,7 +560,7 @@ public class ParameterBlock implements Cloneable, Serializable { /** * Gets the number of elements in the vector of parameters. * - * @return the number of elements in the vector of parameters + * @return the number of elements in the vector of parameters. */ public int getNumParameters() { return parameters.size(); diff --git a/awt/java/awt/image/renderable/RenderContext.java b/awt/java/awt/image/renderable/RenderContext.java index 3a3b93c7af936fa1c8e8ee9088b7f5cbc223f363..0db512faf19ff23df5aca3575678e9c511386963 100644 --- a/awt/java/awt/image/renderable/RenderContext.java +++ b/awt/java/awt/image/renderable/RenderContext.java @@ -18,6 +18,7 @@ * @author Igor V. Stolyarov * @version $Revision$ */ + package java.awt.image.renderable; import java.awt.RenderingHints; @@ -25,27 +26,37 @@ import java.awt.Shape; import java.awt.geom.AffineTransform; /** - * The Class RenderContext stores data on how an image is to be - * rendered: the affine transform, the area of interest, and - * the rendering hints. + * The Class RenderContext stores data on how an image is to be rendered: the + * affine transform, the area of interest, and the rendering hints. + * + * @since Android 1.0 */ public class RenderContext implements Cloneable { - /** The affine transform. */ + /** + * The affine transform. + */ AffineTransform transform; - - /** The area of interest. */ + + /** + * The area of interest. + */ Shape aoi; - - /** The rendering hints. */ + + /** + * The rendering hints. + */ RenderingHints hints; /** * Instantiates a new render context. * - * @param usr2dev the affine transform - * @param aoi the area of interest - * @param hints the rendering hints + * @param usr2dev + * the affine transform. + * @param aoi + * the area of interest. + * @param hints + * the rendering hints. */ public RenderContext(AffineTransform usr2dev, Shape aoi, RenderingHints hints) { this.transform = (AffineTransform)usr2dev.clone(); @@ -56,8 +67,10 @@ public class RenderContext implements Cloneable { /** * Instantiates a new render context with no specified hints. * - * @param usr2dev the affine transform - * @param aoi the area of interest + * @param usr2dev + * the affine transform. + * @param aoi + * the area of interest. */ public RenderContext(AffineTransform usr2dev, Shape aoi) { this(usr2dev, aoi, null); @@ -66,18 +79,21 @@ public class RenderContext implements Cloneable { /** * Instantiates a new render context with no specified area of interest. * - * @param usr2dev the affine transform - * @param hints the rendering hints + * @param usr2dev + * the affine transform. + * @param hints + * the rendering hints. */ public RenderContext(AffineTransform usr2dev, RenderingHints hints) { this(usr2dev, null, hints); } /** - * Instantiates a new render context with no rendering hints or - * area of interest. + * Instantiates a new render context with no rendering hints or area of + * interest. * - * @param usr2dev the affine transform + * @param usr2dev + * the affine transform. */ public RenderContext(AffineTransform usr2dev) { this(usr2dev, null, null); @@ -91,36 +107,36 @@ public class RenderContext implements Cloneable { /** * Sets the affine transform for this render context. * - * @param newTransform the new affine transform + * @param newTransform + * the new affine transform. */ public void setTransform(AffineTransform newTransform) { transform = (AffineTransform)newTransform.clone(); } /** - * Concatenates the current transform with the specified transform - * (so they are applied with the specified transform acting first) - * and sets the resulting transform as the affine transform of - * this rendering context. - * - * @param modTransform the new transform which modifies the - * current transform - * - * @deprecated use {@link RenderContext#preConcatenateTransform(AffineTransform)} + * Concatenates the current transform with the specified transform (so they + * are applied with the specified transform acting first) and sets the + * resulting transform as the affine transform of this rendering context. + * + * @param modTransform + * the new transform which modifies the current transform. + * @deprecated use + * {@link RenderContext#preConcatenateTransform(AffineTransform)} + * . */ - @Deprecated + @Deprecated public void preConcetenateTransform(AffineTransform modTransform) { preConcatenateTransform(modTransform); } /** - * Concatenates the current transform with the specified transform - * (so they are applied with the specified transform acting first) - * and sets the resulting transform as the affine transform of - * this rendering context. + * Concatenates the current transform with the specified transform (so they + * are applied with the specified transform acting first) and sets the + * resulting transform as the affine transform of this rendering context. * - * @param modTransform the new transform which modifies the - * current transform + * @param modTransform + * the new transform which modifies the current transform. */ public void preConcatenateTransform(AffineTransform modTransform) { transform.preConcatenate(modTransform); @@ -129,10 +145,10 @@ public class RenderContext implements Cloneable { /** * Concatenate the specified transform with the current transform. * - * @param modTransform the new transform which modifies the - * current transform - * - * @deprecated use {@link RenderContext#concatenateTransform(AffineTransform)} + * @param modTransform + * the new transform which modifies the current transform. + * @deprecated use + * {@link RenderContext#concatenateTransform(AffineTransform)}. */ @Deprecated public void concetenateTransform(AffineTransform modTransform) { @@ -142,8 +158,8 @@ public class RenderContext implements Cloneable { /** * Concatenate the specified transform with the current transform. * - * @param modTransform the new transform which modifies the - * current transform + * @param modTransform + * the new transform which modifies the current transform. */ public void concatenateTransform(AffineTransform modTransform) { transform.concatenate(modTransform); @@ -152,7 +168,7 @@ public class RenderContext implements Cloneable { /** * Gets the transform. * - * @return the transform + * @return the transform. */ public AffineTransform getTransform() { return (AffineTransform)transform.clone(); @@ -161,7 +177,8 @@ public class RenderContext implements Cloneable { /** * Sets the area of interest. * - * @param newAoi the new area of interest + * @param newAoi + * the new area of interest. */ public void setAreaOfInterest(Shape newAoi) { aoi = newAoi; @@ -170,7 +187,7 @@ public class RenderContext implements Cloneable { /** * Gets the area of interest. * - * @return the area of interest + * @return the area of interest. */ public Shape getAreaOfInterest() { return aoi; @@ -179,7 +196,8 @@ public class RenderContext implements Cloneable { /** * Sets the rendering hints. * - * @param hints the new rendering hints + * @param hints + * the new rendering hints. */ public void setRenderingHints(RenderingHints hints) { this.hints = hints; @@ -188,7 +206,7 @@ public class RenderContext implements Cloneable { /** * Gets the rendering hints. * - * @return the rendering hints + * @return the rendering hints. */ public RenderingHints getRenderingHints() { return hints; diff --git a/awt/java/awt/image/renderable/RenderableImage.java b/awt/java/awt/image/renderable/RenderableImage.java index 885dc0609ff9cb56245ae10c9cd643ecef1dc367..21332f7d155fc218585d950f75156435d25dc31f 100644 --- a/awt/java/awt/image/renderable/RenderableImage.java +++ b/awt/java/awt/image/renderable/RenderableImage.java @@ -18,6 +18,7 @@ * @author Igor V. Stolyarov * @version $Revision$ */ + package java.awt.image.renderable; import java.awt.RenderingHints; @@ -25,108 +26,113 @@ import java.awt.image.RenderedImage; import java.util.Vector; /** - * The Interface RenderableImage is implemented by an object that - * collects all of the image-specific data that defines a single image - * that could be rendered to different rendering targets. + * The Interface RenderableImage is implemented by an object that collects all + * of the image-specific data that defines a single image that could be rendered + * to different rendering targets. + * + * @since Android 1.0 */ public interface RenderableImage { - /** The Constant HINTS_OBSERVED indicates that the rendering - * hints are applied rather than ignored. */ + /** + * The Constant HINTS_OBSERVED indicates that the rendering hints are + * applied rather than ignored. + */ public static final String HINTS_OBSERVED = "HINTS_OBSERVED"; //$NON-NLS-1$ /** * Gets the property from the RenderableImage's parameter block. * - * @param name the name of the property to get. - * - * @return the value of the property + * @param name + * the name of the property to get. + * @return the value of the property. */ public Object getProperty(String name); /** - * Creates the rendered image based on the information contained - * in the parameters and the render context. + * Creates the rendered image based on the information contained in the + * parameters and the render context. * - * @param renderContext the render context giving rendering specifications - * such as transformations - * - * @return the rendered image + * @param renderContext + * the render context giving rendering specifications such as + * transformations. + * @return the rendered image. */ public RenderedImage createRendering(RenderContext renderContext); /** - * Creates the scaled rendered image based on the information contained - * in the parameters and the render context. - * - * @param w the desired width after scaling or zero if the scaling - * should be proportional, based on the height - * @param h the desired height after scaling or zero if the scaling - * should be proportional, based on the width - * @param hints the rendering hints to use + * Creates the scaled rendered image based on the information contained in + * the parameters and the render context. * - * @return the rendered image - * - * @throws IllegalArgumentException if both the height and width are zero + * @param w + * the desired width after scaling or zero if the scaling should + * be proportional, based on the height. + * @param h + * the desired height after scaling or zero if the scaling should + * be proportional, based on the width. + * @param hints + * the rendering hints to use. + * @return the rendered image. + * @throws IllegalArgumentException + * if both the height and width are zero. */ public RenderedImage createScaledRendering(int w, int h, RenderingHints hints); /** * Gets the vector of sources from the parameter block. * - * @return the sources + * @return the sources. */ public Vector getSources(); /** * Gets the names of all of the supported properties in the current context. * - * @return the property names + * @return the property names. */ public String[] getPropertyNames(); /** - * Creates the default rendering (using the identity transform - * and default render context). + * Creates the default rendering (using the identity transform and default + * render context). * - * @return the rendered image + * @return the rendered image. */ public RenderedImage createDefaultRendering(); /** * Checks if this context supports dynamic rendering. * - * @return true, if this context supports dynamic rendering + * @return true, if this context supports dynamic rendering. */ public boolean isDynamic(); /** * Gets the width of the image. * - * @return the width of the image + * @return the width of the image. */ public float getWidth(); /** * Gets the y coordinate of the upper left corner. * - * @return the y coordinate of the upper left corner + * @return the y coordinate of the upper left corner. */ public float getMinY(); /** * Gets the x coordinate of the upper left corner. * - * @return the x coordinate of the upper left corner + * @return the x coordinate of the upper left corner. */ public float getMinX(); /** * Gets the height of the image. * - * @return the height of the image + * @return the height of the image. */ public float getHeight(); } - diff --git a/awt/java/awt/image/renderable/RenderableImageOp.java b/awt/java/awt/image/renderable/RenderableImageOp.java index 993ba5fdc3ea45515251eebeaeeffdf03300e70d..dc453727bb40cd171c761ad5819bf3000d30f457 100644 --- a/awt/java/awt/image/renderable/RenderableImageOp.java +++ b/awt/java/awt/image/renderable/RenderableImageOp.java @@ -18,6 +18,7 @@ * @author Igor V. Stolyarov * @version $Revision$ */ + package java.awt.image.renderable; import java.awt.RenderingHints; @@ -29,35 +30,44 @@ import java.util.Vector; import org.apache.harmony.awt.internal.nls.Messages; /** - * The Class RenderableImageOp is a basic implementation of RenderableImage, - * with methods to access the parameter data and perform rendering - * operations. + * The Class RenderableImageOp is a basic implementation of RenderableImage, + * with methods to access the parameter data and perform rendering operations. + * + * @since Android 1.0 */ public class RenderableImageOp implements RenderableImage { - /** The CRIF. */ + /** + * The CRIF. + */ ContextualRenderedImageFactory CRIF; - - /** The param block. */ + + /** + * The param block. + */ ParameterBlock paramBlock; - - /** The height. */ + + /** + * The height. + */ float minX, minY, width, height; /** * Instantiates a new renderable image op. * - * @param CRIF the cRIF - * @param paramBlock the param block + * @param CRIF + * the cRIF. + * @param paramBlock + * the param block. */ public RenderableImageOp(ContextualRenderedImageFactory CRIF, ParameterBlock paramBlock) { this.CRIF = CRIF; - this.paramBlock = (ParameterBlock) paramBlock.clone(); + this.paramBlock = (ParameterBlock)paramBlock.clone(); Rectangle2D r = CRIF.getBounds2D(paramBlock); - minX = (float) r.getMinX(); - minY = (float) r.getMinY(); - width = (float) r.getWidth(); - height = (float) r.getHeight(); + minX = (float)r.getMinX(); + minY = (float)r.getMinY(); + width = (float)r.getWidth(); + height = (float)r.getHeight(); } public Object getProperty(String name) { @@ -67,27 +77,27 @@ public class RenderableImageOp implements RenderableImage { /** * Sets the parameter block. * - * @param paramBlock the param block - * - * @return the parameter block + * @param paramBlock + * the param block. + * @return the parameter block. */ public ParameterBlock setParameterBlock(ParameterBlock paramBlock) { ParameterBlock oldParam = this.paramBlock; - this.paramBlock = (ParameterBlock) paramBlock.clone(); + this.paramBlock = (ParameterBlock)paramBlock.clone(); return oldParam; } public RenderedImage createRendering(RenderContext renderContext) { Vector sources = getSources(); - ParameterBlock rdParam = (ParameterBlock) paramBlock.clone(); + ParameterBlock rdParam = (ParameterBlock)paramBlock.clone(); if (sources != null) { Vector rdSources = new Vector(); int i = 0; while (i < sources.size()) { - RenderContext newContext = CRIF.mapRenderContext(i, renderContext, paramBlock, - this); + RenderContext newContext = CRIF + .mapRenderContext(i, renderContext, paramBlock, this); RenderedImage rdim = sources.elementAt(i).createRendering(newContext); if (rdim != null) { @@ -103,20 +113,20 @@ public class RenderableImageOp implements RenderableImage { } public RenderedImage createScaledRendering(int w, int h, RenderingHints hints) { - if(w == 0 && h == 0) { + if (w == 0 && h == 0) { // awt.60=Width and Height mustn't be equal zero both throw new IllegalArgumentException(Messages.getString("awt.60")); //$NON-NLS-1$ } - if(w == 0){ - w = Math.round(h*(getWidth()/getHeight())); + if (w == 0) { + w = Math.round(h * (getWidth() / getHeight())); } - if(h == 0){ - h = Math.round(w*(getHeight()/getWidth())); + if (h == 0) { + h = Math.round(w * (getHeight() / getWidth())); } - double sx = (double)w/getWidth(); - double sy = (double)h/getHeight(); + double sx = (double)w / getWidth(); + double sy = (double)h / getHeight(); AffineTransform at = AffineTransform.getScaleInstance(sx, sy); RenderContext context = new RenderContext(at, hints); @@ -124,15 +134,15 @@ public class RenderableImageOp implements RenderableImage { } public Vector getSources() { - if(paramBlock.getNumSources() == 0) { + if (paramBlock.getNumSources() == 0) { return null; } Vector v = new Vector(); - int i = 0; - while(i < paramBlock.getNumSources()){ + int i = 0; + while (i < paramBlock.getNumSources()) { Object o = paramBlock.getSource(i); - if(o instanceof RenderableImage){ - v.addElement((RenderableImage) o); + if (o instanceof RenderableImage) { + v.addElement((RenderableImage)o); } i++; } @@ -179,4 +189,3 @@ public class RenderableImageOp implements RenderableImage { } } - diff --git a/awt/java/awt/image/renderable/RenderableImageProducer.java b/awt/java/awt/image/renderable/RenderableImageProducer.java index 7fda98cb56e5f9e6df822fb6633f6bacedc376c4..e83ebc76be84645dd8faeef20895e98507c30ff8 100644 --- a/awt/java/awt/image/renderable/RenderableImageProducer.java +++ b/awt/java/awt/image/renderable/RenderableImageProducer.java @@ -18,6 +18,7 @@ * @author Igor V. Stolyarov * @version $Revision$ */ + package java.awt.image.renderable; import java.awt.image.ColorModel; @@ -28,25 +29,35 @@ import java.awt.image.RenderedImage; import java.util.Vector; /** - * The Class RenderableImageProducer provides the implementation for - * the image rendering. + * The Class RenderableImageProducer provides the implementation for the image + * rendering. + * + * @since Android 1.0 */ public class RenderableImageProducer implements ImageProducer, Runnable { - /** The rbl. */ + /** + * The rbl. + */ RenderableImage rbl; - - /** The rc. */ + + /** + * The rc. + */ RenderContext rc; - - /** The consumers. */ + + /** + * The consumers. + */ Vector consumers = new Vector(); /** * Instantiates a new renderable image producer. * - * @param rdblImage the rdbl image - * @param rc the rc + * @param rdblImage + * the rdbl image. + * @param rc + * the rc. */ public RenderableImageProducer(RenderableImage rdblImage, RenderContext rc) { this.rbl = rdblImage; @@ -56,7 +67,8 @@ public class RenderableImageProducer implements ImageProducer, Runnable { /** * Sets the render context. * - * @param rc the new render context + * @param rc + * the new render context. */ public synchronized void setRenderContext(RenderContext rc) { this.rc = rc; @@ -72,16 +84,17 @@ public class RenderableImageProducer implements ImageProducer, Runnable { t.start(); } - public void requestTopDownLeftRightResend(ImageConsumer ic) {} + public void requestTopDownLeftRightResend(ImageConsumer ic) { + } public synchronized void removeConsumer(ImageConsumer ic) { - if(ic != null) { + if (ic != null) { consumers.removeElement(ic); } } public synchronized void addConsumer(ImageConsumer ic) { - if(ic != null && !consumers.contains(ic)){ + if (ic != null && !consumers.contains(ic)) { consumers.addElement(ic); } } @@ -90,19 +103,19 @@ public class RenderableImageProducer implements ImageProducer, Runnable { * Creates the rendered image in a new thread. */ public void run() { - if(rbl == null) { + if (rbl == null) { return; } RenderedImage rd; - if(rc != null) { + if (rc != null) { rd = rbl.createRendering(rc); } else { rd = rbl.createDefaultRendering(); } ColorModel cm = rd.getColorModel(); - if(cm == null) { + if (cm == null) { cm = ColorModel.getRGBdefault(); } @@ -112,17 +125,15 @@ public class RenderableImageProducer implements ImageProducer, Runnable { for (ImageConsumer c : consumers) { c.setDimensions(w, h); - c.setHints(ImageConsumer.TOPDOWNLEFTRIGHT | - ImageConsumer.COMPLETESCANLINES | - ImageConsumer.SINGLEFRAME | - ImageConsumer.SINGLEPASS); + c.setHints(ImageConsumer.TOPDOWNLEFTRIGHT | ImageConsumer.COMPLETESCANLINES + | ImageConsumer.SINGLEFRAME | ImageConsumer.SINGLEPASS); } int scanLine[] = new int[w]; int pixel[] = null; - for(int y = 0; y < h; y++){ - for(int x = 0; x < w; x++){ + for (int y = 0; y < h; y++) { + for (int x = 0; x < w; x++) { pixel = r.getPixel(x, y, pixel); scanLine[x] = cm.getDataElement(pixel, 0); } @@ -138,4 +149,3 @@ public class RenderableImageProducer implements ImageProducer, Runnable { } } - diff --git a/awt/java/awt/image/renderable/RenderedImageFactory.java b/awt/java/awt/image/renderable/RenderedImageFactory.java index 345d82c61a629af5e4a0ff75c63f9622ad9c595d..881a40ab793975ca0b419649c43ffffdaf1ecb64 100644 --- a/awt/java/awt/image/renderable/RenderedImageFactory.java +++ b/awt/java/awt/image/renderable/RenderedImageFactory.java @@ -18,26 +18,29 @@ * @author Igor V. Stolyarov * @version $Revision$ */ + package java.awt.image.renderable; import java.awt.RenderingHints; import java.awt.image.RenderedImage; /** - * A factory for creating RenderedImage objects based on parameters - * and rendering hints. + * A factory for creating RenderedImage objects based on parameters and + * rendering hints. + * + * @since Android 1.0 */ public interface RenderedImageFactory { /** * Creates the rendered image. * - * @param a0 the ParameterBlock - * @param a1 the RenderingHints - * - * @return the rendered image + * @param a0 + * the ParameterBlock. + * @param a1 + * the RenderingHints. + * @return the rendered image. */ public RenderedImage create(ParameterBlock a0, RenderingHints a1); } - diff --git a/awt/java/awt/image/renderable/package.html b/awt/java/awt/image/renderable/package.html new file mode 100644 index 0000000000000000000000000000000000000000..43aaabc8368704f327d58067e093da36ef6887c9 --- /dev/null +++ b/awt/java/awt/image/renderable/package.html @@ -0,0 +1,8 @@ + + +

    + This package contains classes to create images which are rendering-independent. +

    + @since Android 1.0 + + diff --git a/awt/java/awt/package.html b/awt/java/awt/package.html new file mode 100644 index 0000000000000000000000000000000000000000..5a6f9f011fc7d9425d0ff9031daf309aa4a8ce06 --- /dev/null +++ b/awt/java/awt/package.html @@ -0,0 +1,8 @@ + + +

    + This package contains classes and interfaces for creating (graphical) user interfaces (GUI), painting 2D graphics and creating, manipulating and drawing images. +

    + @since Android 1.0 + + diff --git a/awt/java/beans/IndexedPropertyChangeEvent.java b/awt/java/beans/IndexedPropertyChangeEvent.java deleted file mode 100644 index c9084c6c54c7ffd168fb95429ff7e92d888f8b62..0000000000000000000000000000000000000000 --- a/awt/java/beans/IndexedPropertyChangeEvent.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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 java.beans; - -/** - * A type of {@link PropertyChangeEvent} that indicates that an indexed property - * has changed. - * - * @since 1.5 - */ -public class IndexedPropertyChangeEvent extends PropertyChangeEvent { - - private static final long serialVersionUID = -320227448495806870L; - - private final int index; - - /** - * Creates a new property changed event with an indication of the property - * index. - * - * @param source - * the changed bean. - * @param propertyName - * the changed property, or null to indicate an - * unspecified set of the properties have changed. - * @param oldValue - * the previous value of the property, or null if - * the propertyName is null or the - * previous value is unknown. - * @param newValue - * the new value of the property, or null if the - * propertyName is null or the new - * value is unknown.. - * @param index - * the index of the property. - */ - public IndexedPropertyChangeEvent(Object source, String propertyName, - Object oldValue, Object newValue, int index) { - super(source, propertyName, oldValue, newValue); - this.index = index; - } - - /** - * Answer the index of the property that was changed in this event. - * - * @return The property element index. - */ - public int getIndex() { - return index; - } -} diff --git a/awt/java/beans/PropertyChangeEvent.java b/awt/java/beans/PropertyChangeEvent.java deleted file mode 100644 index 97c703af5d372f25001c5d2f67b1472d81eeec85..0000000000000000000000000000000000000000 --- a/awt/java/beans/PropertyChangeEvent.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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 java.beans; - -import java.util.EventObject; - -public class PropertyChangeEvent extends EventObject { - - private static final long serialVersionUID = 7042693688939648123L; - - String propertyName; - - Object oldValue; - - Object newValue; - - Object propagationId; - - public PropertyChangeEvent(Object source, String propertyName, - Object oldValue, Object newValue) { - super(source); - - this.propertyName = propertyName; - this.oldValue = oldValue; - this.newValue = newValue; - } - - public String getPropertyName() { - return propertyName; - } - - public void setPropagationId(Object propagationId) { - this.propagationId = propagationId; - } - - public Object getPropagationId() { - return propagationId; - } - - public Object getOldValue() { - return oldValue; - } - - public Object getNewValue() { - return newValue; - } -} diff --git a/awt/java/beans/PropertyChangeListener.java b/awt/java/beans/PropertyChangeListener.java deleted file mode 100644 index 94422c0b6f23969ef5acfde62b3bef209e297077..0000000000000000000000000000000000000000 --- a/awt/java/beans/PropertyChangeListener.java +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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 java.beans; - -import java.util.EventListener; - -public interface PropertyChangeListener extends EventListener { - - public void propertyChange(PropertyChangeEvent event); -} diff --git a/awt/java/beans/PropertyChangeListenerProxy.java b/awt/java/beans/PropertyChangeListenerProxy.java deleted file mode 100644 index f4f3aec06e880ff0eb4c2917de9cbcbe32c3405b..0000000000000000000000000000000000000000 --- a/awt/java/beans/PropertyChangeListenerProxy.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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 java.beans; - -import java.util.EventListenerProxy; - -public class PropertyChangeListenerProxy extends EventListenerProxy implements - PropertyChangeListener { - - String propertyName; - - public PropertyChangeListenerProxy(String propertyName, - PropertyChangeListener listener) { - super(listener); - this.propertyName = propertyName; - } - - public String getPropertyName() { - return propertyName; - } - - public void propertyChange(PropertyChangeEvent event) { - PropertyChangeListener listener = (PropertyChangeListener) getListener(); - listener.propertyChange(event); - } -} diff --git a/awt/java/beans/PropertyChangeSupport.java b/awt/java/beans/PropertyChangeSupport.java deleted file mode 100644 index d56e63a784bd57adaf0e5fa5d68edcdf52586b6d..0000000000000000000000000000000000000000 --- a/awt/java/beans/PropertyChangeSupport.java +++ /dev/null @@ -1,351 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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 java.beans; - -import java.io.IOException; -import java.io.ObjectInputStream; -import java.io.ObjectOutputStream; -import java.io.Serializable; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.Hashtable; -import java.util.Iterator; -import java.util.List; -import java.util.Map; - -public class PropertyChangeSupport implements Serializable { - - private static final long serialVersionUID = 6401253773779951803l; - - private transient Object sourceBean; - - private transient List allPropertiesChangeListeners = - new ArrayList(); - - private transient Map> - selectedPropertiesChangeListeners = - new HashMap>(); - - // fields for serialization compatibility - private Hashtable> children; - - private Object source; - - private int propertyChangeSupportSerializedDataVersion = 1; - - public PropertyChangeSupport(Object sourceBean) { - if (sourceBean == null) { - throw new NullPointerException(); - } - this.sourceBean = sourceBean; - } - - public void firePropertyChange(String propertyName, Object oldValue, - Object newValue) { - PropertyChangeEvent event = createPropertyChangeEvent(propertyName, - oldValue, newValue); - doFirePropertyChange(event); - } - - public void fireIndexedPropertyChange(String propertyName, int index, - Object oldValue, Object newValue) { - - // nulls and equals check done in doFire... - doFirePropertyChange(new IndexedPropertyChangeEvent(sourceBean, - propertyName, oldValue, newValue, index)); - } - - public synchronized void removePropertyChangeListener(String propertyName, - PropertyChangeListener listener) { - if ((propertyName != null) && (listener != null)) { - List listeners = - selectedPropertiesChangeListeners.get(propertyName); - - if (listeners != null) { - listeners.remove(listener); - } - } - } - - public synchronized void addPropertyChangeListener(String propertyName, - PropertyChangeListener listener) { - if ((listener != null) && (propertyName != null)) { - List listeners = - selectedPropertiesChangeListeners.get(propertyName); - - if (listeners == null) { - listeners = new ArrayList(); - selectedPropertiesChangeListeners.put(propertyName, listeners); - } - - // RI compatibility - if (listener instanceof PropertyChangeListenerProxy) { - PropertyChangeListenerProxy proxy = - (PropertyChangeListenerProxy) listener; - - listeners.add(new PropertyChangeListenerProxy( - proxy.getPropertyName(), - (PropertyChangeListener) proxy.getListener())); - } else { - listeners.add(listener); - } - } - } - - public synchronized PropertyChangeListener[] getPropertyChangeListeners( - String propertyName) { - List listeners = null; - - if (propertyName != null) { - listeners = selectedPropertiesChangeListeners.get(propertyName); - } - - return (listeners == null) ? new PropertyChangeListener[] {} - : listeners.toArray( - new PropertyChangeListener[listeners.size()]); - } - - public void firePropertyChange(String propertyName, boolean oldValue, - boolean newValue) { - PropertyChangeEvent event = createPropertyChangeEvent(propertyName, - oldValue, newValue); - doFirePropertyChange(event); - } - - public void fireIndexedPropertyChange(String propertyName, int index, - boolean oldValue, boolean newValue) { - - if (oldValue != newValue) { - fireIndexedPropertyChange(propertyName, index, Boolean - .valueOf(oldValue), Boolean.valueOf(newValue)); - } - } - - public void firePropertyChange(String propertyName, int oldValue, - int newValue) { - PropertyChangeEvent event = createPropertyChangeEvent(propertyName, - oldValue, newValue); - doFirePropertyChange(event); - } - - public void fireIndexedPropertyChange(String propertyName, int index, - int oldValue, int newValue) { - - if (oldValue != newValue) { - fireIndexedPropertyChange(propertyName, index, - new Integer(oldValue), new Integer(newValue)); - } - } - - public synchronized boolean hasListeners(String propertyName) { - boolean result = allPropertiesChangeListeners.size() > 0; - if (!result && (propertyName != null)) { - List listeners = - selectedPropertiesChangeListeners.get(propertyName); - if (listeners != null) { - result = listeners.size() > 0; - } - } - return result; - } - - public synchronized void removePropertyChangeListener( - PropertyChangeListener listener) { - if (listener != null) { - if (listener instanceof PropertyChangeListenerProxy) { - String name = ((PropertyChangeListenerProxy) listener) - .getPropertyName(); - PropertyChangeListener lst = (PropertyChangeListener) - ((PropertyChangeListenerProxy) listener).getListener(); - - removePropertyChangeListener(name, lst); - } else { - allPropertiesChangeListeners.remove(listener); - } - } - } - - public synchronized void addPropertyChangeListener( - PropertyChangeListener listener) { - if (listener != null) { - if (listener instanceof PropertyChangeListenerProxy) { - String name = ((PropertyChangeListenerProxy) listener) - .getPropertyName(); - PropertyChangeListener lst = (PropertyChangeListener) - ((PropertyChangeListenerProxy) listener).getListener(); - addPropertyChangeListener(name, lst); - } else { - allPropertiesChangeListeners.add(listener); - } - } - } - - public synchronized PropertyChangeListener[] getPropertyChangeListeners() { - ArrayList result = - new ArrayList( - allPropertiesChangeListeners); - - for (String propertyName : selectedPropertiesChangeListeners.keySet()) { - List selectedListeners = - selectedPropertiesChangeListeners.get(propertyName); - - if (selectedListeners != null) { - - for (PropertyChangeListener listener : selectedListeners) { - result.add(new PropertyChangeListenerProxy(propertyName, - listener)); - } - } - } - - return result.toArray(new PropertyChangeListener[result.size()]); - } - - private void writeObject(ObjectOutputStream oos) throws IOException { - List allSerializedPropertiesChangeListeners = - new ArrayList(); - - for (PropertyChangeListener pcl : allPropertiesChangeListeners) { - if (pcl instanceof Serializable) { - allSerializedPropertiesChangeListeners.add(pcl); - } - } - - Map> - selectedSerializedPropertiesChangeListeners = - new HashMap>(); - - for (String propertyName : selectedPropertiesChangeListeners.keySet()) { - List keyValues = - selectedPropertiesChangeListeners.get(propertyName); - - if (keyValues != null) { - List serializedPropertiesChangeListeners - = new ArrayList(); - - for (PropertyChangeListener pcl : keyValues) { - if (pcl instanceof Serializable) { - serializedPropertiesChangeListeners.add(pcl); - } - } - - if (!serializedPropertiesChangeListeners.isEmpty()) { - selectedSerializedPropertiesChangeListeners.put( - propertyName, serializedPropertiesChangeListeners); - } - } - } - - children = new Hashtable>( - selectedSerializedPropertiesChangeListeners); - children.put("", allSerializedPropertiesChangeListeners); //$NON-NLS-1$ - oos.writeObject(children); - - Object source = null; - if (sourceBean instanceof Serializable) { - source = sourceBean; - } - oos.writeObject(source); - - oos.writeInt(propertyChangeSupportSerializedDataVersion); - } - - @SuppressWarnings("unchecked") - private void readObject(ObjectInputStream ois) throws IOException, - ClassNotFoundException { - children = (Hashtable>) ois - .readObject(); - - selectedPropertiesChangeListeners = new HashMap>( - children); - allPropertiesChangeListeners = selectedPropertiesChangeListeners - .remove(""); //$NON-NLS-1$ - if (allPropertiesChangeListeners == null) { - allPropertiesChangeListeners = new ArrayList(); - } - - sourceBean = ois.readObject(); - propertyChangeSupportSerializedDataVersion = ois.readInt(); - } - - public void firePropertyChange(PropertyChangeEvent event) { - doFirePropertyChange(event); - } - - private PropertyChangeEvent createPropertyChangeEvent(String propertyName, - Object oldValue, Object newValue) { - return new PropertyChangeEvent(sourceBean, propertyName, oldValue, - newValue); - } - - private PropertyChangeEvent createPropertyChangeEvent(String propertyName, - boolean oldValue, boolean newValue) { - return new PropertyChangeEvent(sourceBean, propertyName, oldValue, - newValue); - } - - private PropertyChangeEvent createPropertyChangeEvent(String propertyName, - int oldValue, int newValue) { - return new PropertyChangeEvent(sourceBean, propertyName, oldValue, - newValue); - } - - private void doFirePropertyChange(PropertyChangeEvent event) { - String propertyName = event.getPropertyName(); - Object oldValue = event.getOldValue(); - Object newValue = event.getNewValue(); - - if ((newValue != null) && (oldValue != null) - && newValue.equals(oldValue)) { - return; - } - - /* - * Copy the listeners collections so they can be modified while we fire - * events. - */ - - // Listeners to all property change events - PropertyChangeListener[] listensToAll; - // Listens to a given property change - PropertyChangeListener[] listensToOne = null; - synchronized (this) { - listensToAll = allPropertiesChangeListeners - .toArray(new PropertyChangeListener[allPropertiesChangeListeners - .size()]); - - List listeners = selectedPropertiesChangeListeners - .get(propertyName); - if (listeners != null) { - listensToOne = listeners - .toArray(new PropertyChangeListener[listeners.size()]); - } - } - - // Fire the listeners - for (PropertyChangeListener listener : listensToAll) { - listener.propertyChange(event); - } - if (listensToOne != null) { - for (PropertyChangeListener listener : listensToOne) { - listener.propertyChange(event); - } - } - } - -} diff --git a/awt/javax/imageio/IIOException.java b/awt/javax/imageio/IIOException.java index fbfeb42fd062fed7826a7515bde8dc1194431c34..c77716c439af9918988a68c35753208f195a88bc 100644 --- a/awt/javax/imageio/IIOException.java +++ b/awt/javax/imageio/IIOException.java @@ -18,22 +18,28 @@ * @author Rustem V. Rafikov * @version $Revision: 1.3 $ */ + package javax.imageio; import java.io.IOException; /** * The IIOException class indicates errors in reading/writing operations. + * + * @since Android 1.0 */ public class IIOException extends IOException { - /** The Constant serialVersionUID. */ + /** + * The Constant serialVersionUID. + */ private static final long serialVersionUID = -3216210718638985251L; /** * Instantiates a new IIOException. * - * @param message the detailed message. + * @param message + * the detailed message. */ public IIOException(String message) { super(message); @@ -42,8 +48,10 @@ public class IIOException extends IOException { /** * Instantiates a new IIOException. * - * @param message the detailed message. - * @param cause the cause of this exception. + * @param message + * the detailed message. + * @param cause + * the cause of this exception. */ public IIOException(String message, Throwable cause) { super(message); diff --git a/awt/javax/imageio/IIOImage.java b/awt/javax/imageio/IIOImage.java index e17a9fc07cfc46d9f003705bfd8d463e0ad56a7e..e9e5130cfabe76470ba24692e6eae64c0f64dbb5 100644 --- a/awt/javax/imageio/IIOImage.java +++ b/awt/javax/imageio/IIOImage.java @@ -18,6 +18,7 @@ * @author Rustem V. Rafikov * @version $Revision: 1.3 $ */ + package javax.imageio; import javax.imageio.metadata.IIOMetadata; @@ -27,33 +28,47 @@ import java.awt.image.BufferedImage; import java.util.List; /** - * The IIOImage class combines the image, image's thumbnail and image's metadata. - * The image can be presented as RenderedImage or Raster object. + * The IIOImage class combines the image, image's thumbnail and image's + * metadata. The image can be presented as RenderedImage or Raster object. + * + * @since Android 1.0 */ public class IIOImage { - /** The image of this IIOImage. */ + /** + * The image of this IIOImage. + */ protected RenderedImage image; - - /** The raster of this IIOImage. */ + + /** + * The raster of this IIOImage. + */ protected Raster raster; - - /** The list with thumbnails associated with the image. */ + + /** + * The list with thumbnails associated with the image. + */ protected List thumbnails; - - /** The metadata associated with the image. */ + + /** + * The metadata associated with the image. + */ protected IIOMetadata metadata; /** - * Instantiates a new IIOImage with the specified RenderedImage, - * list of thumbnails and metadata. + * Instantiates a new IIOImage with the specified RenderedImage, list of + * thumbnails and metadata. * - * @param image the image specified by RenderedImage. - * @param thumbnails the list of BufferedImage objects which - * represent the thumbnails of the image. - * @param metadata the metadata of the image. + * @param image + * the image specified by RenderedImage. + * @param thumbnails + * the list of BufferedImage objects which represent the + * thumbnails of the image. + * @param metadata + * the metadata of the image. */ - public IIOImage(RenderedImage image, List thumbnails, IIOMetadata metadata) { + public IIOImage(RenderedImage image, List thumbnails, + IIOMetadata metadata) { if (image == null) { throw new IllegalArgumentException("image should not be NULL"); } @@ -64,13 +79,16 @@ public class IIOImage { } /** - * Instantiates a new IIOImage with the specified Raster, list of - * thumbnails and metadata. + * Instantiates a new IIOImage with the specified Raster, list of thumbnails + * and metadata. * - * @param raster the Raster. - * @param thumbnails the list of BufferedImage objects which - * represent the thumbnails of Raster data. - * @param metadata the metadata. + * @param raster + * the Raster. + * @param thumbnails + * the list of BufferedImage objects which represent the + * thumbnails of Raster data. + * @param metadata + * the metadata. */ public IIOImage(Raster raster, List thumbnails, IIOMetadata metadata) { if (raster == null) { @@ -83,11 +101,11 @@ public class IIOImage { } /** - * Gets the RenderedImage object or returns null if this IIOImage - * object is associated with a Raster. + * Gets the RenderedImage object or returns null if this IIOImage object is + * associated with a Raster. * - * @return the RenderedImage object or null if this IIOImage - * object is associated with a Raster. + * @return the RenderedImage object or null if this IIOImage object is + * associated with a Raster. */ public RenderedImage getRenderedImage() { return image; @@ -96,7 +114,8 @@ public class IIOImage { /** * Sets the RenderedImage to this IIOImage object. * - * @param image the RenderedImage to be set to this IIOImage. + * @param image + * the RenderedImage to be set to this IIOImage. */ public void setRenderedImage(RenderedImage image) { if (image == null) { @@ -107,11 +126,11 @@ public class IIOImage { } /** - * Returns true if the IIOImage object associated with a Raster, or - * false if it's associated with a RenderedImage. + * Returns true if the IIOImage object associated with a Raster, or false if + * it's associated with a RenderedImage. * - * @return true if the IIOImage object associated with a Raster, or - * false if it's associated with a RenderedImage. + * @return true, if the IIOImage object associated with a Raster, or false + * if it's associated with a RenderedImage. */ public boolean hasRaster() { return raster != null; @@ -121,8 +140,8 @@ public class IIOImage { * Gets the Raster object or returns null if this IIOImage object is * associated with a RenderedImage. * - * @return the Raster or null if this IIOImage object - * is associated with a RenderedImage. + * @return the Raster or null if this IIOImage object is associated with a + * RenderedImage. */ public Raster getRaster() { return raster; @@ -131,7 +150,8 @@ public class IIOImage { /** * Sets the Raster to the IIOImage. * - * @param raster the new Raster to the IIOImage. + * @param raster + * the new Raster to the IIOImage. */ public void setRaster(Raster raster) { if (raster == null) { @@ -153,8 +173,8 @@ public class IIOImage { /** * Gets the thumbnail with the specified index in the list. * - * @param index the index of the thumbnail in the list. - * + * @param index + * the index of the thumbnail in the list. * @return the thumbnail with the specified index in the list. */ public BufferedImage getThumbnail(int index) { @@ -176,8 +196,8 @@ public class IIOImage { /** * Sets the list of thumbnails images to this IIOImage object. * - * @param thumbnails the list of BufferedImage which represent - * thumbnails. + * @param thumbnails + * the list of BufferedImage which represent thumbnails. */ public void setThumbnails(List thumbnails) { this.thumbnails = thumbnails; @@ -195,7 +215,8 @@ public class IIOImage { /** * Sets the metadata to this IIOImage object. * - * @param metadata the IIOMetadata, or null. + * @param metadata + * the IIOMetadata, or null. */ public void setMetadata(IIOMetadata metadata) { this.metadata = metadata; diff --git a/awt/javax/imageio/IIOParam.java b/awt/javax/imageio/IIOParam.java index d998b6e513720c68c26fc18af5c5bf142dc3256b..2ccc9450f5b4a5ade2802e5fd87202d98de0990f 100644 --- a/awt/javax/imageio/IIOParam.java +++ b/awt/javax/imageio/IIOParam.java @@ -18,56 +18,80 @@ * @author Rustem V. Rafikov * @version $Revision: 1.3 $ */ + package javax.imageio; import java.awt.*; /** - * The IIOParam abstract class is superclass for - * ImageReadParam and ImageWriteParam classes and provides - * methods and variables which they share. + * The IIOParam abstract class is superclass for ImageReadParam and + * ImageWriteParam classes and provides methods and variables which they share. + * + * @since Android 1.0 */ public abstract class IIOParam { - - /** The source region. */ + + /** + * The source region. + */ protected Rectangle sourceRegion; - - /** The source x subsampling. */ + + /** + * The source x subsampling. + */ protected int sourceXSubsampling = 1; - - /** The source y subsampling. */ + + /** + * The source y subsampling. + */ protected int sourceYSubsampling = 1; - - /** The subsampling x offset. */ + + /** + * The subsampling x offset. + */ protected int subsamplingXOffset; - - /** The subsampling y offset. */ + + /** + * The subsampling y offset. + */ protected int subsamplingYOffset; - - /** The source bands. */ + + /** + * The source bands. + */ protected int[] sourceBands; - - /** The destination type. */ + + /** + * The destination type. + */ protected ImageTypeSpecifier destinationType; - - /** The destination offset. */ + + /** + * The destination offset. + */ protected Point destinationOffset = new Point(0, 0); - - /** The default controller. */ + + /** + * The default controller. + */ protected IIOParamController defaultController; - - /** The controller. */ + + /** + * The controller. + */ protected IIOParamController controller; /** * Instantiates a new IIOParam. */ - protected IIOParam() {} + protected IIOParam() { + } /** * Sets the source region as a Rectangle object. * - * @param sourceRegion the Rectangle which specifies the source region. + * @param sourceRegion + * the Rectangle which specifies the source region. */ public void setSourceRegion(Rectangle sourceRegion) { if (sourceRegion != null) { @@ -91,8 +115,8 @@ public abstract class IIOParam { if (sourceRegion.height <= subsamplingYOffset) { throw new IllegalArgumentException("height <= subsamplingXOffset"); } - //-- clone it to avoid unexpected modifications - this.sourceRegion = (Rectangle) sourceRegion.clone(); + // -- clone it to avoid unexpected modifications + this.sourceRegion = (Rectangle)sourceRegion.clone(); } else { this.sourceRegion = null; } @@ -107,24 +131,26 @@ public abstract class IIOParam { if (sourceRegion == null) { return null; } - //-- clone it to avoid unexpected modifications - return (Rectangle) sourceRegion.clone(); + // -- clone it to avoid unexpected modifications + return (Rectangle)sourceRegion.clone(); } /** - * Sets the source subsampling. The sourceXSubsampling and - * sourceYSubsampling parameters specify the number of rows - * and columns to advance after every source pixel. + * Sets the source subsampling. The sourceXSubsampling and + * sourceYSubsampling parameters specify the number of rows and columns to + * advance after every source pixel. * - * @param sourceXSubsampling the source X subsampling. - * @param sourceYSubsampling the source Y subsampling. - * @param subsamplingXOffset the subsampling X offset. - * @param subsamplingYOffset the subsampling Y offset. + * @param sourceXSubsampling + * the source X subsampling. + * @param sourceYSubsampling + * the source Y subsampling. + * @param subsamplingXOffset + * the subsampling X offset. + * @param subsamplingYOffset + * the subsampling Y offset. */ - public void setSourceSubsampling(int sourceXSubsampling, - int sourceYSubsampling, - int subsamplingXOffset, - int subsamplingYOffset) { + public void setSourceSubsampling(int sourceXSubsampling, int sourceYSubsampling, + int subsamplingXOffset, int subsamplingYOffset) { if (sourceXSubsampling <= 0) { throw new IllegalArgumentException("sourceXSubsampling <= 0"); @@ -141,10 +167,10 @@ public abstract class IIOParam { throw new IllegalArgumentException("subsamplingYOffset is wrong"); } - //-- does region contain pixels + // -- does region contain pixels if (sourceRegion != null) { - if (sourceRegion.width <= subsamplingXOffset || - sourceRegion.height <= subsamplingYOffset) { + if (sourceRegion.width <= subsamplingXOffset + || sourceRegion.height <= subsamplingYOffset) { throw new IllegalArgumentException("there are no pixels in region"); } } @@ -156,8 +182,8 @@ public abstract class IIOParam { } /** - * Gets the source X subsampling - the number of source - * columns to advance for each pixel. + * Gets the source X subsampling - the number of source columns to advance + * for each pixel. * * @return the source X subsampling. */ @@ -166,8 +192,8 @@ public abstract class IIOParam { } /** - * Gets the source Y subsampling - the number of source - * rows to advance for each pixel. + * Gets the source Y subsampling - the number of source rows to advance for + * each pixel. * * @return the source Y subsampling. */ @@ -196,7 +222,8 @@ public abstract class IIOParam { /** * Sets the indices of the source bands. * - * @param sourceBands the indices of the source bands. + * @param sourceBands + * the indices of the source bands. */ public void setSourceBands(int[] sourceBands) { // TODO implement @@ -216,7 +243,8 @@ public abstract class IIOParam { /** * Sets the specified ImageTypeSpecifier for the destination image. * - * @param destinationType the ImageTypeSpecifier. + * @param destinationType + * the ImageTypeSpecifier. */ public void setDestinationType(ImageTypeSpecifier destinationType) { // TODO implement @@ -225,7 +253,7 @@ public abstract class IIOParam { /** * Gets the type of the destination image as an ImageTypeSpecifier. . - * + * * @return the ImageTypeSpecifier. */ public ImageTypeSpecifier getDestinationType() { @@ -234,18 +262,19 @@ public abstract class IIOParam { } /** - * Sets the offset in the destination image where - * the decoded pixels are placed as a result of reading, - * or specified an area to be written while writing operation. + * Sets the offset in the destination image where the decoded pixels are + * placed as a result of reading, or specified an area to be written while + * writing operation. * - * @param destinationOffset the destination offset. + * @param destinationOffset + * the destination offset. */ public void setDestinationOffset(Point destinationOffset) { if (destinationOffset == null) { throw new IllegalArgumentException("destinationOffset == null!"); } - - this.destinationOffset = (Point) destinationOffset.clone(); + + this.destinationOffset = (Point)destinationOffset.clone(); } /** @@ -254,14 +283,15 @@ public abstract class IIOParam { * @return the offset in the destination image. */ public Point getDestinationOffset() { - return (Point) destinationOffset.clone(); + return (Point)destinationOffset.clone(); } /** - * Sets the IIOParamController to this IIOParam object for - * providing settings to this IIOParam. + * Sets the IIOParamController to this IIOParam object for providing + * settings to this IIOParam. * - * @param controller the new IIOParamController. + * @param controller + * the new IIOParamController. */ public void setController(IIOParamController controller) { // TODO implement @@ -269,11 +299,9 @@ public abstract class IIOParam { } /** - * Gets the current IIOParamController controller - * for this IIOParam. + * Gets the current IIOParamController controller for this IIOParam. * - * @return the current IIOParamController controller - * for this IIOParam. + * @return the current IIOParamController controller for this IIOParam. */ public IIOParamController getController() { // TODO implement @@ -281,11 +309,10 @@ public abstract class IIOParam { } /** - * Gets the default IIOParamController controller - * for this IIOParam. + * Gets the default IIOParamController controller for this IIOParam. * - * @return the default IIOParamController controller - * for this IIOParam, or null. + * @return the default IIOParamController controller for this IIOParam, or + * null. */ public IIOParamController getDefaultController() { // TODO implement @@ -293,11 +320,10 @@ public abstract class IIOParam { } /** - * Returns true if IIOParamController is installed for - * this IIOParam. + * Returns true if IIOParamController is installed for this IIOParam. * - * @return true if IIOParamController is installed for - * this IIOParam, false otherwise. + * @return true, if IIOParamController is installed for this IIOParam, false + * otherwise. */ public boolean hasController() { // TODO implement diff --git a/awt/javax/imageio/IIOParamController.java b/awt/javax/imageio/IIOParamController.java index 31522c19bad82c4644605e8d1bae3165a4bd4cc0..338cb25a7200e64ec8e043dc74b398fdd703fc88 100644 --- a/awt/javax/imageio/IIOParamController.java +++ b/awt/javax/imageio/IIOParamController.java @@ -18,6 +18,7 @@ * @author Sergey I. Salishev * @version $Revision: 1.2 $ */ + package javax.imageio; /* @@ -26,18 +27,19 @@ package javax.imageio; */ /** - * The IIOParamController specifies an activate method that invokes the + * The IIOParamController specifies an activate method that invokes the * controller. + * + * @since Android 1.0 */ public interface IIOParamController { /** - * Activates the controller. - * - * @param param the IIOParam. + * Activates the controller. * - * @return true if the IIOParam has been modified, false otherwise. + * @param param + * the IIOParam. + * @return true, if the IIOParam has been modified, false otherwise. */ boolean activate(IIOParam param); } - diff --git a/awt/javax/imageio/ImageIO.java b/awt/javax/imageio/ImageIO.java index d4cd1dda1ae1a90027906441ed93e94f1885518b..e0d7ec9904d783e044b545bb24e3779bf2dbe7ff 100644 --- a/awt/javax/imageio/ImageIO.java +++ b/awt/javax/imageio/ImageIO.java @@ -18,6 +18,7 @@ * @author Rustem V. Rafikov * @version $Revision: 1.3 $ */ + package javax.imageio; import javax.imageio.stream.ImageInputStream; @@ -34,44 +35,47 @@ import java.awt.image.RenderedImage; import java.net.URL; /** - * The ImageIO class provides static methods to perfom - * reading and writing operations using registered - * ImageReader and ImageWriter objects. + * The ImageIO class provides static methods to perform reading and writing + * operations using registered ImageReader and ImageWriter objects. + * + * @since Android 1.0 */ public final class ImageIO { - /** The Constant registry. */ + /** + * The constant registry. + */ private static final IIORegistry registry = IIORegistry.getDefaultInstance(); /** - * Instantiates a new image io. + * Instantiates a new ImageIO. */ - private ImageIO() {} - + private ImageIO() { + } /** - * Scans for plug-ins in the class path, - * loads spi classes, and registers them with the IIORegistry. + * Scans for plug-ins in the class path, loads spi classes, and registers + * them with the IIORegistry. */ public static void scanForPlugins() { throw new UnsupportedOperationException("Not supported yet"); } /** - * Sets flag which indicates whether a cache file is used when - * creating ImageInputStreams and ImageOutputStreams or not. + * Sets flag which indicates whether a cache file is used when creating + * ImageInputStreams and ImageOutputStreams or not. * - * @param useCache the use cache flag. + * @param useCache + * the use cache flag. */ public static void setUseCache(boolean useCache) { throw new UnsupportedOperationException("Not supported yet"); } /** - * Gets the flag which indicates whether a cache file is used when - * creating ImageInputStreams and ImageOutputStreams or not. - * This method returns the current value which is set by setUseCache - * method. + * Gets the flag which indicates whether a cache file is used when creating + * ImageInputStreams and ImageOutputStreams or not. This method returns the + * current value which is set by setUseCache method. * * @return the use cache flag. */ @@ -83,44 +87,44 @@ public final class ImageIO { /** * Sets the cache directory. * - * @param cacheDirectory the File which specifies a cache directory. + * @param cacheDirectory + * the File which specifies a cache directory. */ public static void setCacheDirectory(File cacheDirectory) { throw new UnsupportedOperationException("Not supported yet"); } /** - * Gets the directory where cache files are created, returned - * the file which is set by setCacheDirectory method, or null. + * Gets the directory where cache files are created, returned the file which + * is set by setCacheDirectory method, or null. * - * @return the File object which is set by setCacheDirectory method, - * or null. + * @return the File object which is set by setCacheDirectory method, or + * null. */ public static File getCacheDirectory() { // TODO implement - //-- null indicates system-dep default temporary directory + // -- null indicates system-dep default temporary directory return null; } /** - * Creates an ImageInputStream from the specified Object. - * The specified Object should obtain the input source - * such as File, or InputStream. - * - * @param input the input Object such as File, or InputStream. + * Creates an ImageInputStream from the specified Object. The specified + * Object should obtain the input source such as File, or InputStream. * + * @param input + * the input Object such as File, or InputStream. * @return the ImageInputStream object, or null. - * - * @throws IOException signals that an I/O exception has occurred. + * @throws IOException + * if an I/O exception has occurred. */ - public static ImageInputStream createImageInputStream(Object input) - throws IOException { + public static ImageInputStream createImageInputStream(Object input) throws IOException { if (input == null) { throw new IllegalArgumentException("input source cannot be NULL"); } - Iterator it = registry.getServiceProviders(ImageInputStreamSpi.class, true); + Iterator it = registry.getServiceProviders(ImageInputStreamSpi.class, + true); while (it.hasNext()) { ImageInputStreamSpi spi = it.next(); @@ -132,23 +136,22 @@ public final class ImageIO { } /** - * Creates an ImageOutputStream using the specified Object. - * The specified Object should obtain the output source - * such as File, or OutputStream. - * - * @param output the output Object such as File, or OutputStream. + * Creates an ImageOutputStream using the specified Object. The specified + * Object should obtain the output source such as File, or OutputStream. * + * @param output + * the output Object such as File, or OutputStream. * @return the ImageOutputStream object, or null. - * - * @throws IOException signals that an I/O exception has occurred. + * @throws IOException + * if an I/O exception has occurred. */ - public static ImageOutputStream createImageOutputStream(Object output) - throws IOException { + public static ImageOutputStream createImageOutputStream(Object output) throws IOException { if (output == null) { throw new IllegalArgumentException("output destination cannot be NULL"); } - Iterator it = registry.getServiceProviders(ImageOutputStreamSpi.class, true); + Iterator it = registry.getServiceProviders( + ImageOutputStreamSpi.class, true); while (it.hasNext()) { ImageOutputStreamSpi spi = it.next(); @@ -161,8 +164,8 @@ public final class ImageIO { } /** - * Gets the array of format names as String which can be - * decoded by registered ImageReader objects. + * Gets the array of format names as String which can be decoded by + * registered ImageReader objects. * * @return the array of format names. */ @@ -171,8 +174,8 @@ public final class ImageIO { } /** - * Gets the array of MIME types as String which can be - * decoded by registered ImageReader objects. + * Gets the array of MIME types as String which can be decoded by registered + * ImageReader objects. * * @return the array of MIME types. */ @@ -181,13 +184,13 @@ public final class ImageIO { } /** - * Gets the Iterator of registered ImageReader which are able to - * decode an imput data specified by input Object. - * - * @param input the input Object with encoded data such as - * ImageInputStream object. + * Gets the Iterator of registered ImageReader which are able to decode an + * input data specified by input Object. * - * @return the Iterator of registered ImageReader. + * @param input + * the input Object with encoded data such as ImageInputStream + * object. + * @return the Iterator of registered ImageReader. */ public static Iterator getImageReaders(Object input) { if (input == null) { @@ -201,11 +204,11 @@ public final class ImageIO { } /** - * Gets the Iterator of registered ImageReader which are able to - * decode the specified format. - * - * @param formatName the format name such as "jpeg", or "gif". + * Gets the Iterator of registered ImageReader which are able to decode the + * specified format. * + * @param formatName + * the format name such as "jpeg", or "gif". * @return the Iterator of registered ImageReader. */ public static Iterator getImageReadersByFormatName(String formatName) { @@ -220,11 +223,11 @@ public final class ImageIO { } /** - * Gets the Iterator which lists the registered ImageReader objects that - * are able to decode files with the specified suffix. - * - * @param fileSuffix the file suffix such as "jpg". + * Gets the Iterator which lists the registered ImageReader objects that are + * able to decode files with the specified suffix. * + * @param fileSuffix + * the file suffix such as "jpg". * @return the Iterator of registered ImageReaders. */ public static Iterator getImageReadersBySuffix(String fileSuffix) { @@ -238,11 +241,11 @@ public final class ImageIO { } /** - * Gets the Iterator of registered ImageReader objects that - * are able to decode files with the specified MIME type. - * - * @param MIMEType the MIME type such as "image/jpeg". + * Gets the Iterator of registered ImageReader objects that are able to + * decode files with the specified MIME type. * + * @param MIMEType + * the MIME type such as "image/jpeg". * @return the Iterator of registered ImageReaders. */ public static Iterator getImageReadersByMIMEType(String MIMEType) { @@ -250,8 +253,8 @@ public final class ImageIO { } /** - * Gets an array of Strings giving the names of the formats supported - * by registered ImageWriter objects. + * Gets an array of Strings giving the names of the formats supported by + * registered ImageWriter objects. * * @return the array of format names. */ @@ -260,7 +263,7 @@ public final class ImageIO { } /** - * Gets an array of Strings giving the MIME types of the formats supported + * Gets an array of Strings giving the MIME types of the formats supported * by registered ImageWriter objects. * * @return the array of MIME types. @@ -270,11 +273,11 @@ public final class ImageIO { } /** - * Gets the Iterator which lists the registered ImageReader objects that - * are able to encode the specified image format. - * - * @param formatName the image format name such as "jpeg". + * Gets the Iterator which lists the registered ImageReader objects that are + * able to encode the specified image format. * + * @param formatName + * the image format name such as "jpeg". * @return the Iterator of registered ImageWriter. */ public static Iterator getImageWritersByFormatName(String formatName) { @@ -289,11 +292,11 @@ public final class ImageIO { } /** - * Gets the Iterator which lists the registered ImageReader objects that - * are able to encode the specified suffix. - * - * @param fileSuffix the file suffix such as "jpg". + * Gets the Iterator which lists the registered ImageReader objects that are + * able to encode the specified suffix. * + * @param fileSuffix + * the file suffix such as "jpg". * @return the Iterator of registered ImageWriter. */ public static Iterator getImageWritersBySuffix(String fileSuffix) { @@ -306,11 +309,11 @@ public final class ImageIO { } /** - * Gets the Iterator which lists the registered ImageReader objects that - * are able to encode the specified MIME type. - * - * @param MIMEType the MIME type such as "image/jpeg". + * Gets the Iterator which lists the registered ImageReader objects that are + * able to encode the specified MIME type. * + * @param MIMEType + * the MIME type such as "image/jpeg". * @return the Iterator of registered ImageWriter. */ public static Iterator getImageWritersByMIMEType(String MIMEType) { @@ -318,12 +321,12 @@ public final class ImageIO { } /** - * Gets an ImageWriter object which corresponds to the - * specified ImageReader, or returns null if the specified - * ImageReader is not registered. - * - * @param reader the specified ImageReader. + * Gets an ImageWriter object which corresponds to the specified + * ImageReader, or returns null if the specified ImageReader is not + * registered. * + * @param reader + * the specified ImageReader. * @return the ImageWriter, or null. */ public static ImageWriter getImageWriter(ImageReader reader) { @@ -331,12 +334,12 @@ public final class ImageIO { } /** - * Gets an ImageReader object which corresponds to the - * specified ImageWriter, or returns null if the specified - * ImageWriter is not registered. - * - * @param writer the registered ImageWriter object. + * Gets an ImageReader object which corresponds to the specified + * ImageWriter, or returns null if the specified ImageWriter is not + * registered. * + * @param writer + * the registered ImageWriter object. * @return the ImageReader. */ public static ImageReader getImageReader(ImageWriter writer) { @@ -344,17 +347,16 @@ public final class ImageIO { } /** - * Gets the Iterator of ImageWriter objects which are able to - * encode images with the specified ImageTypeSpecifier and - * format. - * - * @param type the ImageTypeSpecifier, which defines layout. - * @param formatName the format name. + * Gets the Iterator of ImageWriter objects which are able to encode images + * with the specified ImageTypeSpecifier and format. * + * @param type + * the ImageTypeSpecifier, which defines layout. + * @param formatName + * the format name. * @return the Iterator of ImageWriter objects. */ - public static Iterator getImageWriters(ImageTypeSpecifier type, - String formatName) { + public static Iterator getImageWriters(ImageTypeSpecifier type, String formatName) { if (type == null) { throw new NullPointerException("type cannot be NULL"); } @@ -370,31 +372,31 @@ public final class ImageIO { } /** - * Gets the Iterator of registered ImageTranscoders which - * are able to transcode the metadata of the specified - * ImageReader object to a suitable object for encoding - * by the specified ImageWriter. - * - * @param reader the specified ImageReader. - * @param writer the specified ImageWriter. + * Gets the Iterator of registered ImageTranscoders which are able to + * transcode the metadata of the specified ImageReader object to a suitable + * object for encoding by the specified ImageWriter. * + * @param reader + * the specified ImageReader. + * @param writer + * the specified ImageWriter. * @return the Iterator of registered ImageTranscoders. */ public static Iterator getImageTranscoders(ImageReader reader, - ImageWriter writer) { + ImageWriter writer) { throw new UnsupportedOperationException("Not supported yet"); } /** - * Reads image data from the specified File and decodes it using - * the appropriate registered ImageReader object. - * The File is wrapped in an ImageInputStream. - * - * @param input the File to be read. + * Reads image data from the specified File and decodes it using the + * appropriate registered ImageReader object. The File is wrapped in an + * ImageInputStream. * + * @param input + * the File to be read. * @return the BufferedImage decoded from the specified File, or null. - * - * @throws IOException Signals that an I/O exception has occurred. + * @throws IOException + * if an I/O exception has occurred. */ public static BufferedImage read(File input) throws IOException { if (input == null) { @@ -406,15 +408,15 @@ public final class ImageIO { } /** - * Reads image data from the specified InputStream and decodes it - * using an appropriate registered an ImageReader object. + * Reads image data from the specified InputStream and decodes it using an + * appropriate registered an ImageReader object. * - * @param input the InputStream. - * - * @return the BufferedImage decoded from the specified InputStream, - * or null. - * - * @throws IOException Signals that an I/O exception has occurred. + * @param input + * the InputStream. + * @return the BufferedImage decoded from the specified InputStream, or + * null. + * @throws IOException + * if an I/O exception has occurred. */ public static BufferedImage read(InputStream input) throws IOException { if (input == null) { @@ -426,14 +428,14 @@ public final class ImageIO { } /** - * Reads image data from the specified URL and decodes it using - * the appropriate registered ImageReader object. - * - * @param input the URL to be read. + * Reads image data from the specified URL and decodes it using the + * appropriate registered ImageReader object. * + * @param input + * the URL to be read. * @return the BufferedImage decoded from the specified URL, or null. - * - * @throws IOException Signals that an I/O exception has occurred. + * @throws IOException + * if an I/O exception has occurred. */ public static BufferedImage read(URL input) throws IOException { if (input == null) { @@ -443,20 +445,20 @@ public final class ImageIO { InputStream stream = input.openStream(); BufferedImage res = read(stream); stream.close(); - + return res; } /** - * Reads image data from the specified ImageInputStream and decodes it - * using appropriate registered an ImageReader object. - * - * @param stream the ImageInputStream. + * Reads image data from the specified ImageInputStream and decodes it using + * appropriate registered an ImageReader object. * - * @return the BufferedImage decoded from the specified ImageInputStream, - * or null. - * - * @throws IOException Signals that an I/O exception has occurred. + * @param stream + * the ImageInputStream. + * @return the BufferedImage decoded from the specified ImageInputStream, or + * null. + * @throws IOException + * if an I/O exception has occurred. */ public static BufferedImage read(ImageInputStream stream) throws IOException { if (stream == null) { @@ -478,25 +480,25 @@ public final class ImageIO { } catch (IOException e) { // Stream could be already closed, proceed silently in this case } - + return res; } /** - * Writes the specified image in the specified format (using an - * appropriate ImageWriter) to the specified ImageOutputStream. - * - * @param im the RenderedImage. - * @param formatName the format name. - * @param output the ImageOutputStream where Image to be written. + * Writes the specified image in the specified format (using an appropriate + * ImageWriter) to the specified ImageOutputStream. * + * @param im + * the RenderedImage. + * @param formatName + * the format name. + * @param output + * the ImageOutputStream where Image to be written. * @return true, if Image is written successfully, false otherwise. - * - * @throws IOException Signals that an I/O exception has occurred. + * @throws IOException + * if an I/O exception has occurred. */ - public static boolean write(RenderedImage im, - String formatName, - ImageOutputStream output) + public static boolean write(RenderedImage im, String formatName, ImageOutputStream output) throws IOException { if (im == null) { @@ -509,7 +511,8 @@ public final class ImageIO { throw new IllegalArgumentException("output cannot be NULL"); } - Iterator it = getImageWriters(ImageTypeSpecifier.createFromRenderedImage(im), formatName); + Iterator it = getImageWriters(ImageTypeSpecifier.createFromRenderedImage(im), + formatName); if (it.hasNext()) { ImageWriter writer = it.next(); writer.setOutput(output); @@ -522,20 +525,20 @@ public final class ImageIO { } /** - * Writes the specified image in the specified format (using an - * appropriate ImageWriter) to the specified File. - * - * @param im the RenderedImage. - * @param formatName the format name. - * @param output the output File where Image to be written. + * Writes the specified image in the specified format (using an appropriate + * ImageWriter) to the specified File. * + * @param im + * the RenderedImage. + * @param formatName + * the format name. + * @param output + * the output File where Image to be written. * @return true, if Image is written successfully, false otherwise. - * - * @throws IOException Signals that an I/O exception has occurred. + * @throws IOException + * if an I/O exception has occurred. */ - public static boolean write(RenderedImage im, - String formatName, - File output) + public static boolean write(RenderedImage im, String formatName, File output) throws IOException { if (output == null) { @@ -553,20 +556,20 @@ public final class ImageIO { } /** - * Writes the specified image in the specified format (using an - * appropriate ImageWriter) to the specified OutputStream. - * - * @param im the RenderedImage. - * @param formatName the format name. - * @param output the OutputStream where Image is to be written. + * Writes the specified image in the specified format (using an appropriate + * ImageWriter) to the specified OutputStream. * + * @param im + * the RenderedImage. + * @param formatName + * the format name. + * @param output + * the OutputStream where Image is to be written. * @return true, if Image is written successfully, false otherwise. - * - * @throws IOException Signals that an I/O exception has occurred. + * @throws IOException + * if an I/O exception has occurred. */ - public static boolean write(RenderedImage im, - String formatName, - OutputStream output) + public static boolean write(RenderedImage im, String formatName, OutputStream output) throws IOException { if (output == null) { @@ -579,26 +582,28 @@ public final class ImageIO { return rt; } - /** * Filter to match spi by format name. */ static class FormatFilter implements ServiceRegistry.Filter { - - /** The name. */ + + /** + * The name. + */ private String name; /** * Instantiates a new format filter. * - * @param name the name + * @param name + * the name. */ public FormatFilter(String name) { this.name = name; } public boolean filter(Object provider) { - ImageReaderWriterSpi spi = (ImageReaderWriterSpi) provider; + ImageReaderWriterSpi spi = (ImageReaderWriterSpi)provider; return Arrays.asList(spi.getFormatNames()).contains(name); } } @@ -608,14 +613,18 @@ public final class ImageIO { */ static class FormatAndEncodeFilter extends FormatFilter { - /** The type. */ + /** + * The type. + */ private ImageTypeSpecifier type; /** * Instantiates a new format and encode filter. * - * @param type the type - * @param name the name + * @param type + * the type. + * @param name + * the name. */ public FormatAndEncodeFilter(ImageTypeSpecifier type, String name) { super(name); @@ -624,7 +633,7 @@ public final class ImageIO { @Override public boolean filter(Object provider) { - ImageWriterSpi spi = (ImageWriterSpi) provider; + ImageWriterSpi spi = (ImageWriterSpi)provider; return super.filter(provider) && spi.canEncodeImage(type); } } @@ -633,21 +642,24 @@ public final class ImageIO { * Filter to match spi by suffix. */ static class SuffixFilter implements ServiceRegistry.Filter { - - /** The suf. */ + + /** + * The suf. + */ private String suf; /** * Instantiates a new suffix filter. * - * @param suf the suf + * @param suf + * the suf. */ public SuffixFilter(String suf) { this.suf = suf; } public boolean filter(Object provider) { - ImageReaderWriterSpi spi = (ImageReaderWriterSpi) provider; + ImageReaderWriterSpi spi = (ImageReaderWriterSpi)provider; return Arrays.asList(spi.getFileSuffixes()).contains(suf); } } @@ -656,21 +668,24 @@ public final class ImageIO { * Filter to match spi by decoding possibility. */ static class CanReadFilter implements ServiceRegistry.Filter { - - /** The input. */ + + /** + * The input. + */ private Object input; /** * Instantiates a new can read filter. * - * @param input the input + * @param input + * the input. */ public CanReadFilter(Object input) { this.input = input; } public boolean filter(Object provider) { - ImageReaderSpi spi = (ImageReaderSpi) provider; + ImageReaderSpi spi = (ImageReaderSpi)provider; try { return spi.canDecodeInput(input); } catch (IOException e) { @@ -684,13 +699,16 @@ public final class ImageIO { */ static class SpiIteratorToWritersIteratorWrapper implements Iterator { - /** The backend. */ + /** + * The backend. + */ private Iterator backend; /** * Instantiates a new spi iterator to writers iterator wrapper. * - * @param backend the backend + * @param backend + * the backend. */ public SpiIteratorToWritersIteratorWrapper(Iterator backend) { this.backend = backend; @@ -699,7 +717,7 @@ public final class ImageIO { /** * Next. * - * @return the image writer + * @return the image writer. */ public ImageWriter next() { try { @@ -713,7 +731,7 @@ public final class ImageIO { /** * Checks for next. * - * @return true, if successful + * @return true, if successful. */ public boolean hasNext() { return backend.hasNext(); @@ -723,7 +741,8 @@ public final class ImageIO { * Removes the. */ public void remove() { - throw new UnsupportedOperationException("Use deregisterServiceprovider instead of Iterator.remove()"); + throw new UnsupportedOperationException( + "Use deregisterServiceprovider instead of Iterator.remove()"); } } @@ -731,14 +750,17 @@ public final class ImageIO { * Wraps spi's iterator to ImageReader iterator. */ static class SpiIteratorToReadersIteratorWrapper implements Iterator { - - /** The backend. */ + + /** + * The backend. + */ private Iterator backend; /** * Instantiates a new spi iterator to readers iterator wrapper. * - * @param backend the backend + * @param backend + * the backend. */ public SpiIteratorToReadersIteratorWrapper(Iterator backend) { this.backend = backend; @@ -747,7 +769,7 @@ public final class ImageIO { /** * Next. * - * @return the image reader + * @return the image reader. */ public ImageReader next() { try { @@ -761,7 +783,7 @@ public final class ImageIO { /** * Checks for next. * - * @return true, if successful + * @return true, if successful. */ public boolean hasNext() { return backend.hasNext(); @@ -771,7 +793,8 @@ public final class ImageIO { * Removes the. */ public void remove() { - throw new UnsupportedOperationException("Use deregisterServiceprovider instead of Iterator.remove()"); + throw new UnsupportedOperationException( + "Use deregisterServiceprovider instead of Iterator.remove()"); } } } diff --git a/awt/javax/imageio/ImageReadParam.java b/awt/javax/imageio/ImageReadParam.java index e67ed7d91edde6ef5c7436d4fba79b8c658232b2..9cc5c5f1b11dde411de750168526221f2782a583 100644 --- a/awt/javax/imageio/ImageReadParam.java +++ b/awt/javax/imageio/ImageReadParam.java @@ -18,6 +18,7 @@ * @author Sergey I. Salishev * @version $Revision: 1.2 $ */ + package javax.imageio; import java.awt.Dimension; @@ -29,45 +30,50 @@ import java.awt.image.BufferedImage; */ /** - * The ImageReadParam class provides information to the ImageReader about - * how an image is to be decoded. + * The ImageReadParam class provides information to the ImageReader about how an + * image is to be decoded. + * + * @since Android 1.0 */ - public class ImageReadParam extends IIOParam { - /** - * This flag indicates if this ImageReadParam supports setting the source - * rendering size. + /** + * This flag indicates if this ImageReadParam supports setting the source + * rendering size. */ protected boolean canSetSourceRenderSize; - - /** - * The destination BufferedImage. + + /** + * The destination BufferedImage. */ protected BufferedImage destination; - - /** The destination bands. */ + + /** + * The destination bands. + */ protected int[] destinationBands; - - /** - * The minimum progressive pass. + + /** + * The minimum progressive pass. */ protected int minProgressivePass; - - /** - * The number of progressive passes. + + /** + * The number of progressive passes. */ protected int numProgressivePasses; - - /** The source render size. */ + + /** + * The source render size. + */ protected Dimension sourceRenderSize; /** - * Returns true if this ImageReaderParam supports rendering a - * source image at an arbitrary size. + * Returns true if this ImageReaderParam supports rendering a source image + * at an arbitrary size. * - * @return true if this ImageReaderParam supports rendering a - * source image at an arbitrary size, false otherwise. + * @return true, if this ImageReaderParam supports rendering a source image + * at an arbitrary size, false otherwise. */ public boolean canSetSourceRenderSize() { return canSetSourceRenderSize; @@ -92,11 +98,9 @@ public class ImageReadParam extends IIOParam { } /** - * Gets the index of the maximum pass to be decoded. - * This method returns Integer.MAX_VALUE, if - * getSourceNumProgressivePasses() method returns value - * that is equal to Integer.MAX_VALUE. Otherwise - * this method returns + * Gets the index of the maximum pass to be decoded. This method returns + * Integer.MAX_VALUE, if getSourceNumProgressivePasses() method returns + * value that is equal to Integer.MAX_VALUE. Otherwise this method returns * getSourceMinProgressivePass() + getSourceNumProgressivePasses() - 1. * * @return the index of the maximum pass to be decoded. @@ -109,19 +113,19 @@ public class ImageReadParam extends IIOParam { } /** - * Gets the index of the minimum progressive pass that is decoded, - * default is 0. + * Gets the index of the minimum progressive pass that is decoded, default + * is 0. * * @return the index of the minimum progressive pass that is decoded, - * default is 0. + * default is 0. */ public int getSourceMinProgressivePass() { return minProgressivePass; } /** - * Gets the number of progressive passes. - * The default value is Integer.MAX_VALUE. + * Gets the number of progressive passes. The default value is + * Integer.MAX_VALUE. * * @return the number of progressive passes. */ @@ -130,8 +134,8 @@ public class ImageReadParam extends IIOParam { } /** - * Gets the dimension of source image which will be rendered - * during decoding process. + * Gets the dimension of source image which will be rendered during decoding + * process. * * @return the source render size. */ @@ -140,11 +144,12 @@ public class ImageReadParam extends IIOParam { } /** - * Sets the specified destination image. - * This image will be used by read, readAll, and readRaster methods, - * and a reference to it will be returned by those methods. + * Sets the specified destination image. This image will be used by read, + * readAll, and readRaster methods, and a reference to it will be returned + * by those methods. * - * @param destination the destination image. + * @param destination + * the destination image. */ public void setDestination(BufferedImage destination) { this.destination = destination; @@ -153,7 +158,8 @@ public class ImageReadParam extends IIOParam { /** * Sets the indices of the destination bands. * - * @param destinationBands the indices of the destination bands. + * @param destinationBands + * the indices of the destination bands. */ public void setDestinationBands(int[] destinationBands) { this.destinationBands = destinationBands; @@ -167,8 +173,10 @@ public class ImageReadParam extends IIOParam { /** * Sets the source progressive passes. * - * @param minPass the index of the minimum pass to be decoded. - * @param numPasses the number of passes to be decoded. + * @param minPass + * the index of the minimum pass to be decoded. + * @param numPasses + * the number of passes to be decoded. */ public void setSourceProgressivePasses(int minPass, int numPasses) { minProgressivePass = minPass; @@ -176,18 +184,18 @@ public class ImageReadParam extends IIOParam { } /** - * Sets the dimension size of source image if an - * image can be rendered at an arbitrary size. + * Sets the dimension size of source image if an image can be rendered at an + * arbitrary size. * - * @param size the size of rendered image. - * - * @throws UnsupportedOperationException the unsupported operation exception + * @param size + * the size of rendered image. + * @throws UnsupportedOperationException + * the unsupported operation exception. */ public void setSourceRenderSize(Dimension size) throws UnsupportedOperationException { if (!canSetSourceRenderSize) { throw new UnsupportedOperationException("can't set source renderer size"); } - sourceRenderSize = size; + sourceRenderSize = size; } } - diff --git a/awt/javax/imageio/ImageReader.java b/awt/javax/imageio/ImageReader.java index 780de266a3718afa563140c166522e2b2fcad146..cf282ed2a82af99793653b9eb6c39a12e57a5006 100644 --- a/awt/javax/imageio/ImageReader.java +++ b/awt/javax/imageio/ImageReader.java @@ -18,6 +18,7 @@ * @author Rustem V. Rafikov * @version $Revision: 1.3 $ */ + package javax.imageio; import javax.imageio.spi.ImageReaderSpi; @@ -37,56 +38,77 @@ import java.awt.image.RenderedImage; import java.awt.*; /** - * The ImageReader class is an abstract class for decoding images. - * ImageReader objects are instantiated by the service provider - * interface, ImageReaderSpi class, for the specific format. - * ImageReaderSpi class should be registered with the IIORegistry, - * which uses them for format recognition and presentation of available - * format readers and writers. + * The ImageReader class is an abstract class for decoding images. ImageReader + * objects are instantiated by the service provider interface, ImageReaderSpi + * class, for the specific format. ImageReaderSpi class should be registered + * with the IIORegistry, which uses them for format recognition and presentation + * of available format readers and writers. + * + * @since Android 1.0 */ public abstract class ImageReader { - /** The originating provider. */ + /** + * The originating provider. + */ protected ImageReaderSpi originatingProvider; - /** The input object such as ImageInputStream. */ + /** + * The input object such as ImageInputStream. + */ protected Object input; - /** The seek forward only. */ + /** + * The seek forward only. + */ protected boolean seekForwardOnly; - /** - * The ignore metadata flag indicates whether current input source - * has been marked as metadata is allowed to be ignored by setInput. + /** + * The ignore metadata flag indicates whether current input source has been + * marked as metadata is allowed to be ignored by setInput. */ protected boolean ignoreMetadata; - /** The minimum index. */ + /** + * The minimum index. + */ protected int minIndex; - /** The available locales. */ + /** + * The available locales. + */ protected Locale[] availableLocales; - /** The locale. */ + /** + * The locale. + */ protected Locale locale; - /** The list of warning listeners. */ + /** + * The list of warning listeners. + */ protected List warningListeners; - /** The list of warning locales. */ + /** + * The list of warning locales. + */ protected List warningLocales; - /** The list of progress listeners. */ + /** + * The list of progress listeners. + */ protected List progressListeners; - /** The list of update listeners. */ + /** + * The list of update listeners. + */ protected List updateListeners; /** * Instantiates a new ImageReader. * - * @param originatingProvider the ImageReaderSpi which - * instanties this ImageReader. + * @param originatingProvider + * the ImageReaderSpi which instantiates this ImageReader. */ protected ImageReader(ImageReaderSpi originatingProvider) { this.originatingProvider = originatingProvider; @@ -96,15 +118,15 @@ public abstract class ImageReader { * Gets the format name of this input source. * * @return the format name of this input source. - * - * @throws IOException Signals that an I/O exception has occurred. + * @throws IOException + * if an I/O exception has occurred. */ public String getFormatName() throws IOException { return originatingProvider.getFormatNames()[0]; } /** - * Gets the ImageReaderSpi which instantiated this ImageReader. + * Gets the ImageReaderSpi which instantiated this ImageReader. * * @return the ImageReaderSpi. */ @@ -113,14 +135,17 @@ public abstract class ImageReader { } /** - * Sets the specified Object as the input source of this ImageReader. + * Sets the specified Object as the input source of this ImageReader. * - * @param input the input source, it can - * be an ImageInputStream or other supported objects. - * @param seekForwardOnly indicates whether the stream must - * be read sequentially from its current starting point. - * @param ignoreMetadata parameter which indicates - * if metadata may be ignored during reads or not. + * @param input + * the input source, it can be an ImageInputStream or other + * supported objects. + * @param seekForwardOnly + * indicates whether the stream must be read sequentially from + * its current starting point. + * @param ignoreMetadata + * parameter which indicates if metadata may be ignored during + * reads or not. */ public void setInput(Object input, boolean seekForwardOnly, boolean ignoreMetadata) { if (input != null) { @@ -137,9 +162,9 @@ public abstract class ImageReader { /** * Checks if is supported. * - * @param input the input - * - * @return true, if is supported + * @param input + * the input. + * @return true, if is supported. */ private boolean isSupported(Object input) { ImageReaderSpi spi = getOriginatingProvider(); @@ -158,10 +183,12 @@ public abstract class ImageReader { * Sets the specified Object as the input source of this ImageReader. * Metadata is not ignored. * - * @param input the input source, it can - * be an ImageInputStream or other supported objects. - * @param seekForwardOnly indicates whether the stream must - * be read sequentially from its current starting point. + * @param input + * the input source, it can be an ImageInputStream or other + * supported objects. + * @param seekForwardOnly + * indicates whether the stream must be read sequentially from + * its current starting point. */ public void setInput(Object input, boolean seekForwardOnly) { setInput(input, seekForwardOnly, false); @@ -171,8 +198,8 @@ public abstract class ImageReader { * Sets the specified Object as the input source of this ImageReader. * Metadata is not ignored and forward seeking is not required. * - * @param input the input source, it can - * be ImageInputStream or other objects. + * @param input + * the input source, it can be ImageInputStream or other objects. */ public void setInput(Object input) { setInput(input, false, false); @@ -181,8 +208,7 @@ public abstract class ImageReader { /** * Gets the input source object of this ImageReader, or returns null. * - * @return the the input source object such as ImageInputStream, - * or null. + * @return the input source object such as ImageInputStream, or null. */ public Object getInput() { return input; @@ -191,32 +217,31 @@ public abstract class ImageReader { /** * Checks if the input source supports only forward reading, or not. * - * @return true, if the input source supports only forward reading, - * false otherwise. + * @return true, if the input source supports only forward reading, false + * otherwise. */ public boolean isSeekForwardOnly() { return seekForwardOnly; } /** - * Returns true if the current input source allows - * to metadata to be ignored by passing true as - * the ignoreMetadata argument to the setInput method. + * Returns true if the current input source allows to metadata to be ignored + * by passing true as the ignoreMetadata argument to the setInput method. * - * @return true, if true if the current input source allows - * to metadata to be ignored by passing true as - * the ignoreMetadata argument to the setInput method. + * @return true, if the current input source allows to metadata to be + * ignored by passing true as the ignoreMetadata argument to the + * setInput method. */ public boolean isIgnoringMetadata() { return ignoreMetadata; } /** - * Gets the minimum valid index for reading an image, thumbnail, - * or image metadata. + * Gets the minimum valid index for reading an image, thumbnail, or image + * metadata. * - * @return the minimum valid index for reading an image, thumbnail, - * or image metadata. + * @return the minimum valid index for reading an image, thumbnail, or image + * metadata. */ public int getMinIndex() { return minIndex; @@ -234,7 +259,8 @@ public abstract class ImageReader { /** * Sets the locale to this ImageReader. * - * @param locale the Locale. + * @param locale + * the Locale. */ public void setLocale(Locale locale) { throw new UnsupportedOperationException("Not implemented yet"); @@ -252,89 +278,88 @@ public abstract class ImageReader { /** * Gets the number of images available in the current input source. * - * @param allowSearch the parameter which indicates what - * a search is required; if false, the reader may return -1 - * without searching. - * + * @param allowSearch + * the parameter which indicates what a search is required; if + * false, the reader may return -1 without searching. * @return the number of images. - * - * @throws IOException Signals that an I/O exception has occurred. + * @throws IOException + * if an I/O exception has occurred. */ public abstract int getNumImages(boolean allowSearch) throws IOException; /** * Gets the width of the specified image in input source. * - * @param imageIndex the image index. - * + * @param imageIndex + * the image index. * @return the width in pixels. - * - * @throws IOException Signals that an I/O exception has occurred. + * @throws IOException + * if an I/O exception has occurred. */ public abstract int getWidth(int imageIndex) throws IOException; /** * Gets the height of the specified image in input source. * - * @param imageIndex the image index. - * + * @param imageIndex + * the image index. * @return the height in pixels. - * - * @throws IOException Signals that an I/O exception has occurred. + * @throws IOException + * if an I/O exception has occurred. */ public abstract int getHeight(int imageIndex) throws IOException; /** - * Checks if the storage format of the specified image places - * an impediment on random pixels access or not. - * - * @param imageIndex the image's index. - * - * @return true, if the storage format of the specified image places - * an impediment on random pixels access, false otherwise. + * Checks if the storage format of the specified image places an impediment + * on random pixels access or not. * - * @throws IOException Signals that an I/O exception has occurred. + * @param imageIndex + * the image's index. + * @return true, if the storage format of the specified image places an + * impediment on random pixels access, false otherwise. + * @throws IOException + * if an I/O exception has occurred. */ public boolean isRandomAccessEasy(int imageIndex) throws IOException { - return false; //def + return false; // def } /** * Gets the aspect ratio (width devided by height) of the image. * - * @param imageIndex the image index. - * + * @param imageIndex + * the image index. * @return the aspect ratio of the image. - * - * @throws IOException Signals that an I/O exception has occurred. + * @throws IOException + * if an I/O exception has occurred. */ public float getAspectRatio(int imageIndex) throws IOException { - return (float) getWidth(imageIndex) / getHeight(imageIndex); + return (float)getWidth(imageIndex) / getHeight(imageIndex); } /** - * Gets an ImageTypeSpecifier which indicates the type of the - * specified image. - * - * @param imageIndex the image's index. + * Gets an ImageTypeSpecifier which indicates the type of the specified + * image. * + * @param imageIndex + * the image's index. * @return the ImageTypeSpecifier. - * - * @throws IOException Signals that an I/O exception has occurred. + * @throws IOException + * if an I/O exception has occurred. */ public ImageTypeSpecifier getRawImageType(int imageIndex) throws IOException { throw new UnsupportedOperationException("Not implemented yet"); } /** - * Gets an Iterator of ImageTypeSpecifier objects which are associated - * with image types that may be used when decoding specified image. - * - * @param imageIndex the image index. + * Gets an Iterator of ImageTypeSpecifier objects which are associated with + * image types that may be used when decoding specified image. * + * @param imageIndex + * the image index. * @return an Iterator of ImageTypeSpecifier objects. - * - * @throws IOException Signals that an I/O exception has occurred. + * @throws IOException + * if an I/O exception has occurred. */ public abstract Iterator getImageTypes(int imageIndex) throws IOException; @@ -351,21 +376,22 @@ public abstract class ImageReader { * Gets an IIOMetadata object for this input source. * * @return the IIOMetadata. - * - * @throws IOException Signals that an I/O exception has occurred. + * @throws IOException + * if an I/O exception has occurred. */ public abstract IIOMetadata getStreamMetadata() throws IOException; /** * Gets an IIOMetadata object for this input source. * - * @param formatName the desired metadata format to be used in the - * returned IIOMetadata object. - * @param nodeNames the node names of the document. - * + * @param formatName + * the desired metadata format to be used in the returned + * IIOMetadata object. + * @param nodeNames + * the node names of the document. * @return the IIOMetadata. - * - * @throws IOException Signals that an I/O exception has occurred. + * @throws IOException + * if an I/O exception has occurred. */ public IIOMetadata getStreamMetadata(String formatName, Set nodeNames) throws IOException { @@ -375,83 +401,86 @@ public abstract class ImageReader { /** * Gets the image metadata of the specified image in input source. * - * @param imageIndex the image index. - * + * @param imageIndex + * the image index. * @return the IIOMetadata. - * - * @throws IOException Signals that an I/O exception has occurred. + * @throws IOException + * if an I/O exception has occurred. */ public abstract IIOMetadata getImageMetadata(int imageIndex) throws IOException; /** * Gets the image metadata of the specified image input source. * - * @param imageIndex the image index. - * @param formatName the desired metadata format to be used in the - * returned IIOMetadata object. - * @param nodeNames the node names which can be contained in - * the document. - * + * @param imageIndex + * the image index. + * @param formatName + * the desired metadata format to be used in the returned + * IIOMetadata object. + * @param nodeNames + * the node names which can be contained in the document. * @return the IIOMetadata. - * - * @throws IOException Signals that an I/O exception has occurred. + * @throws IOException + * if an I/O exception has occurred. */ - public IIOMetadata getImageMetadata(int imageIndex, String formatName, - Set nodeNames) throws IOException { + public IIOMetadata getImageMetadata(int imageIndex, String formatName, Set nodeNames) + throws IOException { throw new UnsupportedOperationException("Not implemented yet"); } /** - * Reads the specified image and returns it as a BufferedImage - * using the default ImageReadParam. - * - * @param imageIndex the image index. + * Reads the specified image and returns it as a BufferedImage using the + * default ImageReadParam. * + * @param imageIndex + * the image index. * @return the BufferedImage. - * - * @throws IOException Signals that an I/O exception has occurred. + * @throws IOException + * if an I/O exception has occurred. */ public BufferedImage read(int imageIndex) throws IOException { return read(imageIndex, null); } /** - * Reads the specified image and returns it as a BufferedImage - * using the specified ImageReadParam. - * - * @param imageIndex the image index. - * @param param the ImageReadParam. + * Reads the specified image and returns it as a BufferedImage using the + * specified ImageReadParam. * + * @param imageIndex + * the image index. + * @param param + * the ImageReadParam. * @return the BufferedImage. - * - * @throws IOException Signals that an I/O exception has occurred. + * @throws IOException + * if an I/O exception has occurred. */ public abstract BufferedImage read(int imageIndex, ImageReadParam param) throws IOException; /** * Reads the specified image and returns an IIOImage with this image, - * thumbnails, and metadata for this image, using - * the specified ImageReadParam. - * - * @param imageIndex the image index. - * @param param the ImageReadParam. + * thumbnails, and metadata for this image, using the specified + * ImageReadParam. * + * @param imageIndex + * the image index. + * @param param + * the ImageReadParam. * @return the IIOImage. - * - * @throws IOException Signals that an I/O exception has occurred. + * @throws IOException + * if an I/O exception has occurred. */ public IIOImage readAll(int imageIndex, ImageReadParam param) throws IOException { throw new UnsupportedOperationException("Not implemented yet"); } /** - * Returns an Iterator of IIOImages from the input source. - * - * @param params the Iterator of ImageReadParam objects. + * Returns an Iterator of IIOImages from the input source. * + * @param params + * the Iterator of ImageReadParam objects. * @return the iterator of IIOImages. - * - * @throws IOException Signals that an I/O exception has occurred. + * @throws IOException + * if an I/O exception has occurred. */ public Iterator readAll(Iterator params) throws IOException { throw new UnsupportedOperationException("Not implemented yet"); @@ -460,23 +489,23 @@ public abstract class ImageReader { /** * Checks whether or not this plug-in supports reading a Raster. * - * @return true, if this plug-in supports reading a Raster, - * false otherwise. + * @return true, if this plug-in supports reading a Raster, false otherwise. */ public boolean canReadRaster() { - return false; //def + return false; // def } /** - * Reads a new Raster object which contains the raw pixel data from - * the image. - * - * @param imageIndex the image index. - * @param param the ImageReadParam. + * Reads a new Raster object which contains the raw pixel data from the + * image. * + * @param imageIndex + * the image index. + * @param param + * the ImageReadParam. * @return the Raster. - * - * @throws IOException Signals that an I/O exception has occurred. + * @throws IOException + * if an I/O exception has occurred. */ public Raster readRaster(int imageIndex, ImageReadParam param) throws IOException { throw new UnsupportedOperationException("Unsupported"); @@ -485,220 +514,226 @@ public abstract class ImageReader { /** * Checks if the specified image has tiles or not. * - * @param imageIndex the image's index. - * - * @return true, if the specified image has tiles, - * false otherwise. - * - * @throws IOException Signals that an I/O exception has occurred. + * @param imageIndex + * the image's index. + * @return true, if the specified image has tiles, false otherwise. + * @throws IOException + * if an I/O exception has occurred. */ public boolean isImageTiled(int imageIndex) throws IOException { - return false; //def + return false; // def } /** * Gets the tile width in the specified image. * - * @param imageIndex the image's index. - * + * @param imageIndex + * the image's index. * @return the tile width. - * - * @throws IOException Signals that an I/O exception has occurred. + * @throws IOException + * if an I/O exception has occurred. */ public int getTileWidth(int imageIndex) throws IOException { - return getWidth(imageIndex); //def + return getWidth(imageIndex); // def } /** * Gets the tile height in the specified image. * - * @param imageIndex the image's index. - * + * @param imageIndex + * the image's index. * @return the tile height. - * - * @throws IOException Signals that an I/O exception has occurred. + * @throws IOException + * if an I/O exception has occurred. */ public int getTileHeight(int imageIndex) throws IOException { - return getHeight(imageIndex); //def + return getHeight(imageIndex); // def } /** - * Gets the X coordinate of the upper left corner of the tile grid in the + * Gets the X coordinate of the upper left corner of the tile grid in the * specified image. * - * @param imageIndex the image's index. - * + * @param imageIndex + * the image's index. * @return the X coordinate of the upper left corner of the tile grid. - * - * @throws IOException Signals that an I/O exception has occurred. + * @throws IOException + * if an I/O exception has occurred. */ public int getTileGridXOffset(int imageIndex) throws IOException { - return 0; //def + return 0; // def } /** - * Gets the Y coordinate of the upper left corner of the tile grid in the + * Gets the Y coordinate of the upper left corner of the tile grid in the * specified image. * - * @param imageIndex the image's index. - * + * @param imageIndex + * the image's index. * @return the Y coordinate of the upper left corner of the tile grid. - * - * @throws IOException Signals that an I/O exception has occurred. + * @throws IOException + * if an I/O exception has occurred. */ public int getTileGridYOffset(int imageIndex) throws IOException { - return 0; //def + return 0; // def } /** - * Reads the tile specified by the tileX and tileY parameters - * of the specified image and returns it as a BufferedImage. - * - * @param imageIndex the image index. - * @param tileX the X index of tile. - * @param tileY the Y index of tile. + * Reads the tile specified by the tileX and tileY parameters of the + * specified image and returns it as a BufferedImage. * + * @param imageIndex + * the image index. + * @param tileX + * the X index of tile. + * @param tileY + * the Y index of tile. * @return the BufferedImage. - * - * @throws IOException Signals that an I/O exception has occurred. + * @throws IOException + * if an I/O exception has occurred. */ public BufferedImage readTile(int imageIndex, int tileX, int tileY) throws IOException { throw new UnsupportedOperationException("Not implemented yet"); } /** - * Reads the tile specified by the tileX and tileY parameters - * of the specified image and returns it as a Raster. - * - * @param imageIndex the image index. - * @param tileX the X index of tile. - * @param tileY the Y index of tile. + * Reads the tile specified by the tileX and tileY parameters of the + * specified image and returns it as a Raster. * + * @param imageIndex + * the image index. + * @param tileX + * the X index of tile. + * @param tileY + * the Y index of tile. * @return the Raster. - * - * @throws IOException Signals that an I/O exception has occurred. + * @throws IOException + * if an I/O exception has occurred. */ public Raster readTileRaster(int imageIndex, int tileX, int tileY) throws IOException { throw new UnsupportedOperationException("Not implemented yet"); } /** - * Reads the specified image using the specified - * ImageReadParam and returns it as a RenderedImage. - * - * @param imageIndex the image index. - * @param param the ImageReadParam. + * Reads the specified image using the specified ImageReadParam and returns + * it as a RenderedImage. * + * @param imageIndex + * the image index. + * @param param + * the ImageReadParam. * @return the RenderedImage. - * - * @throws IOException Signals that an I/O exception has occurred. + * @throws IOException + * if an I/O exception has occurred. */ - public RenderedImage readAsRenderedImage(int imageIndex, ImageReadParam param) throws IOException { + public RenderedImage readAsRenderedImage(int imageIndex, ImageReadParam param) + throws IOException { return read(imageIndex, param); } /** - * Returns true if the image format supported by this reader - * supports thumbnail preview images. + * Returns true if the image format supported by this reader supports + * thumbnail preview images. * - * @return true if the image format supported by this reader - * supports thumbnail preview images, false otherwise. + * @return true, if the image format supported by this reader supports + * thumbnail preview images, false otherwise. */ public boolean readerSupportsThumbnails() { - return false; //def + return false; // def } /** * Checks if the specified image has thumbnails or not. * - * @param imageIndex the image's index. - * - * @return true, if the specified image has thumbnails, - * false otherwise. - * - * @throws IOException Signals that an I/O exception has occurred. + * @param imageIndex + * the image's index. + * @return true, if the specified image has thumbnails, false otherwise. + * @throws IOException + * if an I/O exception has occurred. */ public boolean hasThumbnails(int imageIndex) throws IOException { - return getNumThumbnails(imageIndex) > 0; //def + return getNumThumbnails(imageIndex) > 0; // def } /** * Gets the number of thumbnails for the specified image. * - * @param imageIndex the image's index. - * + * @param imageIndex + * the image's index. * @return the number of thumbnails. - * - * @throws IOException Signals that an I/O exception has occurred. + * @throws IOException + * if an I/O exception has occurred. */ public int getNumThumbnails(int imageIndex) throws IOException { - return 0; //def + return 0; // def } /** * Gets the width of the specified thumbnail for the specified image. * - * @param imageIndex the image's index. - * @param thumbnailIndex the thumbnail's index. - * + * @param imageIndex + * the image's index. + * @param thumbnailIndex + * the thumbnail's index. * @return the thumbnail width. - * - * @throws IOException Signals that an I/O exception has occurred. + * @throws IOException + * if an I/O exception has occurred. */ public int getThumbnailWidth(int imageIndex, int thumbnailIndex) throws IOException { - return readThumbnail(imageIndex, thumbnailIndex).getWidth(); //def + return readThumbnail(imageIndex, thumbnailIndex).getWidth(); // def } /** * Gets the height of the specified thumbnail for the specified image. * - * @param imageIndex the image's index. - * @param thumbnailIndex the thumbnail's index. - * + * @param imageIndex + * the image's index. + * @param thumbnailIndex + * the thumbnail's index. * @return the thumbnail height. - * - * @throws IOException Signals that an I/O exception has occurred. + * @throws IOException + * if an I/O exception has occurred. */ public int getThumbnailHeight(int imageIndex, int thumbnailIndex) throws IOException { - return readThumbnail(imageIndex, thumbnailIndex).getHeight(); //def + return readThumbnail(imageIndex, thumbnailIndex).getHeight(); // def } /** - * Reads the thumbnail image for the specified image - * as a BufferedImage. - * - * @param imageIndex the image index. - * @param thumbnailIndex the thumbnail index. + * Reads the thumbnail image for the specified image as a BufferedImage. * + * @param imageIndex + * the image index. + * @param thumbnailIndex + * the thumbnail index. * @return the BufferedImage. - * - * @throws IOException Signals that an I/O exception has occurred. + * @throws IOException + * if an I/O exception has occurred. */ public BufferedImage readThumbnail(int imageIndex, int thumbnailIndex) throws IOException { - throw new UnsupportedOperationException("Unsupported"); //def + throw new UnsupportedOperationException("Unsupported"); // def } /** - * Requests an abort operation for current reading operation. + * Requests an abort operation for current reading operation. */ public void abort() { throw new UnsupportedOperationException("Not implemented yet"); } /** - * Checks whether or not a request to abort the current read operation - * has been made successfully. + * Checks whether or not a request to abort the current read operation has + * been made successfully. * - * @return true, if the request to abort the current read operation - * has been made successfully, false otherwise. + * @return true, if the request to abort the current read operation has been + * made successfully, false otherwise. */ protected boolean abortRequested() { throw new UnsupportedOperationException("Not implemented yet"); } /** - * Clears all previous abort request, and abortRequested returns false - * after calling this method. + * Clears all previous abort request, and abortRequested returns false after + * calling this method. */ protected void clearAbortRequest() { throw new UnsupportedOperationException("Not implemented yet"); @@ -707,7 +742,8 @@ public abstract class ImageReader { /** * Adds the IIOReadWarningListener. * - * @param listener the IIOReadWarningListener. + * @param listener + * the IIOReadWarningListener. */ public void addIIOReadWarningListener(IIOReadWarningListener listener) { throw new UnsupportedOperationException("Not implemented yet"); @@ -716,7 +752,8 @@ public abstract class ImageReader { /** * Removes the specified IIOReadWarningListener. * - * @param listener the IIOReadWarningListener to be removed. + * @param listener + * the IIOReadWarningListener to be removed. */ public void removeIIOReadWarningListener(IIOReadWarningListener listener) { throw new UnsupportedOperationException("Not implemented yet"); @@ -732,7 +769,8 @@ public abstract class ImageReader { /** * Adds the IIOReadProgressListener. * - * @param listener the IIOReadProgressListener. + * @param listener + * the IIOReadProgressListener. */ public void addIIOReadProgressListener(IIOReadProgressListener listener) { throw new UnsupportedOperationException("Not implemented yet"); @@ -741,7 +779,8 @@ public abstract class ImageReader { /** * Removes the specified IIOReadProgressListener. * - * @param listener the IIOReadProgressListener to be removed. + * @param listener + * the IIOReadProgressListener to be removed. */ public void removeIIOReadProgressListener(IIOReadProgressListener listener) { throw new UnsupportedOperationException("Not implemented yet"); @@ -757,7 +796,8 @@ public abstract class ImageReader { /** * Adds the IIOReadUpdateListener. * - * @param listener the IIOReadUpdateListener. + * @param listener + * the IIOReadUpdateListener. */ public void addIIOReadUpdateListener(IIOReadUpdateListener listener) { throw new UnsupportedOperationException("Not implemented yet"); @@ -766,7 +806,8 @@ public abstract class ImageReader { /** * Removes the specified IIOReadUpdateListener. * - * @param listener the IIOReadUpdateListener to be removed. + * @param listener + * the IIOReadUpdateListener to be removed. */ public void removeIIOReadUpdateListener(IIOReadUpdateListener listener) { throw new UnsupportedOperationException("Not implemented yet"); @@ -780,229 +821,243 @@ public abstract class ImageReader { } /** - * Processes the start of an sequence of image reads - * by calling the sequenceStarted method on all registered - * IIOReadProgressListeners. + * Processes the start of an sequence of image reads by calling the + * sequenceStarted method on all registered IIOReadProgressListeners. * - * @param minIndex the minimum index. + * @param minIndex + * the minimum index. */ protected void processSequenceStarted(int minIndex) { throw new UnsupportedOperationException("Not implemented yet"); } /** - * Processes the completion of an sequence of image reads - * by calling sequenceComplete method on all registered - * IIOReadProgressListeners. + * Processes the completion of an sequence of image reads by calling + * sequenceComplete method on all registered IIOReadProgressListeners. */ protected void processSequenceComplete() { throw new UnsupportedOperationException("Not implemented yet"); } /** - * Processes the start of an image read by calling the imageStarted - * method on all registered IIOReadProgressListeners. + * Processes the start of an image read by calling the imageStarted method + * on all registered IIOReadProgressListeners. * - * @param imageIndex the image index. + * @param imageIndex + * the image index. */ protected void processImageStarted(int imageIndex) { throw new UnsupportedOperationException("Not implemented yet"); } /** - * Processes the current percentage of image completion by calling - * the imageProgress method on all registered IIOReadProgressListeners. + * Processes the current percentage of image completion by calling the + * imageProgress method on all registered IIOReadProgressListeners. * - * @param percentageDone the percentage done. + * @param percentageDone + * the percentage done. */ protected void processImageProgress(float percentageDone) { throw new UnsupportedOperationException("Not implemented yet"); } /** - * Processes image completion by calling the imageComplete method - * on all registered IIOReadProgressListeners. + * Processes image completion by calling the imageComplete method on all + * registered IIOReadProgressListeners. */ protected void processImageComplete() { throw new UnsupportedOperationException("Not implemented yet"); } /** - * Processes the start of a thumbnail read by calling the - * thumbnailStarted method on all registered IIOReadProgressListeners. + * Processes the start of a thumbnail read by calling the thumbnailStarted + * method on all registered IIOReadProgressListeners. * - * @param imageIndex the image index. - * @param thumbnailIndex the thumbnail index. + * @param imageIndex + * the image index. + * @param thumbnailIndex + * the thumbnail index. */ protected void processThumbnailStarted(int imageIndex, int thumbnailIndex) { throw new UnsupportedOperationException("Not implemented yet"); } /** - * Processes the current percentage of thumbnail completion - * by calling the thumbnailProgress method on all registered - * IIOReadProgressListeners. + * Processes the current percentage of thumbnail completion by calling the + * thumbnailProgress method on all registered IIOReadProgressListeners. * - * @param percentageDone the percentage done. + * @param percentageDone + * the percentage done. */ protected void processThumbnailProgress(float percentageDone) { throw new UnsupportedOperationException("Not implemented yet"); } /** - * Processes the completion of a thumbnail read - * by calling the thumbnailComplete method - * on all registered IIOReadProgressListeners. + * Processes the completion of a thumbnail read by calling the + * thumbnailComplete method on all registered IIOReadProgressListeners. */ protected void processThumbnailComplete() { throw new UnsupportedOperationException("Not implemented yet"); } /** - * Processes a read aborted event by calling the readAborted - * method on all registered IIOReadProgressListeners. + * Processes a read aborted event by calling the readAborted method on all + * registered IIOReadProgressListeners. */ protected void processReadAborted() { throw new UnsupportedOperationException("Not implemented yet"); } /** - * Processes the beginning of a progressive pass by calling - * the passStarted method on all registered IIOReadUpdateListeners. - * - * @param theImage the image to be updated. - * @param pass the current pass index. - * @param minPass the minimum pass index. - * @param maxPass the maximum pass index. - * @param minX the X coordinate of of the upper left pixel. - * @param minY the Y coordinate of of the upper left pixel. - * @param periodX the horizontal separation between pixels. - * @param periodY the vertical separation between pixels. - * @param bands the number of affected bands. - */ - protected void processPassStarted(BufferedImage theImage, - int pass, - int minPass, - int maxPass, - int minX, - int minY, - int periodX, - int periodY, - int[] bands) { + * Processes the beginning of a progressive pass by calling the passStarted + * method on all registered IIOReadUpdateListeners. + * + * @param theImage + * the image to be updated. + * @param pass + * the current pass index. + * @param minPass + * the minimum pass index. + * @param maxPass + * the maximum pass index. + * @param minX + * the X coordinate of of the upper left pixel. + * @param minY + * the Y coordinate of of the upper left pixel. + * @param periodX + * the horizontal separation between pixels. + * @param periodY + * the vertical separation between pixels. + * @param bands + * the number of affected bands. + */ + protected void processPassStarted(BufferedImage theImage, int pass, int minPass, int maxPass, + int minX, int minY, int periodX, int periodY, int[] bands) { throw new UnsupportedOperationException("Not implemented yet"); } /** - * Processes the update of a set of samples by calling - * the imageUpdate method on all registered IIOReadUpdateListeners. - * - * @param theImage the image to be updated. - * @param minX the X coordinate of the upper left pixel. - * @param minY the Y coordinate of the upper left pixel. - * @param width the width of updated area. - * @param height the height of updated area. - * @param periodX the horizontal separation between pixels. - * @param periodY the vertical separation between pixels. - * @param bands the number of affected bands. - */ - protected void processImageUpdate(BufferedImage theImage, - int minX, - int minY, - int width, - int height, - int periodX, - int periodY, - int[] bands) { + * Processes the update of a set of samples by calling the imageUpdate + * method on all registered IIOReadUpdateListeners. + * + * @param theImage + * the image to be updated. + * @param minX + * the X coordinate of the upper left pixel. + * @param minY + * the Y coordinate of the upper left pixel. + * @param width + * the width of updated area. + * @param height + * the height of updated area. + * @param periodX + * the horizontal separation between pixels. + * @param periodY + * the vertical separation between pixels. + * @param bands + * the number of affected bands. + */ + protected void processImageUpdate(BufferedImage theImage, int minX, int minY, int width, + int height, int periodX, int periodY, int[] bands) { throw new UnsupportedOperationException("Not implemented yet"); } /** - * Processes the end of a progressive pass by calling passComplete - * method of registered IIOReadUpdateListeners. + * Processes the end of a progressive pass by calling passComplete method of + * registered IIOReadUpdateListeners. * - * @param theImage the image to be updated. + * @param theImage + * the image to be updated. */ protected void processPassComplete(BufferedImage theImage) { throw new UnsupportedOperationException("Not implemented yet"); } /** - * Processes the beginning of a thumbnail progressive pass - * by calling the thumbnailPassStarted method on all - * registered IIOReadUpdateListeners. - * - * @param theThumbnail the the thumbnail to be updated. - * @param pass the current pass index. - * @param minPass the minimum pass index. - * @param maxPass the maximum pass index. - * @param minX the X coordinate of the upper left pixel. - * @param minY the Y coordinate of the upper left pixel. - * @param periodX the horizontal separation between pixels. - * @param periodY the vertical separation between pixels. - * @param bands the number of affected bands. - */ - protected void processThumbnailPassStarted(BufferedImage theThumbnail, - int pass, - int minPass, - int maxPass, - int minX, - int minY, - int periodX, - int periodY, - int[] bands) { + * Processes the beginning of a thumbnail progressive pass by calling the + * thumbnailPassStarted method on all registered IIOReadUpdateListeners. + * + * @param theThumbnail + * the thumbnail to be updated. + * @param pass + * the current pass index. + * @param minPass + * the minimum pass index. + * @param maxPass + * the maximum pass index. + * @param minX + * the X coordinate of the upper left pixel. + * @param minY + * the Y coordinate of the upper left pixel. + * @param periodX + * the horizontal separation between pixels. + * @param periodY + * the vertical separation between pixels. + * @param bands + * the number of affected bands. + */ + protected void processThumbnailPassStarted(BufferedImage theThumbnail, int pass, int minPass, + int maxPass, int minX, int minY, int periodX, int periodY, int[] bands) { throw new UnsupportedOperationException("Not implemented yet"); } /** - * Processes the update of a set of samples in a thumbnail - * image by calling the thumbnailUpdate method on all - * registered IIOReadUpdateListeners. - * - * @param theThumbnail the the thumbnail to be updated. - * @param minX the X coordinate of the upper left pixel. - * @param minY the Y coordinate of the upper left pixel. - * @param periodX the horizontal separation between pixels. - * @param periodY the vertical separation between pixels. - * @param bands the number of affected bands. - */ - protected void processThumbnailUpdate(BufferedImage theThumbnail, - int minX, - int minY, - int width, - int height, - int periodX, - int periodY, - int[] bands) { + * Processes the update of a set of samples in a thumbnail image by calling + * the thumbnailUpdate method on all registered IIOReadUpdateListeners. + * + * @param theThumbnail + * the thumbnail to be updated. + * @param minX + * the X coordinate of the upper left pixel. + * @param minY + * the Y coordinate of the upper left pixel. + * @param width + * the total width of the updated area. + * @param height + * the total height of the updated area. + * @param periodX + * the horizontal separation between pixels. + * @param periodY + * the vertical separation between pixels. + * @param bands + * the number of affected bands. + */ + protected void processThumbnailUpdate(BufferedImage theThumbnail, int minX, int minY, + int width, int height, int periodX, int periodY, int[] bands) { throw new UnsupportedOperationException("Not implemented yet"); } /** - * Processes the end of a thumbnail progressive pass - * by calling the thumbnailPassComplete method - * on all registered IIOReadUpdateListeners. + * Processes the end of a thumbnail progressive pass by calling the + * thumbnailPassComplete method on all registered IIOReadUpdateListeners. * - * @param theThumbnail the thumbnail to be updated. + * @param theThumbnail + * the thumbnail to be updated. */ protected void processThumbnailPassComplete(BufferedImage theThumbnail) { throw new UnsupportedOperationException("Not implemented yet"); } /** - * Processes a warning message by calling warningOccurred method - * of registered IIOReadWarningListeners. + * Processes a warning message by calling warningOccurred method of + * registered IIOReadWarningListeners. * - * @param warning the warning. + * @param warning + * the warning. */ protected void processWarningOccurred(String warning) { throw new UnsupportedOperationException("Not implemented yet"); } /** - * Processes a warning by calling the warningOccurred method - * of on all registered IIOReadWarningListeners. + * Processes a warning by calling the warningOccurred method of on all + * registered IIOReadWarningListeners. * - * @param baseName the base name of ResourceBundles. - * @param keyword the keyword to index the warning among ResourceBundles. + * @param baseName + * the base name of ResourceBundles. + * @param keyword + * the keyword to index the warning among ResourceBundles. */ protected void processWarningOccurred(String baseName, String keyword) { throw new UnsupportedOperationException("Not implemented yet"); @@ -1029,13 +1084,15 @@ public abstract class ImageReader { } /** - * Gets the region of source image that should be read with the - * specified width, height and ImageReadParam. - * - * @param param the ImageReadParam object, or null. - * @param srcWidth the source image's width. - * @param srcHeight the source image's height. + * Gets the region of source image that should be read with the specified + * width, height and ImageReadParam. * + * @param param + * the ImageReadParam object, or null. + * @param srcWidth + * the source image's width. + * @param srcHeight + * the source image's height. * @return the Rectangle of source region. */ protected static Rectangle getSourceRegion(ImageReadParam param, int srcWidth, int srcHeight) { @@ -1043,58 +1100,63 @@ public abstract class ImageReader { } /** - * Computes the specified source region and the specified destination - * region with the specified the width and height of the source image, - * an optional destination image, and an ImageReadParam. + * Computes the specified source region and the specified destination region + * with the specified the width and height of the source image, an optional + * destination image, and an ImageReadParam. * - * @param param the an ImageReadParam object, or null. - * @param srcWidth the source image's width. - * @param srcHeight the source image's height. - * @param image the destination image. - * @param srcRegion the source region. - * @param destRegion the destination region. + * @param param + * the an ImageReadParam object, or null. + * @param srcWidth + * the source image's width. + * @param srcHeight + * the source image's height. + * @param image + * the destination image. + * @param srcRegion + * the source region. + * @param destRegion + * the destination region. */ - protected static void computeRegions(ImageReadParam param, - int srcWidth, - int srcHeight, - BufferedImage image, - Rectangle srcRegion, - Rectangle destRegion) { + protected static void computeRegions(ImageReadParam param, int srcWidth, int srcHeight, + BufferedImage image, Rectangle srcRegion, Rectangle destRegion) { throw new UnsupportedOperationException("Not implemented yet"); } /** - * Checks the validity of the source and destination band and is called - * when the reader knows the number of bands of the source image and - * the number of bands of the destination image. + * Checks the validity of the source and destination band and is called when + * the reader knows the number of bands of the source image and the number + * of bands of the destination image. * - * @param param the ImageReadParam for reading the Image. - * @param numSrcBands the number of bands in the source. - * @param numDstBands the number of bands in the destination. + * @param param + * the ImageReadParam for reading the Image. + * @param numSrcBands + * the number of bands in the source. + * @param numDstBands + * the number of bands in the destination. */ - protected static void checkReadParamBandSettings(ImageReadParam param, - int numSrcBands, - int numDstBands) { + protected static void checkReadParamBandSettings(ImageReadParam param, int numSrcBands, + int numDstBands) { throw new UnsupportedOperationException("Not implemented yet"); } /** - * Gets the destination image where the decoded data is written. - * - * @param param the ImageReadParam. - * @param imageTypes the iterator of ImageTypeSpecifier objects. - * @param width the width of the image being decoded. - * @param height the height of the image being decoded. + * Gets the destination image where the decoded data is written. * + * @param param + * the ImageReadParam. + * @param imageTypes + * the iterator of ImageTypeSpecifier objects. + * @param width + * the width of the image being decoded. + * @param height + * the height of the image being decoded. * @return the BufferedImage where decoded pixels should be written. - * - * @throws IIOException the IIOException is thrown if - * there is no suitable ImageTypeSpecifier. + * @throws IIOException + * the IIOException is thrown if there is no suitable + * ImageTypeSpecifier. */ - protected static BufferedImage getDestination(ImageReadParam param, Iterator imageTypes, - int width, - int height) - throws IIOException { + protected static BufferedImage getDestination(ImageReadParam param, + Iterator imageTypes, int width, int height) throws IIOException { throw new UnsupportedOperationException("Not implemented yet"); } } diff --git a/awt/javax/imageio/ImageTranscoder.java b/awt/javax/imageio/ImageTranscoder.java index 1a0de764a5c5376cc4d1bdd77d1f1a83a9feb23d..632d890f87fdc0214e3120ef0f3d10a65bacd9ac 100644 --- a/awt/javax/imageio/ImageTranscoder.java +++ b/awt/javax/imageio/ImageTranscoder.java @@ -18,43 +18,50 @@ * @author Rustem V. Rafikov * @version $Revision: 1.3 $ */ + package javax.imageio; import javax.imageio.metadata.IIOMetadata; import javax.imageio.ImageTypeSpecifier; /** - * The ImageTranscoder interface is to be implemented by classes that - * perform image transcoding operations, that is, take images written - * in one format and write them in another format using - * read/write operations. Some image data can be lost in such processes. - * The ImageTranscoder interface converts metadata objects (IIOMetadata) - * of ImageReader to apropriate metadata object for ImageWriter. + * The ImageTranscoder interface is to be implemented by classes that perform + * image transcoding operations, that is, take images written in one format and + * write them in another format using read/write operations. Some image data can + * be lost in such processes. The ImageTranscoder interface converts metadata + * objects (IIOMetadata) of ImageReader to appropriate metadata object for + * ImageWriter. + * + * @since Android 1.0 */ public interface ImageTranscoder { - + /** * Converts the specified IIOMetadata object using the specified * ImageWriteParam for obtaining writer's metadata structure. * - * @param inData the IIOMetadata. - * @param param the ImageWriteParam. - * + * @param inData + * the IIOMetadata. + * @param param + * the ImageWriteParam. * @return the IIOMetadata, or null. */ IIOMetadata convertStreamMetadata(IIOMetadata inData, ImageWriteParam param); /** * Converts the specified IIOMetadata object using the specified - * ImageWriteParam for obtaining writer's metadata structure - * and ImageTypeSpecifier object for obtaining the layout and - * color information of the image for this metadata. - * - * @param inData the IIOMetadata. - * @param imageType the ImageTypeSpecifier. - * @param param the ImageWriteParam. + * ImageWriteParam for obtaining writer's metadata structure and + * ImageTypeSpecifier object for obtaining the layout and color information + * of the image for this metadata. * + * @param inData + * the IIOMetadata. + * @param imageType + * the ImageTypeSpecifier. + * @param param + * the ImageWriteParam. * @return the IIOMetadata, or null. */ - IIOMetadata convertImageMetadata(IIOMetadata inData, ImageTypeSpecifier imageType, ImageWriteParam param); + IIOMetadata convertImageMetadata(IIOMetadata inData, ImageTypeSpecifier imageType, + ImageWriteParam param); } diff --git a/awt/javax/imageio/ImageTypeSpecifier.java b/awt/javax/imageio/ImageTypeSpecifier.java index c93f269baafa7b41939192ba39d1e5c72b73b98b..505b1c484d5f997b1568e3214e4aee1efc2647c7 100644 --- a/awt/javax/imageio/ImageTypeSpecifier.java +++ b/awt/javax/imageio/ImageTypeSpecifier.java @@ -18,6 +18,7 @@ * @author Rustem V. Rafikov * @version $Revision: 1.3 $ */ + package javax.imageio; import java.awt.image.ColorModel; @@ -27,27 +28,31 @@ import java.awt.image.RenderedImage; import java.awt.color.ColorSpace; /** - * The ImageTypeSpecifier class performs conversion operations - * on the SampleModel and the ColorModel of an image. + * The ImageTypeSpecifier class performs conversion operations on the + * SampleModel and the ColorModel of an image. + * + * @since Android 1.0 */ public class ImageTypeSpecifier { - - /** + + /** * The ColorModel of this ImageTypeSpecifier. */ protected ColorModel colorModel; - - /** - * The SampleModel of this ImageTypeSpecifier. + + /** + * The SampleModel of this ImageTypeSpecifier. */ protected SampleModel sampleModel; /** - * Instantiates a new ImageTypeSpecifier with the specified - * ColorModel and SampleModel objects. + * Instantiates a new ImageTypeSpecifier with the specified ColorModel and + * SampleModel objects. * - * @param colorModel the ColorModel. - * @param sampleModel the SampleModel. + * @param colorModel + * the ColorModel. + * @param sampleModel + * the SampleModel. */ public ImageTypeSpecifier(ColorModel colorModel, SampleModel sampleModel) { if (colorModel == null) { @@ -65,10 +70,10 @@ public class ImageTypeSpecifier { } /** - * Instantiates a new ImageTypeSpecifier using the specified - * RenderedImage. + * Instantiates a new ImageTypeSpecifier using the specified RenderedImage. * - * @param renderedImage the RenderedImage. + * @param renderedImage + * the RenderedImage. */ public ImageTypeSpecifier(RenderedImage renderedImage) { if (renderedImage == null) { @@ -79,136 +84,139 @@ public class ImageTypeSpecifier { } /** - * Creates an ImageTypeSpecifier with the specified - * DirectColorModel and a packed SampleModel. - * - * @param colorSpace the ColorSpace. - * @param redMask the red mask. - * @param greenMask the green mask. - * @param blueMask the blue mask. - * @param alphaMask the alpha mask. - * @param transferType the transfer type. - * @param isAlphaPremultiplied the parameter indicates - * if the color channel is premultiplied by alpha. + * Creates an ImageTypeSpecifier with the specified DirectColorModel and a + * packed SampleModel. * + * @param colorSpace + * the ColorSpace. + * @param redMask + * the red mask. + * @param greenMask + * the green mask. + * @param blueMask + * the blue mask. + * @param alphaMask + * the alpha mask. + * @param transferType + * the transfer type. + * @param isAlphaPremultiplied + * the parameter indicates if the color channel is pre-multiplied + * by alpha. * @return the ImageTypeSpecifier. */ - public static ImageTypeSpecifier createPacked(ColorSpace colorSpace, - int redMask, - int greenMask, - int blueMask, - int alphaMask, - int transferType, - boolean isAlphaPremultiplied) { + public static ImageTypeSpecifier createPacked(ColorSpace colorSpace, int redMask, + int greenMask, int blueMask, int alphaMask, int transferType, + boolean isAlphaPremultiplied) { throw new UnsupportedOperationException("Not supported yet"); } /** - * Creates an ImageTypeSpecifier with specified - * ComponentColorModel and a PixelInterleavedSampleModel. - * - * @param colorSpace the ColorSpace. - * @param bandOffsets the band offsets. - * @param dataType the data type. - * @param hasAlpha the parameter indicates if alpha channel - * is needed. - * @param isAlphaPremultiplied the parameter indicates - * if the color channel is premultiplied by alpha. + * Creates an ImageTypeSpecifier with specified ComponentColorModel and a + * PixelInterleavedSampleModel. * + * @param colorSpace + * the ColorSpace. + * @param bandOffsets + * the band offsets. + * @param dataType + * the data type. + * @param hasAlpha + * the parameter indicates if alpha channel is needed. + * @param isAlphaPremultiplied + * the parameter indicates if the color channel is pre-multiplied + * by alpha. * @return the ImageTypeSpecifier. */ - public static ImageTypeSpecifier createInterleaved(ColorSpace colorSpace, - int[] bandOffsets, - int dataType, - boolean hasAlpha, - boolean isAlphaPremultiplied) { + public static ImageTypeSpecifier createInterleaved(ColorSpace colorSpace, int[] bandOffsets, + int dataType, boolean hasAlpha, boolean isAlphaPremultiplied) { throw new UnsupportedOperationException("Not supported yet"); } - /** - * Creates a ImageTypeSpecifier for a image with a - * BandedSampleModel and a ComponentColorModel. - * - * @param colorSpace the ColorSpace. - * @param bankIndices the bank indices. - * @param bandOffsets the band offsets. - * @param dataType the data type. - * @param hasAlpha the parameter indicates a presence of alpha channel. - * @param isAlphaPremultiplied the parameter indicates whether - * or not color channel is alpha premultiplied. + * Creates a ImageTypeSpecifier for a image with a BandedSampleModel and a + * ComponentColorModel. * + * @param colorSpace + * the ColorSpace. + * @param bankIndices + * the bank indices. + * @param bandOffsets + * the band offsets. + * @param dataType + * the data type. + * @param hasAlpha + * the parameter indicates a presence of alpha channel. + * @param isAlphaPremultiplied + * the parameter indicates whether or not color channel is alpha + * pre-multiplied. * @return the image type specifier */ - public static ImageTypeSpecifier createBanded(ColorSpace colorSpace, - int[] bankIndices, - int[] bandOffsets, - int dataType, - boolean hasAlpha, - boolean isAlphaPremultiplied) { + public static ImageTypeSpecifier createBanded(ColorSpace colorSpace, int[] bankIndices, + int[] bandOffsets, int dataType, boolean hasAlpha, boolean isAlphaPremultiplied) { throw new UnsupportedOperationException("Not supported yet"); } /** * Creates a ImageTypeSpecifier for a grayscale image. * - * @param bits the number of bits per gray value. - * @param dataType the data type. - * @param isSigned a signed flag. - * + * @param bits + * the number of bits per gray value. + * @param dataType + * the data type. + * @param isSigned + * a signed flag. * @return the ImageTypeSpecifier. */ - public static ImageTypeSpecifier createGrayscale(int bits, - int dataType, - boolean isSigned) { + public static ImageTypeSpecifier createGrayscale(int bits, int dataType, boolean isSigned) { throw new UnsupportedOperationException("Not supported yet"); } /** * Creates a ImageTypeSpecifier for a grayscale image. * - * @param bits the number of bits per gray value. - * @param dataType the data type. - * @param isSigned a signed flag. - * @param isAlphaPremultiplied the parameter indicates - * if color channel is premultiplied by alpha, or not. - * + * @param bits + * the number of bits per gray value. + * @param dataType + * the data type. + * @param isSigned + * a signed flag. + * @param isAlphaPremultiplied + * the parameter indicates if color channel is pre-multiplied by + * alpha, or not. * @return the ImageTypeSpecifier. */ - public static ImageTypeSpecifier createGrayscale(int bits, - int dataType, - boolean isSigned, - boolean isAlphaPremultiplied) { + public static ImageTypeSpecifier createGrayscale(int bits, int dataType, boolean isSigned, + boolean isAlphaPremultiplied) { throw new UnsupportedOperationException("Not supported yet"); } /** * Creates a ImageTypeSpecifier with the indexed image format. * - * @param redLUT the red values of indecies. - * @param greenLUT the green values of indecies. - * @param blueLUT the blue values of indecies. - * @param alphaLUT the alpha values of indecies. - * @param bits the bits number for each index. - * @param dataType the data type. - * + * @param redLUT + * the red values of indices. + * @param greenLUT + * the green values of indices. + * @param blueLUT + * the blue values of indices. + * @param alphaLUT + * the alpha values of indices. + * @param bits + * the bits number for each index. + * @param dataType + * the data type. * @return the ImageTypeSpecifier. */ - public static ImageTypeSpecifier createIndexed(byte[] redLUT, - byte[] greenLUT, - byte[] blueLUT, - byte[] alphaLUT, - int bits, - int dataType) { + public static ImageTypeSpecifier createIndexed(byte[] redLUT, byte[] greenLUT, byte[] blueLUT, + byte[] alphaLUT, int bits, int dataType) { throw new UnsupportedOperationException("Not supported yet"); } /** - * Creates the ImageTypeSpecifier from - * the specified buffered image type. - * - * @param bufferedImageType the buffered image type. + * Creates the ImageTypeSpecifier from the specified buffered image type. * + * @param bufferedImageType + * the buffered image type. * @return the ImageTypeSpecifier. */ public static ImageTypeSpecifier createFromBufferedImageType(int bufferedImageType) { @@ -216,11 +224,10 @@ public class ImageTypeSpecifier { } /** - * Creates the ImageTypeSpecifier from - * the specified RenderedImage. - * - * @param image the RenderedImage. + * Creates the ImageTypeSpecifier from the specified RenderedImage. * + * @param image + * the RenderedImage. * @return the ImageTypeSpecifier. */ public static ImageTypeSpecifier createFromRenderedImage(RenderedImage image) { @@ -242,7 +249,7 @@ public class ImageTypeSpecifier { /** * Gets the number of components. * - * @return the number of components + * @return the number of components. */ public int getNumComponents() { return colorModel.getNumComponents(); @@ -251,7 +258,7 @@ public class ImageTypeSpecifier { /** * Gets the number of bands. * - * @return the number of bands + * @return the number of bands. */ public int getNumBands() { return sampleModel.getNumBands(); @@ -260,8 +267,8 @@ public class ImageTypeSpecifier { /** * Gets the number of bits per the specified band. * - * @param band the index of band. - * + * @param band + * the index of band. * @return the number of bits per the specified band. */ public int getBitsPerBand(int band) { @@ -283,13 +290,14 @@ public class ImageTypeSpecifier { /** * Gets a compatible SampleModel with the specified width and height. * - * @param width the width. - * @param height the height. - * + * @param width + * the width. + * @param height + * the height. * @return the SampleModel. */ public SampleModel getSampleModel(int width, int height) { - if ((long)width*height > Integer.MAX_VALUE) { + if ((long)width * height > Integer.MAX_VALUE) { throw new IllegalArgumentException("width * height > Integer.MAX_VALUE"); } return sampleModel.createCompatibleSampleModel(width, height); @@ -298,20 +306,21 @@ public class ImageTypeSpecifier { /** * Gets the ColorModel associated with this ImageTypeSpecifier. * - * @return the ColorModel associated with this ImageTypeSpecifier. + * @return the ColorModel associated with this ImageTypeSpecifier. */ public ColorModel getColorModel() { return colorModel; } /** - * Creates the BufferedImage with the specified width and height - * and the ColorMadel and SampleModel which are specified by this + * Creates the BufferedImage with the specified width and height and the + * ColorMadel and SampleModel which are specified by this * ImageTypeSpecifier. * - * @param width the width of the BufferedImage. - * @param height the height of the BufferedImage. - * + * @param width + * the width of the BufferedImage. + * @param height + * the height of the BufferedImage. * @return the BufferedImage. */ public BufferedImage createBufferedImage(int width, int height) { @@ -319,19 +328,18 @@ public class ImageTypeSpecifier { } /** - * Compares this ImageTypeSpecifier object with the specified - * object. - * - * @param o the Object to be compared. + * Compares this ImageTypeSpecifier object with the specified object. * - * @return true, if the object is an ImageTypeSpecifier with the same - * data as this ImageTypeSpecifier, false otherwise. + * @param o + * the Object to be compared. + * @return true, if the object is an ImageTypeSpecifier with the same data + * as this ImageTypeSpecifier, false otherwise. */ @Override public boolean equals(Object o) { boolean rt = false; if (o instanceof ImageTypeSpecifier) { - ImageTypeSpecifier ts = (ImageTypeSpecifier) o; + ImageTypeSpecifier ts = (ImageTypeSpecifier)o; rt = colorModel.equals(ts.colorModel) && sampleModel.equals(ts.sampleModel); } return rt; diff --git a/awt/javax/imageio/ImageWriteParam.java b/awt/javax/imageio/ImageWriteParam.java index d32fa591d411aef9a4c942f8812796bcb74ef3d6..d661889b2fcfa67b1c24a6a15583aa0919091ba6 100644 --- a/awt/javax/imageio/ImageWriteParam.java +++ b/awt/javax/imageio/ImageWriteParam.java @@ -18,103 +18,141 @@ * @author Rustem V. Rafikov * @version $Revision: 1.3 $ */ + package javax.imageio; import java.util.Locale; import java.awt.*; /** - * The ImageWriteParam class provides information to an ImageWriter - * about how an image is to be encoded. + * The ImageWriteParam class provides information to an ImageWriter about how an + * image is to be encoded. + * + * @since Android 1.0 */ public class ImageWriteParam extends IIOParam { - /** - * The Constant MODE_DISABLED indicates that - * stream is not tiled, progressive, or compressed. + /** + * The Constant MODE_DISABLED indicates that stream is not tiled, + * progressive, or compressed. */ public static final int MODE_DISABLED = 0; - - /** - * The Constant MODE_DEFAULT indicates that the stream will be tiled, - * progressive, or compressed according to the plug-in's default. + + /** + * The Constant MODE_DEFAULT indicates that the stream will be tiled, + * progressive, or compressed according to the plug-in's default. */ public static final int MODE_DEFAULT = 1; - - /** + + /** * The Constant MODE_EXPLICIT indicates that the stream will be tiled, - * progressive, or compressed according to current settings - * which are defined by set methods. + * progressive, or compressed according to current settings which are + * defined by set methods. */ public static final int MODE_EXPLICIT = 2; - - /** - * The Constant MODE_COPY_FROM_METADATA indicates that the stream - * will be tiled, progressive, or compressed according to - * stream or image metadata. + + /** + * The Constant MODE_COPY_FROM_METADATA indicates that the stream will be + * tiled, progressive, or compressed according to stream or image metadata. */ public static final int MODE_COPY_FROM_METADATA = 3; - - /** Whether the ImageWriter can write tiles. */ + + /** + * Whether the ImageWriter can write tiles. + */ protected boolean canWriteTiles = false; - - /** The tiling mode. */ + + /** + * The tiling mode. + */ protected int tilingMode = MODE_COPY_FROM_METADATA; - - /** The preferred tile sizes. */ + + /** + * The preferred tile sizes. + */ protected Dimension[] preferredTileSizes = null; - - /** The tiling set. */ + + /** + * The tiling set. + */ protected boolean tilingSet = false; - - /** The tile width. */ + + /** + * The tile width. + */ protected int tileWidth = 0; - - /** The tile height. */ + + /** + * The tile height. + */ protected int tileHeight = 0; - - /** Whether the ImageWriter can offset tiles. */ + + /** + * Whether the ImageWriter can offset tiles. + */ protected boolean canOffsetTiles = false; - - /** The tile grid x offset. */ + + /** + * The tile grid x offset. + */ protected int tileGridXOffset = 0; - - /** The tile grid y offset. */ + + /** + * The tile grid y offset. + */ protected int tileGridYOffset = 0; - - /** Whether the ImageWriter can write in progressive mode. */ + + /** + * Whether the ImageWriter can write in progressive mode. + */ protected boolean canWriteProgressive = false; - - /** The progressive mode. */ + + /** + * The progressive mode. + */ protected int progressiveMode = MODE_COPY_FROM_METADATA; - - /** Whether the ImageWriter can write in compressed mode. */ + + /** + * Whether the ImageWriter can write in compressed mode. + */ protected boolean canWriteCompressed = false; - - /** The compression mode. */ + + /** + * The compression mode. + */ protected int compressionMode = MODE_COPY_FROM_METADATA; - - /** The compression types. */ + + /** + * The compression types. + */ protected String[] compressionTypes = null; - - /** The compression type. */ + + /** + * The compression type. + */ protected String compressionType = null; - - /** The compression quality. */ + + /** + * The compression quality. + */ protected float compressionQuality = 1.0f; - - /** The locale. */ + + /** + * The locale. + */ protected Locale locale = null; /** * Instantiates a new ImageWriteParam. */ - protected ImageWriteParam() {} + protected ImageWriteParam() { + } /** * Instantiates a new ImageWriteParam with the specified Locale. * - * @param locale the Locale. + * @param locale + * the Locale. */ public ImageWriteParam(Locale locale) { this.locale = locale; @@ -122,7 +160,7 @@ public class ImageWriteParam extends IIOParam { } /** - * Gets the mode for writing the stream in a progressive sequence. + * Gets the mode for writing the stream in a progressive sequence. * * @return the current progressive mode. */ @@ -134,24 +172,24 @@ public class ImageWriteParam extends IIOParam { } /** - * Returns true if images can be written using - * increasing quality passes by progressive. + * Returns true if images can be written using increasing quality passes by + * progressive. * - * @return true if images can be written using - * increasing quality passes by progressive, false otherwise. + * @return true if images can be written using increasing quality passes by + * progressive, false otherwise. */ public boolean canWriteProgressive() { return canWriteProgressive; } /** - * Sets the progressive mode which defines whether the stream - * contains a progressive sequence of increasing quality - * during writing. The progressive mode should be one of - * the following values: MODE_DISABLED, MODE_DEFAULT, or - * MODE_COPY_FROM_METADATA. + * Sets the progressive mode which defines whether the stream contains a + * progressive sequence of increasing quality during writing. The + * progressive mode should be one of the following values: MODE_DISABLED, + * MODE_DEFAULT, or MODE_COPY_FROM_METADATA. * - * @param mode the new progressive mode. + * @param mode + * the new progressive mode. */ public void setProgressiveMode(int mode) { if (canWriteProgressive()) { @@ -164,22 +202,21 @@ public class ImageWriteParam extends IIOParam { } /** - * Returns true if the writer can use tiles with non zero - * grid offsets while writing. + * Returns true if the writer can use tiles with non zero grid offsets while + * writing. * - * @return true if the writer can use tiles with non zero - * grid offsets while writing, false otherwise. + * @return true, if the writer can use tiles with non zero grid offsets + * while writing, false otherwise. */ public boolean canOffsetTiles() { return canOffsetTiles; } /** - * Returns true if this writer can write images with - * compression. + * Returns true if this writer can write images with compression. * - * @return true, true if this writer can write images with - * compression, false otherwise. + * @return true, if this writer can write images with compression, false + * otherwise. */ public boolean canWriteCompressed() { return canWriteCompressed; @@ -188,7 +225,7 @@ public class ImageWriteParam extends IIOParam { /** * Returns true if the writer can write tiles. * - * @return true if the writer can write tiles, false otherwise. + * @return true, if the writer can write tiles, false otherwise. */ public boolean canWriteTiles() { return canWriteTiles; @@ -247,8 +284,7 @@ public class ImageWriteParam extends IIOParam { /** * Gets the current compression type, or returns null. * - * @return the current compression type, or returns null - * if it is not set. + * @return the current compression type, or returns null if it is not set. */ public String getCompressionType() { checkWriteCompressed(); @@ -257,14 +293,12 @@ public class ImageWriteParam extends IIOParam { } /** - * Gets a bit rate which represents an estimate of the number of bits - * of output data for each bit of input image data with the specified - * quality. + * Gets a bit rate which represents an estimate of the number of bits of + * output data for each bit of input image data with the specified quality. * - * @param quality the quality. - * - * @return an estimate of the bit rate, or -1.0F if there is no - * estimate. + * @param quality + * the quality. + * @return an estimate of the bit rate, or -1.0F if there is no estimate. */ public float getBitRate(float quality) { checkWriteCompressed(); @@ -301,8 +335,7 @@ public class ImageWriteParam extends IIOParam { } /** - * Gets an array of floats which decribe - * compression quality levels. + * Gets an array of floats which describes compression quality levels. * * @return the array of compression quality values. */ @@ -323,7 +356,7 @@ public class ImageWriteParam extends IIOParam { } /** - * Gets the current compression type using the current Locale. + * Gets the current compression type using the current Locale. * * @return the current compression type using the current Locale. */ @@ -377,8 +410,8 @@ public class ImageWriteParam extends IIOParam { } /** - * Gets an array of Dimensions giving the sizes of the tiles as - * they are encoded in the output file or stream. + * Gets an array of Dimensions giving the sizes of the tiles as they are + * encoded in the output file or stream. * * @return the preferred tile sizes. */ @@ -420,11 +453,10 @@ public class ImageWriteParam extends IIOParam { } /** - * Gets the tile height in an image as it is written to the - * output stream. + * Gets the tile height in an image as it is written to the output stream. * - * @return the tile height in an image as it is written to the - * output stream. + * @return the tile height in an image as it is written to the output + * stream. */ public int getTileHeight() { checkTiling(); @@ -434,11 +466,9 @@ public class ImageWriteParam extends IIOParam { } /** - * Gets the tile width in an image as it is written to the - * output stream. + * Gets the tile width in an image as it is written to the output stream. * - * @return the tile width in an image as it is written to the - * output stream. + * @return the tile width in an image as it is written to the output stream. */ public int getTileWidth() { checkTiling(); @@ -448,11 +478,10 @@ public class ImageWriteParam extends IIOParam { } /** - * Checks if the current compression type has lossless - * compression or not. + * Checks if the current compression type has lossless compression or not. * - * @return true, if the current compression type has lossless - * compression, false otherwise. + * @return true, if the current compression type has lossless compression, + * false otherwise. */ public boolean isCompressionLossless() { checkWriteCompressed(); @@ -472,12 +501,12 @@ public class ImageWriteParam extends IIOParam { } /** - * Sets the compression mode to the specified value. - * The specified mode can be one of the predefined - * constants: MODE_DEFAULT, MODE_DISABLED, MODE_EXPLICIT, - * or MODE_COPY_FROM_METADATA. - * - * @param mode the new compression mode to be set. + * Sets the compression mode to the specified value. The specified mode can + * be one of the predefined constants: MODE_DEFAULT, MODE_DISABLED, + * MODE_EXPLICIT, or MODE_COPY_FROM_METADATA. + * + * @param mode + * the new compression mode to be set. */ public void setCompressionMode(int mode) { checkWriteCompressed(); @@ -502,8 +531,8 @@ public class ImageWriteParam extends IIOParam { /** * Sets the compression quality. The value should be between 0 and 1. * - * @param quality the new compression quality, - * float value between 0 and 1. + * @param quality + * the new compression quality, float value between 0 and 1. */ public void setCompressionQuality(float quality) { checkWriteCompressed(); @@ -516,11 +545,11 @@ public class ImageWriteParam extends IIOParam { } /** - * Sets the compression type. The specified string - * should be one of the values returned - * by getCompressionTypes method. + * Sets the compression type. The specified string should be one of the + * values returned by getCompressionTypes method. * - * @param compressionType the new compression type. + * @param compressionType + * the new compression type. */ public void setCompressionType(String compressionType) { checkWriteCompressed(); @@ -547,13 +576,17 @@ public class ImageWriteParam extends IIOParam { } /** - * Sets the instruction that tiling should be performed for - * the image in the output stream with the specified parameters. + * Sets the instruction that tiling should be performed for the image in the + * output stream with the specified parameters. * - * @param tileWidth the tile's width. - * @param tileHeight the tile's height. - * @param tileGridXOffset the tile grid's x offset. - * @param tileGridYOffset the tile grid's y offset. + * @param tileWidth + * the tile's width. + * @param tileHeight + * the tile's height. + * @param tileGridXOffset + * the tile grid's x offset. + * @param tileGridYOffset + * the tile grid's y offset. */ public void setTiling(int tileWidth, int tileHeight, int tileGridXOffset, int tileGridYOffset) { checkTiling(); @@ -563,19 +596,17 @@ public class ImageWriteParam extends IIOParam { throw new UnsupportedOperationException("Can't offset tiles!"); } - if (tileWidth <=0 || tileHeight <= 0) { + if (tileWidth <= 0 || tileHeight <= 0) { throw new IllegalArgumentException("tile dimensions are non-positive!"); } Dimension preferredTileSizes[] = getPreferredTileSizes(); if (preferredTileSizes != null) { - for (int i = 0; i < preferredTileSizes.length; i+=2) { + for (int i = 0; i < preferredTileSizes.length; i += 2) { Dimension minSize = preferredTileSizes[i]; - Dimension maxSize = preferredTileSizes[i+1]; - if ( - tileWidth < minSize.width || tileWidth > maxSize.width || - tileHeight < minSize.height || tileHeight > maxSize.height - ) { + Dimension maxSize = preferredTileSizes[i + 1]; + if (tileWidth < minSize.width || tileWidth > maxSize.width + || tileHeight < minSize.height || tileHeight > maxSize.height) { throw new IllegalArgumentException("Illegal tile size!"); } } @@ -603,11 +634,12 @@ public class ImageWriteParam extends IIOParam { } /** - * Sets the tiling mode. The specified mode should be one of the - * following values: MODE_DISABLED, MODE_DEFAULT, MODE_EXPLICIT, - * or MODE_COPY_FROM_METADATA. + * Sets the tiling mode. The specified mode should be one of the following + * values: MODE_DISABLED, MODE_DEFAULT, MODE_EXPLICIT, or + * MODE_COPY_FROM_METADATA. * - * @param mode the new tiling mode. + * @param mode + * the new tiling mode. */ public void setTilingMode(int mode) { checkTiling(); @@ -630,4 +662,3 @@ public class ImageWriteParam extends IIOParam { } } } - diff --git a/awt/javax/imageio/ImageWriter.java b/awt/javax/imageio/ImageWriter.java index d6119b0789ab320e0522ef1d49bd7237cd276b16..86879e0401007dc8173c8ae88aed7ad3f19e47c9 100644 --- a/awt/javax/imageio/ImageWriter.java +++ b/awt/javax/imageio/ImageWriter.java @@ -18,6 +18,7 @@ * @author Rustem V. Rafikov * @version $Revision: 1.3 $ */ + package javax.imageio; import java.awt.Dimension; @@ -40,34 +41,49 @@ import javax.imageio.metadata.IIOMetadata; import javax.imageio.spi.ImageWriterSpi; /** - * The ImageWriter class is an abstract class for encoding images. - * ImageWriter objects are instantiated by the service provider - * interface, ImageWriterSpi class, for the specific format. - * ImageWriterSpi class should be registered with the IIORegistry, - * which uses them for format recognition and presentation of available - * format readers and writers. + * The ImageWriter class is an abstract class for encoding images. ImageWriter + * objects are instantiated by the service provider interface, ImageWriterSpi + * class, for the specific format. ImageWriterSpi class should be registered + * with the IIORegistry, which uses them for format recognition and presentation + * of available format readers and writers. + * + * @since Android 1.0 */ public abstract class ImageWriter implements ImageTranscoder { - /** The available locales. */ + /** + * The available locales. + */ protected Locale[] availableLocales; - - /** The locale. */ + + /** + * The locale. + */ protected Locale locale; - - /** The originating provider. */ + + /** + * The originating provider. + */ protected ImageWriterSpi originatingProvider; - - /** The output. */ + + /** + * The output. + */ protected Object output; - - /** The progress listeners. */ + + /** + * The progress listeners. + */ protected List progressListeners; - - /** The warning listeners. */ + + /** + * The warning listeners. + */ protected List warningListeners; - - /** The warning locales. */ + + /** + * The warning locales. + */ protected List warningLocales; // Indicates that abort operation is requested @@ -78,22 +94,21 @@ public abstract class ImageWriter implements ImageTranscoder { /** * Instantiates a new ImageWriter. * - * @param originatingProvider the ImageWriterSpi which - * instanties this ImageWriter. + * @param originatingProvider + * the ImageWriterSpi which instantiates this ImageWriter. */ protected ImageWriter(ImageWriterSpi originatingProvider) { this.originatingProvider = originatingProvider; } public abstract IIOMetadata convertStreamMetadata(IIOMetadata iioMetadata, - ImageWriteParam imageWriteParam); + ImageWriteParam imageWriteParam); public abstract IIOMetadata convertImageMetadata(IIOMetadata iioMetadata, - ImageTypeSpecifier imageTypeSpecifier, - ImageWriteParam imageWriteParam); + ImageTypeSpecifier imageTypeSpecifier, ImageWriteParam imageWriteParam); /** - * Gets the ImageWriterSpi which instantiated this ImageWriter. + * Gets the ImageWriterSpi which instantiated this ImageWriter. * * @return the ImageWriterSpi. */ @@ -102,10 +117,11 @@ public abstract class ImageWriter implements ImageTranscoder { } /** - * Processes the start of an image read by calling their imageStarted - * method of registered IIOWriteProgressListeners. + * Processes the start of an image read by calling their imageStarted method + * of registered IIOWriteProgressListeners. * - * @param imageIndex the image index. + * @param imageIndex + * the image index. */ protected void processImageStarted(int imageIndex) { if (null != progressListeners) { @@ -116,10 +132,11 @@ public abstract class ImageWriter implements ImageTranscoder { } /** - * Processes the current percentage of image completion by calling + * Processes the current percentage of image completion by calling * imageProgress method of registered IIOWriteProgressListener. * - * @param percentageDone the percentage done. + * @param percentageDone + * the percentage done. */ protected void processImageProgress(float percentageDone) { if (null != progressListeners) { @@ -130,8 +147,8 @@ public abstract class ImageWriter implements ImageTranscoder { } /** - * Processes image completion by calling imageComplete method - * of registered IIOWriteProgressListeners. + * Processes image completion by calling imageComplete method of registered + * IIOWriteProgressListeners. */ protected void processImageComplete() { if (null != progressListeners) { @@ -142,11 +159,13 @@ public abstract class ImageWriter implements ImageTranscoder { } /** - * Processes a warning message by calling warningOccurred method - * of registered IIOWriteWarningListeners. + * Processes a warning message by calling warningOccurred method of + * registered IIOWriteWarningListeners. * - * @param imageIndex the image index. - * @param warning the warning. + * @param imageIndex + * the image index. + * @param warning + * the warning. */ protected void processWarningOccurred(int imageIndex, String warning) { if (null == warning) { @@ -160,13 +179,15 @@ public abstract class ImageWriter implements ImageTranscoder { } /** - * Processes a warning message by calling warningOccurred method - * of registered IIOWriteWarningListeners with string from - * ResourceBundle. + * Processes a warning message by calling warningOccurred method of + * registered IIOWriteWarningListeners with string from ResourceBundle. * - * @param imageIndex the image index. - * @param bundle the name of ResourceBundle. - * @param key the keyword. + * @param imageIndex + * the image index. + * @param bundle + * the name of ResourceBundle. + * @param key + * the keyword. */ protected void processWarningOccurred(int imageIndex, String bundle, String key) { if (warningListeners != null) { // Don't check the parameters @@ -180,17 +201,18 @@ public abstract class ImageWriter implements ImageTranscoder { throw new IllegalArgumentException("keyword == null!"); } - // Get the context class loader and try to locate the bundle with it first - ClassLoader contextClassloader = AccessController.doPrivileged( - new PrivilegedAction() { + // Get the context class loader and try to locate the bundle with it + // first + ClassLoader contextClassloader = AccessController + .doPrivileged(new PrivilegedAction() { public ClassLoader run() { return Thread.currentThread().getContextClassLoader(); } - }); + }); // Iterate through both listeners and locales int n = warningListeners.size(); - for (int i=0; i < n; i++) { + for (int i = 0; i < n; i++) { IIOWriteWarningListener listener = warningListeners.get(i); Locale locale = warningLocales.get(i); @@ -218,10 +240,11 @@ public abstract class ImageWriter implements ImageTranscoder { } /** - * Sets the specified Object to the output of this ImageWriter. + * Sets the specified Object to the output of this ImageWriter. * - * @param output the Object which represents destination, it can - * be ImageOutputStream or other objects. + * @param output + * the Object which represents destination, it can be + * ImageOutputStream or other objects. */ public void setOutput(Object output) { if (output != null) { @@ -244,26 +267,26 @@ public abstract class ImageWriter implements ImageTranscoder { } /** - * Writes a completed image stream that contains the specified image, + * Writes a completed image stream that contains the specified image, * default metadata, and thumbnails to the output. * - * @param image the specified image to be written. - * - * @throws IOException Signals that an I/O exception has occurred - * during writting. + * @param image + * the specified image to be written. + * @throws IOException + * if an I/O exception has occurred during writing. */ public void write(IIOImage image) throws IOException { write(null, image, null); } /** - * Writes a completed image stream that contains the specified - * rendered image, default metadata, and thumbnails to the output. - * - * @param image the specified RenderedImage to be written. + * Writes a completed image stream that contains the specified rendered + * image, default metadata, and thumbnails to the output. * - * @throws IOException Signals that an I/O exception has occurred - * during writting. + * @param image + * the specified RenderedImage to be written. + * @throws IOException + * if an I/O exception has occurred during writing. */ public void write(RenderedImage image) throws IOException { write(null, new IIOImage(image, null, null), null); @@ -273,16 +296,18 @@ public abstract class ImageWriter implements ImageTranscoder { * Writes a completed image stream that contains the specified image, * metadata and thumbnails to the output. * - * @param streamMetadata the stream metadata, or null. - * @param image the specified image to be written, if - * canWriteRaster() method returns false, then Image must contain - * only RenderedImage. - * @param param the ImageWriteParam, or null. - * - * @throws IOException - if an error occurs during writing. + * @param streamMetadata + * the stream metadata, or null. + * @param image + * the specified image to be written, if canWriteRaster() method + * returns false, then Image must contain only RenderedImage. + * @param param + * the ImageWriteParam, or null. + * @throws IOException + * if an error occurs during writing. */ - public abstract void write(IIOMetadata streamMetadata, - IIOImage image, ImageWriteParam param) throws IOException; + public abstract void write(IIOMetadata streamMetadata, IIOImage image, ImageWriteParam param) + throws IOException; /** * Disposes of any resources. @@ -292,26 +317,26 @@ public abstract class ImageWriter implements ImageTranscoder { } /** - * Requests an abort operation for current writing operation. + * Requests an abort operation for current writing operation. */ public synchronized void abort() { aborted = true; } /** - * Checks whether or not a request to abort the current write operation - * has been made successfully. + * Checks whether or not a request to abort the current write operation has + * been made successfully. * - * @return true, if the request to abort the current write operation - * has been made successfully, false otherwise. + * @return true, if the request to abort the current write operation has + * been made successfully, false otherwise. */ protected synchronized boolean abortRequested() { return aborted; } /** - * Clears all previous abort request, and abortRequested returns false - * after calling this method. + * Clears all previous abort request, and abortRequested returns false after + * calling this method. */ protected synchronized void clearAbortRequest() { aborted = false; @@ -320,7 +345,8 @@ public abstract class ImageWriter implements ImageTranscoder { /** * Adds the IIOWriteProgressListener listener. * - * @param listener the IIOWriteProgressListener listener. + * @param listener + * the IIOWriteProgressListener listener. */ public void addIIOWriteProgressListener(IIOWriteProgressListener listener) { if (listener == null) { @@ -337,7 +363,8 @@ public abstract class ImageWriter implements ImageTranscoder { /** * Adds the IIOWriteWarningListener. * - * @param listener the IIOWriteWarningListener listener. + * @param listener + * the IIOWriteWarningListener listener. */ public void addIIOWriteWarningListener(IIOWriteWarningListener listener) { if (listener == null) { @@ -356,8 +383,8 @@ public abstract class ImageWriter implements ImageTranscoder { /** * Gets the output object that was set by setOutput method. * - * @return the output object such as ImageOutputStream, or null if - * it is not set. + * @return the output object such as ImageOutputStream, or null if it is not + * set. */ public Object getOutput() { return output; @@ -366,7 +393,7 @@ public abstract class ImageWriter implements ImageTranscoder { /** * Check output return false. * - * @return true, if successful + * @return true, if successful. */ private final boolean checkOutputReturnFalse() { if (getOutput() == null) { @@ -385,124 +412,122 @@ public abstract class ImageWriter implements ImageTranscoder { throw new UnsupportedOperationException("Unsupported write variant!"); } - /** - * Returns true if a new empty image can be inserted at - * the specified index. + * Returns true if a new empty image can be inserted at the specified index. * - * @param imageIndex the specified index of image. - * - * @return true if a new empty image can be inserted at - * the specified index, false otherwise. - * - * @throws IOException Signals that an I/O exception has occurred. + * @param imageIndex + * the specified index of image. + * @return true if a new empty image can be inserted at the specified index, + * false otherwise. + * @throws IOException + * Signals that an I/O exception has occurred. */ public boolean canInsertEmpty(int imageIndex) throws IOException { return checkOutputReturnFalse(); } /** - * Returns true if a new image can be inserted at the specified index. - * - * @param imageIndex the specified index of image. + * Returns true if a new image can be inserted at the specified index. * - * @return true if a new image can be inserted at the specified index, - * false otherwise. - * - * @throws IOException Signals that an I/O exception has occurred. + * @param imageIndex + * the specified index of image. + * @return true if a new image can be inserted at the specified index, false + * otherwise. + * @throws IOException + * Signals that an I/O exception has occurred. */ public boolean canInsertImage(int imageIndex) throws IOException { return checkOutputReturnFalse(); } /** - * Returnes true if the image with the specified index can be removed. - * - * @param imageIndex the specified index of image. + * Returns true if the image with the specified index can be removed. * - * @return true if the image with the specified index can be removed, - * false otherwise. - * - * @throws IOException Signals that an I/O exception has occurred. + * @param imageIndex + * the specified index of image. + * @return true if the image with the specified index can be removed, false + * otherwise. + * @throws IOException + * Signals that an I/O exception has occurred. */ public boolean canRemoveImage(int imageIndex) throws IOException { return checkOutputReturnFalse(); } /** - * Returns true if metadata of the image with the specified index - * can be replaced. - * - * @param imageIndex the specified image index. + * Returns true if metadata of the image with the specified index can be + * replaced. * - * @return true if metadata of the image with the specified index - * can be replaced, false otherwise. - * - * @throws IOException Signals that an I/O exception has occurred. + * @param imageIndex + * the specified image index. + * @return true if metadata of the image with the specified index can be + * replaced, false otherwise. + * @throws IOException + * if an I/O exception has occurred. */ public boolean canReplaceImageMetadata(int imageIndex) throws IOException { return checkOutputReturnFalse(); } /** - * Returns true if pixels of the image with the specified index - * can be replaced by the replacePixels methods. - * - * @param imageIndex the image's index. + * Returns true if pixels of the image with the specified index can be + * replaced by the replacePixels methods. * - * @return true if pixels of the image with the specified index - * can be replaced by the replacePixels methods, false otherwise. - * - * @throws IOException Signals that an I/O exception has occurred. + * @param imageIndex + * the image's index. + * @return true if pixels of the image with the specified index can be + * replaced by the replacePixels methods, false otherwise. + * @throws IOException + * Signals that an I/O exception has occurred. */ public boolean canReplacePixels(int imageIndex) throws IOException { return checkOutputReturnFalse(); } /** - * Returns true if the stream metadata presented in the output - * can be removed. - * - * @return true if the stream metadata presented in the output - * can be removed, false otherwise. + * Returns true if the stream metadata presented in the output can be + * removed. * - * @throws IOException Signals that an I/O exception has occurred. + * @return true if the stream metadata presented in the output can be + * removed, false otherwise. + * @throws IOException + * if an I/O exception has occurred. */ public boolean canReplaceStreamMetadata() throws IOException { return checkOutputReturnFalse(); } /** - * Returns true if the writing of a complete image stream which - * contains a single image is supported with undefined pixel - * values and associated metadata and thumbnails to the output. - * - * @return true if the writing of a complete image stream which - * contains a single image is supported, false otherwise. + * Returns true if the writing of a complete image stream which contains a + * single image is supported with undefined pixel values and associated + * metadata and thumbnails to the output. * - * @throws IOException Signals that an I/O exception has occurred. + * @return true if the writing of a complete image stream which contains a + * single image is supported, false otherwise. + * @throws IOException + * if an I/O exception has occurred. */ public boolean canWriteEmpty() throws IOException { return checkOutputReturnFalse(); } /** - * Returns true if the methods which taken an IIOImageParameter - * can deal with a Raster source image. + * Returns true if the methods which taken an IIOImageParameter can deal + * with a Raster source image. * - * @return true if the methods which taken an IIOImageParameter - * can deal with a Raster source image, false otherwise. + * @return true if the methods which taken an IIOImageParameter can deal + * with a Raster source image, false otherwise. */ public boolean canWriteRasters() { return false; } /** - * Returns true if the writer can add an image to stream that - * already contains header information. + * Returns true if the writer can add an image to stream that already + * contains header information. * - * @return if the writer can add an image to stream that - * already contains header information, false otherwise. + * @return if the writer can add an image to stream that already contains + * header information, false otherwise. */ public boolean canWriteSequence() { return false; @@ -511,16 +536,18 @@ public abstract class ImageWriter implements ImageTranscoder { /** * Ends the insertion of a new image. * - * @throws IOException Signals that an I/O exception has occurred. + * @throws IOException + * if an I/O exception has occurred. */ public void endInsertEmpty() throws IOException { unsupportedOperation(); } /** - * Ends the repalce pixels operation. + * Ends the replace pixels operation. * - * @throws IOException Signals that an I/O exception has occurred. + * @throws IOException + * if an I/O exception has occurred. */ public void endReplacePixels() throws IOException { unsupportedOperation(); @@ -529,7 +556,8 @@ public abstract class ImageWriter implements ImageTranscoder { /** * Ends an empty write operation. * - * @throws IOException Signals that an I/O exception has occurred. + * @throws IOException + * if an I/O exception has occurred. */ public void endWriteEmpty() throws IOException { unsupportedOperation(); @@ -538,7 +566,8 @@ public abstract class ImageWriter implements ImageTranscoder { /** * Ends the sequence of write operations. * - * @throws IOException Signals that an I/O exception has occurred. + * @throws IOException + * if an I/O exception has occurred. */ public void endWriteSequence() throws IOException { unsupportedOperation(); @@ -558,25 +587,24 @@ public abstract class ImageWriter implements ImageTranscoder { } /** - * Gets an IIOMetadata object that contains default values - * for encoding an image with the specified type. - * - * @param imageType the ImageTypeSpecifier. - * @param param the ImageWriteParam. + * Gets an IIOMetadata object that contains default values for encoding an + * image with the specified type. * + * @param imageType + * the ImageTypeSpecifier. + * @param param + * the ImageWriteParam. * @return the IIOMetadata object. */ - public abstract IIOMetadata getDefaultImageMetadata( - ImageTypeSpecifier imageType, - ImageWriteParam param - ); + public abstract IIOMetadata getDefaultImageMetadata(ImageTypeSpecifier imageType, + ImageWriteParam param); /** - * Gets an IIOMetadata object that contains default values - * for encoding a stream of images. - * - * @param param the ImageWriteParam. + * Gets an IIOMetadata object that contains default values for encoding a + * stream of images. * + * @param param + * the ImageWriteParam. * @return the IIOMetadata object. */ public abstract IIOMetadata getDefaultStreamMetadata(ImageWriteParam param); @@ -591,9 +619,8 @@ public abstract class ImageWriter implements ImageTranscoder { } /** - * Gets the default write param. - * Gets a new ImageWriteParam object for this ImageWriter with the - * current Locale. + * Gets the default write param. Gets a new ImageWriteParam object for this + * ImageWriter with the current Locale. * * @return a new ImageWriteParam object for this ImageWriter. */ @@ -602,124 +629,131 @@ public abstract class ImageWriter implements ImageTranscoder { } /** - * Gets the number of thumbnails suported by the format - * being written with supported image type, image write - * parameters, stream, and image metadata objects. + * Gets the number of thumbnails supported by the format being written with + * supported image type, image write parameters, stream, and image metadata + * objects. * - * @param imageType the ImageTypeSpecifier. - * @param param the image's parameters. - * @param streamMetadata the stream metadata. - * @param imageMetadata the image metadata. - * - * @return the number of thumbnails supported + * @param imageType + * the ImageTypeSpecifier. + * @param param + * the image's parameters. + * @param streamMetadata + * the stream metadata. + * @param imageMetadata + * the image metadata. + * @return the number of thumbnails supported. */ - public int getNumThumbnailsSupported( - ImageTypeSpecifier imageType, - ImageWriteParam param, - IIOMetadata streamMetadata, - IIOMetadata imageMetadata - ) { + public int getNumThumbnailsSupported(ImageTypeSpecifier imageType, ImageWriteParam param, + IIOMetadata streamMetadata, IIOMetadata imageMetadata) { return 0; } /** - * Gets the preferred thumbnail sizes. - * Gets an array of Dimensions with the sizes for thumbnail images - * as they are encoded in the output file or stream. - * - * @param imageType the ImageTypeSpecifier. - * @param param the ImageWriteParam. - * @param streamMetadata the stream metadata. - * @param imageMetadata the image metadata. + * Gets the preferred thumbnail sizes. Gets an array of Dimensions with the + * sizes for thumbnail images as they are encoded in the output file or + * stream. * - * @return the preferred thumbnail sizes + * @param imageType + * the ImageTypeSpecifier. + * @param param + * the ImageWriteParam. + * @param streamMetadata + * the stream metadata. + * @param imageMetadata + * the image metadata. + * @return the preferred thumbnail sizes. */ - public Dimension[] getPreferredThumbnailSizes( - ImageTypeSpecifier imageType, - ImageWriteParam param, - IIOMetadata streamMetadata, - IIOMetadata imageMetadata - ) { + public Dimension[] getPreferredThumbnailSizes(ImageTypeSpecifier imageType, + ImageWriteParam param, IIOMetadata streamMetadata, IIOMetadata imageMetadata) { return null; } /** - * Prepares insertion of an empty image by requesting the insertion of - * a new image into an existing image stream. - * - * @param imageIndex the image index. - * @param imageType the image type. - * @param width the width of the image. - * @param height the height of the image. - * @param imageMetadata the image metadata, or null. - * @param thumbnails the array thumbnails for this image, or null. - * @param param the ImageWriteParam, or null. - * - * @throws IOException Signals that an I/O exception has occurred. - */ - public void prepareInsertEmpty( - int imageIndex, ImageTypeSpecifier imageType, - int width, int height, - IIOMetadata imageMetadata, List thumbnails, - ImageWriteParam param - ) throws IOException { + * Prepares insertion of an empty image by requesting the insertion of a new + * image into an existing image stream. + * + * @param imageIndex + * the image index. + * @param imageType + * the image type. + * @param width + * the width of the image. + * @param height + * the height of the image. + * @param imageMetadata + * the image metadata, or null. + * @param thumbnails + * the array thumbnails for this image, or null. + * @param param + * the ImageWriteParam, or null. + * @throws IOException + * if an I/O exception has occurred. + */ + public void prepareInsertEmpty(int imageIndex, ImageTypeSpecifier imageType, int width, + int height, IIOMetadata imageMetadata, List thumbnails, + ImageWriteParam param) throws IOException { unsupportedOperation(); } /** - * Prepares the writer to call the replacePixels method for the - * specified region. - * - * @param imageIndex the image's index. - * @param region the specified region. + * Prepares the writer to call the replacePixels method for the specified + * region. * - * @throws IOException Signals that an I/O exception has occurred. + * @param imageIndex + * the image's index. + * @param region + * the specified region. + * @throws IOException + * if an I/O exception has occurred. */ public void prepareReplacePixels(int imageIndex, Rectangle region) throws IOException { unsupportedOperation(); } /** - * Prepares the writer for writing an empty image by beginning the - * process of writing a complete image stream that contains a single image - * with undefined pixel values, metadata and thumbnails, - * to the output. - * - * @param streamMetadata the stream metadata. - * @param imageType the image type. - * @param width the width of the image. - * @param height the height of the image. - * @param imageMetadata the image's metadata, or null. - * @param thumbnails the image's thumbnails, or null. - * @param param the image's parameters, or null. - * - * @throws IOException Signals that an I/O exception has occurred. - */ - public void prepareWriteEmpty( - IIOMetadata streamMetadata, ImageTypeSpecifier imageType, - int width, int height, - IIOMetadata imageMetadata, List thumbnails, - ImageWriteParam param - ) throws IOException { + * Prepares the writer for writing an empty image by beginning the process + * of writing a complete image stream that contains a single image with + * undefined pixel values, metadata and thumbnails, to the output. + * + * @param streamMetadata + * the stream metadata. + * @param imageType + * the image type. + * @param width + * the width of the image. + * @param height + * the height of the image. + * @param imageMetadata + * the image's metadata, or null. + * @param thumbnails + * the image's thumbnails, or null. + * @param param + * the image's parameters, or null. + * @throws IOException + * if an I/O exception has occurred. + */ + public void prepareWriteEmpty(IIOMetadata streamMetadata, ImageTypeSpecifier imageType, + int width, int height, IIOMetadata imageMetadata, + List thumbnails, ImageWriteParam param) throws IOException { unsupportedOperation(); } /** - * Prepares a stream to accept calls of writeToSequence method - * using the metadata object. - * - * @param streamMetadata the stream metadata. + * Prepares a stream to accept calls of writeToSequence method using the + * metadata object. * - * @throws IOException Signals that an I/O exception has occurred. + * @param streamMetadata + * the stream metadata. + * @throws IOException + * if an I/O exception has occurred. */ public void prepareWriteSequence(IIOMetadata streamMetadata) throws IOException { unsupportedOperation(); } /** - * Processes the completion of a thumbnail read - * by calling their thumbnailComplete method - * of registered IIOWriteProgressListeners. + * Processes the completion of a thumbnail read by calling their + * thumbnailComplete method of registered IIOWriteProgressListeners. */ protected void processThumbnailComplete() { if (progressListeners != null) { @@ -730,11 +764,11 @@ public abstract class ImageWriter implements ImageTranscoder { } /** - * Processes the current percentage of thumbnail completion - * by calling their thumbnailProgress method of registered - * IIOWriteProgressListeners. + * Processes the current percentage of thumbnail completion by calling their + * thumbnailProgress method of registered IIOWriteProgressListeners. * - * @param percentageDone the percentage done. + * @param percentageDone + * the percentage done. */ protected void processThumbnailProgress(float percentageDone) { if (progressListeners != null) { @@ -745,11 +779,13 @@ public abstract class ImageWriter implements ImageTranscoder { } /** - * Processes the start of a thumbnail read by calling - * thumbnailStarted method of registered IIOWriteProgressListeners. + * Processes the start of a thumbnail read by calling thumbnailStarted + * method of registered IIOWriteProgressListeners. * - * @param imageIndex the image index. - * @param thumbnailIndex the thumbnail index. + * @param imageIndex + * the image index. + * @param thumbnailIndex + * the thumbnail index. */ protected void processThumbnailStarted(int imageIndex, int thumbnailIndex) { if (progressListeners != null) { @@ -760,7 +796,7 @@ public abstract class ImageWriter implements ImageTranscoder { } /** - * Processes that the writing has been aborted by calling writeAborted + * Processes that the writing has been aborted by calling writeAborted * method of registered IIOWriteProgressListeners. */ protected void processWriteAborted() { @@ -789,8 +825,8 @@ public abstract class ImageWriter implements ImageTranscoder { /** * Removes the specified IIOWriteProgressListener listener. * - * @param listener the registered IIOWriteProgressListener - * to be removed. + * @param listener + * the registered IIOWriteProgressListener to be removed. */ public void removeIIOWriteProgressListener(IIOWriteProgressListener listener) { if (progressListeners != null && listener != null) { @@ -803,8 +839,8 @@ public abstract class ImageWriter implements ImageTranscoder { /** * Removes the specified IIOWriteWarningListener listener. * - * @param listener the registered IIOWriteWarningListener listener - * to be removed. + * @param listener + * the registered IIOWriteWarningListener listener to be removed. */ public void removeIIOWriteWarningListener(IIOWriteWarningListener listener) { if (warningListeners == null || listener == null) { @@ -826,9 +862,10 @@ public abstract class ImageWriter implements ImageTranscoder { /** * Removes the image with the specified index from the stream. * - * @param imageIndex the image's index. - * - * @throws IOException Signals that an I/O exception has occurred. + * @param imageIndex + * the image's index. + * @throws IOException + * if an I/O exception has occurred. */ public void removeImage(int imageIndex) throws IOException { unsupportedOperation(); @@ -837,36 +874,42 @@ public abstract class ImageWriter implements ImageTranscoder { /** * Replaces image metadata of the image with specified index. * - * @param imageIndex the image's index. - * @param imageMetadata the image metadata. - * - * @throws IOException Signals that an I/O exception has occurred. + * @param imageIndex + * the image's index. + * @param imageMetadata + * the image metadata. + * @throws IOException + * if an I/O exception has occurred. */ public void replaceImageMetadata(int imageIndex, IIOMetadata imageMetadata) throws IOException { unsupportedOperation(); } /** - * Replaces a part of an image presented in the output - * with the specified RenderedImage. + * Replaces a part of an image presented in the output with the specified + * RenderedImage. * - * @param image the RenderedImage. - * @param param the ImageWriteParam. - * - * @throws IOException Signals that an I/O exception has occurred. + * @param image + * the RenderedImage. + * @param param + * the ImageWriteParam. + * @throws IOException + * if an I/O exception has occurred. */ public void replacePixels(RenderedImage image, ImageWriteParam param) throws IOException { unsupportedOperation(); } /** - * Replaces a part of an image presented in the output - * with the specified Raster. - * - * @param raster the Raster. - * @param param the ImageWriteParam. + * Replaces a part of an image presented in the output with the specified + * Raster. * - * @throws IOException Signals that an I/O exception has occurred. + * @param raster + * the Raster. + * @param param + * the ImageWriteParam. + * @throws IOException + * if an I/O exception has occurred. */ public void replacePixels(Raster raster, ImageWriteParam param) throws IOException { unsupportedOperation(); @@ -875,9 +918,10 @@ public abstract class ImageWriter implements ImageTranscoder { /** * Replaces the stream metadata of the output with new IIOMetadata. * - * @param streamMetadata the new stream metadata. - * - * @throws IOException Signals that an I/O exception has occurred. + * @param streamMetadata + * the new stream metadata. + * @throws IOException + * if an I/O exception has occurred. */ public void replaceStreamMetadata(IIOMetadata streamMetadata) throws IOException { unsupportedOperation(); @@ -886,7 +930,8 @@ public abstract class ImageWriter implements ImageTranscoder { /** * Sets the locale of this ImageWriter. * - * @param locale the new locale. + * @param locale + * the new locale. */ public void setLocale(Locale locale) { if (locale == null) { @@ -924,26 +969,31 @@ public abstract class ImageWriter implements ImageTranscoder { } /** - * Inserts image into existing output stream. - * - * @param imageIndex the image index where an image will be written. - * @param image the specified image to be written. - * @param param the ImageWriteParam, or null. + * Inserts image into existing output stream. * - * @throws IOException Signals that an I/O exception has occurred. + * @param imageIndex + * the image index where an image will be written. + * @param image + * the specified image to be written. + * @param param + * the ImageWriteParam, or null. + * @throws IOException + * if an I/O exception has occurred. */ - public void writeInsert(int imageIndex, IIOImage image, ImageWriteParam param) throws IOException { + public void writeInsert(int imageIndex, IIOImage image, ImageWriteParam param) + throws IOException { unsupportedOperation(); } /** * Writes the specified image to the sequence. * - * @param image the image to be written. - * @param param the ImageWriteParam, or null. - * - * @throws IOException Signals that an I/O exception has occurred - * during writting. + * @param image + * the image to be written. + * @param param + * the ImageWriteParam, or null. + * @throws IOException + * if an I/O exception has occurred during writing. */ public void writeToSequence(IIOImage image, ImageWriteParam param) throws IOException { unsupportedOperation(); diff --git a/awt/javax/imageio/event/IIOReadProgressListener.java b/awt/javax/imageio/event/IIOReadProgressListener.java index 3d658076cf261a070e622f53e8783cefdd60e682..29448963965606cf46d18bbc8ce316434d8453ac 100644 --- a/awt/javax/imageio/event/IIOReadProgressListener.java +++ b/awt/javax/imageio/event/IIOReadProgressListener.java @@ -18,86 +18,104 @@ * @author Sergey I. Salishev * @version $Revision: 1.2 $ */ + package javax.imageio.event; import java.util.EventListener; import javax.imageio.ImageReader; /** - * The IIOReadProgressListener interface notifies callers - * about the progress of the image and thumbnail reading methods. + * The IIOReadProgressListener interface notifies callers about the progress of + * the image and thumbnail reading methods. + * + * @since Android 1.0 */ public interface IIOReadProgressListener extends EventListener { /** - * Notifies this listener that the image reading has been completed. + * Notifies this listener that the image reading has been completed. * - * @param source the ImageReader object which calls this method. + * @param source + * the ImageReader object which calls this method. */ void imageComplete(ImageReader source); - + /** * Notifies this listener about the degree of completion of the read call. * - * @param source the ImageReader object which calls this method. - * @param percentageDone the percentage of decoding done. + * @param source + * the ImageReader object which calls this method. + * @param percentageDone + * the percentage of decoding done. */ void imageProgress(ImageReader source, float percentageDone); - + /** - * Notifies this listener that an image read operation has been started. + * Notifies this listener that an image read operation has been started. * - * @param source the ImageReader object which calls this method. - * @param imageIndex the index of the image in an input file or - * stream to be read. + * @param source + * the ImageReader object which calls this method. + * @param imageIndex + * the index of the image in an input file or stream to be read. */ void imageStarted(ImageReader source, int imageIndex); - + /** * Notifies this listener that a read operation has been aborted. * - * @param source the ImageReader object which calls this method. + * @param source + * the ImageReader object which calls this method. */ void readAborted(ImageReader source); - + /** - * Notifies this listener that a sequence of read operations has been completed. + * Notifies this listener that a sequence of read operations has been + * completed. * - * @param source the ImageReader object which calls this method. + * @param source + * the ImageReader object which calls this method. */ void sequenceComplete(ImageReader source); - + /** - * Notifies this listener that a sequence of read operation has been started. + * Notifies this listener that a sequence of read operation has been + * started. * - * @param source the ImageReader object which calls this method. - * @param minIndex the index of the first image to be read. + * @param source + * the ImageReader object which calls this method. + * @param minIndex + * the index of the first image to be read. */ void sequenceStarted(ImageReader source, int minIndex); - + /** * Notifies that a thumbnail read operation has been completed. * - * @param source the ImageReader object which calls this method. + * @param source + * the ImageReader object which calls this method. */ void thumbnailComplete(ImageReader source); - + /** * Notifies this listener about the degree of completion of the read call. * - * @param source the ImageReader object which calls this method. - * @param percentageDone the percentage of decoding done. + * @param source + * the ImageReader object which calls this method. + * @param percentageDone + * the percentage of decoding done. */ void thumbnailProgress(ImageReader source, float percentageDone); - + /** - * Notifies this listener that a thumbnail reading operation has been started. + * Notifies this listener that a thumbnail reading operation has been + * started. * - * @param source the ImageReader object which calls this method. - * @param imageIndex the index of the image in an input file or - * stream to be read. - * @param thumbnailIndex the index of the thumbnail to be read. + * @param source + * the ImageReader object which calls this method. + * @param imageIndex + * the index of the image in an input file or stream to be read. + * @param thumbnailIndex + * the index of the thumbnail to be read. */ void thumbnailStarted(ImageReader source, int imageIndex, int thumbnailIndex); } - diff --git a/awt/javax/imageio/event/IIOReadUpdateListener.java b/awt/javax/imageio/event/IIOReadUpdateListener.java index ce5e2f1a8b555dc3ab03bb53e0622272f07784da..49bdbcb411f33afe866030de4bcd5c99c77a9803 100644 --- a/awt/javax/imageio/event/IIOReadUpdateListener.java +++ b/awt/javax/imageio/event/IIOReadUpdateListener.java @@ -18,6 +18,7 @@ * @author Sergey I. Salishev * @version $Revision: 1.2 $ */ + package javax.imageio.event; import java.awt.image.BufferedImage; @@ -30,109 +31,152 @@ import javax.imageio.ImageReader; */ /** - * The IIOReadUpdateListener interface provides functionality - * to receive notification of pixel updates during image and thumbnail - * reading operations. + * The IIOReadUpdateListener interface provides functionality to receive + * notification of pixel updates during image and thumbnail reading operations. + * + * @since Android 1.0 */ public interface IIOReadUpdateListener extends EventListener { /** - * Notifies this listener that the specified area of the image has been updated. + * Notifies this listener that the specified area of the image has been + * updated. * - * @param source the ImageReader object which calls this method. - * @param theImage the image to be updated. - * @param minX the minimum X coordinate of the pixels in the updated area. - * @param minY the minimum Y coordinate of the pixels in the updated area. - * @param width the width of updated area. - * @param height the height of updated area. - * @param periodX the horizontal spacing period between updated - * pixels, if it equals 1, there is no space between pixels. - * @param periodY the vertical spacing period between updated - * pixels, if it equals 1, there is no space between pixels. - * @param bands the array of int values indicating the bands being updated. + * @param source + * the ImageReader object which calls this method. + * @param theImage + * the image to be updated. + * @param minX + * the minimum X coordinate of the pixels in the updated area. + * @param minY + * the minimum Y coordinate of the pixels in the updated area. + * @param width + * the width of updated area. + * @param height + * the height of updated area. + * @param periodX + * the horizontal spacing period between updated pixels, if it + * equals 1, there is no space between pixels. + * @param periodY + * the vertical spacing period between updated pixels, if it + * equals 1, there is no space between pixels. + * @param bands + * the array of integer values indicating the bands being + * updated. */ - void imageUpdate(ImageReader source, BufferedImage theImage, int minX, - int minY, int width, int height, int periodX, int periodY, - int[] bands); - + void imageUpdate(ImageReader source, BufferedImage theImage, int minX, int minY, int width, + int height, int periodX, int periodY, int[] bands); + /** - * Notifies this listener that the current read operation has completed a + * Notifies this listener that the current read operation has completed a * progressive pass. * - * @param source the ImageReader object which calls this method. - * @param theImage the image to be updated. + * @param source + * the ImageReader object which calls this method. + * @param theImage + * the image to be updated. */ void passComplete(ImageReader source, BufferedImage theImage); - + /** - * Notifies this listener that the current read operation has begun - * a progressive pass. + * Notifies this listener that the current read operation has begun a + * progressive pass. * - * @param source the ImageReader object which calls this method. - * @param theImage the image to be updated. - * @param pass the numer of the pass. - * @param minPass the index of the first pass that will be decoded. - * @param maxPass the index of the last pass that will be decoded. - * @param minX the minimum X coordinate of the pixels in the updated area. - * @param minY the minimum Y coordinate of the pixels in the updated area. - * @param periodX the horizontal spacing period between updated - * pixels, if it equals 1, there is no space between pixels. - * @param periodY the vertical spacing period between updated - * pixels, if it equals 1, there is no space between pixels. - * @param bands the array of int values indicating the bands being updated. + * @param source + * the ImageReader object which calls this method. + * @param theImage + * the image to be updated. + * @param pass + * the number of the pass. + * @param minPass + * the index of the first pass that will be decoded. + * @param maxPass + * the index of the last pass that will be decoded. + * @param minX + * the minimum X coordinate of the pixels in the updated area. + * @param minY + * the minimum Y coordinate of the pixels in the updated area. + * @param periodX + * the horizontal spacing period between updated pixels, if it + * equals 1, there is no space between pixels. + * @param periodY + * the vertical spacing period between updated pixels, if it + * equals 1, there is no space between pixels. + * @param bands + * the array of integer values indicating the bands being + * updated. */ - void passStarted(ImageReader source, BufferedImage theImage, int pass, - int minPass, int maxPass, int minX, int minY, int periodX, - int periodY, int[] bands); + void passStarted(ImageReader source, BufferedImage theImage, int pass, int minPass, + int maxPass, int minX, int minY, int periodX, int periodY, int[] bands); /** - * Notifies this listener that the current thumbnail read operation has + * Notifies this listener that the current thumbnail read operation has * completed a progressive pass. * - * @param source the ImageReader object which calls this method. - * @param theImage the thumbnail to be updated. + * @param source + * the ImageReader object which calls this method. + * @param theImage + * the thumbnail to be updated. */ void thumbnailPassComplete(ImageReader source, BufferedImage theImage); - + /** - * Notifies this listener that the current thumbnail read operation has + * Notifies this listener that the current thumbnail read operation has * begun a progressive pass. * - * @param source the ImageReader object which calls this method. - * @param theThumbnail the thumbnail to be updated. - * @param pass the numer of the pass. - * @param minPass the index of the first pass that will be decoded. - * @param maxPass the index of the last pass that will be decoded. - * @param minX the minimum X coordinate of the pixels in the updated area. - * @param minY the minimum Y coordinate of the pixels in the updated area. - * @param periodX the horizontal spacing period between updated - * pixels, if it equals 1, there is no space between pixels. - * @param periodY the vertical spacing period between updated - * pixels, if it equals 1, there is no space between pixels. - * @param bands the array of int values indicating the bands being updated. + * @param source + * the ImageReader object which calls this method. + * @param theThumbnail + * the thumbnail to be updated. + * @param pass + * the number of the pass. + * @param minPass + * the index of the first pass that will be decoded. + * @param maxPass + * the index of the last pass that will be decoded. + * @param minX + * the minimum X coordinate of the pixels in the updated area. + * @param minY + * the minimum Y coordinate of the pixels in the updated area. + * @param periodX + * the horizontal spacing period between updated pixels, if it + * equals 1, there is no space between pixels. + * @param periodY + * the vertical spacing period between updated pixels, if it + * equals 1, there is no space between pixels. + * @param bands + * the array of integer values indicating the bands being + * updated. */ - void thumbnailPassStarted(ImageReader source, BufferedImage theThumbnail, - int pass, int minPass, int maxPass, int minX, int minY, - int periodX, int periodY, int[] bands); - + void thumbnailPassStarted(ImageReader source, BufferedImage theThumbnail, int pass, + int minPass, int maxPass, int minX, int minY, int periodX, int periodY, int[] bands); + /** - * Notifies this listener that a specified area of a thumbnail image has been - * updated. + * Notifies this listener that a specified area of a thumbnail image has + * been updated. * - * @param source the ImageReader object which calls this method. - * @param theThumbnail the thumbnail to be updated. - * @param minX the minimum X coordinate of the pixels in the updated area. - * @param minY the minimum Y coordinate of the pixels in the updated area. - * @param width the width of updated area. - * @param height the height of updated area. - * @param periodX the horizontal spacing period between updated - * pixels, if it equals 1, there is no space between pixels. - * @param periodY the vertical spacing period between updated - * pixels, if it equals 1, there is no space between pixels. - * @param bands the array of int values indicating the bands being updated. + * @param source + * the ImageReader object which calls this method. + * @param theThumbnail + * the thumbnail to be updated. + * @param minX + * the minimum X coordinate of the pixels in the updated area. + * @param minY + * the minimum Y coordinate of the pixels in the updated area. + * @param width + * the width of updated area. + * @param height + * the height of updated area. + * @param periodX + * the horizontal spacing period between updated pixels, if it + * equals 1, there is no space between pixels. + * @param periodY + * the vertical spacing period between updated pixels, if it + * equals 1, there is no space between pixels. + * @param bands + * the array of integer values indicating the bands being + * updated. */ - void thumbnailUpdate(ImageReader source, BufferedImage theThumbnail, - int minX, int minY, int width, int height, int periodX, - int periodY, int[] bands); + void thumbnailUpdate(ImageReader source, BufferedImage theThumbnail, int minX, int minY, + int width, int height, int periodX, int periodY, int[] bands); } - diff --git a/awt/javax/imageio/event/IIOReadWarningListener.java b/awt/javax/imageio/event/IIOReadWarningListener.java index 92fa275adbdd95007460c40ebe572bf2e2880b71..318a5df4634895be9023c1c067087c3c389c79d2 100644 --- a/awt/javax/imageio/event/IIOReadWarningListener.java +++ b/awt/javax/imageio/event/IIOReadWarningListener.java @@ -18,6 +18,7 @@ * @author Sergey I. Salishev * @version $Revision: 1.2 $ */ + package javax.imageio.event; import java.util.EventListener; @@ -29,18 +30,20 @@ import javax.imageio.ImageReader; */ /** - * The IIOReadWarningListener provides methods to receive notification - * of warning messages generated by image - * and thumbnail reading methods. + * The IIOReadWarningListener provides methods to receive notification of + * warning messages generated by image and thumbnail reading methods. + * + * @since Android 1.0 */ public interface IIOReadWarningListener extends EventListener { /** - * Notifies this listener about a warning (non-fatal error) during decoding. + * Notifies this listener about a warning (non-fatal error) during decoding. * - * @param source the ImageReader object which calls this method. - * @param warning the string describing the warning. + * @param source + * the ImageReader object which calls this method. + * @param warning + * the string describing the warning. */ public void warningOccurred(ImageReader source, String warning); } - diff --git a/awt/javax/imageio/event/IIOWriteProgressListener.java b/awt/javax/imageio/event/IIOWriteProgressListener.java index 19ae495ab654fe44783b239d32ed32f42743aac4..4a2c595ab2f57946928e6bea5ef9c5bef6f080ce 100644 --- a/awt/javax/imageio/event/IIOWriteProgressListener.java +++ b/awt/javax/imageio/event/IIOWriteProgressListener.java @@ -18,69 +18,84 @@ * @author Rustem V. Rafikov * @version $Revision: 1.3 $ */ + package javax.imageio.event; import javax.imageio.ImageWriter; import java.util.EventListener; /** - * The IIOWriteProgressListener interface provides methods to - * receive notification about the progress of the image and - * thumbnail writing methods. + * The IIOWriteProgressListener interface provides methods to receive + * notification about the progress of the image and thumbnail writing methods. + * + * @since Android 1.0 */ public interface IIOWriteProgressListener extends EventListener { - + /** - * Notifies this listener that an image write operation has been started. + * Notifies this listener that an image write operation has been started. * - * @param source the ImageWriter object which calls this method. - * @param imageIndex the index of the image being written. + * @param source + * the ImageWriter object which calls this method. + * @param imageIndex + * the index of the image being written. */ void imageStarted(ImageWriter source, int imageIndex); - + /** * Notifies this listener about the degree of completion of the write call. * - * @param source the ImageWriter object which calls this method. - * @param percentageDone the percentage of encoding done. + * @param source + * the ImageWriter object which calls this method. + * @param percentageDone + * the percentage of encoding done. */ void imageProgress(ImageWriter source, float percentageDone); - + /** - * Notifies this listener that the image writing has been completed. + * Notifies this listener that the image writing has been completed. * - * @param source the ImageWriter object which calls this method. + * @param source + * the ImageWriter object which calls this method. */ void imageComplete(ImageWriter source); - + /** - * Notifies this listener that a thumbnail write operation has been started. + * Notifies this listener that a thumbnail write operation has been started. * - * @param source the ImageWriter object which calls this method. - * @param imageIndex the index of the image being written. - * @param thumbnailIndex the index of the thumbnail being written. + * @param source + * the ImageWriter object which calls this method. + * @param imageIndex + * the index of the image being written. + * @param thumbnailIndex + * the index of the thumbnail being written. */ void thumbnailStarted(ImageWriter source, int imageIndex, int thumbnailIndex); - + /** * Notifies this listener about the degree of completion of the write call. * - * @param source the ImageWriter object which calls this method. - * @param percentageDone the percentage of encoding done. + * @param source + * the ImageWriter object which calls this method. + * @param percentageDone + * the percentage of encoding done. */ void thumbnailProgress(ImageWriter source, float percentageDone); - + /** - * Notifies this listener that a thumbnail write operation has been completed. + * Notifies this listener that a thumbnail write operation has been + * completed. * - * @param source the ImageWriter object which calls this method. + * @param source + * the ImageWriter object which calls this method. */ void thumbnailComplete(ImageWriter source); - + /** * Notifies this listener that writing operation has been aborted. * - * @param source the ImageWriter object which calls this method. + * @param source + * the ImageWriter object which calls this method. */ void writeAborted(ImageWriter source); } diff --git a/awt/javax/imageio/event/IIOWriteWarningListener.java b/awt/javax/imageio/event/IIOWriteWarningListener.java index f530d256e2b771a827ddf20771316b7601aed92e..8ee41cddd0604b8cc1f83b8664b62f15546ac278 100644 --- a/awt/javax/imageio/event/IIOWriteWarningListener.java +++ b/awt/javax/imageio/event/IIOWriteWarningListener.java @@ -18,23 +18,29 @@ * @author Rustem V. Rafikov * @version $Revision: 1.3 $ */ + package javax.imageio.event; import javax.imageio.ImageWriter; import java.util.EventListener; /** - * The IIOWriteWarningListener provides methods to receive notification - * of warnings generated by image and thumbnail writing methods. + * The IIOWriteWarningListener provides methods to receive notification of + * warnings generated by image and thumbnail writing methods. + * + * @since Android 1.0 */ public interface IIOWriteWarningListener extends EventListener { - + /** - * Notifies this listener about a warning (non-fatal error) during encoding. + * Notifies this listener about a warning (non-fatal error) during encoding. * - * @param source the ImageWriter object which calls this method. - * @param imageIndex the index of the image generating the warning. - * @param warning the string describing the warning. + * @param source + * the ImageWriter object which calls this method. + * @param imageIndex + * the index of the image generating the warning. + * @param warning + * the string describing the warning. */ void warningOccurred(ImageWriter source, int imageIndex, String warning); } diff --git a/awt/javax/imageio/event/package.html b/awt/javax/imageio/event/package.html new file mode 100644 index 0000000000000000000000000000000000000000..c2fe39fae42f30faead7551db8710a180af56f28 --- /dev/null +++ b/awt/javax/imageio/event/package.html @@ -0,0 +1,8 @@ + + +

    + This package provides interfaces to handle events which can be fired during the reading or writing of images. +

    + @since Android 1.0 + + diff --git a/awt/javax/imageio/metadata/IIOInvalidTreeException.java b/awt/javax/imageio/metadata/IIOInvalidTreeException.java index 8690b2bb65a4cefb26ec65ebbd0ef7b581a326ef..ba906577b3766a89584b6cf6795b2e84ddf6cc9a 100644 --- a/awt/javax/imageio/metadata/IIOInvalidTreeException.java +++ b/awt/javax/imageio/metadata/IIOInvalidTreeException.java @@ -21,21 +21,26 @@ import org.w3c.dom.Node; import javax.imageio.IIOException; /** - * The IIOInvalidTreeException provides notification about - * fails of IIOMetadataNodes tree parsing by IIOMetadata object. + * The IIOInvalidTreeException provides notification about fails of + * IIOMetadataNodes tree parsing by IIOMetadata object. + * + * @since Android 1.0 */ public class IIOInvalidTreeException extends IIOException { - - /** The offending node. */ + + /** + * The offending node. + */ protected Node offendingNode = null; /** - * Instantiates an IIOInvalidTreeException with the - * specified detailed message and specified offending - * Node. + * Instantiates an IIOInvalidTreeException with the specified detailed + * message and specified offending Node. * - * @param message the detailed message. - * @param offendingNode the offending node. + * @param message + * the detailed message. + * @param offendingNode + * the offending node. */ public IIOInvalidTreeException(String message, Node offendingNode) { super(message); @@ -43,13 +48,15 @@ public class IIOInvalidTreeException extends IIOException { } /** - * Instantiates a new IIOInvalidTreeException with the - * specified detailed message and specified offending - * Node. + * Instantiates a new IIOInvalidTreeException with the specified detailed + * message and specified offending Node. * - * @param message the detailed message. - * @param cause the cause of this exception. - * @param offendingNode the offending node + * @param message + * the detailed message. + * @param cause + * the cause of this exception. + * @param offendingNode + * the offending node. */ public IIOInvalidTreeException(String message, Throwable cause, Node offendingNode) { super(message, cause); diff --git a/awt/javax/imageio/metadata/IIOMetadata.java b/awt/javax/imageio/metadata/IIOMetadata.java index f2387cc6d2c4a98cf2d09a5a1b0ad17501a3f877..96cebf98d63bfb4481d527307253d3e3dd202b87 100644 --- a/awt/javax/imageio/metadata/IIOMetadata.java +++ b/awt/javax/imageio/metadata/IIOMetadata.java @@ -14,6 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package javax.imageio.metadata; import java.util.ArrayList; @@ -22,73 +23,90 @@ import org.apache.harmony.x.imageio.metadata.IIOMetadataUtils; import org.w3c.dom.Node; /** - * The Class IIOMetadata represents the metadata (bundled with an image) - * as a Dom-type tree. + * The class IIOMetadata represents the metadata (bundled with an image) as a + * Dom-type tree. + * + * @since Android 1.0 */ public abstract class IIOMetadata { - /** Whether the standard metadata format is supported. */ + /** + * Whether the standard metadata format is supported. + */ protected boolean standardFormatSupported; - - /** The native metadata format name. */ + + /** + * The native metadata format name. + */ protected String nativeMetadataFormatName; - - /** The native metadata format class name. */ + + /** + * The native metadata format class name. + */ protected String nativeMetadataFormatClassName; - - /** The extra metadata format names. */ + + /** + * The extra metadata format names. + */ protected String[] extraMetadataFormatNames; - - /** The extra metadata format class names. */ + + /** + * The extra metadata format class names. + */ protected String[] extraMetadataFormatClassNames; - - /** The default controller. */ + + /** + * The default controller. + */ protected IIOMetadataController defaultController; - - /** The controller. */ + + /** + * The controller. + */ protected IIOMetadataController controller; /** * Instantiates a new IIOMetadata with no data set. */ - protected IIOMetadata() {} + protected IIOMetadata() { + } /** * Instantiates a new IIOMetadata with the specified data parameters. * - * @param standardMetadataFormatSupported whether the standard metadata format is supported - * @param nativeMetadataFormatName the native metadata format name - * @param nativeMetadataFormatClassName the native metadata format class name - * @param extraMetadataFormatNames the extra metadata format names - * @param extraMetadataFormatClassNames the extra metadata format class names - */ - protected IIOMetadata(boolean standardMetadataFormatSupported, - String nativeMetadataFormatName, - String nativeMetadataFormatClassName, - String[] extraMetadataFormatNames, - String[] extraMetadataFormatClassNames) { + * @param standardMetadataFormatSupported + * whether the standard metadata format is supported. + * @param nativeMetadataFormatName + * the native metadata format name. + * @param nativeMetadataFormatClassName + * the native metadata format class name. + * @param extraMetadataFormatNames + * the extra metadata format names. + * @param extraMetadataFormatClassNames + * the extra metadata format class names. + */ + protected IIOMetadata(boolean standardMetadataFormatSupported, String nativeMetadataFormatName, + String nativeMetadataFormatClassName, String[] extraMetadataFormatNames, + String[] extraMetadataFormatClassNames) { standardFormatSupported = standardMetadataFormatSupported; this.nativeMetadataFormatName = nativeMetadataFormatName; this.nativeMetadataFormatClassName = nativeMetadataFormatClassName; if (extraMetadataFormatNames == null) { if (extraMetadataFormatClassNames != null) { throw new IllegalArgumentException( - "extraMetadataFormatNames == null && extraMetadataFormatClassNames != null!" - ); + "extraMetadataFormatNames == null && extraMetadataFormatClassNames != null!"); } } else { if (extraMetadataFormatClassNames == null) { throw new IllegalArgumentException( - "extraMetadataFormatNames != null && extraMetadataFormatClassNames == null!" - ); + "extraMetadataFormatNames != null && extraMetadataFormatClassNames == null!"); } if (extraMetadataFormatNames.length == 0) { throw new IllegalArgumentException("extraMetadataFormatNames.length == 0!"); } if (extraMetadataFormatClassNames.length != extraMetadataFormatNames.length) { throw new IllegalArgumentException( - "extraMetadataFormatClassNames.length != extraMetadataFormatNames.length!" - ); + "extraMetadataFormatClassNames.length != extraMetadataFormatNames.length!"); } this.extraMetadataFormatNames = extraMetadataFormatNames.clone(); this.extraMetadataFormatClassNames = extraMetadataFormatClassNames.clone(); @@ -98,30 +116,32 @@ public abstract class IIOMetadata { /** * Gets the metadata as tree-type document. * - * @param formatName the format name - * - * @return the node in tree format + * @param formatName + * the format name. + * @return the node in tree format. */ public abstract Node getAsTree(String formatName); - + /** * Checks if the metadata is read only. * * @return true, if the metadata is read only. */ public abstract boolean isReadOnly(); - + /** * Merges the specified tree with this metadata tree. * - * @param formatName the format of the specified tree - * @param root the root node of the metadata tree - * - * @throws IIOInvalidTreeException if the specified tree - * is incompatible with the this metadata tree. + * @param formatName + * the format of the specified tree. + * @param root + * the root node of the metadata tree. + * @throws IIOInvalidTreeException + * if the specified tree is incompatible with the this metadata + * tree. */ public abstract void mergeTree(String formatName, Node root) throws IIOInvalidTreeException; - + /** * Resets the controller. */ @@ -130,7 +150,7 @@ public abstract class IIOMetadata { /** * Gets the controller associated with this metadata document. * - * @return the controller + * @return the controller. */ public IIOMetadataController getController() { return controller; @@ -139,7 +159,7 @@ public abstract class IIOMetadata { /** * Checks whether this metadata has a controller. * - * @return true, if this metadata has a controller + * @return true, if this metadata has a controller. */ public boolean hasController() { return getController() != null; @@ -148,7 +168,7 @@ public abstract class IIOMetadata { /** * Activate the controller. * - * @return true, if successful + * @return true, if successful. */ public boolean activateController() { if (!hasController()) { @@ -160,7 +180,7 @@ public abstract class IIOMetadata { /** * Gets the default controller. * - * @return the default controller + * @return the default controller. */ public IIOMetadataController getDefaultController() { return defaultController; @@ -169,7 +189,7 @@ public abstract class IIOMetadata { /** * Gets the extra metadata format names. * - * @return the extra metadata format names + * @return the extra metadata format names. */ public String[] getExtraMetadataFormatNames() { return extraMetadataFormatNames == null ? null : extraMetadataFormatNames.clone(); @@ -178,23 +198,20 @@ public abstract class IIOMetadata { /** * Gets the metadata format. * - * @param formatName the format name - * - * @return the metadata format + * @param formatName + * the format name. + * @return the metadata format. */ public IIOMetadataFormat getMetadataFormat(String formatName) { - return IIOMetadataUtils.instantiateMetadataFormat( - formatName, - standardFormatSupported, - nativeMetadataFormatName, nativeMetadataFormatClassName, - extraMetadataFormatNames, extraMetadataFormatClassNames - ); + return IIOMetadataUtils.instantiateMetadataFormat(formatName, standardFormatSupported, + nativeMetadataFormatName, nativeMetadataFormatClassName, extraMetadataFormatNames, + extraMetadataFormatClassNames); } /** * Gets the native metadata format name. * - * @return the native metadata format name + * @return the native metadata format name. */ public String getNativeMetadataFormatName() { return nativeMetadataFormatName; @@ -203,7 +220,7 @@ public abstract class IIOMetadata { /** * Checks if the standard metadata format is supported. * - * @return true, if the standard metadata format is supported + * @return true, if the standard metadata format is supported. */ public boolean isStandardMetadataFormatSupported() { return standardFormatSupported; @@ -212,7 +229,7 @@ public abstract class IIOMetadata { /** * Gets the metadata format names. * - * @return the metadata format names + * @return the metadata format names. */ public String[] getMetadataFormatNames() { ArrayList res = new ArrayList(); @@ -239,7 +256,7 @@ public abstract class IIOMetadata { /** * Gets the standard chroma node. * - * @return the standard chroma node + * @return the standard chroma node. */ protected IIOMetadataNode getStandardChromaNode() { return null; @@ -248,7 +265,7 @@ public abstract class IIOMetadata { /** * Gets the standard compression node. * - * @return the standard compression node + * @return the standard compression node. */ protected IIOMetadataNode getStandardCompressionNode() { return null; @@ -257,7 +274,7 @@ public abstract class IIOMetadata { /** * Gets the standard data node. * - * @return the standard data node + * @return the standard data node. */ protected IIOMetadataNode getStandardDataNode() { return null; @@ -266,7 +283,7 @@ public abstract class IIOMetadata { /** * Gets the standard dimension node. * - * @return the standard dimension node + * @return the standard dimension node. */ protected IIOMetadataNode getStandardDimensionNode() { return null; @@ -275,7 +292,7 @@ public abstract class IIOMetadata { /** * Gets the standard document node. * - * @return the standard document node + * @return the standard document node. */ protected IIOMetadataNode getStandardDocumentNode() { return null; @@ -284,7 +301,7 @@ public abstract class IIOMetadata { /** * Gets the standard text node. * - * @return the standard text node + * @return the standard text node. */ protected IIOMetadataNode getStandardTextNode() { return null; @@ -293,7 +310,7 @@ public abstract class IIOMetadata { /** * Gets the standard tile node. * - * @return the standard tile node + * @return the standard tile node. */ protected IIOMetadataNode getStandardTileNode() { return null; @@ -302,7 +319,7 @@ public abstract class IIOMetadata { /** * Gets the standard transparency node. * - * @return the standard transparency node + * @return the standard transparency node. */ protected IIOMetadataNode getStandardTransparencyNode() { return null; @@ -311,7 +328,7 @@ public abstract class IIOMetadata { /** * Gets the metadata as a tree in standard format. * - * @return the metadata as a tree in standard format + * @return the metadata as a tree in standard format. */ protected final IIOMetadataNode getStandardTree() { // Create root node @@ -342,14 +359,15 @@ public abstract class IIOMetadata { if ((node = getStandardTransparencyNode()) != null) { root.appendChild(node); } - + return root; } /** * Sets the controller. * - * @param controller the new controller + * @param controller + * the new controller. */ public void setController(IIOMetadataController controller) { this.controller = controller; @@ -358,11 +376,13 @@ public abstract class IIOMetadata { /** * Sets the from tree. * - * @param formatName the name of the metatdata format of the from tree - * @param root the root node of the from tree - * - * @throws IIOInvalidTreeException if the tree or its format is not compatible with - * this metadata. + * @param formatName + * the name of the metatdata format of the from tree. + * @param root + * the root node of the from tree. + * @throws IIOInvalidTreeException + * if the tree or its format is not compatible with this + * metadata. */ public void setFromTree(String formatName, Node root) throws IIOInvalidTreeException { reset(); diff --git a/awt/javax/imageio/metadata/IIOMetadataController.java b/awt/javax/imageio/metadata/IIOMetadataController.java index dfd4e5c16951041a3b8ab8b7c898db8d67247d5b..140594830152dc9274f10f230b25807c90c87eb4 100644 --- a/awt/javax/imageio/metadata/IIOMetadataController.java +++ b/awt/javax/imageio/metadata/IIOMetadataController.java @@ -18,6 +18,7 @@ * @author Sergey I. Salishev * @version $Revision: 1.2 $ */ + package javax.imageio.metadata; /* @@ -26,20 +27,20 @@ package javax.imageio.metadata; */ /** - * The IIOMetadataController interface provides a method for - * implementing objects to activate the controller without - * defining how the controller obtains values. + * The IIOMetadataController interface provides a method for implementing + * objects to activate the controller without defining how the controller + * obtains values. + * + * @since Android 1.0 */ public interface IIOMetadataController { /** * Activates a controller. * - * @param metadata the metadata to be modified. - * - * @return true if the IIOMetadata has been modified, - * false otherwise. + * @param metadata + * the metadata to be modified. + * @return true, if the IIOMetadata has been modified, false otherwise. */ public boolean activate(IIOMetadata metadata); } - diff --git a/awt/javax/imageio/metadata/IIOMetadataFormat.java b/awt/javax/imageio/metadata/IIOMetadataFormat.java index 9e246b48c280caa80cfafd418a625d106a5e8d2d..0e7e6979c20800e4841e7b13c0f0641b39b626d0 100644 --- a/awt/javax/imageio/metadata/IIOMetadataFormat.java +++ b/awt/javax/imageio/metadata/IIOMetadataFormat.java @@ -21,327 +21,384 @@ import javax.imageio.ImageTypeSpecifier; import java.util.Locale; /** - * The Interface IIOMetadataFormat is implemented by classes that - * describe the rules and allowed elements for a metadata document - * tree. + * The Interface IIOMetadataFormat is implemented by classes that describe the + * rules and allowed elements for a metadata document tree. + * + * @since Android 1.0 */ public interface IIOMetadataFormat { - /** The CHILD_POLICY_EMPTY. */ + /** + * The CHILD_POLICY_EMPTY. + */ int CHILD_POLICY_EMPTY = 0; - - /** The CHILD_POLICY_ALL. */ + + /** + * The CHILD_POLICY_ALL. + */ int CHILD_POLICY_ALL = 1; - - /** The CHILD_POLICY_SOME. */ + + /** + * The CHILD_POLICY_SOME. + */ int CHILD_POLICY_SOME = 2; - - /** The CHILD_POLICY_CHOICE. */ + + /** + * The CHILD_POLICY_CHOICE. + */ int CHILD_POLICY_CHOICE = 3; - - /** The CHILD_POLICY_SEQUENCE. */ + + /** + * The CHILD_POLICY_SEQUENCE. + */ int CHILD_POLICY_SEQUENCE = 4; - - /** The CHILD_POLICY_REPEAT. */ + + /** + * The CHILD_POLICY_REPEAT. + */ int CHILD_POLICY_REPEAT = 5; - - /** The maximum value for the child policy. */ + + /** + * The maximum value for the child policy. + */ int CHILD_POLICY_MAX = CHILD_POLICY_REPEAT; - /** The DATATYPE_STRING. */ + /** + * The DATATYPE_STRING. + */ int DATATYPE_STRING = 0; - - /** The DATATYPE_BOOLEAN. */ + + /** + * The DATATYPE_BOOLEAN. + */ int DATATYPE_BOOLEAN = 1; - - /** The DATATYPE_INTEGER. */ + + /** + * The DATATYPE_INTEGER. + */ int DATATYPE_INTEGER = 2; - - /** The DATATYPE_FLOAT. */ + + /** + * The DATATYPE_FLOAT. + */ int DATATYPE_FLOAT = 3; - - /** The DATATYPE_DOUBLE. */ + + /** + * The DATATYPE_DOUBLE. + */ int DATATYPE_DOUBLE = 4; - /** The VALUE_NONE. */ + /** + * The VALUE_NONE. + */ int VALUE_NONE = 0; - - /** The VALUE_ARBITRARY. */ + + /** + * The VALUE_ARBITRARY. + */ int VALUE_ARBITRARY = 1; - - /** The VALUE_RANGE. */ + + /** + * The VALUE_RANGE. + */ int VALUE_RANGE = 2; - - /** The VALUE_RANGE_MIN_INCLUSIVE_MASK. */ + + /** + * The VALUE_RANGE_MIN_INCLUSIVE_MASK. + */ int VALUE_RANGE_MIN_INCLUSIVE_MASK = 4; - - /** The VALUE_RANGE_MAX_INCLUSIVE_MASK. */ + + /** + * The VALUE_RANGE_MAX_INCLUSIVE_MASK. + */ int VALUE_RANGE_MAX_INCLUSIVE_MASK = 8; - - /** The VALUE_ENUMERATION. */ + + /** + * The VALUE_ENUMERATION. + */ int VALUE_ENUMERATION = 16; - - /** The VALUE_LIST. */ + + /** + * The VALUE_LIST. + */ int VALUE_LIST = 32; - - /** The VALUE_RANGE_MIN_INCLUSIVE. */ + + /** + * The VALUE_RANGE_MIN_INCLUSIVE. + */ int VALUE_RANGE_MIN_INCLUSIVE = VALUE_RANGE | VALUE_RANGE_MIN_INCLUSIVE_MASK; - - /** The VALUE_RANGE_MAX_INCLUSIVE. */ + + /** + * The VALUE_RANGE_MAX_INCLUSIVE. + */ int VALUE_RANGE_MAX_INCLUSIVE = VALUE_RANGE | VALUE_RANGE_MAX_INCLUSIVE_MASK; - - /** The VALUE_RANGE_MIN_MAX_INCLUSIVE. */ - int VALUE_RANGE_MIN_MAX_INCLUSIVE = - VALUE_RANGE | VALUE_RANGE_MIN_INCLUSIVE_MASK | VALUE_RANGE_MAX_INCLUSIVE_MASK; /** - * Tells whether the specified element is allowed for the specified - * image type. - * - * @param elementName the element name - * @param imageType the image type - * - * @return true, if the specified element is allowed for the specified - * image type + * The VALUE_RANGE_MIN_MAX_INCLUSIVE. + */ + int VALUE_RANGE_MIN_MAX_INCLUSIVE = VALUE_RANGE | VALUE_RANGE_MIN_INCLUSIVE_MASK + | VALUE_RANGE_MAX_INCLUSIVE_MASK; + + /** + * Tells whether the specified element is allowed for the specified image + * type. + * + * @param elementName + * the element name. + * @param imageType + * the image type. + * @return true, if the specified element is allowed for the specified image + * type. */ boolean canNodeAppear(String elementName, ImageTypeSpecifier imageType); /** * Gets data type of the specified attribute of the specified element. * - * @param elementName the element name - * @param attrName the attribute name - * - * @return the attribute's data type + * @param elementName + * the element name. + * @param attrName + * the attribute name. + * @return the attribute's data type. */ int getAttributeDataType(String elementName, String attrName); - + /** - * Gets the default value of the specified attribute of the specified element. - * - * @param elementName the element name - * @param attrName the attribute name - * - * @return the attribute's default value + * Gets the default value of the specified attribute of the specified + * element. + * + * @param elementName + * the element name. + * @param attrName + * the attribute name. + * @return the attribute's default value. */ String getAttributeDefaultValue(String elementName, String attrName); - + /** * Gets the user-friendly description of the attribute. * - * @param elementName the element name - * @param attrName the attribute name - * @param locale the locale giving the desired language for the - * description - * - * @return the attribute description + * @param elementName + * the element name. + * @param attrName + * the attribute name. + * @param locale + * the locale giving the desired language for the description. + * @return the attribute description. */ String getAttributeDescription(String elementName, String attrName, Locale locale); - + /** * Gets the attribute enumerations. * - * @param elementName the element name - * @param attrName the attribute name - * - * @return the attribute enumerations + * @param elementName + * the element name. + * @param attrName + * the attribute name. + * @return the attribute enumerations. */ String[] getAttributeEnumerations(String elementName, String attrName); - + /** * Gets the maximum length of the attribute list. * - * @param elementName the element name - * @param attrName the attribute name - * - * @return the maximum length of the attribute list + * @param elementName + * the element name. + * @param attrName + * the attribute name. + * @return the maximum length of the attribute list. */ int getAttributeListMaxLength(String elementName, String attrName); - + /** * Gets the minimum length of the attribute list. * - * @param elementName the element name - * @param attrName the attribute name - * - * @return the minimum length of the attribute list + * @param elementName + * the element name. + * @param attrName + * the attribute name. + * @return the minimum length of the attribute list. */ int getAttributeListMinLength(String elementName, String attrName); - + /** * Gets the maximum value allowed for the attribute. * - * @param elementName the element name - * @param attrName the attribute name - * - * @return the maximum value allowed for the attribute + * @param elementName + * the element name. + * @param attrName + * the attribute name. + * @return the maximum value allowed for the attribute. */ String getAttributeMaxValue(String elementName, String attrName); - + /** * Gets the minimum value allowed for the attribute. * - * @param elementName the element name - * @param attrName the attribute name - * - * @return the minimum value allowed for the attribute + * @param elementName + * the element name. + * @param attrName + * the attribute name. + * @return the minimum value allowed for the attribute. */ String getAttributeMinValue(String elementName, String attrName); - + /** * Gets the attribute names allowed for the specified element. * - * @param elementName the element name - * - * @return the attribute names + * @param elementName + * the element name. + * @return the attribute names. */ String[] getAttributeNames(String elementName); - + /** * Gets the attribute value type. * - * @param elementName the element name - * @param attrName the attribute name - * - * @return the attribute value type + * @param elementName + * the element name. + * @param attrName + * the attribute name. + * @return the attribute value type. */ int getAttributeValueType(String elementName, String attrName); - + /** - * Checks whether the specified attribute is required - * for the specified element. - * - * @param elementName the element name - * @param attrName the attribute name - * - * @return true, if the specified attribute is required for the - * specified element + * Checks whether the specified attribute is required for the specified + * element. + * + * @param elementName + * the element name. + * @param attrName + * the attribute name. + * @return true, if the specified attribute is required for the specified + * element. */ boolean isAttributeRequired(String elementName, String attrName); /** * Gets the names of the possible child elements for the given element. * - * @param elementName the element name - * - * @return the child names + * @param elementName + * the element name. + * @return the child names. */ String[] getChildNames(String elementName); - + /** * Gets the constant describing the element's child policy. * - * @param elementName the element name - * - * @return the child policy + * @param elementName + * the element name. + * @return the child policy. */ int getChildPolicy(String elementName); /** * Gets the user-friendly description of the element. * - * @param elementName the element name - * @param locale the locale giving the desired language for the - * description - * - * @return the element description + * @param elementName + * the element name. + * @param locale + * the locale giving the desired language for the description. + * @return the element description. */ String getElementDescription(String elementName, Locale locale); - + /** * Gets the maximum number of children allowed for the element. * - * @param elementName the element name - * - * @return the maximum number of children allowed for the element + * @param elementName + * the element name. + * @return the maximum number of children allowed for the element. */ int getElementMaxChildren(String elementName); - + /** * Gets the minimum number of children allowed for the element. * - * @param elementName the element name - * - * @return the minimum number of children allowed for the element + * @param elementName + * the element name. + * @return the minimum number of children allowed for the element. */ int getElementMinChildren(String elementName); /** * Gets the maximum object array length allowed for the element. * - * @param elementName the element name - * - * @return the maximum object array length allowed for the element + * @param elementName + * the element name. + * @return the maximum object array length allowed for the element. */ int getObjectArrayMaxLength(String elementName); - + /** * Gets the minimum object array length allowed for the element. * - * @param elementName the element name - * - * @return the minimum object array length allowed for the element + * @param elementName + * the element name. + * @return the minimum object array length allowed for the element. */ int getObjectArrayMinLength(String elementName); - + /** * Gets the object class corresponding to the specified element. * - * @param elementName the element name - * - * @return the object class corresponding to the specified element + * @param elementName + * the element name. + * @return the object class corresponding to the specified element. */ Class getObjectClass(String elementName); - + /** * Gets the object default value for the element. * - * @param elementName the element name - * - * @return the object default value for the element + * @param elementName + * the element name. + * @return the object default value for the element. */ Object getObjectDefaultValue(String elementName); - + /** * Gets the object enumerations. * - * @param elementName the element name - * - * @return the object enumerations + * @param elementName + * the element name. + * @return the object enumerations. */ Object[] getObjectEnumerations(String elementName); - + /** * Gets the maximum value allowed for the element's object. * - * @param elementName the element name - * - * @return the maximum value allowed for the element's object + * @param elementName + * the element name. + * @return the maximum value allowed for the element's object. */ Comparable getObjectMaxValue(String elementName); - + /** * Gets the minimum value allowed for the element's object. * - * @param elementName the element name - * - * @return the minimum value allowed for the element's object + * @param elementName + * the element name. + * @return the minimum value allowed for the element's object. */ Comparable getObjectMinValue(String elementName); - + /** * Gets the constant that indicates the type of the element's value. * - * @param elementName the element name - * - * @return the constant that indicates the type of the element's value + * @param elementName + * the element name. + * @return the constant that indicates the type of the element's value. */ int getObjectValueType(String elementName); /** * Gets the name of the root element. * - * @return the name of the root element + * @return the name of the root element. */ String getRootName(); } diff --git a/awt/javax/imageio/metadata/IIOMetadataFormatImpl.java b/awt/javax/imageio/metadata/IIOMetadataFormatImpl.java index 438ae909560f2ab5ddee8ec20b3bcf990f341c67..1a6e5685386a2658af9fefc94e5d1b145f1a2827 100644 --- a/awt/javax/imageio/metadata/IIOMetadataFormatImpl.java +++ b/awt/javax/imageio/metadata/IIOMetadataFormatImpl.java @@ -23,45 +23,60 @@ import java.security.AccessController; import java.security.PrivilegedAction; /** - * The IIOMetadataFormatImpl class provides an implementation of the + * The IIOMetadataFormatImpl class provides an implementation of the * IIOMetadataFormat interface. + * + * @since Android 1.0 */ public abstract class IIOMetadataFormatImpl implements IIOMetadataFormat { - - /** The Constant standardMetadataFormatName. */ - @SuppressWarnings({"ConstantDeclaredInAbstractClass"}) + + /** + * The Constant standardMetadataFormatName. + */ + @SuppressWarnings( { + "ConstantDeclaredInAbstractClass" + }) public static final String standardMetadataFormatName = "javax_imageio_1.0"; - /** The standard format. */ - @SuppressWarnings({"StaticNonFinalField"}) + /** + * The standard format. + */ + @SuppressWarnings( { + "StaticNonFinalField" + }) private static IIOMetadataFormatImpl standardFormat; - /** The root name. */ + /** + * The root name. + */ private String rootName; - - /** The element hash. */ + + /** + * The element hash. + */ private HashMap elementHash = new HashMap(); - /** The resource base name. */ + /** + * The resource base name. + */ private String resourceBaseName = getClass().getName() + "Resources"; /** - * Instantiates an IIOMetadataFormatImpl with the specified root - * name and child policy (not CHILD_POLICY_REPEAT). + * Instantiates an IIOMetadataFormatImpl with the specified root name and + * child policy (not CHILD_POLICY_REPEAT). * - * @param rootName the name of root element. - * @param childPolicy the child policy defined by one of the - * CHILD_POLICY_* constants (except CHILD_POLICY_REPEAT). + * @param rootName + * the name of root element. + * @param childPolicy + * the child policy defined by one of the CHILD_POLICY_* + * constants (except CHILD_POLICY_REPEAT). */ public IIOMetadataFormatImpl(String rootName, int childPolicy) { if (rootName == null) { throw new IllegalArgumentException("rootName is null"); } - if ( - childPolicy < CHILD_POLICY_EMPTY || - childPolicy > CHILD_POLICY_MAX || - childPolicy == CHILD_POLICY_REPEAT - ) { + if (childPolicy < CHILD_POLICY_EMPTY || childPolicy > CHILD_POLICY_MAX + || childPolicy == CHILD_POLICY_REPEAT) { throw new IllegalArgumentException("childPolicy is not one of the predefined constants"); } @@ -73,12 +88,15 @@ public abstract class IIOMetadataFormatImpl implements IIOMetadataFormat { } /** - * Instantiates an IIOMetadataFormatImpl with the specified root - * name and CHILD_POLICY_REPEAT child policy. + * Instantiates an IIOMetadataFormatImpl with the specified root name and + * CHILD_POLICY_REPEAT child policy. * - * @param rootName the name of root element. - * @param minChildren the minimum number of children. - * @param maxChildren the maximum number of children + * @param rootName + * the name of root element. + * @param minChildren + * the minimum number of children. + * @param maxChildren + * the maximum number of children */ public IIOMetadataFormatImpl(String rootName, int minChildren, int maxChildren) { if (rootName == null) { @@ -100,25 +118,31 @@ public abstract class IIOMetadataFormatImpl implements IIOMetadataFormat { elementHash.put(rootName, root); } - @SuppressWarnings({"AbstractMethodOverridesAbstractMethod"}) + @SuppressWarnings( { + "AbstractMethodOverridesAbstractMethod" + }) public abstract boolean canNodeAppear(String elementName, ImageTypeSpecifier imageType); /** * Adds a new attribute to an existing element. * - * @param elementName the name of the element to which the new attribute - * will be added. - * @param attrName the attribute name. - * @param dataType the data type of the new attribute. - * @param required the flag which indicates whether this attribute - * must be present. - * @param listMinLength the minimum legal number of list items. - * @param listMaxLength the the maximum legal number of list items. - */ - protected void addAttribute( - String elementName, String attrName, int dataType, - boolean required, int listMinLength, int listMaxLength - ) { + * @param elementName + * the name of the element to which the new attribute will be + * added. + * @param attrName + * the attribute name. + * @param dataType + * the data type of the new attribute. + * @param required + * the flag which indicates whether this attribute must be + * present. + * @param listMinLength + * the minimum legal number of list items. + * @param listMaxLength + * the the maximum legal number of list items. + */ + protected void addAttribute(String elementName, String attrName, int dataType, + boolean required, int listMinLength, int listMaxLength) { if (attrName == null) { throw new IllegalArgumentException("attrName == null!"); } @@ -144,18 +168,21 @@ public abstract class IIOMetadataFormatImpl implements IIOMetadataFormat { /** * Adds a new attribute to an existing element. * - * @param elementName the name of the element to which the new attribute - * will be added. - * @param attrName the attribute name. - * @param dataType the data type of the new attribute. - * @param required the flag which indicates whether this attribute - * must be present. - * @param defaultValue the default value of the attribute. - */ - protected void addAttribute( - String elementName, String attrName, int dataType, - boolean required, String defaultValue - ) { + * @param elementName + * the name of the element to which the new attribute will be + * added. + * @param attrName + * the attribute name. + * @param dataType + * the data type of the new attribute. + * @param required + * the flag which indicates whether this attribute must be + * present. + * @param defaultValue + * the default value of the attribute. + */ + protected void addAttribute(String elementName, String attrName, int dataType, + boolean required, String defaultValue) { if (attrName == null) { throw new IllegalArgumentException("attrName == null!"); } @@ -177,20 +204,23 @@ public abstract class IIOMetadataFormatImpl implements IIOMetadataFormat { /** * Adds a new attribute to an existing element. * - * @param elementName the name of the element to which the new attribute - * will be added. - * @param attrName the attribute name. - * @param dataType the data type of the new attribute. - * @param required the flag which indicates whether this attribute - * must be present. - * @param defaultValue the default value of the attribute. - * @param enumeratedValues the legal values for the attribute as - * a list of strings. - */ - protected void addAttribute( - String elementName, String attrName, int dataType, - boolean required, String defaultValue, List enumeratedValues - ) { + * @param elementName + * the name of the element to which the new attribute will be + * added. + * @param attrName + * the attribute name. + * @param dataType + * the data type of the new attribute. + * @param required + * the flag which indicates whether this attribute must be + * present. + * @param defaultValue + * the default value of the attribute. + * @param enumeratedValues + * the legal values for the attribute as a list of strings. + */ + protected void addAttribute(String elementName, String attrName, int dataType, + boolean required, String defaultValue, List enumeratedValues) { if (attrName == null) { throw new IllegalArgumentException("attrName == null!"); } @@ -226,26 +256,30 @@ public abstract class IIOMetadataFormatImpl implements IIOMetadataFormat { /** * Adds a new attribute to an existing element. * - * @param elementName the name of the element to which the new attribute - * will be added. - * @param attrName the attribute name. - * @param dataType the data type of the new attribute. - * @param required the flag which indicates whether this attribute - * must be present. - * @param defaultValue the default value of attribute. - * @param minValue the minimum legal value of an attribute. - * @param maxValue the maximum legal value of an attribute. - * @param minInclusive the flag which indicates - * whether the minValue is inclusive. - * @param maxInclusive the flag which indicates - * whether the maxValue is inclusive. - */ - protected void addAttribute( - String elementName, String attrName, int dataType, - boolean required, String defaultValue, - String minValue, String maxValue, - boolean minInclusive, boolean maxInclusive - ) { + * @param elementName + * the name of the element to which the new attribute will be + * added. + * @param attrName + * the attribute name. + * @param dataType + * the data type of the new attribute. + * @param required + * the flag which indicates whether this attribute must be + * present. + * @param defaultValue + * the default value of attribute. + * @param minValue + * the minimum legal value of an attribute. + * @param maxValue + * the maximum legal value of an attribute. + * @param minInclusive + * the flag which indicates whether the minValue is inclusive. + * @param maxInclusive + * the flag which indicates whether the maxValue is inclusive. + */ + protected void addAttribute(String elementName, String attrName, int dataType, + boolean required, String defaultValue, String minValue, String maxValue, + boolean minInclusive, boolean maxInclusive) { if (attrName == null) { throw new IllegalArgumentException("attrName == null!"); } @@ -272,20 +306,21 @@ public abstract class IIOMetadataFormatImpl implements IIOMetadataFormat { } /** - * Adds a new attribute with boolean data type to an existing - * element. + * Adds a new attribute with boolean data type to an existing element. * - * @param elementName the name of the element to which the new attribute - * will be added. - * @param attrName the attribute name. - * @param hasDefaultValue the flag which indicates whether this attribute - * must have a default value. - * @param defaultValue the default value. - */ - protected void addBooleanAttribute( - String elementName, String attrName, - boolean hasDefaultValue, boolean defaultValue - ) { + * @param elementName + * the name of the element to which the new attribute will be + * added. + * @param attrName + * the attribute name. + * @param hasDefaultValue + * the flag which indicates whether this attribute must have a + * default value. + * @param defaultValue + * the default value. + */ + protected void addBooleanAttribute(String elementName, String attrName, + boolean hasDefaultValue, boolean defaultValue) { String defaultVal = hasDefaultValue ? (defaultValue ? "TRUE" : "FALSE") : null; ArrayList values = new ArrayList(2); values.add("TRUE"); @@ -295,11 +330,13 @@ public abstract class IIOMetadataFormatImpl implements IIOMetadataFormat { } /** - * Adds an existing element to the list of child elements - * of the specified parent element. + * Adds an existing element to the list of child elements of the specified + * parent element. * - * @param elementName the name of the element to be added. - * @param parentName the parent element name. + * @param elementName + * the name of the element to be added. + * @param parentName + * the parent element name. */ protected void addChildElement(String elementName, String parentName) { Element parent = findElement(parentName); @@ -308,23 +345,23 @@ public abstract class IIOMetadataFormatImpl implements IIOMetadataFormat { } /** - * Adds a new element type to this IIOMetadataFormat with - * a child policy (if policy is not CHILD_POLICY_REPEAT). + * Adds a new element type to this IIOMetadataFormat with a child policy (if + * policy is not CHILD_POLICY_REPEAT). * - * @param elementName the name of the element to be added. - * @param parentName the parent element name. - * @param childPolicy one of the CHILD_POLICY_* constants defined - * by IIOMetadataFormat. + * @param elementName + * the name of the element to be added. + * @param parentName + * the parent element name. + * @param childPolicy + * one of the CHILD_POLICY_* constants defined by + * IIOMetadataFormat. */ protected void addElement(String elementName, String parentName, int childPolicy) { - if ( - childPolicy < CHILD_POLICY_EMPTY || - childPolicy > CHILD_POLICY_MAX || - childPolicy == CHILD_POLICY_REPEAT - ) { + if (childPolicy < CHILD_POLICY_EMPTY || childPolicy > CHILD_POLICY_MAX + || childPolicy == CHILD_POLICY_REPEAT) { throw new IllegalArgumentException("childPolicy is not one of the predefined constants"); } - + Element parent = findElement(parentName); Element element = new Element(); element.name = elementName; @@ -334,19 +371,21 @@ public abstract class IIOMetadataFormatImpl implements IIOMetadataFormat { } /** - * Adds a new element type to this IIOMetadataFormat with - * CHILD_POLICY_REPEAT and the specified minimum and maximum - * number of child elements. + * Adds a new element type to this IIOMetadataFormat with + * CHILD_POLICY_REPEAT and the specified minimum and maximum number of child + * elements. * - * @param elementName the element name to be added. - * @param parentName the parent element name. - * @param minChildren the minimum number of child elements. - * @param maxChildren the maximum number of child elements. - */ - protected void addElement( - String elementName, String parentName, - int minChildren, int maxChildren - ) { + * @param elementName + * the element name to be added. + * @param parentName + * the parent element name. + * @param minChildren + * the minimum number of child elements. + * @param maxChildren + * the maximum number of child elements. + */ + protected void addElement(String elementName, String parentName, int minChildren, + int maxChildren) { if (minChildren < 0) { throw new IllegalArgumentException("minChildren < 0!"); } @@ -365,19 +404,20 @@ public abstract class IIOMetadataFormatImpl implements IIOMetadataFormat { } /** - * Adds an Object reference with the specified class type to be - * stored as element's value. + * Adds an Object reference with the specified class type to be stored as + * element's value. * - * @param elementName the element name. - * @param classType the class indicates the legal types for - * the object's value. - * @param arrayMinLength the minimum legal length for the array. - * @param arrayMaxLength the maximum legal length for the array. - */ - protected void addObjectValue( - String elementName, Class classType, - int arrayMinLength, int arrayMaxLength - ) { + * @param elementName + * the element name. + * @param classType + * the class indicates the legal types for the object's value. + * @param arrayMinLength + * the minimum legal length for the array. + * @param arrayMaxLength + * the maximum legal length for the array. + */ + protected void addObjectValue(String elementName, Class classType, int arrayMinLength, + int arrayMaxLength) { Element element = findElement(elementName); ObjectValue objVal = new ObjectValue(); @@ -390,20 +430,20 @@ public abstract class IIOMetadataFormatImpl implements IIOMetadataFormat { } /** - * Adds an Object reference with the specified class type to be - * stored as an element's value. + * Adds an Object reference with the specified class type to be stored as an + * element's value. * - * @param elementName the element name. - * @param classType the class indicates the legal types for - * the object's value. - * @param required a flag indicated that this object value - * must be present. - * @param defaultValue the default value, or null. - */ - protected void addObjectValue( - String elementName, Class classType, - boolean required, T defaultValue - ) { + * @param elementName + * the element name. + * @param classType + * the class indicates the legal types for the object's value. + * @param required + * a flag indicated that this object value must be present. + * @param defaultValue + * the default value, or null. + */ + protected void addObjectValue(String elementName, Class classType, boolean required, + T defaultValue) { // note: reqired is an unused parameter Element element = findElement(elementName); @@ -416,22 +456,22 @@ public abstract class IIOMetadataFormatImpl implements IIOMetadataFormat { } /** - * Adds an Object reference with the specified class type to be - * stored as the element's value. + * Adds an Object reference with the specified class type to be stored as + * the element's value. * - * @param elementName the element name. - * @param classType the class indicates the legal types for - * the object value. - * @param required a flag indicated that this object value - * must be present. - * @param defaultValue the default value, or null. - * @param enumeratedValues the list of legal values for the object. - */ - protected void addObjectValue( - String elementName, Class classType, - boolean required, T defaultValue, - List enumeratedValues - ) { + * @param elementName + * the element name. + * @param classType + * the class indicates the legal types for the object value. + * @param required + * a flag indicated that this object value must be present. + * @param defaultValue + * the default value, or null. + * @param enumeratedValues + * the list of legal values for the object. + */ + protected void addObjectValue(String elementName, Class classType, boolean required, + T defaultValue, List enumeratedValues) { // note: reqired is an unused parameter if (enumeratedValues == null || enumeratedValues.isEmpty()) { throw new IllegalArgumentException("enumeratedValues is empty or null"); @@ -444,7 +484,8 @@ public abstract class IIOMetadataFormatImpl implements IIOMetadataFormat { } } } catch (ClassCastException e) { - throw new IllegalArgumentException("enumeratedValues contains a value not of class classType!"); + throw new IllegalArgumentException( + "enumeratedValues contains a value not of class classType!"); } Element element = findElement(elementName); @@ -459,25 +500,27 @@ public abstract class IIOMetadataFormatImpl implements IIOMetadataFormat { } /** - * Adds an Object reference with the specified class type to be - * stored as the element's value. + * Adds an Object reference with the specified class type to be stored as + * the element's value. * - * @param elementName the element name. - * @param classType the class indicates the legal types for - * the object value. - * @param defaultValue the default value, or null. - * @param minValue the minimum legal value for the object value. - * @param maxValue the maximum legal value for the object value. - * @param minInclusive the flag which indicates - * whether the minValue is inclusive. - * @param maxInclusive the flag which indicates - * whether the maxValue is inclusive. - */ - protected > void addObjectValue( - String elementName, Class classType, - T defaultValue, Comparable minValue, Comparable maxValue, - boolean minInclusive, boolean maxInclusive - ) { + * @param elementName + * the element name. + * @param classType + * the class indicates the legal types for the object value. + * @param defaultValue + * the default value, or null. + * @param minValue + * the minimum legal value for the object value. + * @param maxValue + * the maximum legal value for the object value. + * @param minInclusive + * the flag which indicates whether the minValue is inclusive. + * @param maxInclusive + * the flag which indicates whether the maxValue is inclusive. + */ + protected > void addObjectValue(String elementName, + Class classType, T defaultValue, Comparable minValue, + Comparable maxValue, boolean minInclusive, boolean maxInclusive) { Element element = findElement(elementName); ObjectValue objVal = new ObjectValue(); @@ -540,7 +583,7 @@ public abstract class IIOMetadataFormatImpl implements IIOMetadataFormat { if ((attr.valueType & VALUE_RANGE) == 0) { throw new IllegalArgumentException("Attribute is not a range!"); } - return attr.maxValue; + return attr.maxValue; } public String getAttributeMinValue(String elementName, String attrName) { @@ -558,12 +601,13 @@ public abstract class IIOMetadataFormatImpl implements IIOMetadataFormat { public int getAttributeValueType(String elementName, String attrName) { Attlist attr = findAttribute(elementName, attrName); - return attr.valueType; + return attr.valueType; } public String[] getChildNames(String elementName) { Element element = findElement(elementName); - if (element.childPolicy == CHILD_POLICY_EMPTY) { // Element cannot have children + if (element.childPolicy == CHILD_POLICY_EMPTY) { // Element cannot have + // children return null; } return element.children.toArray(new String[element.children.size()]); @@ -689,10 +733,12 @@ public abstract class IIOMetadataFormatImpl implements IIOMetadataFormat { } /** - * Removes the specified attribute from the specified element. - * - * @param elementName the specified element name. - * @param attrName the specified attribute name. + * Removes the specified attribute from the specified element. + * + * @param elementName + * the specified element name. + * @param attrName + * the specified attribute name. */ protected void removeAttribute(String elementName, String attrName) { Element element = findElement(elementName); @@ -702,7 +748,8 @@ public abstract class IIOMetadataFormatImpl implements IIOMetadataFormat { /** * Removes the specified element from this format. * - * @param elementName the specified element name. + * @param elementName + * the specified element name. */ protected void removeElement(String elementName) { Element element; @@ -717,18 +764,20 @@ public abstract class IIOMetadataFormatImpl implements IIOMetadataFormat { /** * Removes the object value from the specified element. * - * @param elementName the element name. + * @param elementName + * the element name. */ protected void removeObjectValue(String elementName) { Element element = findElement(elementName); element.objectValue = null; } - + /** - * Sets a new base name for ResourceBundles containing - * descriptions of elements and attributes for this format. + * Sets a new base name for ResourceBundles containing descriptions of + * elements and attributes for this format. * - * @param resourceBaseName the new resource base name. + * @param resourceBaseName + * the new resource base name. */ protected void setResourceBaseName(String resourceBaseName) { if (resourceBaseName == null) { @@ -740,117 +789,181 @@ public abstract class IIOMetadataFormatImpl implements IIOMetadataFormat { /** * The Class Element. */ - @SuppressWarnings({"ClassWithoutConstructor"}) + @SuppressWarnings( { + "ClassWithoutConstructor" + }) private class Element { - - /** The name. */ + + /** + * The name. + */ String name; - /** The children. */ + /** + * The children. + */ ArrayList children = new ArrayList(); - - /** The attributes. */ + + /** + * The attributes. + */ HashMap attributes = new HashMap(); - /** The min children. */ + /** + * The min children. + */ int minChildren; - - /** The max children. */ + + /** + * The max children. + */ int maxChildren; - - /** The child policy. */ + + /** + * The child policy. + */ int childPolicy; - /** The object value. */ + /** + * The object value. + */ ObjectValue objectValue; } /** * The Class Attlist. */ - @SuppressWarnings({"ClassWithoutConstructor"}) + @SuppressWarnings( { + "ClassWithoutConstructor" + }) private class Attlist { - - /** The name. */ + + /** + * The name. + */ String name; - /** The data type. */ + /** + * The data type. + */ int dataType; - - /** The required. */ + + /** + * The required. + */ boolean required; - - /** The list min length. */ + + /** + * The list min length. + */ int listMinLength; - - /** The list max length. */ + + /** + * The list max length. + */ int listMaxLength; - - /** The default value. */ + + /** + * The default value. + */ String defaultValue; - - /** The enumerated values. */ + + /** + * The enumerated values. + */ List enumeratedValues; - - /** The min value. */ + + /** + * The min value. + */ String minValue; - - /** The max value. */ + + /** + * The max value. + */ String maxValue; - - /** The min inclusive. */ + + /** + * The min inclusive. + */ boolean minInclusive; - - /** The max inclusive. */ + + /** + * The max inclusive. + */ boolean maxInclusive; - /** The value type. */ + /** + * The value type. + */ int valueType; } /** * The Class ObjectValue. */ - @SuppressWarnings({"ClassWithoutConstructor"}) + @SuppressWarnings( { + "ClassWithoutConstructor" + }) private class ObjectValue { - - /** The class type. */ + + /** + * The class type. + */ Class classType; - - /** The array min length. */ + + /** + * The array min length. + */ int arrayMinLength; - - /** The array max length. */ + + /** + * The array max length. + */ int arrayMaxLength; - - /** The default value. */ + + /** + * The default value. + */ T defaultValue; - - /** The enumerated values. */ + + /** + * The enumerated values. + */ List enumeratedValues; - - /** The min value. */ + + /** + * The min value. + */ Comparable minValue; - - /** The max value. */ + + /** + * The max value. + */ Comparable maxValue; - - /** The min inclusive. */ + + /** + * The min inclusive. + */ boolean minInclusive; - - /** The max inclusive. */ + + /** + * The max inclusive. + */ boolean maxInclusive; - /** The value type. */ + /** + * The value type. + */ int valueType; } /** * Find element. * - * @param name the name - * - * @return the element + * @param name + * the name. + * @return the element. */ private Element findElement(String name) { Element element; @@ -864,16 +977,18 @@ public abstract class IIOMetadataFormatImpl implements IIOMetadataFormat { /** * Find attribute. * - * @param elementName the element name - * @param attributeName the attribute name - * - * @return the attlist + * @param elementName + * the element name. + * @param attributeName + * the attribute name. + * @return the attlist. */ private Attlist findAttribute(String elementName, String attributeName) { Element element = findElement(elementName); Attlist attribute; if ((attribute = element.attributes.get(attributeName)) == null) { - throw new IllegalArgumentException("attribute name is null or no such attribute: " + attributeName); + throw new IllegalArgumentException("attribute name is null or no such attribute: " + + attributeName); } return attribute; @@ -882,9 +997,9 @@ public abstract class IIOMetadataFormatImpl implements IIOMetadataFormat { /** * Find object value. * - * @param elementName the element name - * - * @return the object value + * @param elementName + * the element name. + * @return the object value. */ private ObjectValue findObjectValue(String elementName) { Element element = findElement(elementName); @@ -898,23 +1013,25 @@ public abstract class IIOMetadataFormatImpl implements IIOMetadataFormat { /** * Gets the resource string. * - * @param key the key - * @param locale the locale - * - * @return the resource string + * @param key + * the key. + * @param locale + * the locale. + * @return the resource string. */ private String getResourceString(String key, Locale locale) { if (locale == null) { locale = Locale.getDefault(); } - // Get the context class loader and try to locate the bundle with it first - ClassLoader contextClassloader = AccessController.doPrivileged( - new PrivilegedAction() { + // Get the context class loader and try to locate the bundle with it + // first + ClassLoader contextClassloader = AccessController + .doPrivileged(new PrivilegedAction() { public ClassLoader run() { return Thread.currentThread().getContextClassLoader(); } - }); + }); // Now try to get the resource bundle ResourceBundle rb; diff --git a/awt/javax/imageio/metadata/IIOMetadataNode.java b/awt/javax/imageio/metadata/IIOMetadataNode.java index d5ab7a52b41f0ac95d971217660682896def5c65..adc6d67b62b2dd3304d099d5e9708812130c4b4f 100644 --- a/awt/javax/imageio/metadata/IIOMetadataNode.java +++ b/awt/javax/imageio/metadata/IIOMetadataNode.java @@ -27,47 +27,71 @@ import org.w3c.dom.Element; import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; import org.w3c.dom.NodeList; + //???AWT //import org.w3c.dom.TypeInfo; //import org.w3c.dom.UserDataHandler; /** - * The Class IIOMetadataNode represents a node of the - * (DOM-style) metadata tree. + * The Class IIOMetadataNode represents a node of the (DOM-style) metadata tree. + * + * @since Android 1.0 */ public class IIOMetadataNode implements Element, NodeList { - /** The node name. */ + /** + * The node name. + */ private String nodeName; - - /** The node value. */ + + /** + * The node value. + */ private String nodeValue; - - /** The attributes. */ + + /** + * The attributes. + */ private IIOMetadataNodeList attrs = new IIOMetadataNodeList(new ArrayList()); - /** The parent node. */ + /** + * The parent node. + */ private IIOMetadataNode parent; - - /** The first child node. */ + + /** + * The first child node. + */ private IIOMetadataNode firstChild; - - /** The last child node. */ + + /** + * The last child node. + */ private IIOMetadataNode lastChild; - - /** The previous sibling. */ + + /** + * The previous sibling. + */ private IIOMetadataNode previousSibling; - - /** The next sibling. */ + + /** + * The next sibling. + */ private IIOMetadataNode nextSibling; - /** The number of children. */ + /** + * The number of children. + */ private int nChildren; - /** The user object associated with this node. */ + /** + * The user object associated with this node. + */ private Object userObject; - /** The text content of this node. */ + /** + * The text content of this node. + */ private String textContent; /** @@ -79,18 +103,20 @@ public class IIOMetadataNode implements Element, NodeList { /** * Instantiates a new empty node with the specified name. * - * @param nodeName the node name + * @param nodeName + * the node name. */ public IIOMetadataNode(String nodeName) { this.nodeName = nodeName; } /** - * Instantiates a new IIOMetadataNode with the specified - * name and value. + * Instantiates a new IIOMetadataNode with the specified name and value. * - * @param nodeName the node name - * @param nodeValue the node value + * @param nodeName + * the node name. + * @param nodeValue + * the node value. */ private IIOMetadataNode(String nodeName, String nodeValue) { this.nodeName = nodeName; @@ -102,12 +128,12 @@ public class IIOMetadataNode implements Element, NodeList { } public String getAttribute(String name) { - Attr attrNode = (Attr) attrs.getNamedItem(name); + Attr attrNode = (Attr)attrs.getNamedItem(name); return (attrNode == null) ? "" : attrNode.getValue(); } public void setAttribute(String name, String value) throws DOMException { - Attr attr = (Attr) attrs.getNamedItem(name); + Attr attr = (Attr)attrs.getNamedItem(name); if (attr != null) { attr.setValue(value); } else { @@ -116,7 +142,7 @@ public class IIOMetadataNode implements Element, NodeList { } public void removeAttribute(String name) throws DOMException { - IIOMetadataAttr attr = (IIOMetadataAttr) attrs.getNamedItem(name); + IIOMetadataAttr attr = (IIOMetadataAttr)attrs.getNamedItem(name); if (attr != null) { attr.setOwnerElement(null); attrs.list.remove(attr); @@ -124,17 +150,19 @@ public class IIOMetadataNode implements Element, NodeList { } public Attr getAttributeNode(String name) { - return (Attr) attrs.getNamedItem(name); + return (Attr)attrs.getNamedItem(name); } public Attr setAttributeNode(Attr newAttr) throws DOMException { // Check if this attribute is already in use. Element owner = newAttr.getOwnerElement(); if (owner != null) { - if (owner == this) { // Replacing an attribute node by itself has no effect + if (owner == this) { // Replacing an attribute node by itself has no + // effect return null; } else { - throw new DOMException(DOMException.INUSE_ATTRIBUTE_ERR, "Attribute is already in use"); + throw new DOMException(DOMException.INUSE_ATTRIBUTE_ERR, + "Attribute is already in use"); } } @@ -146,7 +174,7 @@ public class IIOMetadataNode implements Element, NodeList { IIOMetadataAttr iioAttr; if (newAttr instanceof IIOMetadataAttr) { - iioAttr = (IIOMetadataAttr) newAttr; + iioAttr = (IIOMetadataAttr)newAttr; iioAttr.setOwnerElement(this); } else { iioAttr = new IIOMetadataAttr(name, newAttr.getValue(), this); @@ -206,7 +234,8 @@ public class IIOMetadataNode implements Element, NodeList { return getAttribute(localName); } - public void setAttributeNS(String namespaceURI, String qualifiedName, String value) throws DOMException { + public void setAttributeNS(String namespaceURI, String qualifiedName, String value) + throws DOMException { setAttribute(qualifiedName, value); } @@ -222,7 +251,8 @@ public class IIOMetadataNode implements Element, NodeList { return setAttributeNode(newAttr); } - public NodeList getElementsByTagNameNS(String namespaceURI, String localName) throws DOMException { + public NodeList getElementsByTagNameNS(String namespaceURI, String localName) + throws DOMException { return getElementsByTagName(localName); } @@ -234,20 +264,105 @@ public class IIOMetadataNode implements Element, NodeList { return hasAttribute(localName); } - //???AWT + // ???AWT /* - public TypeInfo getSchemaTypeInfo() { - throw new DOMException(DOMException.NOT_SUPPORTED_ERR, "Method not supported"); - }*/ + * public TypeInfo getSchemaTypeInfo() { throw new + * DOMException(DOMException.NOT_SUPPORTED_ERR, "Method not supported"); } + */ + /** + * Description copied from interface: org.w3c.dom.Element (DOM Level + * 3) + *

    + * If the parameter isId is true, this method declares the specified + * attribute to be a user-determined ID attribute . This affects the value + * of Attr.isId and the behavior of Document.getElementById, but does not + * change any schema that may be in use, in particular this does not affect + * the Attr.schemaTypeInfo of the specified Attr node. Use the value false + * for the parameter isId to undeclare an attribute for being a + * user-determined ID attribute. To specify an attribute by local name and + * namespace URI, use the setIdAttributeNS method. + *

    + * + * @param name + * the name of the attribute. + * @param isId + * the flag which determines whether this attribute is of type + * ID. + * @throws DOMException + * if a DOM error occurred while setting the attribute type. + *

    + * NO_MODIFICATION_ALLOWED_ERR: Raised if this node is readonly. + *
    + * NOT_FOUND_ERR: Raised if the specified node is not an + * attribute of this element. + *

    + */ public void setIdAttribute(String name, boolean isId) throws DOMException { throw new DOMException(DOMException.NOT_SUPPORTED_ERR, "Method not supported"); } - public void setIdAttributeNS(String namespaceURI, String localName, boolean isId) throws DOMException { + /** + * Description copied from interface: org.w3c.dom.Element (DOM Level + * 3) + *

    + * If the parameter isId is true, this method declares the specified + * attribute to be a user-determined ID attribute . This affects the value + * of Attr.isId and the behavior of Document.getElementById, but does not + * change any schema that may be in use, in particular this does not affect + * the Attr.schemaTypeInfo of the specified Attr node. Use the value false + * for the parameter isId to undeclare an attribute for being a + * user-determined ID attribute. + *

    + * + * @param namespaceURI + * the namespace URI of the attribute. + * @param localName + * the local name of the attribute. + * @param isId + * the flag which determines whether this attribute is of type + * ID. + * @throws DOMException + * if a DOM error occurred while setting the attribute type. + *

    + * NO_MODIFICATION_ALLOWED_ERR: Raised if this node is readonly. + *
    + * NOT_FOUND_ERR: Raised if the specified node is not an + * attribute of this element. + *

    + */ + public void setIdAttributeNS(String namespaceURI, String localName, boolean isId) + throws DOMException { throw new DOMException(DOMException.NOT_SUPPORTED_ERR, "Method not supported"); } + /** + * Description copied from interface: org.w3c.dom.Element (DOM Level + * 3) + *

    + * If the parameter isId is true, this method declares the specified + * attribute to be a user-determined ID attribute . This affects the value + * of Attr.isId and the behavior of Document.getElementById, but does not + * change any schema that may be in use, in particular this does not affect + * the Attr.schemaTypeInfo of the specified Attr node. Use the value false + * for the parameter isId to undeclare an attribute for being a + * user-determined ID attribute. + *

    + * + * @param idAttr + * the attribute node. + * @param isId + * the flag which determines whether this attribute is of type + * ID. + * @throws DOMException + * if a DOM error occurred while setting the attribute type. + *

    + * NO_MODIFICATION_ALLOWED_ERR: Raised if this node is readonly. + *
    + * NOT_FOUND_ERR: Raised if the specified node is not an + * attribute of this element. + *

    + */ public void setIdAttributeNode(Attr idAttr, boolean isId) throws DOMException { throw new DOMException(DOMException.NOT_SUPPORTED_ERR, "Method not supported"); } @@ -305,8 +420,8 @@ public class IIOMetadataNode implements Element, NodeList { throw new IllegalArgumentException("newChild == null!"); } - IIOMetadataNode newIIOChild = (IIOMetadataNode) newChild; - IIOMetadataNode refIIOChild = (IIOMetadataNode) refChild; + IIOMetadataNode newIIOChild = (IIOMetadataNode)newChild; + IIOMetadataNode refIIOChild = (IIOMetadataNode)refChild; newIIOChild.parent = this; @@ -349,8 +464,8 @@ public class IIOMetadataNode implements Element, NodeList { throw new IllegalArgumentException("newChild == null!"); } - IIOMetadataNode newIIOChild = (IIOMetadataNode) newChild; - IIOMetadataNode oldIIOChild = (IIOMetadataNode) oldChild; + IIOMetadataNode newIIOChild = (IIOMetadataNode)newChild; + IIOMetadataNode oldIIOChild = (IIOMetadataNode)oldChild; IIOMetadataNode next = oldIIOChild.nextSibling; IIOMetadataNode previous = oldIIOChild.previousSibling; @@ -389,7 +504,7 @@ public class IIOMetadataNode implements Element, NodeList { throw new IllegalArgumentException("oldChild == null!"); } - IIOMetadataNode oldIIOChild = (IIOMetadataNode) oldChild; + IIOMetadataNode oldIIOChild = (IIOMetadataNode)oldChild; // Fix next and previous IIOMetadataNode previous = oldIIOChild.previousSibling; @@ -439,7 +554,8 @@ public class IIOMetadataNode implements Element, NodeList { } } - return cloned; //To change body of implemented methods use File | Settings | File Templates. + return cloned; // To change body of implemented methods use File | + // Settings | File Templates. } public void normalize() { @@ -470,52 +586,314 @@ public class IIOMetadataNode implements Element, NodeList { return attrs.list.size() > 0; } + /** + * Description copied from interface: org.w3c.dom.Node (DOM Level 3) + *

    + * The absolute base URI of this node or null if the implementation wasn't + * able to obtain an absolute URI. This value is computed as described in. + * However, when the Document supports the feature "HTML" [DOM Level 2 + * HTML], the base URI is computed using first the value of the href + * attribute of the HTML BASE element if any, and the value of the + * documentURI attribute from the Document interface otherwise. + *

    + * + * @return the string representation of the absolute base URI. + */ public String getBaseURI() { throw new DOMException(DOMException.NOT_SUPPORTED_ERR, "Method not supported"); } + /** + * Description copied from interface: org.w3c.dom.Node (DOM Level 3) + *

    + * Compares the reference node, i.e. the node on which this method is being + * called, with a node, i.e. the one passed as a parameter, with regard to + * their position in the document and according to the document order. + *

    + * + * @param other + * the node to compare against the reference node. + * @return Returns how the node is positioned relatively to the reference + * node. + * @throws DOMException + * NOT_SUPPORTED_ERR: when the compared nodes are from different + * DOM implementations that do not coordinate to return + * consistent implementation-specific results. + */ public short compareDocumentPosition(Node other) throws DOMException { throw new DOMException(DOMException.NOT_SUPPORTED_ERR, "Method not supported"); } + /** + * Description copied from interface: org.w3c.dom.Node (DOM Level 3) + *

    + * This attribute returns the text content of this node and its descendants. + * When it is defined to be null, setting it has no effect. On setting, any + * possible children this node may have are removed and, if it the new + * string is not empty or null, replaced by a single Text node containing + * the string this attribute is set to. On getting, no serialization is + * performed, the returned string does not contain any markup. No whitespace + * normalization is performed and the returned string does not contain the + * white spaces in element content (see the attribute + * Text.isElementContentWhitespace). Similarly, on setting, no parsing is + * performed either, the input string is taken as pure textual content. The + * string returned is made of the text content of this node depending on its + * type, as defined below: + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
    Node typeContent
    ELEMENT_NODE, ATTRIBUTE_NODE, ENTITY_NODE, ENTITY_REFERENCE_NODE, + * DOCUMENT_FRAGMENT_NODEconcatenation of the textContent attribute value of every child node, + * excluding COMMENT_NODE and PROCESSING_INSTRUCTION_NODE nodes. This is the + * empty string if the node has no children.
    TEXT_NODE, CDATA_SECTION_NODE, COMMENT_NODE, + * PROCESSING_INSTRUCTION_NODEnodeValue
    DOCUMENT_NODE, DOCUMENT_TYPE_NODE, NOTATION_NODEnull
    + *

    + * + * @return the text content depending on the type of this node. + * @throws DOMException + * DOMSTRING_SIZE_ERR: Raised when it would return more + * characters than fit in a DOMString variable on the + * implementation platform. + */ public String getTextContent() throws DOMException { return textContent; } + /** + * Description copied from interface: org.w3c.dom.Node (DOM Level 3) + *

    + * This attribute returns the text content of this node and its descendants. + * When it is defined to be null, setting it has no effect. On setting, any + * possible children this node may have are removed and, if it the new + * string is not empty or null, replaced by a single Text node containing + * the string this attribute is set to. On getting, no serialization is + * performed, the returned string does not contain any markup. No whitespace + * normalization is performed and the returned string does not contain the + * white spaces in element content (see the attribute + * Text.isElementContentWhitespace). Similarly, on setting, no parsing is + * performed either, the input string is taken as pure textual content. The + * string returned is made of the text content of this node depending on its + * type, as defined below: + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
    Node typeContent
    ELEMENT_NODE, ATTRIBUTE_NODE, ENTITY_NODE, ENTITY_REFERENCE_NODE, + * DOCUMENT_FRAGMENT_NODEconcatenation of the textContent attribute value of every child node, + * excluding COMMENT_NODE and PROCESSING_INSTRUCTION_NODE nodes. This is the + * empty string if the node has no children.
    TEXT_NODE, CDATA_SECTION_NODE, COMMENT_NODE, + * PROCESSING_INSTRUCTION_NODEnodeValue
    DOCUMENT_NODE, DOCUMENT_TYPE_NODE, NOTATION_NODEnull
    + *

    + * + * @param textContent + * the text content for this node. + * @throws DOMException + * NO_MODIFICATION_ALLOWED_ERR: Raised when the node is + * readonly. + */ public void setTextContent(String textContent) throws DOMException { this.textContent = textContent; } + /** + * Description copied from interface: org.w3c.dom.Node (DOM Level 3) + *

    + * Returns whether this node is the same node as the given one. This method + * provides a way to determine whether two Node references returned by the + * implementation reference the same object. When two Node references are + * references to the same object, even if through a proxy, the references + * may be used completely interchangeably, such that all attributes have the + * same values and calling the same DOM method on either reference always + * has exactly the same effect. + *

    + * + * @param other + * the node to test against. + * @return true, if the nodes are the same, false otherwise. + */ public boolean isSameNode(Node other) { throw new DOMException(DOMException.NOT_SUPPORTED_ERR, "Method not supported"); } + /** + * Description copied from interface: org.w3c.dom.Node (DOM Level 3) + *

    + * Look up the prefix associated to the given namespace URI, starting from + * this node. The default namespace declarations are ignored by this method. + * See for details on the algorithm used by this method. + *

    + * + * @param namespaceURI + * the namespace URI to look for. + * @return the associated namespace prefix if found or null if none is + * found. If more than one prefix are associated to the namespace + * prefix, the returned namespace prefix is implementation + * dependent. + */ public String lookupPrefix(String namespaceURI) { throw new DOMException(DOMException.NOT_SUPPORTED_ERR, "Method not supported"); } + /** + * Description copied from interface: org.w3c.dom.Node (DOM Level 3) + *

    + * This method checks if the specified namespaceURI is the default namespace + * or not. + *

    + * + * @param namespaceURI + * the namespace URI to look for. + * @return true, if the specified namespaceURI is the default namespace, + * false otherwise. + */ public boolean isDefaultNamespace(String namespaceURI) { throw new DOMException(DOMException.NOT_SUPPORTED_ERR, "Method not supported"); } + /** + * Description copied from interface: org.w3c.dom.Node (DOM Level 3) + *

    + * Look up the namespace URI associated to the given prefix, starting from + * this node. See for details on the algorithm used by this method. + *

    + * + * @param prefix + * the prefix to look for. If this parameter is null, the method + * will return the default namespace URI if any. + * @return the associated namespace URI or null if none is found. + */ public String lookupNamespaceURI(String prefix) { throw new DOMException(DOMException.NOT_SUPPORTED_ERR, "Method not supported"); } + /** + * Description copied from interface: org.w3c.dom.Node (DOM Level 3) + *

    + * Tests whether two nodes are equal. This method tests for equality of + * nodes, not sameness (i.e., whether the two nodes are references to the + * same object) which can be tested with Node.isSameNode(). All nodes that + * are the same will also be equal, though the reverse may not be true. Two + * nodes are equal if and only if the following conditions are satisfied: + *

    + *

  • The two nodes are of the same type.
  • + *
  • The following string attributes are equal: nodeName, localName, + * namespaceURI, prefix, nodeValue . This is: they are both null, or they + * have the same length and are character for character identical.
  • + *
  • The attributes NamedNodeMaps are equal. This is: they are both null, + * or they have the same length and for each node that exists in one map + * there is a node that exists in the other map and is equal, although not + * necessarily at the same index.
  • + *
  • The childNodes NodeLists are equal. This is: they are both null, or + * they have the same length and contain equal nodes at the same index. Note + * that normalization can affect equality; to avoid this, nodes should be + * normalized before being compared.
  • + *

    + * For two DocumentType nodes to be equal, the following conditions must + * also be satisfied: + *

    + *

  • The following string attributes are equal: publicId, systemId, + * internalSubset.
  • + *
  • The entities NamedNodeMaps are equal.
  • + *
  • The notations NamedNodeMaps are equal.
  • + *

    + * On the other hand, the following do not affect equality: the + * ownerDocument, baseURI, and parentNode attributes, the specified + * attribute for Attr nodes, the schemaTypeInfo attribute for Attr and + * Element nodes, the Text.isElementContentWhitespace attribute for Text + * nodes, as well as any user data or event listeners registered on the + * nodes.

    + *

    + * Note: As a general rule, anything not mentioned in the description above + * is not significant in consideration of equality checking. Note that + * future versions of this specification may take into account more + * attributes and implementations conform to this specification are expected + * to be updated accordingly. + *

    + * + * @param arg + * the node to compare equality with. + * @return true, if the nodes are equal, false otherwise. + */ public boolean isEqualNode(Node arg) { throw new DOMException(DOMException.NOT_SUPPORTED_ERR, "Method not supported"); } + /** + * Description copied from interface: org.w3c.dom.Node (DOM Level 3) + *

    + * This method returns a specialized object which implements the specialized + * APIs of the specified feature and version, as specified in. The + * specialized object may also be obtained by using binding-specific casting + * methods but is not necessarily expected to, as discussed in. This method + * also allow the implementation to provide specialized objects which do not + * support the Node interface. + *

    + * + * @param feature + * the name of the feature requested. Note that any plus sign "+" + * prepended to the name of the feature will be ignored since it + * is not significant in the context of this method. + * @param version + * this is the version number of the feature to test. + * @return the object which implements the specialized APIs of the specified + * feature and version, if any, or null if there is no object which + * implements interfaces associated with that feature. If the + * DOMObject returned by this method implements the Node interface, + * it must delegate to the primary core Node and not return results + * inconsistent with the primary core Node such as attributes, + * childNodes, etc. + */ public Object getFeature(String feature, String version) { throw new DOMException(DOMException.NOT_SUPPORTED_ERR, "Method not supported"); } - //???AWT + // ???AWT /* - public Object setUserData(String key, Object data, UserDataHandler handler) { - throw new DOMException(DOMException.NOT_SUPPORTED_ERR, "Method not supported"); - }*/ + * public Object setUserData(String key, Object data, UserDataHandler + * handler) { throw new DOMException(DOMException.NOT_SUPPORTED_ERR, + * "Method not supported"); } + */ + /** + * Description copied from interface: org.w3c.dom.Node (DOM Level 3) + *

    + * Retrieves the object associated to a key on a this node. The object must + * first have been set to this node by calling setUserData with the same + * key. + *

    + * + * @param key + * the key the object is associated to. + * @return the DOMUserData associated to the given key on this node, or null + * if there was none. + */ public Object getUserData(String key) { throw new DOMException(DOMException.NOT_SUPPORTED_ERR, "Method not supported"); } @@ -540,7 +918,7 @@ public class IIOMetadataNode implements Element, NodeList { /** * Gets the user object associated with this node. * - * @return the user object associated with this node + * @return the user object associated with this node. */ public Object getUserObject() { return userObject; @@ -549,7 +927,8 @@ public class IIOMetadataNode implements Element, NodeList { /** * Sets the user object associated with this node. * - * @param userObject the new user object associated with this node + * @param userObject + * the new user object associated with this node. */ public void setUserObject(Object userObject) { this.userObject = userObject; @@ -559,16 +938,21 @@ public class IIOMetadataNode implements Element, NodeList { * The Class IIOMetadataAttr. */ private class IIOMetadataAttr extends IIOMetadataNode implements Attr { - - /** The owner element. */ + + /** + * The owner element. + */ private Element ownerElement; /** * Instantiates a new iIO metadata attr. * - * @param name the name - * @param value the value - * @param owner the owner + * @param name + * the name. + * @param value + * the value. + * @param owner + * the owner. */ public IIOMetadataAttr(String name, String value, Element owner) { super(name, value); @@ -598,12 +982,16 @@ public class IIOMetadataNode implements Element, NodeList { /** * Sets the owner element. * - * @param ownerElement the new owner element + * @param ownerElement + * the new owner element. */ public void setOwnerElement(Element ownerElement) { this.ownerElement = ownerElement; } + /** + * @return + */ public boolean isId() { throw new DOMException(DOMException.NOT_SUPPORTED_ERR, "Method not supported"); } @@ -618,14 +1006,17 @@ public class IIOMetadataNode implements Element, NodeList { * The Class IIOMetadataNodeList. */ private class IIOMetadataNodeList implements NodeList, NamedNodeMap { - - /** The list. */ + + /** + * The list. + */ private List list; /** * Instantiates a new iIO metadata node list. * - * @param list the list + * @param list + * the list. */ IIOMetadataNodeList(List list) { this.list = list; @@ -644,7 +1035,7 @@ public class IIOMetadataNode implements Element, NodeList { } public Node getNamedItem(String name) { - for(IIOMetadataNode node:list) { + for (IIOMetadataNode node : list) { if (name.equals(node.getNodeName())) { return node; } @@ -653,11 +1044,13 @@ public class IIOMetadataNode implements Element, NodeList { } public Node setNamedItem(Node arg) throws DOMException { - throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR, "This NamedNodeMap is read-only!"); + throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR, + "This NamedNodeMap is read-only!"); } public Node removeNamedItem(String name) throws DOMException { - throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR, "This NamedNodeMap is read-only!"); + throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR, + "This NamedNodeMap is read-only!"); } public Node getNamedItemNS(String namespaceURI, String localName) throws DOMException { @@ -665,11 +1058,13 @@ public class IIOMetadataNode implements Element, NodeList { } public Node setNamedItemNS(Node arg) throws DOMException { - throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR, "This NamedNodeMap is read-only!"); + throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR, + "This NamedNodeMap is read-only!"); } public Node removeNamedItemNS(String namespaceURI, String localName) throws DOMException { - throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR, "This NamedNodeMap is read-only!"); + throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR, + "This NamedNodeMap is read-only!"); } } } diff --git a/awt/javax/imageio/metadata/IIOStandardMetadataFormat.java b/awt/javax/imageio/metadata/IIOStandardMetadataFormat.java index 94d2125638b3ab1c51161a8f1511b745016669b3..706cb2f7ab283b723a4ce4b25d7dbbb2ef40221b 100644 --- a/awt/javax/imageio/metadata/IIOStandardMetadataFormat.java +++ b/awt/javax/imageio/metadata/IIOStandardMetadataFormat.java @@ -15,18 +15,19 @@ * limitations under the License. */ - package javax.imageio.metadata; import javax.imageio.ImageTypeSpecifier; import java.util.ArrayList; /** - * The Class IIOStandardMetadataFormat describes the rules of the - * standard metadata format. + * The class IIOStandardMetadataFormat describes the rules of the standard + * metadata format. + * + * @since Android 1.0 */ -class IIOStandardMetadataFormat extends IIOMetadataFormatImpl { - +class IIOStandardMetadataFormat extends IIOMetadataFormatImpl { + /** * Instantiates a new IIOStandardMetadataFormat. */ @@ -41,7 +42,7 @@ class IIOStandardMetadataFormat extends IIOMetadataFormatImpl { } /** - * Builds the dtd that describes the standard metadata format. + * Builds the DTD that describes the standard metadata format. */ private void buildDTD() { // CHROMA @@ -80,7 +81,10 @@ class IIOStandardMetadataFormat extends IIOMetadataFormatImpl { addAttribute("ColorSpaceType", "name", DATATYPE_STRING, true, null, values); addElement("NumChannels", "Chroma", CHILD_POLICY_EMPTY); - addAttribute("NumChannels", "value", DATATYPE_INTEGER, true, 0, Integer.MAX_VALUE); // list - why? + addAttribute("NumChannels", "value", DATATYPE_INTEGER, true, 0, Integer.MAX_VALUE); // list + // - + // why + // ? addElement("Gamma", "Chroma", CHILD_POLICY_EMPTY); addAttribute("Gamma", "value", DATATYPE_FLOAT, true, null); @@ -142,10 +146,8 @@ class IIOStandardMetadataFormat extends IIOMetadataFormatImpl { addAttribute("BitsPerSample", "value", DATATYPE_INTEGER, true, 1, Integer.MAX_VALUE); // list addElement("SignificantBitsPerSample", "Data", CHILD_POLICY_EMPTY); - addAttribute( - "SignificantBitsPerSample", "value", - DATATYPE_INTEGER, true, 1, Integer.MAX_VALUE - ); // list + addAttribute("SignificantBitsPerSample", "value", DATATYPE_INTEGER, true, 1, + Integer.MAX_VALUE); // list addElement("SampleMSB", "Data", CHILD_POLICY_EMPTY); addAttribute("SampleMSB", "value", DATATYPE_INTEGER, true, 1, Integer.MAX_VALUE); // list @@ -224,49 +226,29 @@ class IIOStandardMetadataFormat extends IIOMetadataFormatImpl { addElement("ImageCreationTime", "Document", CHILD_POLICY_EMPTY); addAttribute("ImageCreationTime", "year", DATATYPE_INTEGER, true, null); - addAttribute( - "ImageCreationTime", "month", - DATATYPE_INTEGER, true, null, "1", "12", true, true - ); - addAttribute( - "ImageCreationTime", "day", - DATATYPE_INTEGER, true, null, "1", "31", true, true - ); - addAttribute( - "ImageCreationTime", "hour", - DATATYPE_INTEGER, false, "0", "0", "23", true, true - ); - addAttribute( - "ImageCreationTime", "minute", - DATATYPE_INTEGER, false, "0", "0", "59", true, true - ); - addAttribute( - "ImageCreationTime", "second", - DATATYPE_INTEGER, false, "0", "0", "60", true, true - ); + addAttribute("ImageCreationTime", "month", DATATYPE_INTEGER, true, null, "1", "12", true, + true); + addAttribute("ImageCreationTime", "day", DATATYPE_INTEGER, true, null, "1", "31", true, + true); + addAttribute("ImageCreationTime", "hour", DATATYPE_INTEGER, false, "0", "0", "23", true, + true); + addAttribute("ImageCreationTime", "minute", DATATYPE_INTEGER, false, "0", "0", "59", true, + true); + addAttribute("ImageCreationTime", "second", DATATYPE_INTEGER, false, "0", "0", "60", true, + true); addElement("ImageModificationTime", "Document", CHILD_POLICY_EMPTY); addAttribute("ImageModificationTime", "year", DATATYPE_INTEGER, true, null); - addAttribute( - "ImageModificationTime", "month", - DATATYPE_INTEGER, true, null, "1", "12", true, true - ); - addAttribute( - "ImageModificationTime", "day", - DATATYPE_INTEGER, true, null, "1", "31", true, true - ); - addAttribute( - "ImageModificationTime", "hour", - DATATYPE_INTEGER, false, "0", "0", "23", true, true - ); - addAttribute( - "ImageModificationTime", "minute", - DATATYPE_INTEGER, false, "0", "0", "59", true, true - ); - addAttribute( - "ImageModificationTime", "second", - DATATYPE_INTEGER, false, "0", "0", "60", true, true - ); + addAttribute("ImageModificationTime", "month", DATATYPE_INTEGER, true, null, "1", "12", + true, true); + addAttribute("ImageModificationTime", "day", DATATYPE_INTEGER, true, null, "1", "31", true, + true); + addAttribute("ImageModificationTime", "hour", DATATYPE_INTEGER, false, "0", "0", "23", + true, true); + addAttribute("ImageModificationTime", "minute", DATATYPE_INTEGER, false, "0", "0", "59", + true, true); + addAttribute("ImageModificationTime", "second", DATATYPE_INTEGER, false, "0", "0", "60", + true, true); // TEXT addElement("Text", standardMetadataFormatName, 0, Integer.MAX_VALUE); // CHILD_POLICY_REPEAT @@ -313,4 +295,3 @@ class IIOStandardMetadataFormat extends IIOMetadataFormatImpl { addAttribute("OpaqueTile", "y", DATATYPE_INTEGER, true, null); } } - diff --git a/awt/javax/imageio/metadata/package.html b/awt/javax/imageio/metadata/package.html new file mode 100644 index 0000000000000000000000000000000000000000..29bd51b2c4c1444f3546be996cdcf1d9ecce4c7d --- /dev/null +++ b/awt/javax/imageio/metadata/package.html @@ -0,0 +1,8 @@ + + +

    + This package contains classes which allows to read and write describing metadata of image files. +

    + @since Android 1.0 + + diff --git a/awt/javax/imageio/package.html b/awt/javax/imageio/package.html new file mode 100644 index 0000000000000000000000000000000000000000..2fd614874872c62ae0895063aab1dddf6584ec96 --- /dev/null +++ b/awt/javax/imageio/package.html @@ -0,0 +1,8 @@ + + +

    + This package contains classes and interfaces which provides an Image I/O API. The contained classes and interfaces allow reading and writing image files of different formats. +

    + @since Android 1.0 + + diff --git a/awt/javax/imageio/plugins/bmp/BMPImageWriteParam.java b/awt/javax/imageio/plugins/bmp/BMPImageWriteParam.java index 0cd44db4aaea8723a3cf197d02801d7affe1bde1..ecfb20ad38cd3ee0e3615e044d5c8867b41f38a6 100644 --- a/awt/javax/imageio/plugins/bmp/BMPImageWriteParam.java +++ b/awt/javax/imageio/plugins/bmp/BMPImageWriteParam.java @@ -15,19 +15,21 @@ * limitations under the License. */ - package javax.imageio.plugins.bmp; import javax.imageio.ImageWriteParam; import java.util.Locale; /** - * The BMPImageWriteParam class allows encoding an image in - * BMP format. + * The BMPImageWriteParam class allows encoding an image in BMP format. + * + * @since Android 1.0 */ public class BMPImageWriteParam extends ImageWriteParam { - - /** The top down. */ + + /** + * The top down. + */ private boolean topDown; // Default is bottom-up /** @@ -41,33 +43,35 @@ public class BMPImageWriteParam extends ImageWriteParam { /** * Instantiates a new BMPImageWriteParam with the specified Locale. * - * @param locale the specified Locale. + * @param locale + * the specified Locale. */ public BMPImageWriteParam(Locale locale) { super(locale); // Set the compression canWriteCompressed = true; - compressionTypes = new String[] {"BI_RGB", "BI_RLE8", "BI_RLE4", "BI_BITFIELDS"}; - compressionType = compressionTypes[0]; + compressionTypes = new String[] { + "BI_RGB", "BI_RLE8", "BI_RLE4", "BI_BITFIELDS" + }; + compressionType = compressionTypes[0]; } /** - * Sets true if the data will be written in a top-down order, - * false otherwise. + * Sets true if the data will be written in a top-down order, false + * otherwise. * - * @param topDown the new top-down value. + * @param topDown + * the new top-down value. */ public void setTopDown(boolean topDown) { this.topDown = topDown; } /** - * Returns true if the data is written in top-down order, false - * otherwise. + * Returns true if the data is written in top-down order, false otherwise. * - * @return true if the data is written in top-down order, false - * otherwise. + * @return true if the data is written in top-down order, false otherwise. */ public boolean isTopDown() { return topDown; diff --git a/awt/javax/imageio/plugins/bmp/package.html b/awt/javax/imageio/plugins/bmp/package.html new file mode 100644 index 0000000000000000000000000000000000000000..9494a102db7e8a7cc09aa7baea723bfbd2339b5d --- /dev/null +++ b/awt/javax/imageio/plugins/bmp/package.html @@ -0,0 +1,8 @@ + + +

    + This package contains auxiliary classes for the built-in BMP image plug-in. +

    + @since Android 1.0 + + diff --git a/awt/javax/imageio/plugins/jpeg/JPEGHuffmanTable.java b/awt/javax/imageio/plugins/jpeg/JPEGHuffmanTable.java index 398c960ad4965d22527f4a7cd1624aed93ad3a87..67b504be25565b2617c9545c2dce7902e031bcd3 100644 --- a/awt/javax/imageio/plugins/jpeg/JPEGHuffmanTable.java +++ b/awt/javax/imageio/plugins/jpeg/JPEGHuffmanTable.java @@ -18,82 +18,90 @@ package javax.imageio.plugins.jpeg; /** - * The JPEGHuffmanTable class represents a single JPEG Huffman table. - * It contains the standard tables from the JPEG specification. + * The JPEGHuffmanTable class represents a single JPEG Huffman table. It + * contains the standard tables from the JPEG specification. + * + * @since Android 1.0 */ public class JPEGHuffmanTable { - - /** The standard DC luminance Huffman table . */ - public static final JPEGHuffmanTable StdDCLuminance = new JPEGHuffmanTable( - new short[] {0, 1, 5, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0}, - new short[] {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0x0A, 0x0B}, - false - ); - - /** The standard DC chrominance Huffman table. */ - public static final JPEGHuffmanTable StdDCChrominance = new JPEGHuffmanTable( - new short[] {0, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0}, - new short[] {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0x0A, 0x0B}, - false - ); - - /** The standard AC luminance Huffman table. */ - public static final JPEGHuffmanTable StdACLuminance = new JPEGHuffmanTable( - new short[] {0, 2, 1, 3, 3, 2, 4, 3, 5, 5, 4, 4, 0, 0, 1, 0x7D}, - new short[] { - 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12, 0x21, 0x31, 0x41, 0x06, - 0x13, 0x51, 0x61, 0x07, 0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xA1, 0x08, - 0x23, 0x42, 0xB1, 0xC1, 0x15, 0x52, 0xD1, 0xF0, 0x24, 0x33, 0x62, 0x72, - 0x82, 0x09, 0x0A, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x25, 0x26, 0x27, 0x28, - 0x29, 0x2A, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x43, 0x44, 0x45, - 0x46, 0x47, 0x48, 0x49, 0x4A, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, - 0x5A, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x73, 0x74, 0x75, - 0x76, 0x77, 0x78, 0x79, 0x7A, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, - 0x8A, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0xA2, 0xA3, - 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, - 0xB7, 0xB8, 0xB9, 0xBA, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, - 0xCA, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xE1, 0xE2, - 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xF1, 0xF2, 0xF3, 0xF4, - 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA - }, - false - ); - - /** - * The standard AC chrominance Huffman table. */ - public static final JPEGHuffmanTable StdACChrominance = new JPEGHuffmanTable( - new short[] {0, 2, 1, 2, 4, 4, 3, 4, 7, 5, 4, 4, 0, 1, 2, 0x77}, - new short[] { - 0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21, 0x31, 0x06, 0x12, 0x41, - 0x51, 0x07, 0x61, 0x71, 0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91, - 0xA1, 0xB1, 0xC1, 0x09, 0x23, 0x33, 0x52, 0xF0, 0x15, 0x62, 0x72, 0xD1, - 0x0A, 0x16, 0x24, 0x34, 0xE1, 0x25, 0xF1, 0x17, 0x18, 0x19, 0x1A, 0x26, - 0x27, 0x28, 0x29, 0x2A, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x43, 0x44, - 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, - 0x59, 0x5A, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x73, 0x74, - 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, - 0x88, 0x89, 0x8A, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, - 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xB2, 0xB3, 0xB4, - 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, - 0xC8, 0xC9, 0xCA, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, - 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xF2, 0xF3, 0xF4, - 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA - }, - false - ); - - /** The lengths. */ + + /** + * The standard DC luminance Huffman table . + */ + public static final JPEGHuffmanTable StdDCLuminance = new JPEGHuffmanTable(new short[] { + 0, 1, 5, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0 + }, new short[] { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0x0A, 0x0B + }, false); + + /** + * The standard DC chrominance Huffman table. + */ + public static final JPEGHuffmanTable StdDCChrominance = new JPEGHuffmanTable(new short[] { + 0, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0 + }, new short[] { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0x0A, 0x0B + }, false); + + /** + * The standard AC luminance Huffman table. + */ + public static final JPEGHuffmanTable StdACLuminance = new JPEGHuffmanTable(new short[] { + 0, 2, 1, 3, 3, 2, 4, 3, 5, 5, 4, 4, 0, 0, 1, 0x7D + }, new short[] { + 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12, 0x21, 0x31, 0x41, 0x06, 0x13, 0x51, + 0x61, 0x07, 0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xA1, 0x08, 0x23, 0x42, 0xB1, 0xC1, + 0x15, 0x52, 0xD1, 0xF0, 0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0A, 0x16, 0x17, 0x18, + 0x19, 0x1A, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, + 0x3A, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x53, 0x54, 0x55, 0x56, 0x57, + 0x58, 0x59, 0x5A, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x73, 0x74, 0x75, + 0x76, 0x77, 0x78, 0x79, 0x7A, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x92, + 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, + 0xA8, 0xA9, 0xAA, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xC2, 0xC3, + 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, + 0xD9, 0xDA, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xF1, 0xF2, + 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA + }, false); + + /** + * The standard AC chrominance Huffman table. + */ + public static final JPEGHuffmanTable StdACChrominance = new JPEGHuffmanTable(new short[] { + 0, 2, 1, 2, 4, 4, 3, 4, 7, 5, 4, 4, 0, 1, 2, 0x77 + }, new short[] { + 0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21, 0x31, 0x06, 0x12, 0x41, 0x51, 0x07, + 0x61, 0x71, 0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91, 0xA1, 0xB1, 0xC1, 0x09, + 0x23, 0x33, 0x52, 0xF0, 0x15, 0x62, 0x72, 0xD1, 0x0A, 0x16, 0x24, 0x34, 0xE1, 0x25, + 0xF1, 0x17, 0x18, 0x19, 0x1A, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x35, 0x36, 0x37, 0x38, + 0x39, 0x3A, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x53, 0x54, 0x55, 0x56, + 0x57, 0x58, 0x59, 0x5A, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x73, 0x74, + 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, + 0x8A, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0xA2, 0xA3, 0xA4, 0xA5, + 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, + 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, + 0xD7, 0xD8, 0xD9, 0xDA, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xF2, + 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA + }, false); + + /** + * The lengths. + */ private short lengths[]; - - /** The values. */ + + /** + * The values. + */ private short values[]; /** * Instantiates a new jPEG huffman table. * - * @param lengths the lengths - * @param values the values - * @param copy the copy + * @param lengths + * the lengths + * @param values + * the values + * @param copy + * the copy */ JPEGHuffmanTable(short[] lengths, short[] values, boolean copy) { // Construction of standard tables without checks @@ -106,9 +114,11 @@ public class JPEGHuffmanTable { /** * Instantiates a new JPEGHuffmanTable. * - * @param lengths the array of shorts lengths. - * @param values the array of shorts containing - * the values in order of increasing code length. + * @param lengths + * the array of shorts lengths. + * @param values + * the array of shorts containing the values in order of + * increasing code length. */ public JPEGHuffmanTable(short[] lengths, short[] values) { if (lengths == null) { @@ -145,8 +155,8 @@ public class JPEGHuffmanTable { /** * Gets an array of lengths in the Huffman table. * - * @return the array of short values representing the - * length values in the Huffman table. + * @return the array of short values representing the length values in the + * Huffman table. */ public short[] getLengths() { short newLengths[] = new short[lengths.length]; @@ -155,8 +165,7 @@ public class JPEGHuffmanTable { } /** - * Gets an array of values represented by increasing length of - * their codes. + * Gets an array of values represented by increasing length of their codes. * * @return the array of values. */ @@ -169,8 +178,10 @@ public class JPEGHuffmanTable { /** * Check huffman table. * - * @param lengths the lengths - * @param values the values + * @param lengths + * the lengths. + * @param values + * the values. */ private static void checkHuffmanTable(short[] lengths, short[] values) { int numLeaves = 0; @@ -179,13 +190,15 @@ public class JPEGHuffmanTable { numLeaves += length; possibleLeaves -= length; if (possibleLeaves < 0) { - throw new IllegalArgumentException("Invalid Huffman table provided, lengths are incorrect."); + throw new IllegalArgumentException( + "Invalid Huffman table provided, lengths are incorrect."); } possibleLeaves <<= 1; } if (values.length != numLeaves) { - throw new IllegalArgumentException("Invalid Huffman table provided, sum of lengths != values."); + throw new IllegalArgumentException( + "Invalid Huffman table provided, sum of lengths != values."); } } diff --git a/awt/javax/imageio/plugins/jpeg/JPEGImageReadParam.java b/awt/javax/imageio/plugins/jpeg/JPEGImageReadParam.java index dd08d51b603eab03b13b8327865b6d2d79c16222..2f3a9a8fbdb2525e7841ccdc47d2bc94d70444c9 100644 --- a/awt/javax/imageio/plugins/jpeg/JPEGImageReadParam.java +++ b/awt/javax/imageio/plugins/jpeg/JPEGImageReadParam.java @@ -20,18 +20,26 @@ package javax.imageio.plugins.jpeg; import javax.imageio.ImageReadParam; /** - * The JPEGImageReadParam class provides functionality to set Huffman tables - * and quantization tables when using the JPEG reader plug-in. + * The JPEGImageReadParam class provides functionality to set Huffman tables and + * quantization tables when using the JPEG reader plug-in. + * + * @since Android 1.0 */ public class JPEGImageReadParam extends ImageReadParam { - - /** The q tables. */ + + /** + * The q tables. + */ private JPEGQTable qTables[]; - - /** The dc huffman tables. */ + + /** + * The dc huffman tables. + */ private JPEGHuffmanTable dcHuffmanTables[]; - - /** The ac huffman tables. */ + + /** + * The ac huffman tables. + */ private JPEGHuffmanTable acHuffmanTables[]; /** @@ -43,29 +51,28 @@ public class JPEGImageReadParam extends ImageReadParam { /** * Returns true if tables are set, false otherwise. * - * @return true if tables are set, false otherwise. + * @return true, if tables are set, false otherwise. */ public boolean areTablesSet() { return qTables != null; } /** - * Sets the quantization and Huffman tables for using in - * decoding streams. + * Sets the quantization and Huffman tables for using in decoding streams. * - * @param qTables the quantization tables. - * @param DCHuffmanTables the standart DC Huffman tables. - * @param ACHuffmanTables the standart AC huffman tables. + * @param qTables + * the quantization tables. + * @param DCHuffmanTables + * the standart DC Huffman tables. + * @param ACHuffmanTables + * the standart AC huffman tables. */ - public void setDecodeTables( - JPEGQTable[] qTables, - JPEGHuffmanTable[] DCHuffmanTables, - JPEGHuffmanTable[] ACHuffmanTables - ) { + public void setDecodeTables(JPEGQTable[] qTables, JPEGHuffmanTable[] DCHuffmanTables, + JPEGHuffmanTable[] ACHuffmanTables) { if (qTables == null || DCHuffmanTables == null || ACHuffmanTables == null) { throw new IllegalArgumentException("Invalid JPEG table arrays"); } - if(DCHuffmanTables.length != ACHuffmanTables.length) { + if (DCHuffmanTables.length != ACHuffmanTables.length) { throw new IllegalArgumentException("Invalid JPEG table arrays"); } if (qTables.length > 4 || DCHuffmanTables.length > 4) { @@ -112,5 +119,5 @@ public class JPEGImageReadParam extends ImageReadParam { */ public JPEGHuffmanTable[] getACHuffmanTables() { return acHuffmanTables == null ? null : acHuffmanTables.clone(); - } + } } diff --git a/awt/javax/imageio/plugins/jpeg/JPEGImageWriteParam.java b/awt/javax/imageio/plugins/jpeg/JPEGImageWriteParam.java index 34a3cd923f8f4c13233c69163d83d6683f8b638f..b9799112e04da306bb3506becf6bfd5d1b803eb7 100644 --- a/awt/javax/imageio/plugins/jpeg/JPEGImageWriteParam.java +++ b/awt/javax/imageio/plugins/jpeg/JPEGImageWriteParam.java @@ -23,38 +23,52 @@ import javax.imageio.ImageWriteParam; import java.util.Locale; /** - * The JPEGImageWriteParam class allows to set JPEG Huffman tables - * and quantization when using the JPEG writer plug-in. + * The JPEGImageWriteParam class allows to set JPEG Huffman tables and + * quantization when using the JPEG writer plug-in. + * + * @since Android 1.0 */ public class JPEGImageWriteParam extends ImageWriteParam { - - /** The Constant COMP_QUALITY_VALUES. */ - private static final float[] COMP_QUALITY_VALUES = {0.05f, 0.75f, 0.95f}; - - /** The Constant COMP_QUALITY_DESCRIPTIONS. */ + + /** + * The Constant COMP_QUALITY_VALUES. + */ + private static final float[] COMP_QUALITY_VALUES = { + 0.05f, 0.75f, 0.95f + }; + + /** + * The Constant COMP_QUALITY_DESCRIPTIONS. + */ private static final String[] COMP_QUALITY_DESCRIPTIONS = { - "Minimum useful", - "Visually lossless", - "Maximum useful" + "Minimum useful", "Visually lossless", "Maximum useful" }; - /** The q tables. */ + /** + * The q tables. + */ private JPEGQTable[] qTables; - - /** The dc huffman tables. */ + + /** + * The dc huffman tables. + */ private JPEGHuffmanTable[] dcHuffmanTables; - - /** The ac huffman tables. */ + + /** + * The ac huffman tables. + */ private JPEGHuffmanTable[] acHuffmanTables; - /** The optimize huffman tables. */ + /** + * The optimize huffman tables. + */ private boolean optimizeHuffmanTables; /** - * Instantiates a new JPEGImageWriteParam object with - * the specified Locale. + * Instantiates a new JPEGImageWriteParam object with the specified Locale. * - * @param locale the Locale. + * @param locale + * the Locale. */ public JPEGImageWriteParam(Locale locale) { super(locale); @@ -63,37 +77,38 @@ public class JPEGImageWriteParam extends ImageWriteParam { progressiveMode = ImageWriteParam.MODE_DISABLED; canWriteCompressed = true; - compressionTypes = new String[]{"JPEG"}; - compressionType = compressionTypes[0]; + compressionTypes = new String[] { + "JPEG" + }; + compressionType = compressionTypes[0]; compressionQuality = JPEGConsts.DEFAULT_JPEG_COMPRESSION_QUALITY; } /** * Returns true if tables are set, false otherwise. * - * @return true if tables are set, false otherwise. + * @return true, if tables are set, false otherwise. */ public boolean areTablesSet() { return qTables != null; } /** - * Sets the quantization and Huffman tables for using in - * encoding streams. + * Sets the quantization and Huffman tables for using in encoding streams. * - * @param qTables the quantization tables. - * @param DCHuffmanTables the standart DC Huffman tables. - * @param ACHuffmanTables the standart AC huffman tables. + * @param qTables + * the quantization tables. + * @param DCHuffmanTables + * the standart DC Huffman tables. + * @param ACHuffmanTables + * the standart AC huffman tables. */ - public void setEncodeTables( - JPEGQTable[] qTables, - JPEGHuffmanTable[] DCHuffmanTables, - JPEGHuffmanTable[] ACHuffmanTables - ) { + public void setEncodeTables(JPEGQTable[] qTables, JPEGHuffmanTable[] DCHuffmanTables, + JPEGHuffmanTable[] ACHuffmanTables) { if (qTables == null || DCHuffmanTables == null || ACHuffmanTables == null) { throw new IllegalArgumentException("Invalid JPEG table arrays"); } - if(DCHuffmanTables.length != ACHuffmanTables.length) { + if (DCHuffmanTables.length != ACHuffmanTables.length) { throw new IllegalArgumentException("Invalid JPEG table arrays"); } if (qTables.length > 4 || DCHuffmanTables.length > 4) { @@ -155,21 +170,22 @@ public class JPEGImageWriteParam extends ImageWriteParam { } /** - * Sets the flag indicated that the writer will generate optimized - * Huffman tables for the image as part of the writing process. + * Sets the flag indicated that the writer will generate optimized Huffman + * tables for the image as part of the writing process. * - * @param optimize the flag of optimizing huffman tables. + * @param optimize + * the flag of optimizing huffman tables. */ public void setOptimizeHuffmanTables(boolean optimize) { optimizeHuffmanTables = optimize; } /** - * Returns true if the writer generates optimized Huffman tables, - * false otherwise. + * Returns true if the writer generates optimized Huffman tables, false + * otherwise. * - * @return the true if the writer generates optimized Huffman tables, - * false otherwise. + * @return true, if the writer generates optimized Huffman tables, false + * otherwise. */ public boolean getOptimizeHuffmanTables() { return optimizeHuffmanTables; diff --git a/awt/javax/imageio/plugins/jpeg/JPEGQTable.java b/awt/javax/imageio/plugins/jpeg/JPEGQTable.java index 0c5b37edce197cc0f46e6ab5c998a4cba626ca61..3461d466986cf6de0b36bc0613dc4780f11c87a4 100644 --- a/awt/javax/imageio/plugins/jpeg/JPEGQTable.java +++ b/awt/javax/imageio/plugins/jpeg/JPEGQTable.java @@ -18,88 +18,92 @@ * @author Rustem V. Rafikov * @version $Revision: 1.3 $ */ + package javax.imageio.plugins.jpeg; /** - * The JPEGQTable class represents a single JPEG quantization table - * and provides for the standard tables taken from the JPEG specification. + * The JPEGQTable class represents a single JPEG quantization table and provides + * for the standard tables taken from the JPEG specification. + * + * @since Android 1.0 */ public class JPEGQTable { - /** The Constant SIZE. */ + /** + * The Constant SIZE. + */ private final static int SIZE = 64; - - /** The Constant BASELINE_MAX. */ + + /** + * The Constant BASELINE_MAX. + */ private final static int BASELINE_MAX = 255; - - /** The Constant MAX. */ - private final static int MAX = 32767; + /** + * The Constant MAX. + */ + private final static int MAX = 32767; - /** The table. */ + /** + * The table. + */ private int[] theTable; /* - * K1 & K2 tables can be found in the JPEG format specification - * at http://www.w3.org/Graphics/JPEG/itu-t81.pdf + * K1 & K2 tables can be found in the JPEG format specification at + * http://www.w3.org/Graphics/JPEG/itu-t81.pdf */ - /** The Constant K1LumTable. */ + /** + * The Constant K1LumTable. + */ private static final int[] K1LumTable = new int[] { - 16, 11, 10, 16, 24, 40, 51, 61, - 12, 12, 14, 19, 26, 58, 60, 55, - 14, 13, 16, 24, 40, 57, 69, 56, - 14, 17, 22, 29, 51, 87, 80, 62, - 18, 22, 37, 56, 68, 109, 103, 77, - 24, 35, 55, 64, 81, 104, 113, 92, - 49, 64, 78, 87, 103, 121, 120, 101, - 72, 92, 95, 98, 112, 100, 103, 99 + 16, 11, 10, 16, 24, 40, 51, 61, 12, 12, 14, 19, 26, 58, 60, 55, 14, 13, 16, 24, 40, 57, + 69, 56, 14, 17, 22, 29, 51, 87, 80, 62, 18, 22, 37, 56, 68, 109, 103, 77, 24, 35, 55, + 64, 81, 104, 113, 92, 49, 64, 78, 87, 103, 121, 120, 101, 72, 92, 95, 98, 112, 100, + 103, 99 }; - /** The Constant K2ChrTable. */ + /** + * The Constant K2ChrTable. + */ private static final int[] K2ChrTable = new int[] { - 17, 18, 24, 47, 99, 99, 99, 99, - 18, 21, 26, 66, 99, 99, 99, 99, - 24, 26, 56, 99, 99, 99, 99, 99, - 47, 66, 99, 99, 99, 99, 99, 99, - 99, 99, 99, 99, 99, 99, 99, 99, - 99, 99, 99, 99, 99, 99, 99, 99, - 99, 99, 99, 99, 99, 99, 99, 99, - 99, 99, 99, 99, 99, 99, 99, 99 + 17, 18, 24, 47, 99, 99, 99, 99, 18, 21, 26, 66, 99, 99, 99, 99, 24, 26, 56, 99, 99, 99, + 99, 99, 47, 66, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, + 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99 }; - /** - * The K1Luminance indicates standart table K.1 from JPEG - * specification and produces "good" quality output. + /** + * The K1Luminance indicates standard table K.1 from JPEG specification and + * produces "good" quality output. */ public static final JPEGQTable K1Luminance = new JPEGQTable(K1LumTable); - - /** - * The K1Div2Luminance indicates K.1 table from JPEG - * specification with all elements divided by 2 and produces - * "very good" quality output. + + /** + * The K1Div2Luminance indicates K.1 table from JPEG specification with all + * elements divided by 2 and produces "very good" quality output. */ public static final JPEGQTable K1Div2Luminance = K1Luminance.getScaledInstance(0.5f, true); - - /** - * The K2Chrominance indicates K.2 table from JPEG - * specification and produces "good" quality output. + + /** + * The K2Chrominance indicates K.2 table from JPEG specification and + * produces "good" quality output. */ public static final JPEGQTable K2Chrominance = new JPEGQTable(K2ChrTable); - - /** + + /** * The Constant K2Div2Chrominance indicates K.2 table from JPEG - * specification with all elements divided by 2 and produces - * "very good" quality output. + * specification with all elements divided by 2 and produces "very good" + * quality output. */ public static final JPEGQTable K2Div2Chrominance = K2Chrominance.getScaledInstance(0.5f, true);; - /** - * Instantiates a new JPEGQTable from the array, which - * should contain 64 elements in natural order. + * Instantiates a new JPEGQTable from the array, which should contain 64 + * elements in natural order. * - * @param table the quantization table. + * @param table + * the quantization table. */ public JPEGQTable(int[] table) { if (table == null) { @@ -112,23 +116,22 @@ public class JPEGQTable { } /** - * Gets the current quantization table as an array of int values. + * Gets the current quantization table as an array of integer values. * - * @return the current quantization table as an array of int values. + * @return the current quantization table as an array of integer values. */ public int[] getTable() { return theTable.clone(); } /** - * Gets the scaled instance as quantization table where - * the values are multiplied by the scaleFactor and then clamped - * if forceBaseline is true. - * - * @param scaleFactor the scale factor of table. - * @param forceBaseline the force baseline flag, the values - * should be clamped if true. + * Gets the scaled instance as quantization table where the values are + * multiplied by the scaleFactor and then clamped if forceBaseline is true. * + * @param scaleFactor + * the scale factor of table. + * @param forceBaseline + * the force baseline flag, the values should be clamped if true. * @return the new quantization table. */ public JPEGQTable getScaledInstance(float scaleFactor, boolean forceBaseline) { @@ -156,7 +159,7 @@ public class JPEGQTable { */ @Override public String toString() { - //-- TODO more informative info + // -- TODO more informative info return "JPEGQTable"; } } diff --git a/awt/javax/imageio/plugins/jpeg/package.html b/awt/javax/imageio/plugins/jpeg/package.html new file mode 100644 index 0000000000000000000000000000000000000000..14575c417c2c15a2777b5f5711cc484a1acc362e --- /dev/null +++ b/awt/javax/imageio/plugins/jpeg/package.html @@ -0,0 +1,8 @@ + + +

    + This package contains auxiliary classes for the built-in JPEG image plug-in. +

    + @since Android 1.0 + + diff --git a/awt/javax/imageio/spi/IIORegistry.java b/awt/javax/imageio/spi/IIORegistry.java index 3c1c989db3403f0f8a7eb3324b8c085edec34566..01ddeaafeea4a41355266a6d4409b4ec29e55808 100644 --- a/awt/javax/imageio/spi/IIORegistry.java +++ b/awt/javax/imageio/spi/IIORegistry.java @@ -18,6 +18,7 @@ * @author Rustem V. Rafikov * @version $Revision: 1.3 $ */ + package javax.imageio.spi; import java.util.Arrays; @@ -39,37 +40,41 @@ import org.apache.harmony.x.imageio.spi.RAFIOSSpi; */ /** - * The IIORegistry class registers service provider instances - * (SPI). Service provider instances are recognized by specific - * meta-information in the JAR files containing them. The JAR - * files with SPI classes are loaded from the application class - * path. + * The IIORegistry class registers service provider instances (SPI). Service + * provider instances are recognized by specific meta-information in the JAR + * files containing them. The JAR files with SPI classes are loaded from the + * application class path. + * + * @since Android 1.0 */ public final class IIORegistry extends ServiceRegistry { - /** The instance. */ + /** + * The instance. + */ private static IIORegistry instance; - /** The Constant CATEGORIES. */ + /** + * The Constant CATEGORIES. + */ private static final Class[] CATEGORIES = new Class[] { - javax.imageio.spi.ImageWriterSpi.class, - javax.imageio.spi.ImageReaderSpi.class, - javax.imageio.spi.ImageInputStreamSpi.class, - //javax.imageio.spi.ImageTranscoderSpi.class, - javax.imageio.spi.ImageOutputStreamSpi.class + javax.imageio.spi.ImageWriterSpi.class, javax.imageio.spi.ImageReaderSpi.class, + javax.imageio.spi.ImageInputStreamSpi.class, + // javax.imageio.spi.ImageTranscoderSpi.class, + javax.imageio.spi.ImageOutputStreamSpi.class }; /** - * Instantiates a new iIO registry. + * Instantiates a new IIO registry. */ private IIORegistry() { - super(Arrays.>asList(CATEGORIES).iterator()); + super(Arrays.> asList(CATEGORIES).iterator()); registerBuiltinSpis(); registerApplicationClasspathSpis(); } /** - * Register builtin spis. + * Register built-in SPIs. */ private void registerBuiltinSpis() { registerServiceProvider(new JPEGImageWriterSpi()); @@ -80,9 +85,9 @@ public final class IIORegistry extends ServiceRegistry { registerServiceProvider(new FileIISSpi()); registerServiceProvider(new RAFIOSSpi()); registerServiceProvider(new RAFIISSpi()); - registerServiceProvider(new OutputStreamIOSSpi()); + registerServiceProvider(new OutputStreamIOSSpi()); registerServiceProvider(new InputStreamIISSpi()); - //-- TODO implement + // -- TODO implement } /** @@ -91,7 +96,8 @@ public final class IIORegistry extends ServiceRegistry { * @return the default IIORegistry instance. */ public static IIORegistry getDefaultInstance() { - // TODO implement own instance for each ThreadGroup (see also ThreadLocal) + // TODO implement own instance for each ThreadGroup (see also + // ThreadLocal) synchronized (IIORegistry.class) { if (instance == null) { instance = new IIORegistry(); @@ -101,10 +107,9 @@ public final class IIORegistry extends ServiceRegistry { } /** - * Registers all service providers from the application class - * path. + * Registers all service providers from the application class path. */ public void registerApplicationClasspathSpis() { - //-- TODO implement for non-builtin plugins + // -- TODO implement for non-builtin plugins } } diff --git a/awt/javax/imageio/spi/IIOServiceProvider.java b/awt/javax/imageio/spi/IIOServiceProvider.java index f5873bfb4fab74c278afca8e4e2337f948d5ab27..e9476773ae6970b9f55a919c579254dfb0806552 100644 --- a/awt/javax/imageio/spi/IIOServiceProvider.java +++ b/awt/javax/imageio/spi/IIOServiceProvider.java @@ -18,27 +18,36 @@ * @author Rustem V. Rafikov * @version $Revision: 1.3 $ */ + package javax.imageio.spi; import java.util.Locale; /** - * The IIOServiceProvider abstract class provides base functionality - * for imageio service provider interfaces (SPIs). + * The IIOServiceProvider abstract class provides base functionality for ImageIO + * service provider interfaces (SPIs). + * + * @since Android 1.0 */ public abstract class IIOServiceProvider implements RegisterableService { - /** The vendor name of this service provider. */ + /** + * The vendor name of this service provider. + */ protected String vendorName; - - /** The version of this service provider. */ + + /** + * The version of this service provider. + */ protected String version; /** * Instantiates a new IIOServiceProvider. * - * @param vendorName the vendor name of service provider. - * @param version the version of service provider. + * @param vendorName + * the vendor name of service provider. + * @param version + * the version of service provider. */ public IIOServiceProvider(String vendorName, String version) { if (vendorName == null) { @@ -85,12 +94,11 @@ public abstract class IIOServiceProvider implements RegisterableService { } /** - * Gets a description of this service provider. - * The result string should be localized for the specified - * Locale. - * - * @param locale the specified Locale. + * Gets a description of this service provider. The result string should be + * localized for the specified Locale. * + * @param locale + * the specified Locale. * @return the description of this service provider. */ public abstract String getDescription(Locale locale); diff --git a/awt/javax/imageio/spi/ImageInputStreamSpi.java b/awt/javax/imageio/spi/ImageInputStreamSpi.java index 47d210a8426d1b89f84c838213a1d59090f61ea6..fc859a87197ccda42b912166a8d7c9cdbb0c881b 100644 --- a/awt/javax/imageio/spi/ImageInputStreamSpi.java +++ b/awt/javax/imageio/spi/ImageInputStreamSpi.java @@ -18,6 +18,7 @@ * @author Rustem V. Rafikov * @version $Revision: 1.3 $ */ + package javax.imageio.spi; import java.io.File; @@ -25,13 +26,16 @@ import java.io.IOException; import javax.imageio.stream.ImageInputStream; /** - * The ImageInputStreamSpi abstract class is a service provider - * interface (SPI) for ImageInputStreams. + * The ImageInputStreamSpi abstract class is a service provider interface (SPI) + * for ImageInputStreams. + * + * @since Android 1.0 */ -public abstract class ImageInputStreamSpi extends IIOServiceProvider implements - RegisterableService { - - /** The input class. */ +public abstract class ImageInputStreamSpi extends IIOServiceProvider implements RegisterableService { + + /** + * The input class. + */ protected Class inputClass; /** @@ -44,9 +48,12 @@ public abstract class ImageInputStreamSpi extends IIOServiceProvider implements /** * Instantiates a new ImageInputStreamSpi. * - * @param vendorName the vendor name. - * @param version the version. - * @param inputClass the input class. + * @param vendorName + * the vendor name. + * @param version + * the version. + * @param inputClass + * the input class. */ public ImageInputStreamSpi(String vendorName, String version, Class inputClass) { super(vendorName, version); @@ -54,8 +61,8 @@ public abstract class ImageInputStreamSpi extends IIOServiceProvider implements } /** - * Gets an input Class object that represents class or - * interface that must be implemented by an input source. + * Gets an input Class object that represents class or interface that must + * be implemented by an input source. * * @return the input class. */ @@ -64,61 +71,59 @@ public abstract class ImageInputStreamSpi extends IIOServiceProvider implements } /** - * Returns true if the ImageInputStream can use a cache - * file. If this method returns false, the value of the - * useCache parameter of createInputStreamInstance will - * be ignored. The default implementation returns false. + * Returns true if the ImageInputStream can use a cache file. If this method + * returns false, the value of the useCache parameter of + * createInputStreamInstance will be ignored. The default implementation + * returns false. * - * @return true if the ImageInputStream can use a cache - * file, false otherwise. + * @return true, if the ImageInputStream can use a cache file, false + * otherwise. */ public boolean canUseCacheFile() { - return false; //-- def + return false; // -- def } /** - * Returns true if the ImageInputStream implementation - * requires the use of a cache file. The default implementation - * returns false. + * Returns true if the ImageInputStream implementation requires the use of a + * cache file. The default implementation returns false. * - * @return true if the ImageInputStream implementation - * requires the use of a cache file, false otherwise. + * @return true, if the ImageInputStream implementation requires the use of + * a cache file, false otherwise. */ public boolean needsCacheFile() { return false; // def } /** - * Creates the ImageInputStream associated with this - * service provider. The input object should - * be an instance of the class returned by th getInputClass - * method. This method uses the specified directory - * for the cache file if the useCache parameter is true. - * - * @param input the input Object. - * @param useCache the flag indicating if a cache file - * is needed or not. - * @param cacheDir the cache directory. + * Creates the ImageInputStream associated with this service provider. The + * input object should be an instance of the class returned by the + * getInputClass method. This method uses the specified directory for the + * cache file if the useCache parameter is true. * + * @param input + * the input Object. + * @param useCache + * the flag indicating if a cache file is needed or not. + * @param cacheDir + * the cache directory. * @return the ImageInputStream. - * - * @throws IOException Signals that an I/O exception has occurred. + * @throws IOException + * if an I/O exception has occurred. */ public abstract ImageInputStream createInputStreamInstance(Object input, boolean useCache, File cacheDir) throws IOException; /** - * Creates the ImageInputStream associated with this - * service provider. The input object should - * be an instance of the class returned by getInputClass - * method. This method uses the default system directory - * for the cache file, if it is needed. - * - * @param input the input Object. + * Creates the ImageInputStream associated with this service provider. The + * input object should be an instance of the class returned by getInputClass + * method. This method uses the default system directory for the cache file, + * if it is needed. * + * @param input + * the input Object. * @return the ImageInputStream. - * - * @throws IOException Signals that an I/O exception has occurred. + * @throws IOException + * if an I/O exception has occurred. */ public ImageInputStream createInputStreamInstance(Object input) throws IOException { return createInputStreamInstance(input, true, null); diff --git a/awt/javax/imageio/spi/ImageOutputStreamSpi.java b/awt/javax/imageio/spi/ImageOutputStreamSpi.java index d45e24cce6aec1d031e8d6237bf6760ec450f14c..b7a9a5c33322acf6ac7d84ccb693bf5864d8e6f8 100644 --- a/awt/javax/imageio/spi/ImageOutputStreamSpi.java +++ b/awt/javax/imageio/spi/ImageOutputStreamSpi.java @@ -18,6 +18,7 @@ * @author Rustem V. Rafikov * @version $Revision: 1.3 $ */ + package javax.imageio.spi; import javax.imageio.stream.ImageOutputStream; @@ -25,13 +26,17 @@ import java.io.IOException; import java.io.File; /** - * The ImageOutputStreamSpi abstract class is a service provider - * interface (SPI) for ImageOutputStreams. + * The ImageOutputStreamSpi abstract class is a service provider interface (SPI) + * for ImageOutputStreams. + * + * @since Android 1.0 */ public abstract class ImageOutputStreamSpi extends IIOServiceProvider implements RegisterableService { - - /** The output class. */ + + /** + * The output class. + */ protected Class outputClass; /** @@ -44,9 +49,12 @@ public abstract class ImageOutputStreamSpi extends IIOServiceProvider implements /** * Instantiates a new ImageOutputStreamSpi. * - * @param vendorName the vendor name. - * @param version the version. - * @param outputClass the output class. + * @param vendorName + * the vendor name. + * @param version + * the version. + * @param outputClass + * the output class. */ public ImageOutputStreamSpi(String vendorName, String version, Class outputClass) { super(vendorName, version); @@ -54,8 +62,8 @@ public abstract class ImageOutputStreamSpi extends IIOServiceProvider implements } /** - * Gets an output Class object that represents the class or - * interface that must be implemented by an output source. + * Gets an output Class object that represents the class or interface that + * must be implemented by an output source. * * @return the output class. */ @@ -64,63 +72,61 @@ public abstract class ImageOutputStreamSpi extends IIOServiceProvider implements } /** - * Returns true if the ImageOutputStream can use a cache - * file. If this method returns false, the value of the - * useCache parameter of createOutputStreamInstance will - * be ignored. The default implementation returns false. + * Returns true if the ImageOutputStream can use a cache file. If this + * method returns false, the value of the useCache parameter of + * createOutputStreamInstance will be ignored. The default implementation + * returns false. * - * @return true if the ImageOutputStream can use a cache - * file, false otherwise. + * @return true, if the ImageOutputStream can use a cache file, false + * otherwise. */ public boolean canUseCacheFile() { return false; // def } /** - * Returns true if the ImageOutputStream implementation - * requires the use of a cache file. The default implementation - * returns false. + * Returns true if the ImageOutputStream implementation requires the use of + * a cache file. The default implementation returns false. * - * @return true if the ImageOutputStream implementation - * requires the use of a cache file, false otherwise. + * @return true, if the ImageOutputStream implementation requires the use of + * a cache file, false otherwise. */ public boolean needsCacheFile() { return false; // def } /** - * Creates the ImageOutputStream associated with this - * service provider. The output object should - * be an instance of the class returned by getOutputClass - * method. This method uses the default system directory - * for the cache file, if it is needed. - * - * @param output the output Object. + * Creates the ImageOutputStream associated with this service provider. The + * output object should be an instance of the class returned by + * getOutputClass method. This method uses the default system directory for + * the cache file, if it is needed. * + * @param output + * the output Object. * @return the ImageOutputStream. - * - * @throws IOException Signals that an I/O exception has occurred. + * @throws IOException + * if an I/O exception has occurred. */ public ImageOutputStream createOutputStreamInstance(Object output) throws IOException { return createOutputStreamInstance(output, true, null); } /** - * Creates the ImageOutputStream associated with this - * service provider. The output object should - * be an instance of the class returned by getInputClass - * method. This method uses the specified directory - * for the cache file, if the useCache parameter is true. - * - * @param output the output Object. - * @param useCache the flag indicating if cache file - * is needed or not. - * @param cacheDir the cache directory. + * Creates the ImageOutputStream associated with this service provider. The + * output object should be an instance of the class returned by + * getInputClass method. This method uses the specified directory for the + * cache file, if the useCache parameter is true. * + * @param output + * the output Object. + * @param useCache + * the flag indicating if cache file is needed or not. + * @param cacheDir + * the cache directory. * @return the ImageOutputStream. - * - * @throws IOException Signals that an I/O exception has occurred. + * @throws IOException + * if an I/O exception has occurred. */ - public abstract ImageOutputStream createOutputStreamInstance(Object output, - boolean useCache, File cacheDir) throws IOException; + public abstract ImageOutputStream createOutputStreamInstance(Object output, boolean useCache, + File cacheDir) throws IOException; } diff --git a/awt/javax/imageio/spi/ImageReaderSpi.java b/awt/javax/imageio/spi/ImageReaderSpi.java index 2e2484c462aa789fbd62fb71dc5a9034ae887bc2..0528d250b11d41d435b871262fd86dce2c74a925 100644 --- a/awt/javax/imageio/spi/ImageReaderSpi.java +++ b/awt/javax/imageio/spi/ImageReaderSpi.java @@ -18,6 +18,7 @@ * @author Rustem V. Rafikov * @version $Revision: 1.3 $ */ + package javax.imageio.spi; import javax.imageio.stream.ImageInputStream; @@ -25,20 +26,28 @@ import javax.imageio.ImageReader; import java.io.IOException; /** - * The ImageReaderSpi abstract class is a service provider - * interface (SPI) for ImageReaders. + * The ImageReaderSpi abstract class is a service provider interface (SPI) for + * ImageReaders. + * + * @since Android 1.0 */ public abstract class ImageReaderSpi extends ImageReaderWriterSpi { - /** - * The STANDARD_INPUT_TYPE contains ImageInputStream.class. + /** + * The STANDARD_INPUT_TYPE contains ImageInputStream.class. */ - public static final Class[] STANDARD_INPUT_TYPE = new Class[] {ImageInputStream.class}; + public static final Class[] STANDARD_INPUT_TYPE = new Class[] { + ImageInputStream.class + }; - /** The input types. */ + /** + * The input types. + */ protected Class[] inputTypes; - - /** The writer SPI names. */ + + /** + * The writer SPI names. + */ protected String[] writerSpiNames; /** @@ -51,49 +60,62 @@ public abstract class ImageReaderSpi extends ImageReaderWriterSpi { /** * Instantiates a new ImageReaderSpi. * - * @param vendorName the vendor name. - * @param version the version. - * @param names the format names. - * @param suffixes the array of strings representing the file suffixes. - * @param MIMETypes the an array of strings representing MIME types. - * @param pluginClassName the plugin class name. - * @param inputTypes the input types. - * @param writerSpiNames the array of strings with class names of all - * associated ImageWriters. - * @param supportsStandardStreamMetadataFormat the value indicating - * if stream metadata can be described by standart metadata format. - * @param nativeStreamMetadataFormatName the native stream metadata - * format name, returned by getNativeStreamMetadataFormatName. - * @param nativeStreamMetadataFormatClassName the native stream - * metadata format class name, returned by getNativeStreamMetadataFormat. - * @param extraStreamMetadataFormatNames the extra stream metadata - * format names, returned by getExtraStreamMetadataFormatNames. - * @param extraStreamMetadataFormatClassNames the extra stream metadata - * format class names, returned by getStreamMetadataFormat. - * @param supportsStandardImageMetadataFormat the value indicating - * if image metadata can be described by standart metadata format. - * @param nativeImageMetadataFormatName the native image metadata - * format name, returned by getNativeImageMetadataFormatName. - * @param nativeImageMetadataFormatClassName the native image - * metadata format class name, returned by getNativeImageMetadataFormat. - * @param extraImageMetadataFormatNames the extra image metadata - * format names, returned by getExtraImageMetadataFormatNames. - * @param extraImageMetadataFormatClassNames the extra image metadata - * format class names, returned by getImageMetadataFormat. + * @param vendorName + * the vendor name. + * @param version + * the version. + * @param names + * the format names. + * @param suffixes + * the array of strings representing the file suffixes. + * @param MIMETypes + * the an array of strings representing MIME types. + * @param pluginClassName + * the plug-in class name. + * @param inputTypes + * the input types. + * @param writerSpiNames + * the array of strings with class names of all associated + * ImageWriters. + * @param supportsStandardStreamMetadataFormat + * the value indicating if stream metadata can be described by + * standard metadata format. + * @param nativeStreamMetadataFormatName + * the native stream metadata format name, returned by + * getNativeStreamMetadataFormatName. + * @param nativeStreamMetadataFormatClassName + * the native stream metadata format class name, returned by + * getNativeStreamMetadataFormat. + * @param extraStreamMetadataFormatNames + * the extra stream metadata format names, returned by + * getExtraStreamMetadataFormatNames. + * @param extraStreamMetadataFormatClassNames + * the extra stream metadata format class names, returned by + * getStreamMetadataFormat. + * @param supportsStandardImageMetadataFormat + * the value indicating if image metadata can be described by + * standard metadata format. + * @param nativeImageMetadataFormatName + * the native image metadata format name, returned by + * getNativeImageMetadataFormatName. + * @param nativeImageMetadataFormatClassName + * the native image metadata format class name, returned by + * getNativeImageMetadataFormat. + * @param extraImageMetadataFormatNames + * the extra image metadata format names, returned by + * getExtraImageMetadataFormatNames. + * @param extraImageMetadataFormatClassNames + * the extra image metadata format class names, returned by + * getImageMetadataFormat. */ public ImageReaderSpi(String vendorName, String version, String[] names, String[] suffixes, - String[] MIMETypes, String pluginClassName, - Class[] inputTypes, String[] writerSpiNames, - boolean supportsStandardStreamMetadataFormat, - String nativeStreamMetadataFormatName, - String nativeStreamMetadataFormatClassName, - String[] extraStreamMetadataFormatNames, - String[] extraStreamMetadataFormatClassNames, - boolean supportsStandardImageMetadataFormat, - String nativeImageMetadataFormatName, - String nativeImageMetadataFormatClassName, - String[] extraImageMetadataFormatNames, - String[] extraImageMetadataFormatClassNames) { + String[] MIMETypes, String pluginClassName, Class[] inputTypes, + String[] writerSpiNames, boolean supportsStandardStreamMetadataFormat, + String nativeStreamMetadataFormatName, String nativeStreamMetadataFormatClassName, + String[] extraStreamMetadataFormatNames, String[] extraStreamMetadataFormatClassNames, + boolean supportsStandardImageMetadataFormat, String nativeImageMetadataFormatName, + String nativeImageMetadataFormatClassName, String[] extraImageMetadataFormatNames, + String[] extraImageMetadataFormatClassNames) { super(vendorName, version, names, suffixes, MIMETypes, pluginClassName, supportsStandardStreamMetadataFormat, nativeStreamMetadataFormatName, nativeStreamMetadataFormatClassName, extraStreamMetadataFormatNames, @@ -109,8 +131,8 @@ public abstract class ImageReaderSpi extends ImageReaderWriterSpi { } /** - * Gets an array of Class objects whose types can be used - * as input for this reader. + * Gets an array of Class objects whose types can be used as input for this + * reader. * * @return the input types. */ @@ -119,66 +141,62 @@ public abstract class ImageReaderSpi extends ImageReaderWriterSpi { } /** - * Returns true if the format of source object is - * supported by this reader. + * Returns true if the format of source object is supported by this reader. * - * @param source the source object to be decoded - * (for example an ImageInputStream). - * - * @return true if the format of source object is - * supported by this reader, false otherwise. - * - * @throws IOException Signals that an I/O exception has occurred. + * @param source + * the source object to be decoded (for example an + * ImageInputStream). + * @return true, if the format of source object is supported by this reader, + * false otherwise. + * @throws IOException + * if an I/O exception has occurred. */ public abstract boolean canDecodeInput(Object source) throws IOException; /** - * Returns an instance of the ImageReader implementation for - * this service provider. + * Returns an instance of the ImageReader implementation for this service + * provider. * * @return the ImageReader. - * - * @throws IOException Signals that an I/O exception has occurred. + * @throws IOException + * if an I/O exception has occurred. */ public ImageReader createReaderInstance() throws IOException { return createReaderInstance(null); } /** - * Returns an instance of the ImageReader implementation for - * this service provider. - * - * @param extension the a plugin specific extension object, or null. + * Returns an instance of the ImageReader implementation for this service + * provider. * + * @param extension + * the a plug-in specific extension object, or null. * @return the ImageReader. - * - * @throws IOException Signals that an I/O exception has occurred. + * @throws IOException + * if an I/O exception has occurred. */ public abstract ImageReader createReaderInstance(Object extension) throws IOException; /** - * Checks whether or not the specified ImageReader object - * is an instance of the ImageReader associated with this - * service provider or not. - * - * @param reader the ImageReader. + * Checks whether or not the specified ImageReader object is an instance of + * the ImageReader associated with this service provider or not. * - * @return true, if the specified ImageReader object - * is an instance of the ImageReader associated with this - * service provider, false otherwise. + * @param reader + * the ImageReader. + * @return true, if the specified ImageReader object is an instance of the + * ImageReader associated with this service provider, false + * otherwise. */ public boolean isOwnReader(ImageReader reader) { throw new UnsupportedOperationException("Not supported yet"); } /** - * Gets an array of strings with names of the ImageWriterSpi - * classes that support the internal metadata representation - * used by the ImageReader of this service provider, or null if - * there are no such ImageWriters. + * Gets an array of strings with names of the ImageWriterSpi classes that + * support the internal metadata representation used by the ImageReader of + * this service provider, or null if there are no such ImageWriters. * - * @return an array of strings with names of the ImageWriterSpi - * classes. + * @return the array of strings with names of the ImageWriterSpi classes. */ public String[] getImageWriterSpiNames() { throw new UnsupportedOperationException("Not supported yet"); diff --git a/awt/javax/imageio/spi/ImageReaderWriterSpi.java b/awt/javax/imageio/spi/ImageReaderWriterSpi.java index b3c0f92fa064da3706b370a6f407153d67d2207d..9ca08b5ea08532edd1861a19ce014c5c8827fea4 100644 --- a/awt/javax/imageio/spi/ImageReaderWriterSpi.java +++ b/awt/javax/imageio/spi/ImageReaderWriterSpi.java @@ -18,6 +18,7 @@ * @author Rustem V. Rafikov * @version $Revision: 1.3 $ */ + package javax.imageio.spi; import org.apache.harmony.x.imageio.metadata.IIOMetadataUtils; @@ -25,97 +26,138 @@ import org.apache.harmony.x.imageio.metadata.IIOMetadataUtils; import javax.imageio.metadata.IIOMetadataFormat; /** - * The ImageReaderWriterSpi class is a superclass for the - * ImageReaderSpi and ImageWriterSpi SPIs. + * The ImageReaderWriterSpi class is a superclass for the ImageReaderSpi and + * ImageWriterSpi SPIs. + * + * @since Android 1.0 */ -public abstract class ImageReaderWriterSpi extends IIOServiceProvider - implements RegisterableService { +public abstract class ImageReaderWriterSpi extends IIOServiceProvider implements + RegisterableService { - /** The names. */ + /** + * The names. + */ protected String[] names; - - /** The suffixes. */ + + /** + * The suffixes. + */ protected String[] suffixes; - - /** The MIME types. */ + + /** + * The MIME types. + */ protected String[] MIMETypes; - - /** The plugin class name. */ + + /** + * The plug-in class name. + */ protected String pluginClassName; - - /** Whether the reader/writer supports standard stream metadata format. */ + + /** + * Whether the reader/writer supports standard stream metadata format. + */ protected boolean supportsStandardStreamMetadataFormat; - - /** The native stream metadata format name. */ + + /** + * The native stream metadata format name. + */ protected String nativeStreamMetadataFormatName; - - /** The native stream metadata format class name. */ + + /** + * The native stream metadata format class name. + */ protected String nativeStreamMetadataFormatClassName; - - /** The extra stream metadata format names. */ + + /** + * The extra stream metadata format names. + */ protected String[] extraStreamMetadataFormatNames; - - /** The extra stream metadata format class names. */ + + /** + * The extra stream metadata format class names. + */ protected String[] extraStreamMetadataFormatClassNames; - - /** Whether the reader/writer supports standard image metadata format. */ + + /** + * Whether the reader/writer supports standard image metadata format. + */ protected boolean supportsStandardImageMetadataFormat; - - /** The native image metadata format name. */ + + /** + * The native image metadata format name. + */ protected String nativeImageMetadataFormatName; - - /** The native image metadata format class name. */ + + /** + * The native image metadata format class name. + */ protected String nativeImageMetadataFormatClassName; - - /** The extra image metadata format names. */ + + /** + * The extra image metadata format names. + */ protected String[] extraImageMetadataFormatNames; - - /** The extra image metadata format class names. */ + + /** + * The extra image metadata format class names. + */ protected String[] extraImageMetadataFormatClassNames; /** * Instantiates a new ImageReaderWriterSpi. * - * @param vendorName the vendor name. - * @param version the version. - * @param names the format names. - * @param suffixes the array of strings representing the file suffixes. - * @param MIMETypes the an array of strings representing MIME types. - * @param pluginClassName the plugin class name. - * @param supportsStandardStreamMetadataFormat the value indicating - * if stream metadata can be described by standart metadata format. - * @param nativeStreamMetadataFormatName the native stream metadata - * format name, returned by getNativeStreamMetadataFormatName. - * @param nativeStreamMetadataFormatClassName the native stream - * metadata format class name, returned by getNativeStreamMetadataFormat. - * @param extraStreamMetadataFormatNames the extra stream metadata - * format names, returned by getExtraStreamMetadataFormatNames. - * @param extraStreamMetadataFormatClassNames the extra stream metadata - * format class names, returned by getStreamMetadataFormat. - * @param supportsStandardImageMetadataFormat the value indicating - * if image metadata can be described by standard metadata format. - * @param nativeImageMetadataFormatName the native image metadata - * format name, returned by getNativeImageMetadataFormatName. - * @param nativeImageMetadataFormatClassName the native image - * metadata format class name, returned by getNativeImageMetadataFormat. - * @param extraImageMetadataFormatNames the extra image metadata - * format names, returned by getExtraImageMetadataFormatNames. - * @param extraImageMetadataFormatClassNames the extra image metadata - * format class names, returned by getImageMetadataFormat. + * @param vendorName + * the vendor name. + * @param version + * the version. + * @param names + * the format names. + * @param suffixes + * the array of strings representing the file suffixes. + * @param MIMETypes + * the an array of strings representing MIME types. + * @param pluginClassName + * the plug-in class name. + * @param supportsStandardStreamMetadataFormat + * the value indicating if stream metadata can be described by + * standard metadata format. + * @param nativeStreamMetadataFormatName + * the native stream metadata format name, returned by + * getNativeStreamMetadataFormatName. + * @param nativeStreamMetadataFormatClassName + * the native stream metadata format class name, returned by + * getNativeStreamMetadataFormat. + * @param extraStreamMetadataFormatNames + * the extra stream metadata format names, returned by + * getExtraStreamMetadataFormatNames. + * @param extraStreamMetadataFormatClassNames + * the extra stream metadata format class names, returned by + * getStreamMetadataFormat. + * @param supportsStandardImageMetadataFormat + * the value indicating if image metadata can be described by + * standard metadata format. + * @param nativeImageMetadataFormatName + * the native image metadata format name, returned by + * getNativeImageMetadataFormatName. + * @param nativeImageMetadataFormatClassName + * the native image metadata format class name, returned by + * getNativeImageMetadataFormat. + * @param extraImageMetadataFormatNames + * the extra image metadata format names, returned by + * getExtraImageMetadataFormatNames. + * @param extraImageMetadataFormatClassNames + * the extra image metadata format class names, returned by + * getImageMetadataFormat. */ public ImageReaderWriterSpi(String vendorName, String version, String[] names, - String[] suffixes, String[] MIMETypes, - String pluginClassName, - boolean supportsStandardStreamMetadataFormat, - String nativeStreamMetadataFormatName, - String nativeStreamMetadataFormatClassName, - String[] extraStreamMetadataFormatNames, - String[] extraStreamMetadataFormatClassNames, - boolean supportsStandardImageMetadataFormat, - String nativeImageMetadataFormatName, - String nativeImageMetadataFormatClassName, - String[] extraImageMetadataFormatNames, - String[] extraImageMetadataFormatClassNames) { + String[] suffixes, String[] MIMETypes, String pluginClassName, + boolean supportsStandardStreamMetadataFormat, String nativeStreamMetadataFormatName, + String nativeStreamMetadataFormatClassName, String[] extraStreamMetadataFormatNames, + String[] extraStreamMetadataFormatClassNames, + boolean supportsStandardImageMetadataFormat, String nativeImageMetadataFormatName, + String nativeImageMetadataFormatClassName, String[] extraImageMetadataFormatNames, + String[] extraImageMetadataFormatClassNames) { super(vendorName, version); if (names == null || names.length == 0) { @@ -137,60 +179,54 @@ public abstract class ImageReaderWriterSpi extends IIOServiceProvider this.nativeStreamMetadataFormatName = nativeStreamMetadataFormatName; this.nativeStreamMetadataFormatClassName = nativeStreamMetadataFormatClassName; - this.extraStreamMetadataFormatNames = - extraStreamMetadataFormatNames == null ? - null : extraStreamMetadataFormatNames.clone(); + this.extraStreamMetadataFormatNames = extraStreamMetadataFormatNames == null ? null + : extraStreamMetadataFormatNames.clone(); - this.extraStreamMetadataFormatClassNames = - extraStreamMetadataFormatClassNames == null ? - null : extraStreamMetadataFormatClassNames.clone(); + this.extraStreamMetadataFormatClassNames = extraStreamMetadataFormatClassNames == null ? null + : extraStreamMetadataFormatClassNames.clone(); this.supportsStandardImageMetadataFormat = supportsStandardImageMetadataFormat; this.nativeImageMetadataFormatName = nativeImageMetadataFormatName; this.nativeImageMetadataFormatClassName = nativeImageMetadataFormatClassName; - this.extraImageMetadataFormatNames = - extraImageMetadataFormatNames == null ? - null : extraImageMetadataFormatNames.clone(); + this.extraImageMetadataFormatNames = extraImageMetadataFormatNames == null ? null + : extraImageMetadataFormatNames.clone(); - this.extraImageMetadataFormatClassNames = - extraImageMetadataFormatClassNames == null ? - null : extraImageMetadataFormatClassNames.clone(); + this.extraImageMetadataFormatClassNames = extraImageMetadataFormatClassNames == null ? null + : extraImageMetadataFormatClassNames.clone(); } /** * Instantiates a new ImageReaderWriterSpi. */ - public ImageReaderWriterSpi() {} + public ImageReaderWriterSpi() { + } /** - * Gets an array of strings representing names of the formats - * that can be used by the ImageReader - * or ImageWriter implementation associated with this service - * provider. + * Gets an array of strings representing names of the formats that can be + * used by the ImageReader or ImageWriter implementation associated with + * this service provider. * - * @return an array of supported format names. + * @return the array of supported format names. */ public String[] getFormatNames() { return names.clone(); } /** - * Gets an array of strings representing file suffixes - * associated with the formats that can be used by the - * ImageReader or ImageWriter implementation of this - * service provider. + * Gets an array of strings representing file suffixes associated with the + * formats that can be used by the ImageReader or ImageWriter implementation + * of this service provider. * - * @return an array of file suffixes. + * @return the array of file suffixes. */ public String[] getFileSuffixes() { return suffixes == null ? null : suffixes.clone(); } /** - * Gets an array of strings with the names of - * additional formats of the image metadata objects - * produced or consumed by this plug-in. + * Gets an array of strings with the names of additional formats of the + * image metadata objects produced or consumed by this plug-in. * * @return the array of extra image metadata format names. */ @@ -199,52 +235,49 @@ public abstract class ImageReaderWriterSpi extends IIOServiceProvider } /** - * Gets an array of strings with the names of - * additional formats of the stream metadata objects - * produced or consumed by this plug-in. + * Gets an array of strings with the names of additional formats of the + * stream metadata objects produced or consumed by this plug-in. * * @return the array of extra stream metadata format names. */ public String[] getExtraStreamMetadataFormatNames() { - return extraStreamMetadataFormatNames == null ? null : extraStreamMetadataFormatNames.clone(); + return extraStreamMetadataFormatNames == null ? null : extraStreamMetadataFormatNames + .clone(); } /** - * Gets an IIOMetadataFormat object for the specified image - * metadata format name. - * - * @param formatName the format name. + * Gets an IIOMetadataFormat object for the specified image metadata format + * name. * + * @param formatName + * the format name. * @return the IIOMetadataFormat, or null. */ public IIOMetadataFormat getImageMetadataFormat(String formatName) { - return IIOMetadataUtils.instantiateMetadataFormat( - formatName, supportsStandardImageMetadataFormat, - nativeImageMetadataFormatName, nativeImageMetadataFormatClassName, - extraImageMetadataFormatNames, extraImageMetadataFormatClassNames - ); + return IIOMetadataUtils.instantiateMetadataFormat(formatName, + supportsStandardImageMetadataFormat, nativeImageMetadataFormatName, + nativeImageMetadataFormatClassName, extraImageMetadataFormatNames, + extraImageMetadataFormatClassNames); } /** - * Gets an IIOMetadataFormat object for the specified stream - * metadata format name. - * - * @param formatName the format name. + * Gets an IIOMetadataFormat object for the specified stream metadata format + * name. * + * @param formatName + * the format name. * @return the IIOMetadataFormat, or null. */ public IIOMetadataFormat getStreamMetadataFormat(String formatName) { - return IIOMetadataUtils.instantiateMetadataFormat( - formatName, supportsStandardStreamMetadataFormat, - nativeStreamMetadataFormatName, nativeStreamMetadataFormatClassName, - extraStreamMetadataFormatNames, extraStreamMetadataFormatClassNames - ); + return IIOMetadataUtils.instantiateMetadataFormat(formatName, + supportsStandardStreamMetadataFormat, nativeStreamMetadataFormatName, + nativeStreamMetadataFormatClassName, extraStreamMetadataFormatNames, + extraStreamMetadataFormatClassNames); } /** - * Gets an array of strings representing the MIME types - * of the formats that are supported by the - * ImageReader or ImageWriter implementation of this + * Gets an array of strings representing the MIME types of the formats that + * are supported by the ImageReader or ImageWriter implementation of this * service provider. * * @return the array MIME types. @@ -254,32 +287,30 @@ public abstract class ImageReaderWriterSpi extends IIOServiceProvider } /** - * Gets the name of the native image metadata format for - * this reader/writer, which allows for lossless encoding - * or decoding of the image metadata with the format. + * Gets the name of the native image metadata format for this reader/writer, + * which allows for lossless encoding or decoding of the image metadata with + * the format. * - * @return the string with native image metadata format name, - * or null. + * @return the string with native image metadata format name, or null. */ public String getNativeImageMetadataFormatName() { return nativeImageMetadataFormatName; } /** - * Gets the name of the native stream metadata format for - * this reader/writer, which allows for lossless encoding - * or decoding of the stream metadata with the format. + * Gets the name of the native stream metadata format for this + * reader/writer, which allows for lossless encoding or decoding of the + * stream metadata with the format. * - * @return the string with native stream metadata format name, - * or null. + * @return the string with native stream metadata format name, or null. */ public String getNativeStreamMetadataFormatName() { return nativeStreamMetadataFormatName; } /** - * Gets the class name of the ImageReader - * or ImageWriter associated with this service provider. + * Gets the class name of the ImageReader or ImageWriter associated with + * this service provider. * * @return the class name. */ @@ -288,26 +319,24 @@ public abstract class ImageReaderWriterSpi extends IIOServiceProvider } /** - * Checks if the standard metadata format is supported - * by the getAsTree and setFromTree methods for the - * image metadata objects produced or consumed by this - * reader or writer. + * Checks if the standard metadata format is supported by the getAsTree and + * setFromTree methods for the image metadata objects produced or consumed + * by this reader or writer. * - * @return true, if standard image metadata format is - * supported, false otherwise. + * @return true, if standard image metadata format is supported, false + * otherwise. */ public boolean isStandardImageMetadataFormatSupported() { return supportsStandardImageMetadataFormat; } /** - * Checks if the standard metadata format is supported - * by the getAsTree and setFromTree methods for the - * stream metadata objects produced or consumed by this - * reader or writer. + * Checks if the standard metadata format is supported by the getAsTree and + * setFromTree methods for the stream metadata objects produced or consumed + * by this reader or writer. * - * @return true, if standard stream metadata format is - * supported, false otherwise. + * @return true, if standard stream metadata format is supported, false + * otherwise. */ public boolean isStandardStreamMetadataFormatSupported() { return supportsStandardStreamMetadataFormat; diff --git a/awt/javax/imageio/spi/ImageTranscoderSpi.java b/awt/javax/imageio/spi/ImageTranscoderSpi.java index 68c4024f5c5d5dc9bb775dd6daeda812a3e27f90..742af190829976c1ea6920fccc0ec46b69db34bb 100644 --- a/awt/javax/imageio/spi/ImageTranscoderSpi.java +++ b/awt/javax/imageio/spi/ImageTranscoderSpi.java @@ -18,16 +18,18 @@ * @author Rustem V. Rafikov * @version $Revision: 1.3 $ */ + package javax.imageio.spi; import javax.imageio.ImageTranscoder; /** - * The ImageTranscoderSpi class is a service provider interface (SPI) - * for ImageTranscoders. + * The ImageTranscoderSpi class is a service provider interface (SPI) for + * ImageTranscoders. + * + * @since Android 1.0 */ -public abstract class ImageTranscoderSpi extends IIOServiceProvider - implements RegisterableService { +public abstract class ImageTranscoderSpi extends IIOServiceProvider implements RegisterableService { /** * Instantiates a new ImageTranscoderSpi. @@ -36,37 +38,37 @@ public abstract class ImageTranscoderSpi extends IIOServiceProvider } /** - * Instantiates a new ImageTranscoderSpi with the specified - * vendor name and version. + * Instantiates a new ImageTranscoderSpi with the specified vendor name and + * version. * - * @param vendorName the vendor name. - * @param version the version. + * @param vendorName + * the vendor name. + * @param version + * the version. */ public ImageTranscoderSpi(String vendorName, String version) { super(vendorName, version); } /** - * Gets the class name of an ImageReaderSpi that - * produces IIOMetadata objects that can be used as - * input to this transcoder. + * Gets the class name of an ImageReaderSpi that produces IIOMetadata + * objects that can be used as input to this transcoder. * * @return the class name of an ImageReaderSpi. */ public abstract String getReaderServiceProviderName(); /** - * Gets the class name of an ImageWriterSpi that - * produces IIOMetadata objects that can be used as - * input to this transcoder. + * Gets the class name of an ImageWriterSpi that produces IIOMetadata + * objects that can be used as input to this transcoder. * * @return the class name of an ImageWriterSpi. */ public abstract String getWriterServiceProviderName(); /** - * Creates an instance of the ImageTranscoder associated - * with this service provider. + * Creates an instance of the ImageTranscoder associated with this service + * provider. * * @return the ImageTranscoder instance. */ diff --git a/awt/javax/imageio/spi/ImageWriterSpi.java b/awt/javax/imageio/spi/ImageWriterSpi.java index 979ef77ce74cfe7df959d1abec793ae93d4d8707..bf25455920dc7d050559633a3168a73136b19fc1 100644 --- a/awt/javax/imageio/spi/ImageWriterSpi.java +++ b/awt/javax/imageio/spi/ImageWriterSpi.java @@ -18,6 +18,7 @@ * @author Rustem V. Rafikov * @version $Revision: 1.3 $ */ + package javax.imageio.spi; import javax.imageio.stream.ImageInputStream; @@ -27,18 +28,28 @@ import java.awt.image.RenderedImage; import java.io.IOException; /** - * The ImageWriterSpi abstract class is a service provider - * interface (SPI) for ImageWriters. + * The ImageWriterSpi abstract class is a service provider interface (SPI) for + * ImageWriters. + * + * @since Android 1.0 */ public abstract class ImageWriterSpi extends ImageReaderWriterSpi { - /** The STANDARD_OUTPUT_TYPE contains ImageInputStream.class. */ - public static final Class[] STANDARD_OUTPUT_TYPE = new Class[] {ImageInputStream.class}; + /** + * The STANDARD_OUTPUT_TYPE contains ImageInputStream.class. + */ + public static final Class[] STANDARD_OUTPUT_TYPE = new Class[] { + ImageInputStream.class + }; - /** The output types. */ + /** + * The output types. + */ protected Class[] outputTypes; - - /** The reader spi names. */ + + /** + * The reader SPI names. + */ protected String[] readerSpiNames; /** @@ -51,50 +62,62 @@ public abstract class ImageWriterSpi extends ImageReaderWriterSpi { /** * Instantiates a new ImageWriterSpi with the specified parameters. * - * @param vendorName the vendor name. - * @param version the version. - * @param names the format names. - * @param suffixes the array of strings representing the file suffixes. - * @param MIMETypes the an array of strings representing MIME types. - * @param pluginClassName the plugin class name. - * @param outputTypes the output types. - * @param readerSpiNames the array of strings with class names of all - * associated ImageReaders. - * @param supportsStandardStreamMetadataFormat the value indicating - * if stream metadata can be described by standard metadata format. - * @param nativeStreamMetadataFormatName the native stream metadata - * format name, returned by getNativeStreamMetadataFormatName. - * @param nativeStreamMetadataFormatClassName the native stream - * metadata format class name, returned by getNativeStreamMetadataFormat. - * @param extraStreamMetadataFormatNames the extra stream metadata - * format names, returned by getExtraStreamMetadataFormatNames. - * @param extraStreamMetadataFormatClassNames the extra stream metadata - * format class names, returned by getStreamMetadataFormat. - * @param supportsStandardImageMetadataFormat the value indicating - * if image metadata can be described by standard metadata format. - * @param nativeImageMetadataFormatName the native image metadata - * format name, returned by getNativeImageMetadataFormatName. - * @param nativeImageMetadataFormatClassName the native image - * metadata format class name, returned by getNativeImageMetadataFormat. - * @param extraImageMetadataFormatNames the extra image metadata - * format names, returned by getExtraImageMetadataFormatNames. - * @param extraImageMetadataFormatClassNames the extra image metadata - * format class names, returned by getImageMetadataFormat. + * @param vendorName + * the vendor name. + * @param version + * the version. + * @param names + * the format names. + * @param suffixes + * the array of strings representing the file suffixes. + * @param MIMETypes + * the an array of strings representing MIME types. + * @param pluginClassName + * the plug-in class name. + * @param outputTypes + * the output types. + * @param readerSpiNames + * the array of strings with class names of all associated + * ImageReaders. + * @param supportsStandardStreamMetadataFormat + * the value indicating if stream metadata can be described by + * standard metadata format. + * @param nativeStreamMetadataFormatName + * the native stream metadata format name, returned by + * getNativeStreamMetadataFormatName. + * @param nativeStreamMetadataFormatClassName + * the native stream metadata format class name, returned by + * getNativeStreamMetadataFormat. + * @param extraStreamMetadataFormatNames + * the extra stream metadata format names, returned by + * getExtraStreamMetadataFormatNames. + * @param extraStreamMetadataFormatClassNames + * the extra stream metadata format class names, returned by + * getStreamMetadataFormat. + * @param supportsStandardImageMetadataFormat + * the value indicating if image metadata can be described by + * standard metadata format. + * @param nativeImageMetadataFormatName + * the native image metadata format name, returned by + * getNativeImageMetadataFormatName. + * @param nativeImageMetadataFormatClassName + * the native image metadata format class name, returned by + * getNativeImageMetadataFormat. + * @param extraImageMetadataFormatNames + * the extra image metadata format names, returned by + * getExtraImageMetadataFormatNames. + * @param extraImageMetadataFormatClassNames + * the extra image metadata format class names, returned by + * getImageMetadataFormat. */ - public ImageWriterSpi(String vendorName, String version, String[] names, - String[] suffixes, String[] MIMETypes, - String pluginClassName, - Class[] outputTypes, String[] readerSpiNames, - boolean supportsStandardStreamMetadataFormat, - String nativeStreamMetadataFormatName, - String nativeStreamMetadataFormatClassName, - String[] extraStreamMetadataFormatNames, - String[] extraStreamMetadataFormatClassNames, - boolean supportsStandardImageMetadataFormat, - String nativeImageMetadataFormatName, - String nativeImageMetadataFormatClassName, - String[] extraImageMetadataFormatNames, - String[] extraImageMetadataFormatClassNames) { + public ImageWriterSpi(String vendorName, String version, String[] names, String[] suffixes, + String[] MIMETypes, String pluginClassName, Class[] outputTypes, + String[] readerSpiNames, boolean supportsStandardStreamMetadataFormat, + String nativeStreamMetadataFormatName, String nativeStreamMetadataFormatClassName, + String[] extraStreamMetadataFormatNames, String[] extraStreamMetadataFormatClassNames, + boolean supportsStandardImageMetadataFormat, String nativeImageMetadataFormatName, + String nativeImageMetadataFormatClassName, String[] extraImageMetadataFormatNames, + String[] extraImageMetadataFormatClassNames) { super(vendorName, version, names, suffixes, MIMETypes, pluginClassName, supportsStandardStreamMetadataFormat, nativeStreamMetadataFormatName, nativeStreamMetadataFormatClassName, extraStreamMetadataFormatNames, @@ -111,8 +134,8 @@ public abstract class ImageWriterSpi extends ImageReaderWriterSpi { } /** - * Returns true if the format of the writer's output is lossless. - * The default implementation returns true. + * Returns true if the format of the writer's output is lossless. The + * default implementation returns true. * * @return true, if a format is lossless, false otherwise. */ @@ -121,8 +144,8 @@ public abstract class ImageWriterSpi extends ImageReaderWriterSpi { } /** - * Gets an array of Class objects whose types - * can be used as output for this writer. + * Gets an array of Class objects whose types can be used as output for this + * writer. * * @return the output types. */ @@ -131,77 +154,72 @@ public abstract class ImageWriterSpi extends ImageReaderWriterSpi { } /** - * Checks whether or not the ImageWriter implementation associated - * with this service provider can encode an image with - * the specified type. - * - * @param type the ImageTypeSpecifier. + * Checks whether or not the ImageWriter implementation associated with this + * service provider can encode an image with the specified type. * - * @return true, if an image with the specified type can be - * encoded, false otherwise. + * @param type + * the ImageTypeSpecifier. + * @return true, if an image with the specified type can be encoded, false + * otherwise. */ public abstract boolean canEncodeImage(ImageTypeSpecifier type); /** - * Checks whether or not the ImageWriter implementation associated - * with this service provider can encode the specified RenderedImage. + * Checks whether or not the ImageWriter implementation associated with this + * service provider can encode the specified RenderedImage. * - * @param im the RenderedImage. - * - * @return true, if RenderedImage can be encoded, - * false otherwise. + * @param im + * the RenderedImage. + * @return true, if RenderedImage can be encoded, false otherwise. */ public boolean canEncodeImage(RenderedImage im) { return canEncodeImage(ImageTypeSpecifier.createFromRenderedImage(im)); } /** - * Returns an instance of the ImageWriter implementation for - * this service provider. + * Returns an instance of the ImageWriter implementation for this service + * provider. * * @return the ImageWriter. - * - * @throws IOException Signals that an I/O exception has occurred. + * @throws IOException + * if an I/O exception has occurred. */ public ImageWriter createWriterInstance() throws IOException { return createWriterInstance(null); } /** - * Returns an instance of the ImageWriter implementation for - * this service provider. - * - * @param extension the a plugin specific extension object, or null. + * Returns an instance of the ImageWriter implementation for this service + * provider. * + * @param extension + * the a plug-in specific extension object, or null. * @return the ImageWriter. - * - * @throws IOException Signals that an I/O exception has occurred. + * @throws IOException + * if an I/O exception has occurred. */ public abstract ImageWriter createWriterInstance(Object extension) throws IOException; /** - * Checks whether or not the specified ImageWriter object - * is an instance of the ImageWriter associated with this - * service provider or not. - * - * @param writer the ImageWriter. + * Checks whether or not the specified ImageWriter object is an instance of + * the ImageWriter associated with this service provider or not. * - * @return true, if the specified ImageWriter object - * is an instance of the ImageWriter associated with this - * service provider, false otherwise. + * @param writer + * the ImageWriter. + * @return true, if the specified ImageWriter object is an instance of the + * ImageWriter associated with this service provider, false + * otherwise. */ public boolean isOwnWriter(ImageWriter writer) { throw new UnsupportedOperationException("Not supported yet"); } /** - * Gets an array of strings with names of the ImageReaderSpi - * classes that support the internal metadata representation - * used by the ImageWriter of this service provider, or null if - * there are no such ImageReaders. + * Gets an array of strings with names of the ImageReaderSpi classes that + * support the internal metadata representation used by the ImageWriter of + * this service provider, or null if there are no such ImageReaders. * - * @return an array of strings with names of the ImageWriterSpi - * classes. + * @return the array of strings with names of the ImageWriterSpi classes. */ public String[] getImageReaderSpiNames() { return readerSpiNames; diff --git a/awt/javax/imageio/spi/RegisterableService.java b/awt/javax/imageio/spi/RegisterableService.java index b50754ef6cbdcfa5675da30bcec6e94a73d4d101..ae2f4d39f47b44d025214b98fdaccf490c47aac4 100644 --- a/awt/javax/imageio/spi/RegisterableService.java +++ b/awt/javax/imageio/spi/RegisterableService.java @@ -18,33 +18,37 @@ * @author Rustem V. Rafikov * @version $Revision: 1.3 $ */ + package javax.imageio.spi; /** - * The RegisterableService interface provides service provider - * objects that can be registered by a ServiceRegistry, and - * notifications that registration and deregistration have been - * performed. + * The RegisterableService interface provides service provider objects that can + * be registered by a ServiceRegistry, and notifications that registration and + * deregistration have been performed. + * + * @since Android 1.0 */ public interface RegisterableService { - + /** - * This method is called when the object which implements this - * interface is registered to the specified category of the - * specified registry. + * This method is called when the object which implements this interface is + * registered to the specified category of the specified registry. * - * @param registry the ServiceRegistry to be registered. - * @param category the class representing a category. + * @param registry + * the ServiceRegistry to be registered. + * @param category + * the class representing a category. */ void onRegistration(ServiceRegistry registry, Class category); - + /** - * This method is called when the object which implements this - * interface is deregistered to the specified category of the - * specified registry. + * This method is called when the object which implements this interface is + * deregistered to the specified category of the specified registry. * - * @param registry the ServiceRegistry to be registered. - * @param category the class representing a category. + * @param registry + * the ServiceRegistry to be registered. + * @param category + * the class representing a category. */ void onDeregistration(ServiceRegistry registry, Class category); } diff --git a/awt/javax/imageio/spi/ServiceRegistry.java b/awt/javax/imageio/spi/ServiceRegistry.java index 1a18b021e4bb059c742fce04a57d882014c87fb2..79b02a36644dd5803bcb2fa21acfb696e16a4b2e 100644 --- a/awt/javax/imageio/spi/ServiceRegistry.java +++ b/awt/javax/imageio/spi/ServiceRegistry.java @@ -18,48 +18,53 @@ * @author Rustem V. Rafikov * @version $Revision: 1.3 $ */ + package javax.imageio.spi; import java.util.*; import java.util.Map.Entry; /** - * The ServiceRegistry class provides ability to register, - * deregister, look up and obtain service provider instances (SPIs). - * A service means a set of interfaces and classes, and a service - * provider is an implementation of a service. Service providers can - * be associated with one or more categories. Each category is defined - * by a class or interface. Only a single instance of a each class is - * allowed to be registered as a category. + * The ServiceRegistry class provides ability to register, deregister, look up + * and obtain service provider instances (SPIs). A service means a set of + * interfaces and classes, and a service provider is an implementation of a + * service. Service providers can be associated with one or more categories. + * Each category is defined by a class or interface. Only a single instance of a + * each class is allowed to be registered as a category. + * + * @since Android 1.0 */ public class ServiceRegistry { - /** The categories. */ + /** + * The categories. + */ CategoriesMap categories = new CategoriesMap(this); /** * Instantiates a new ServiceRegistry with the specified categories. * - * @param categoriesIterator an Iterator of Class objects - * for defining of categories. + * @param categoriesIterator + * an Iterator of Class objects for defining of categories. */ public ServiceRegistry(Iterator> categoriesIterator) { if (null == categoriesIterator) { throw new IllegalArgumentException("categories iterator should not be NULL"); } - while(categoriesIterator.hasNext()) { - Class c = categoriesIterator.next(); + while (categoriesIterator.hasNext()) { + Class c = categoriesIterator.next(); categories.addCategory(c); } } /** - * Looks up and instantiates the available providers of this service using + * Looks up and instantiates the available providers of this service using * the specified class loader. * - * @param providerClass the Class object of the provider to be looked up. - * @param loader the class loader to be used. - * + * @param providerClass + * the Class object of the provider to be looked up. + * @param loader + * the class loader to be used. * @return the iterator of providers objects for this service. */ public static Iterator lookupProviders(Class providerClass, ClassLoader loader) { @@ -67,11 +72,11 @@ public class ServiceRegistry { } /** - * Looks up and instantiates the available providers of this service using + * Looks up and instantiates the available providers of this service using * the context class loader. * - * @param providerClass the Class object of the provider to be looked up. - * + * @param providerClass + * the Class object of the provider to be looked up. * @return the iterator of providers objects for this service. */ public static Iterator lookupProviders(Class providerClass) { @@ -79,14 +84,15 @@ public class ServiceRegistry { } /** - * Registers the specified service provider object in the - * specified categories. - * - * @param provider the specified provider to be registered. - * @param category the category. + * Registers the specified service provider object in the specified + * categories. * - * @return true if no provider of the same class is registered - * in this category, false otherwise. + * @param provider + * the specified provider to be registered. + * @param category + * the category. + * @return true, if no provider of the same class is registered in this + * category, false otherwise. */ public boolean registerServiceProvider(T provider, Class category) { return categories.addProvider(provider, category); @@ -95,7 +101,8 @@ public class ServiceRegistry { /** * Registers a list of service providers. * - * @param providers the list of service providers. + * @param providers + * the list of service providers. */ public void registerServiceProviders(Iterator providers) { for (Iterator iterator = providers; iterator.hasNext();) { @@ -104,67 +111,70 @@ public class ServiceRegistry { } /** - * Registers the specified service provider object in all - * categories. + * Registers the specified service provider object in all categories. * - * @param provider the service provider. + * @param provider + * the service provider. */ public void registerServiceProvider(Object provider) { categories.addProvider(provider, null); } /** - * Deregisters the specifies service provider from the - * specified category. + * Deregisters the specifies service provider from the specified category. * - * @param provider the service provider to be deregistered. - * @param category the specified category. - * - * @return true if the provider was already registered - * in the specified category, false otherwise. + * @param provider + * the service provider to be deregistered. + * @param category + * the specified category. + * @return true, if the provider was already registered in the specified + * category, false otherwise. */ public boolean deregisterServiceProvider(T provider, Class category) { throw new UnsupportedOperationException("Not supported yet"); } /** - * Deregisters the specified service provider from all - * categories. + * Deregisters the specified service provider from all categories. * - * @param provider the specified service provider. + * @param provider + * the specified service provider. */ public void deregisterServiceProvider(Object provider) { throw new UnsupportedOperationException("Not supported yet"); } /** - * Gets an Iterator of registered service providers - * in the specified category which satisfy the specified Filter. - * The useOrdering parameter indicates whether the iterator will - * return all of the server provider objects in a set order. - * - * @param category the specified category. - * @param filter the specified filter. - * @param useOrdering the flag indicating that providers are ordered - * in the returned Iterator. + * Gets an Iterator of registered service providers in the specified + * category which satisfy the specified Filter. The useOrdering parameter + * indicates whether the iterator will return all of the server provider + * objects in a set order. * + * @param category + * the specified category. + * @param filter + * the specified filter. + * @param useOrdering + * the flag indicating that providers are ordered in the returned + * Iterator. * @return the iterator of registered service providers. */ @SuppressWarnings("unchecked") public Iterator getServiceProviders(Class category, Filter filter, boolean useOrdering) { - return new FilteredIterator(filter, (Iterator)categories.getProviders(category, useOrdering)); + return new FilteredIterator(filter, (Iterator)categories.getProviders(category, + useOrdering)); } /** - * Gets an Iterator of all registered service providers - * in the specified category. The useOrdering parameter - * indicates whether the iterator will return all of the server - * provider objects in a set order. - * - * @param category the specified category. - * @param useOrdering the flag indicating that providers are ordered - * in the returned Iterator. + * Gets an Iterator of all registered service providers in the specified + * category. The useOrdering parameter indicates whether the iterator will + * return all of the server provider objects in a set order. * + * @param category + * the specified category. + * @param useOrdering + * the flag indicating that providers are ordered in the returned + * Iterator. * @return the Iterator of service providers. */ @SuppressWarnings("unchecked") @@ -173,11 +183,11 @@ public class ServiceRegistry { } /** - * Gets the registered service provider object that has the - * specified class type. - * - * @param providerClass the specified provider class. + * Gets the registered service provider object that has the specified class + * type. * + * @param providerClass + * the specified provider class. * @return the service provider object. */ public T getServiceProviderByClass(Class providerClass) { @@ -185,28 +195,32 @@ public class ServiceRegistry { } /** - * Sets an ordering between two service provider objects - * within the specified category. - * - * @param category the specified category. - * @param firstProvider the first provider. - * @param secondProvider the second provider. + * Sets an ordering between two service provider objects within the + * specified category. * - * @return true if a previously unset order was set. + * @param category + * the specified category. + * @param firstProvider + * the first provider. + * @param secondProvider + * the second provider. + * @return true, if a previously unset order was set. */ public boolean setOrdering(Class category, T firstProvider, T secondProvider) { throw new UnsupportedOperationException("Not supported yet"); } /** - * Unsets an ordering between two service provider objects - * within the specified category. - * - * @param category the specified category. - * @param firstProvider the first provider. - * @param secondProvider the second provider. + * Unsets an ordering between two service provider objects within the + * specified category. * - * @return true if a previously unset order was removed. + * @param category + * the specified category. + * @param firstProvider + * the first provider. + * @param secondProvider + * the second provider. + * @return true, if a previously unset order was removed. */ public boolean unsetOrdering(Class category, T firstProvider, T secondProvider) { throw new UnsupportedOperationException("Not supported yet"); @@ -215,7 +229,8 @@ public class ServiceRegistry { /** * Deregisters all providers from the specified category. * - * @param category the specified category. + * @param category + * the specified category. */ public void deregisterAll(Class category) { throw new UnsupportedOperationException("Not supported yet"); @@ -229,32 +244,31 @@ public class ServiceRegistry { } /** - * Finalizes this object. + * Finalizes this object. * - * @throws Throwable throws if an error occurs during - * finalization. + * @throws Throwable + * if an error occurs during finalization. */ @Override public void finalize() throws Throwable { - //TODO uncomment when deregisterAll is implemented - //deregisterAll(); + // TODO uncomment when deregisterAll is implemented + // deregisterAll(); } /** * Checks whether the specified provider has been already registered. * - * @param provider the provider to be checked. - * + * @param provider + * the provider to be checked. * @return true, if the specified provider has been already registered, - * false otherwise. + * false otherwise. */ public boolean contains(Object provider) { throw new UnsupportedOperationException("Not supported yet"); } /** - * Gets an iterator of Class objects representing the current - * categories. + * Gets an iterator of Class objects representing the current categories. * * @return the Iterator of Class objects. */ @@ -263,20 +277,22 @@ public class ServiceRegistry { } /** - * The ServiceRegistry.Filter interface is used by - * ServiceRegistry.getServiceProviders to filter providers according - * to the specified criterion. + * The ServiceRegistry.Filter interface is used by + * ServiceRegistry.getServiceProviders to filter providers according to the + * specified criterion. + * + * @since Android 1.0 */ public static interface Filter { - + /** - * Returns true if the specified provider satisfies the - * criterion of this Filter. + * Returns true if the specified provider satisfies the criterion of + * this Filter. * - * @param provider the provider. - * - * @return true if the specified provider satisfies the - * criterion of this Filter, false otherwise. + * @param provider + * the provider. + * @return true, if the specified provider satisfies the criterion of + * this Filter, false otherwise. */ boolean filter(Object provider); } @@ -285,30 +301,36 @@ public class ServiceRegistry { * The Class CategoriesMap. */ private static class CategoriesMap { - - /** The categories. */ + + /** + * The categories. + */ Map, ProvidersMap> categories = new HashMap, ProvidersMap>(); - /** The registry. */ + /** + * The registry. + */ ServiceRegistry registry; /** * Instantiates a new categories map. * - * @param registry the registry + * @param registry + * the registry. */ public CategoriesMap(ServiceRegistry registry) { this.registry = registry; } - //-- TODO: useOrdering + // -- TODO: useOrdering /** * Gets the providers. * - * @param category the category - * @param useOrdering the use ordering - * - * @return the providers + * @param category + * the category. + * @param useOrdering + * the use ordering. + * @return the providers. */ Iterator getProviders(Class category, boolean useOrdering) { ProvidersMap providers = categories.get(category); @@ -321,7 +343,7 @@ public class ServiceRegistry { /** * List. * - * @return the iterator< class> + * @return the iterator< class>. */ Iterator> list() { return categories.keySet().iterator(); @@ -330,7 +352,8 @@ public class ServiceRegistry { /** * Adds the category. * - * @param category the category + * @param category + * the category. */ void addCategory(Class category) { categories.put(category, new ProvidersMap()); @@ -341,10 +364,11 @@ public class ServiceRegistry { * null then the provider will be added to all categories * which the provider is assignable from. * - * @param provider provider to add - * @param category category to add provider to - * - * @return if there were such provider in some category + * @param provider + * provider to add. + * @param category + * category to add provider to. + * @return true, if there were such provider in some category. */ boolean addProvider(Object provider, Class category) { if (provider == null) { @@ -355,11 +379,11 @@ public class ServiceRegistry { if (category == null) { rt = findAndAdd(provider); } else { - rt = addToNamed(provider, category); + rt = addToNamed(provider, category); } if (provider instanceof RegisterableService) { - ((RegisterableService) provider).onRegistration(registry, category); + ((RegisterableService)provider).onRegistration(registry, category); } return rt; @@ -368,10 +392,11 @@ public class ServiceRegistry { /** * Adds the to named. * - * @param provider the provider - * @param category the category - * - * @return true, if successful + * @param provider + * the provider. + * @param category + * the category. + * @return true, if successful. */ private boolean addToNamed(Object provider, Class category) { Object obj = categories.get(category); @@ -380,15 +405,15 @@ public class ServiceRegistry { throw new IllegalArgumentException("Unknown category: " + category); } - return ((ProvidersMap) obj).addProvider(provider); + return ((ProvidersMap)obj).addProvider(provider); } /** * Find and add. * - * @param provider the provider - * - * @return true, if successful + * @param provider + * the provider. + * @return true, if successful. */ private boolean findAndAdd(Object provider) { boolean rt = false; @@ -405,17 +430,19 @@ public class ServiceRegistry { * The Class ProvidersMap. */ private static class ProvidersMap { - //-- TODO: providers ordering support + // -- TODO: providers ordering support - /** The providers. */ + /** + * The providers. + */ Map, Object> providers = new HashMap, Object>(); /** * Adds the provider. * - * @param provider the provider - * - * @return true, if successful + * @param provider + * the provider. + * @return true, if successful. */ boolean addProvider(Object provider) { return providers.put(provider.getClass(), provider) != null; @@ -424,19 +451,19 @@ public class ServiceRegistry { /** * Gets the provider classes. * - * @return the provider classes + * @return the provider classes. */ Iterator> getProviderClasses() { return providers.keySet().iterator(); } - //-- TODO ordering + // -- TODO ordering /** * Gets the providers. * - * @param userOrdering the user ordering - * - * @return the providers + * @param userOrdering + * the user ordering. + * @return the providers. */ Iterator getProviders(boolean userOrdering) { return providers.values().iterator(); @@ -448,20 +475,28 @@ public class ServiceRegistry { */ private static class FilteredIterator implements Iterator { - /** The filter. */ + /** + * The filter. + */ private Filter filter; - - /** The backend. */ + + /** + * The backend. + */ private Iterator backend; - - /** The next obj. */ + + /** + * The next obj. + */ private E nextObj; /** * Instantiates a new filtered iterator. * - * @param filter the filter - * @param backend the backend + * @param filter + * the filter. + * @param backend + * the backend. */ public FilteredIterator(Filter filter, Iterator backend) { this.filter = filter; @@ -472,7 +507,7 @@ public class ServiceRegistry { /** * Next. * - * @return the e + * @return the e. */ public E next() { if (nextObj == null) { @@ -486,7 +521,7 @@ public class ServiceRegistry { /** * Checks for next. * - * @return true, if successful + * @return true, if successful. */ public boolean hasNext() { return nextObj != null; @@ -500,7 +535,8 @@ public class ServiceRegistry { } /** - * Sets nextObj to a next provider matching the criterion given by the filter. + * Sets nextObj to a next provider matching the criterion given by the + * filter. */ private void findNext() { nextObj = null; diff --git a/awt/javax/imageio/spi/package.html b/awt/javax/imageio/spi/package.html new file mode 100644 index 0000000000000000000000000000000000000000..18ceff4860eabf07afbcfde1d3b92bf0c60fbf94 --- /dev/null +++ b/awt/javax/imageio/spi/package.html @@ -0,0 +1,8 @@ + + +

    + This package provides several Service Provider Interface (SPI) classes for readers, writers, transcoders and streams to handle images. +

    + @since Android 1.0 + + diff --git a/awt/javax/imageio/stream/FileCacheImageInputStream.java b/awt/javax/imageio/stream/FileCacheImageInputStream.java index 47bc1894cd8137425771471d900889c07bd2c66f..710ac6660e7626f90260b8fd1665130e5d60fecb 100644 --- a/awt/javax/imageio/stream/FileCacheImageInputStream.java +++ b/awt/javax/imageio/stream/FileCacheImageInputStream.java @@ -15,38 +15,43 @@ * limitations under the License. */ - package javax.imageio.stream; import java.io.*; /** - * The FileCacheImageInputStream class is an implementation of - * ImageInputStream which reads from its InputStream - * and uses a temporary file as a cache. + * The FileCacheImageInputStream class is an implementation of ImageInputStream + * which reads from its InputStream and uses a temporary file as a cache. + * + * @since Android 1.0 */ public class FileCacheImageInputStream extends ImageInputStreamImpl { - - /** The is. */ + + /** + * The is. + */ private InputStream is; - - /** The file. */ + + /** + * The file. + */ private File file; - - /** The raf. */ - private RandomAccessFile raf; + /** + * The raf. + */ + private RandomAccessFile raf; /** - * Instantiates a new FileCacheImageInputStream from - * the specified InputStream and using the specified - * File as its cache directory. - * - * @param stream the InputStream for reading. - * @param cacheDir the cache directory where the chache file - * will be created. + * Instantiates a new FileCacheImageInputStream from the specified + * InputStream and using the specified File as its cache directory. * - * @throws IOException Signals that an I/O exception has occurred. + * @param stream + * the InputStream for reading. + * @param cacheDir + * the cache directory where the cache file will be created. + * @throws IOException + * if an I/O exception has occurred. */ public FileCacheImageInputStream(InputStream stream, File cacheDir) throws IOException { if (stream == null) { @@ -55,7 +60,8 @@ public class FileCacheImageInputStream extends ImageInputStreamImpl { is = stream; if (cacheDir == null || cacheDir.isDirectory()) { - file = File.createTempFile(FileCacheImageOutputStream.IIO_TEMP_FILE_PREFIX, null, cacheDir); + file = File.createTempFile(FileCacheImageOutputStream.IIO_TEMP_FILE_PREFIX, null, + cacheDir); file.deleteOnExit(); } else { throw new IllegalArgumentException("Not a directory!"); diff --git a/awt/javax/imageio/stream/FileCacheImageOutputStream.java b/awt/javax/imageio/stream/FileCacheImageOutputStream.java index ae485854b3d849b48a21a195e4a3db332f054797..135afab3733e80747bb1f5d854358471b746ea2b 100644 --- a/awt/javax/imageio/stream/FileCacheImageOutputStream.java +++ b/awt/javax/imageio/stream/FileCacheImageOutputStream.java @@ -15,7 +15,6 @@ * limitations under the License. */ - package javax.imageio.stream; import java.io.IOException; @@ -24,35 +23,48 @@ import java.io.OutputStream; import java.io.RandomAccessFile; /** - * The FileCacheImageOutputStream class is an implementation of - * ImageOutputStream that writes to its OutputStream - * using a temporary file as a cache. + * The FileCacheImageOutputStream class is an implementation of + * ImageOutputStream that writes to its OutputStream using a temporary file as a + * cache. + * + * @since Android 1.0 */ public class FileCacheImageOutputStream extends ImageOutputStreamImpl { - - /** The Constant IIO_TEMP_FILE_PREFIX. */ + + /** + * The Constant IIO_TEMP_FILE_PREFIX. + */ static final String IIO_TEMP_FILE_PREFIX = "iioCache"; - - /** The Constant MAX_BUFFER_LEN. */ + + /** + * The Constant MAX_BUFFER_LEN. + */ static final int MAX_BUFFER_LEN = 1048575; // 1 MB - is it not too much? - /** The os. */ + /** + * The os. + */ private OutputStream os; - - /** The file. */ + + /** + * The file. + */ private File file; - - /** The raf. */ + + /** + * The raf. + */ private RandomAccessFile raf; /** * Instantiates a FileCacheImageOutputStream. * - * @param stream the OutputStream for writing. - * @param cacheDir the cache directory where the chache file - * will be created. - * - * @throws IOException Signals that an I/O exception has occurred. + * @param stream + * the OutputStream for writing. + * @param cacheDir + * the cache directory where the cache file will be created. + * @throws IOException + * if an I/O exception has occurred. */ public FileCacheImageOutputStream(OutputStream stream, File cacheDir) throws IOException { if (stream == null) { @@ -96,7 +108,7 @@ public class FileCacheImageOutputStream extends ImageOutputStreamImpl { @Override public void write(int b) throws IOException { flushBits(); // See the flushBits method description - + raf.write(b); streamPos++; } @@ -148,7 +160,7 @@ public class FileCacheImageOutputStream extends ImageOutputStreamImpl { } else { byte buffer[] = new byte[MAX_BUFFER_LEN]; while (bytesToRead > 0) { - int count = (int) Math.min(MAX_BUFFER_LEN, bytesToRead); + int count = (int)Math.min(MAX_BUFFER_LEN, bytesToRead); raf.readFully(buffer, 0, count); os.write(buffer, 0, count); bytesToRead -= count; @@ -169,7 +181,7 @@ public class FileCacheImageOutputStream extends ImageOutputStreamImpl { } raf.seek(pos); - streamPos = raf.getFilePointer(); + streamPos = raf.getFilePointer(); bitOffset = 0; } @@ -177,7 +189,7 @@ public class FileCacheImageOutputStream extends ImageOutputStreamImpl { public long length() { try { return raf.length(); - } catch(IOException e) { + } catch (IOException e) { return -1L; } } diff --git a/awt/javax/imageio/stream/FileImageInputStream.java b/awt/javax/imageio/stream/FileImageInputStream.java index 6680ae0a9738c5984e91cbfeec7c194ceb2e3b61..b9b6002b321da51ab3190e124aff6743bdff28c3 100644 --- a/awt/javax/imageio/stream/FileImageInputStream.java +++ b/awt/javax/imageio/stream/FileImageInputStream.java @@ -15,7 +15,6 @@ * limitations under the License. */ - package javax.imageio.stream; import java.io.IOException; @@ -24,24 +23,31 @@ import java.io.File; import java.io.FileNotFoundException; /** - * The FileImageInputStream class implements ImageInputStream - * and obtains its input data from a File or RandomAccessFile. + * The FileImageInputStream class implements ImageInputStream and obtains its + * input data from a File or RandomAccessFile. + * + * @since Android 1.0 */ public class FileImageInputStream extends ImageInputStreamImpl { - - /** The raf. */ + + /** + * The raf. + */ RandomAccessFile raf; /** * Instantiates a new FileImageInputStream from the specified File. * - * @param f the File of input data. - * - * @throws FileNotFoundException if the specified file - * doesn't exist. - * @throws IOException Signals that an I/O exception has occurred. + * @param f + * the File of input data. + * @throws FileNotFoundException + * if the specified file doesn't exist. + * @throws IOException + * if an I/O exception has occurred. */ - @SuppressWarnings({"DuplicateThrows"}) + @SuppressWarnings( { + "DuplicateThrows" + }) public FileImageInputStream(File f) throws FileNotFoundException, IOException { if (f == null) { throw new IllegalArgumentException("f == null!"); @@ -51,10 +57,11 @@ public class FileImageInputStream extends ImageInputStreamImpl { } /** - * Instantiates a new FileImageInputStream from the specified + * Instantiates a new FileImageInputStream from the specified * RandomAccessFile. * - * @param raf the RandomAccessFile of input data. + * @param raf + * the RandomAccessFile of input data. */ public FileImageInputStream(RandomAccessFile raf) { if (raf == null) { @@ -91,7 +98,7 @@ public class FileImageInputStream extends ImageInputStreamImpl { public long length() { try { return raf.length(); - } catch(IOException e) { + } catch (IOException e) { return -1L; } } diff --git a/awt/javax/imageio/stream/FileImageOutputStream.java b/awt/javax/imageio/stream/FileImageOutputStream.java index eaafe14e3db06376c1159568622bfbcb41017c09..2730ba6a971d595986126539a4ddfdfc4b3df4c2 100644 --- a/awt/javax/imageio/stream/FileImageOutputStream.java +++ b/awt/javax/imageio/stream/FileImageOutputStream.java @@ -18,39 +18,44 @@ * @author Rustem V. Rafikov * @version $Revision: 1.3 $ */ + package javax.imageio.stream; import java.io.*; /** - * The FileImageOutputStream class implements ImageOutputStream - * and writes the output data to a File or RandomAccessFile. + * The FileImageOutputStream class implements ImageOutputStream and writes the + * output data to a File or RandomAccessFile. + * + * @since Android 1.0 */ public class FileImageOutputStream extends ImageOutputStreamImpl { - /** The file. */ + /** + * The file. + */ RandomAccessFile file; /** - * Instantiates a new FileImageOutputStream with the specified - * File. - * - * @param f the output File. + * Instantiates a new FileImageOutputStream with the specified File. * - * @throws FileNotFoundException if the file not found. - * @throws IOException Signals that an I/O exception has occurred. + * @param f + * the output File. + * @throws FileNotFoundException + * if the file not found. + * @throws IOException + * if an I/O exception has occurred. */ public FileImageOutputStream(File f) throws FileNotFoundException, IOException { - this(f != null - ? new RandomAccessFile(f, "rw") - : null); + this(f != null ? new RandomAccessFile(f, "rw") : null); } /** * Instantiates a new FileImageOutputStream with the specified * RandomAccessFile. * - * @param raf the output RandomAccessFile. + * @param raf + * the output RandomAccessFile. */ public FileImageOutputStream(RandomAccessFile raf) { if (raf == null) { @@ -102,14 +107,14 @@ public class FileImageOutputStream extends ImageOutputStreamImpl { try { checkClosed(); return file.length(); - } catch(IOException e) { + } catch (IOException e) { return super.length(); // -1L } } @Override public void seek(long pos) throws IOException { - //-- checkClosed() is performed in super.seek() + // -- checkClosed() is performed in super.seek() super.seek(pos); file.seek(pos); streamPos = file.getFilePointer(); diff --git a/awt/javax/imageio/stream/IIOByteBuffer.java b/awt/javax/imageio/stream/IIOByteBuffer.java index 961a7b3ec7c029b9b595beb4e4713639cd23605b..867d80843d8315aec0bfa203136ee11227c20a1b 100644 --- a/awt/javax/imageio/stream/IIOByteBuffer.java +++ b/awt/javax/imageio/stream/IIOByteBuffer.java @@ -18,35 +18,46 @@ * @author Sergey I. Salishev * @version $Revision: 1.2 $ */ + package javax.imageio.stream; -/** -* @author Sergey I. Salishev -* @version $Revision: 1.2 $ -*/ +// +// @author Sergey I. Salishev +// @version $Revision: 1.2 $ +// /** - * The IIOByteBuffer class represents a byte array with offset and - * length that is used by ImageInputStream for obtaining a sequence - * of bytes. + * The IIOByteBuffer class represents a byte array with offset and length that + * is used by ImageInputStream for obtaining a sequence of bytes. + * + * @since Android 1.0 */ public class IIOByteBuffer { - - /** The data. */ + + /** + * The data. + */ private byte[] data; - - /** The offset. */ + + /** + * The offset. + */ private int offset; - - /** The length. */ + + /** + * The length. + */ private int length; /** * Instantiates a new IIOByteBuffer. * - * @param data the byte array. - * @param offset the offset in the array. - * @param length the length of array. + * @param data + * the byte array. + * @param offset + * the offset in the array. + * @param length + * the length of array. */ public IIOByteBuffer(byte[] data, int offset, int length) { this.data = data; @@ -84,7 +95,8 @@ public class IIOByteBuffer { /** * Sets the new data array to this IIOByteBuffer object. * - * @param data the new data array. + * @param data + * the new data array. */ public void setData(byte[] data) { this.data = data; @@ -93,7 +105,8 @@ public class IIOByteBuffer { /** * Sets the length of data which will be used. * - * @param length the new length. + * @param length + * the new length. */ public void setLength(int length) { this.length = length; @@ -102,10 +115,10 @@ public class IIOByteBuffer { /** * Sets the offset in the data array of this IIOByteBuffer. * - * @param offset the new offset. + * @param offset + * the new offset. */ public void setOffset(int offset) { this.offset = offset; } } - diff --git a/awt/javax/imageio/stream/ImageInputStream.java b/awt/javax/imageio/stream/ImageInputStream.java index 771e9ff96c47b861483ff5e9c387ac08a956c2d1..3dec5d2966911707bdab98307f57ec2da2ed41d6 100644 --- a/awt/javax/imageio/stream/ImageInputStream.java +++ b/awt/javax/imageio/stream/ImageInputStream.java @@ -18,6 +18,7 @@ * @author Rustem V. Rafikov * @version $Revision: 1.2 $ */ + package javax.imageio.stream; import java.io.DataInput; @@ -25,21 +26,24 @@ import java.io.IOException; import java.nio.ByteOrder; /** - * The ImageInputStream represents input stream interface that is - * used by ImageReaders. + * The ImageInputStream represents input stream interface that is used by + * ImageReaders. + * + * @since Android 1.0 */ public interface ImageInputStream extends DataInput { /** - * Sets the specified byte order for reading of data values - * from this stream. + * Sets the specified byte order for reading of data values from this + * stream. * - * @param byteOrder the byte order. + * @param byteOrder + * the byte order. */ void setByteOrder(ByteOrder byteOrder); /** - * Gets the byte order. + * Gets the byte order. * * @return the byte order. */ @@ -48,158 +52,151 @@ public interface ImageInputStream extends DataInput { /** * Reads a byte from the stream. * - * @return the byte of the stream, or -1 for EOF indicating. - * - * @throws IOException Signals that an I/O exception has occurred. + * @return the byte of the stream, or -1 for EOF indicating. + * @throws IOException + * if an I/O exception has occurred. */ int read() throws IOException; /** - * Reads number of bytes which is equal to the specified array's length - * and stores a result to this array. - * - * @param b the byte array. + * Reads number of bytes which is equal to the specified array's length and + * stores a result to this array. * + * @param b + * the byte array. * @return the number of read bytes, or -1 indicated EOF. - * - * @throws IOException Signals that an I/O exception has occurred. + * @throws IOException + * if an I/O exception has occurred. */ int read(byte[] b) throws IOException; /** - * Reads the number of bytes specified by len parameter from - * the stream and stores a result to the specified array - * with the specified offset. - * - * @param b the byte array. - * @param off the offset. - * @param len the number of bytes to be read. + * Reads the number of bytes specified by len parameter from the stream and + * stores a result to the specified array with the specified offset. * + * @param b + * the byte array. + * @param off + * the offset. + * @param len + * the number of bytes to be read. * @return the number of read bytes, or -1 indicated EOF. - * - * @throws IOException Signals that an I/O exception has occurred. + * @throws IOException + * if an I/O exception has occurred. */ int read(byte[] b, int off, int len) throws IOException; /** - * Reads the number of bytes specified by len parameter - * from the stream, and modifies the specified IIOByteBuffer - * with the byte array, offset, and length. - * - * @param buf the IIOByteBuffer. - * @param len the number of bytes to be read. + * Reads the number of bytes specified by len parameter from the stream, and + * modifies the specified IIOByteBuffer with the byte array, offset, and + * length. * - * @throws IOException Signals that an I/O exception has occurred. + * @param buf + * the IIOByteBuffer. + * @param len + * the number of bytes to be read. + * @throws IOException + * if an I/O exception has occurred. */ void readBytes(IIOByteBuffer buf, int len) throws IOException; /** - * Reads a byte from the stream and returns a boolean true value - * if it is non zero, false if it is zero. - * - * @return a boolean value for read byte. + * Reads a byte from the stream and returns a boolean true value if it is + * non zero, false if it is zero. * - * @throws IOException Signals that an I/O exception has occurred. + * @return the boolean value for read byte. + * @throws IOException + * if an I/O exception has occurred. */ boolean readBoolean() throws IOException; /** - * Reads a byte from the stream and returns its value - * as signed byte. + * Reads a byte from the stream and returns its value as signed byte. * - * @return a signed byte value for read byte. - * - * @throws IOException Signals that an I/O exception has occurred. + * @return the signed byte value for read byte. + * @throws IOException + * if an I/O exception has occurred. */ byte readByte() throws IOException; /** - * Reads a byte from the stream and returns its value - * as int. - * - * @return a unsigned byte value for read byte as int. + * Reads a byte from the stream and returns its value as an integer. * - * @throws IOException Signals that an I/O exception has occurred. + * @return the unsigned byte value for read byte as an integer. + * @throws IOException + * if an I/O exception has occurred. */ int readUnsignedByte() throws IOException; /** - * Reads 2 bytes from the stream, and returns the result - * as a short. + * Reads 2 bytes from the stream, and returns the result as a short. * * @return the signed short value from the stream. - * - * @throws IOException Signals that an I/O exception has occurred. + * @throws IOException + * if an I/O exception has occurred. */ short readShort() throws IOException; /** - * Reads 2 bytes from the stream and returns its value - * as an unsigned short. - * - * @return a unsigned short value coded in an int. + * Reads 2 bytes from the stream and returns its value as an unsigned short. * - * @throws IOException Signals that an I/O exception has occurred. + * @return a unsigned short value coded in an integer. + * @throws IOException + * if an I/O exception has occurred. */ int readUnsignedShort() throws IOException; /** - * Reads 2 bytes from the stream and returns their - * unsigned char value. + * Reads 2 bytes from the stream and returns their unsigned char value. * * @return the unsigned char value. - * - * @throws IOException Signals that an I/O exception has occurred. + * @throws IOException + * if an I/O exception has occurred. */ char readChar() throws IOException; /** - * Reads 4 bytes from the stream, and returns the result - * as an int. + * Reads 4 bytes from the stream, and returns the result as an integer. * - * @return the signed int value from the stream. - * - * @throws IOException Signals that an I/O exception has occurred. + * @return the signed integer value from the stream. + * @throws IOException + * if an I/O exception has occurred. */ int readInt() throws IOException; /** - * Reads 4 bytes from the stream and returns its value - * as long. - * - * @return a unsigned int value as long. + * Reads 4 bytes from the stream and returns its value as long. * - * @throws IOException Signals that an I/O exception has occurred. + * @return the unsigned integer value as long. + * @throws IOException + * if an I/O exception has occurred. */ long readUnsignedInt() throws IOException; /** - * Reads 8 bytes from the stream, and returns the result - * as a long. + * Reads 8 bytes from the stream, and returns the result as a long. * * @return the long value from the stream. - * - * @throws IOException Signals that an I/O exception has occurred. + * @throws IOException + * if an I/O exception has occurred. */ long readLong() throws IOException; /** - * Reads 4 bytes from the stream, and returns the result - * as a float. + * Reads 4 bytes from the stream, and returns the result as a float. * * @return the float value from the stream. - * - * @throws IOException Signals that an I/O exception has occurred. + * @throws IOException + * if an I/O exception has occurred. */ float readFloat() throws IOException; /** - * Reads 8 bytes from the stream, and returns the result - * as a double. + * Reads 8 bytes from the stream, and returns the result as a double. * * @return the double value from the stream. - * - * @throws IOException Signals that an I/O exception has occurred. + * @throws IOException + * if an I/O exception has occurred. */ double readDouble() throws IOException; @@ -207,120 +204,134 @@ public interface ImageInputStream extends DataInput { * Reads a line from the stream. * * @return the string contained the line from the stream. - * - * @throws IOException Signals that an I/O exception has occurred. + * @throws IOException + * if an I/O exception has occurred. */ String readLine() throws IOException; /** - * Reads bytes from the stream in a string that has been encoded - * in a modified UTF-8 format. + * Reads bytes from the stream in a string that has been encoded in a + * modified UTF-8 format. * * @return the string read from stream and modified UTF-8 format. - * - * @throws IOException Signals that an I/O exception has occurred. + * @throws IOException + * if an I/O exception has occurred. */ String readUTF() throws IOException; /** - * Reads the specified number of bytes from the stream, - * and stores the result into the specified array starting at - * the specified index offset. + * Reads the specified number of bytes from the stream, and stores the + * result into the specified array starting at the specified index offset. * - * @param b the byte array. - * @param off the offset. - * @param len the number of bytes to be read. - * - * @throws IOException Signals that an I/O exception has occurred. + * @param b + * the byte array. + * @param off + * the offset. + * @param len + * the number of bytes to be read. + * @throws IOException + * if an I/O exception has occurred. */ void readFully(byte[] b, int off, int len) throws IOException; /** - * Reads number of bytes from the stream which is equal to - * the specified array's length, and stores them into - * this array. - * - * @param b the byte array. + * Reads number of bytes from the stream which is equal to the specified + * array's length, and stores them into this array. * - * @throws IOException Signals that an I/O exception has occurred. + * @param b + * the byte array. + * @throws IOException + * if an I/O exception has occurred. */ void readFully(byte[] b) throws IOException; /** - * Reads the specified number of shorts from the stream, - * and stores the result into the specified array starting at - * the specified index offset. - * - * @param s the short array. - * @param off the offset. - * @param len the number of shorts to be read. + * Reads the specified number of shorts from the stream, and stores the + * result into the specified array starting at the specified index offset. * - * @throws IOException Signals that an I/O exception has occurred. + * @param s + * the short array. + * @param off + * the offset. + * @param len + * the number of shorts to be read. + * @throws IOException + * if an I/O exception has occurred. */ void readFully(short[] s, int off, int len) throws IOException; /** - * Reads the specified number of chars from the stream, - * and stores the result into the specified array starting at - * the specified index offset. + * Reads the specified number of chars from the stream, and stores the + * result into the specified array starting at the specified index offset. * - * @param c the char array. - * @param off the offset. - * @param len the number of chars to be read. - * - * @throws IOException Signals that an I/O exception has occurred. + * @param c + * the char array. + * @param off + * the offset. + * @param len + * the number of chars to be read. + * @throws IOException + * if an I/O exception has occurred. */ void readFully(char[] c, int off, int len) throws IOException; /** - * Reads the specified number of ints from the stream, - * and stores the result into the specified array starting at - * the specified index offset. - * - * @param i the int array. - * @param off the offset. - * @param len the number of ints to be read. + * Reads the specified number of integer from the stream, and stores the + * result into the specified array starting at the specified index offset. * - * @throws IOException Signals that an I/O exception has occurred. + * @param i + * the integer array. + * @param off + * the offset. + * @param len + * the number of integer to be read. + * @throws IOException + * if an I/O exception has occurred. */ void readFully(int[] i, int off, int len) throws IOException; /** - * Reads the specified number of longs from the stream, - * and stores the result into the specified array starting at - * the specified index offset. + * Reads the specified number of longs from the stream, and stores the + * result into the specified array starting at the specified index offset. * - * @param l the long array. - * @param off the offset. - * @param len the number of longs to be read. - * - * @throws IOException Signals that an I/O exception has occurred. + * @param l + * the long array. + * @param off + * the offset. + * @param len + * the number of longs to be read. + * @throws IOException + * if an I/O exception has occurred. */ void readFully(long[] l, int off, int len) throws IOException; /** - * Reads the specified number of floats from the stream, - * and stores the result into the specified array starting at - * the specified index offset. - * - * @param f the float array. - * @param off the offset. - * @param len the number of floats to be read. + * Reads the specified number of floats from the stream, and stores the + * result into the specified array starting at the specified index offset. * - * @throws IOException Signals that an I/O exception has occurred. + * @param f + * the float array. + * @param off + * the offset. + * @param len + * the number of floats to be read. + * @throws IOException + * if an I/O exception has occurred. */ void readFully(float[] f, int off, int len) throws IOException; /** - * Reads the specified number of doubles from the stream, - * and stores the result into the specified array starting at - * the specified index offset. - * - * @param d the double array. - * @param off the offset. - * @param len the number of doubles to be read. + * Reads the specified number of doubles from the stream, and stores the + * result into the specified array starting at the specified index offset. * - * @throws IOException Signals that an I/O exception has occurred. + * @param d + * the double array. + * @param off + * the offset. + * @param len + * the number of doubles to be read. + * @throws IOException + * if an I/O exception has occurred. */ void readFully(double[] d, int off, int len) throws IOException; @@ -328,8 +339,8 @@ public interface ImageInputStream extends DataInput { * Gets the stream position. * * @return the stream position. - * - * @throws IOException Signals that an I/O exception has occurred. + * @throws IOException + * if an I/O exception has occurred. */ long getStreamPosition() throws IOException; @@ -337,17 +348,18 @@ public interface ImageInputStream extends DataInput { * Gets the bit offset. * * @return the bit offset. - * - * @throws IOException Signals that an I/O exception has occurred. + * @throws IOException + * if an I/O exception has occurred. */ int getBitOffset() throws IOException; /** - * Sets the bit offset to an integer between 0 and 7. + * Sets the bit offset to an integer between 0 and 7. * - * @param bitOffset the bit offset. - * - * @throws IOException Signals that an I/O exception has occurred. + * @param bitOffset + * the bit offset. + * @throws IOException + * if an I/O exception has occurred. */ void setBitOffset(int bitOffset) throws IOException; @@ -355,90 +367,94 @@ public interface ImageInputStream extends DataInput { * Reads a bit from the stream and returns the value 0 or 1. * * @return the value of single bit: 0 or 1. - * - * @throws IOException Signals that an I/O exception has occurred. + * @throws IOException + * if an I/O exception has occurred. */ int readBit() throws IOException; /** * Read the specified number of bits and returns their values as long. * - * @param numBits the number of bits to be read. - * + * @param numBits + * the number of bits to be read. * @return the bit string as a long. - * - * @throws IOException Signals that an I/O exception has occurred. + * @throws IOException + * if an I/O exception has occurred. */ long readBits(int numBits) throws IOException; /** - * Returns the length of the stream. - * - * @return the length of the stream, or -1 if unknown. + * Returns the length of the stream. * - * @throws IOException Signals that an I/O exception has occurred. + * @return the length of the stream, or -1 if unknown. + * @throws IOException + * if an I/O exception has occurred. */ long length() throws IOException; /** - * Skipes the specified number of bytes by moving stream position. - * - * @param n the number of bytes. + * Skips the specified number of bytes by moving stream position. * + * @param n + * the number of bytes. * @return the actual skipped number of bytes. - * - * @throws IOException Signals that an I/O exception has occurred. + * @throws IOException + * if an I/O exception has occurred. */ int skipBytes(int n) throws IOException; /** - * Skipes the specified number of bytes by moving stream position. - * - * @param n the number of bytes. + * Skips the specified number of bytes by moving stream position. * + * @param n + * the number of bytes. * @return the actual skipped number of bytes. - * - * @throws IOException Signals that an I/O exception has occurred. + * @throws IOException + * if an I/O exception has occurred. */ long skipBytes(long n) throws IOException; /** - * Sets the current stream position to the specified location. + * Sets the current stream position to the specified location. * - * @param pos a file pointer position. - * - * @throws IOException Signals that an I/O exception has occurred. + * @param pos + * a file pointer position. + * @throws IOException + * if an I/O exception has occurred. */ void seek(long pos) throws IOException; /** - * Marks a position in the stream to be returned to by a subsequent - * call to reset. + * Marks a position in the stream to be returned to by a subsequent call to + * reset. */ void mark(); /** * Returns the file pointer to its previous position. * - * @throws IOException Signals that an I/O exception has occurred. + * @throws IOException + * if an I/O exception has occurred. */ void reset() throws IOException; /** - * Flushes the initial position in this stream prior to the - * specified stream position. - * - * @param pos the position. + * Flushes the initial position in this stream prior to the specified stream + * position. * - * @throws IOException Signals that an I/O exception has occurred. + * @param pos + * the position. + * @throws IOException + * if an I/O exception has occurred. */ void flushBefore(long pos) throws IOException; /** - * Flushes the initial position in this stream prior to the - * current stream position. + * Flushes the initial position in this stream prior to the current stream + * position. * - * @throws IOException Signals that an I/O exception has occurred. + * @throws IOException + * if an I/O exception has occurred. */ void flush() throws IOException; @@ -450,36 +466,37 @@ public interface ImageInputStream extends DataInput { long getFlushedPosition(); /** - * Returns true if this ImageInputStream caches data in order - * to allow seeking backwards. + * Returns true if this ImageInputStream caches data in order to allow + * seeking backwards. * - * @return true if this ImageInputStream caches data in order - * to allow seeking backwards, false otherwise. + * @return true, if this ImageInputStream caches data in order to allow + * seeking backwards, false otherwise. */ boolean isCached(); /** - * Returns true if this ImageInputStream caches data in order - * to allow seeking backwards, and keeps it in memory. + * Returns true if this ImageInputStream caches data in order to allow + * seeking backwards, and keeps it in memory. * - * @return true if this ImageInputStream caches data in order - * to allow seeking backwards, and keeps it in memory. + * @return true, if this ImageInputStream caches data in order to allow + * seeking backwards, and keeps it in memory. */ boolean isCachedMemory(); /** - * Returns true if this ImageInputStream caches data in order - * to allow seeking backwards, and keeps it in a temporary file. + * Returns true if this ImageInputStream caches data in order to allow + * seeking backwards, and keeps it in a temporary file. * - * @return true if this ImageInputStream caches data in order - * to allow seeking backwards, and keeps it in a temporary file. + * @return true, if this ImageInputStream caches data in order to allow + * seeking backwards, and keeps it in a temporary file. */ boolean isCachedFile(); /** * Closes this stream. * - * @throws IOException Signals that an I/O exception has occurred. + * @throws IOException + * if an I/O exception has occurred. */ void close() throws IOException; } diff --git a/awt/javax/imageio/stream/ImageInputStreamImpl.java b/awt/javax/imageio/stream/ImageInputStreamImpl.java index 83ac13a9c986d60b492071fec438f01fb3372b58..d79da41859aa00502f0d9deef5a7b730ec14bbee 100644 --- a/awt/javax/imageio/stream/ImageInputStreamImpl.java +++ b/awt/javax/imageio/stream/ImageInputStreamImpl.java @@ -18,6 +18,7 @@ * @author Rustem V. Rafikov * @version $Revision: 1.3 $ */ + package javax.imageio.stream; import java.io.EOFException; @@ -25,38 +26,54 @@ import java.io.IOException; import java.nio.ByteOrder; /** - * The ImageInputStreamImpl abstract class implements - * the ImageInputStream interface. + * The ImageInputStreamImpl abstract class implements the ImageInputStream + * interface. + * + * @since Android 1.0 */ public abstract class ImageInputStreamImpl implements ImageInputStream { - /** The byte order. */ + /** + * The byte order. + */ protected ByteOrder byteOrder = ByteOrder.BIG_ENDIAN; - /** The stream position. */ + /** + * The stream position. + */ protected long streamPos = 0; - - /** The flushed position. */ + + /** + * The flushed position. + */ protected long flushedPos = 0; - - /** The bit offset. */ + + /** + * The bit offset. + */ protected int bitOffset = 0; - /** The closed. */ + /** + * The closed. + */ private boolean closed = false; - /** The position stack. */ + /** + * The position stack. + */ private final PositionStack posStack = new PositionStack(); /** * Instantiates a new ImageInputStreamImpl. */ - public ImageInputStreamImpl() {} + public ImageInputStreamImpl() { + } /** * Check if the stream is closed and if true, throws an IOException. * - * @throws IOException Signals that the stream is closed. + * @throws IOException + * if the stream is closed. */ protected final void checkClosed() throws IOException { if (closed) { @@ -106,7 +123,7 @@ public abstract class ImageInputStreamImpl implements ImageInputStream { if (b < 0) { throw new EOFException("EOF reached"); } - return (byte) b; + return (byte)b; } public int readUnsignedByte() throws IOException { @@ -125,58 +142,57 @@ public abstract class ImageInputStreamImpl implements ImageInputStream { throw new EOFException("EOF reached"); } - return byteOrder == ByteOrder.BIG_ENDIAN ? - (short) ((b1 << 8) | (b2 & 0xff)) : - (short) ((b2 << 8) | (b1 & 0xff)); + return byteOrder == ByteOrder.BIG_ENDIAN ? (short)((b1 << 8) | (b2 & 0xff)) + : (short)((b2 << 8) | (b1 & 0xff)); } public int readUnsignedShort() throws IOException { - //-- TODO implement + // -- TODO implement throw new UnsupportedOperationException("Not implemented yet"); } public char readChar() throws IOException { - //-- TODO implement + // -- TODO implement throw new UnsupportedOperationException("Not implemented yet"); } public int readInt() throws IOException { - //-- TODO implement + // -- TODO implement throw new UnsupportedOperationException("Not implemented yet"); } public long readUnsignedInt() throws IOException { - //-- TODO implement + // -- TODO implement throw new UnsupportedOperationException("Not implemented yet"); } public long readLong() throws IOException { - //-- TODO implement + // -- TODO implement throw new UnsupportedOperationException("Not implemented yet"); } public float readFloat() throws IOException { - //-- TODO implement + // -- TODO implement throw new UnsupportedOperationException("Not implemented yet"); } public double readDouble() throws IOException { - //-- TODO implement + // -- TODO implement throw new UnsupportedOperationException("Not implemented yet"); } public String readLine() throws IOException { - //-- TODO implement + // -- TODO implement throw new UnsupportedOperationException("Not implemented yet"); } public String readUTF() throws IOException { - //-- TODO implement + // -- TODO implement throw new UnsupportedOperationException("Not implemented yet"); } public void readFully(byte[] b, int off, int len) throws IOException { - //-- TODO implement + // -- TODO implement throw new UnsupportedOperationException("Not implemented yet"); } @@ -185,32 +201,32 @@ public abstract class ImageInputStreamImpl implements ImageInputStream { } public void readFully(short[] s, int off, int len) throws IOException { - //-- TODO implement + // -- TODO implement throw new UnsupportedOperationException("Not implemented yet"); } public void readFully(char[] c, int off, int len) throws IOException { - //-- TODO implement + // -- TODO implement throw new UnsupportedOperationException("Not implemented yet"); } public void readFully(int[] i, int off, int len) throws IOException { - //-- TODO implement + // -- TODO implement throw new UnsupportedOperationException("Not implemented yet"); } public void readFully(long[] l, int off, int len) throws IOException { - //-- TODO implement + // -- TODO implement throw new UnsupportedOperationException("Not implemented yet"); } public void readFully(float[] f, int off, int len) throws IOException { - //-- TODO implement + // -- TODO implement throw new UnsupportedOperationException("Not implemented yet"); } public void readFully(double[] d, int off, int len) throws IOException { - //-- TODO implement + // -- TODO implement throw new UnsupportedOperationException("Not implemented yet"); } @@ -230,12 +246,12 @@ public abstract class ImageInputStreamImpl implements ImageInputStream { } public int readBit() throws IOException { - //-- TODO implement + // -- TODO implement throw new UnsupportedOperationException("Not implemented yet"); } public long readBits(int numBits) throws IOException { - //-- TODO implement + // -- TODO implement throw new UnsupportedOperationException("Not implemented yet"); } @@ -244,12 +260,12 @@ public abstract class ImageInputStreamImpl implements ImageInputStream { } public int skipBytes(int n) throws IOException { - //-- TODO implement + // -- TODO implement throw new UnsupportedOperationException("Not implemented yet"); } public long skipBytes(long n) throws IOException { - //-- TODO implement + // -- TODO implement throw new UnsupportedOperationException("Not implemented yet"); } @@ -272,7 +288,7 @@ public abstract class ImageInputStreamImpl implements ImageInputStream { } public void reset() throws IOException { - //-- TODO bit pos + // -- TODO bit pos if (!posStack.isEmpty()) { long p = posStack.pop(); if (p < flushedPos) { @@ -290,7 +306,7 @@ public abstract class ImageInputStreamImpl implements ImageInputStream { throw new IndexOutOfBoundsException("Trying to flush within already flushed portion"); } flushedPos = pos; - //-- TODO implement + // -- TODO implement } public void flush() throws IOException { @@ -302,15 +318,15 @@ public abstract class ImageInputStreamImpl implements ImageInputStream { } public boolean isCached() { - return false; //def + return false; // def } public boolean isCachedMemory() { - return false; //def + return false; // def } public boolean isCachedFile() { - return false; //def + return false; // def } public void close() throws IOException { @@ -322,7 +338,8 @@ public abstract class ImageInputStreamImpl implements ImageInputStream { /** * Finalizes this object. * - * @throws Throwable if an error occurs. + * @throws Throwable + * if an error occurs. */ @Override protected void finalize() throws Throwable { @@ -339,25 +356,31 @@ public abstract class ImageInputStreamImpl implements ImageInputStream { * The Class PositionStack. */ private static class PositionStack { - - /** The Constant SIZE. */ + + /** + * The Constant SIZE. + */ private static final int SIZE = 10; - /** The values. */ + /** + * The values. + */ private long[] values = new long[SIZE]; - - /** The pos. */ - private int pos = 0; + /** + * The pos. + */ + private int pos = 0; /** * Push. * - * @param v the v + * @param v + * the v. */ void push(long v) { if (pos >= values.length) { - ensure(pos+1); + ensure(pos + 1); } values[pos++] = v; } @@ -365,7 +388,7 @@ public abstract class ImageInputStreamImpl implements ImageInputStream { /** * Pop. * - * @return the long + * @return the long. */ long pop() { return values[--pos]; @@ -374,7 +397,7 @@ public abstract class ImageInputStreamImpl implements ImageInputStream { /** * Checks if is empty. * - * @return true, if is empty + * @return true, if is empty. */ boolean isEmpty() { return pos == 0; @@ -383,7 +406,8 @@ public abstract class ImageInputStreamImpl implements ImageInputStream { /** * Ensure. * - * @param size the size + * @param size + * the size. */ private void ensure(int size) { long[] arr = new long[Math.max(2 * values.length, size)]; diff --git a/awt/javax/imageio/stream/ImageOutputStream.java b/awt/javax/imageio/stream/ImageOutputStream.java index e59b69da5234f30bb79305cb9a75e2619c052a1d..28ec93277a44e0f4393f7f5c40e3e6d13fe242cc 100644 --- a/awt/javax/imageio/stream/ImageOutputStream.java +++ b/awt/javax/imageio/stream/ImageOutputStream.java @@ -18,252 +18,289 @@ * @author Rustem V. Rafikov * @version $Revision: 1.2 $ */ + package javax.imageio.stream; import java.io.DataOutput; import java.io.IOException; /** - * The ImageOutputStream represents output stream interface that is - * used by ImageWriters. + * The ImageOutputStream represents output stream interface that is used by + * ImageWriters. + * + * @since Android 1.0 */ public interface ImageOutputStream extends DataOutput, ImageInputStream { /** - * Writes a single byte to the stream at the current position. - * - * @param b the int value, of which the 8 lowest bits - * will be written. + * Writes a single byte to the stream at the current position. * - * @throws IOException Signals that an I/O exception has occurred. + * @param b + * the integer value, of which the 8 lowest bits will be written. + * @throws IOException + * if an I/O exception has occurred. */ void write(int b) throws IOException; /** * Writes the bytes array to the stream. * - * @param b the byte array to be written. - * - * @throws IOException Signals that an I/O exception has occurred. + * @param b + * the byte array to be written. + * @throws IOException + * if an I/O exception has occurred. */ void write(byte[] b) throws IOException; /** - * Writes a number of bytes from the specified byte array - * beggining from the specified offset. - * - * @param b the byte array. - * @param off the offset. - * @param len the number of bytes to be written. - * - * @throws IOException Signals that an I/O exception has occurred. + * Writes a number of bytes from the specified byte array beginning from the + * specified offset. + * + * @param b + * the byte array. + * @param off + * the offset. + * @param len + * the number of bytes to be written. + * @throws IOException + * if an I/O exception has occurred. */ void write(byte[] b, int off, int len) throws IOException; /** - * Writes the specified boolean value to the stream, 1 if it is true, - * 0 if it is false. - * - * @param b the boolean value to be written. + * Writes the specified boolean value to the stream, 1 if it is true, 0 if + * it is false. * - * @throws IOException Signals that an I/O exception has occurred. + * @param b + * the boolean value to be written. + * @throws IOException + * if an I/O exception has occurred. */ void writeBoolean(boolean b) throws IOException; /** - * Writes the 8 lowest bits of the specified int value to the stream. + * Writes the 8 lowest bits of the specified integer value to the stream. * - * @param b the specified int value. - * - * @throws IOException Signals that an I/O exception has occurred. + * @param b + * the specified integer value. + * @throws IOException + * if an I/O exception has occurred. */ void writeByte(int b) throws IOException; /** - * Writes a short value to the output stream. - * - * @param v the short value to be written. + * Writes a short value to the output stream. * - * @throws IOException Signals that an I/O exception has occurred. + * @param v + * the short value to be written. + * @throws IOException + * if an I/O exception has occurred. */ void writeShort(int v) throws IOException; /** - * Writes the 16 lowest bits of the specified int value to the stream. + * Writes the 16 lowest bits of the specified integer value to the stream. * - * @param v the specified int value. - * - * @throws IOException Signals that an I/O exception has occurred. + * @param v + * the specified integer value. + * @throws IOException + * if an I/O exception has occurred. */ void writeChar(int v) throws IOException; /** - * Writes an integer value to the output stream. - * - * @param v the integer value to be written. + * Writes an integer value to the output stream. * - * @throws IOException Signals that an I/O exception has occurred. + * @param v + * the integer value to be written. + * @throws IOException + * if an I/O exception has occurred. */ void writeInt(int v) throws IOException; /** * Write long. * - * @param v the long value - * - * @throws IOException Signals that an I/O exception has occurred. + * @param v + * the long value. + * @throws IOException + * if an I/O exception has occurred. */ void writeLong(long v) throws IOException; /** - * Writes a float value to the output stream. - * - * @param v the float which contains value to be written. + * Writes a float value to the output stream. * - * @throws IOException Signals that an I/O exception has occurred. + * @param v + * the float which contains value to be written. + * @throws IOException + * if an I/O exception has occurred. */ void writeFloat(float v) throws IOException; /** - * Writes a double value to the output stream. + * Writes a double value to the output stream. * - * @param v the double which contains value to be written. - * - * @throws IOException Signals that an I/O exception has occurred. + * @param v + * the double which contains value to be written. + * @throws IOException + * if an I/O exception has occurred. */ void writeDouble(double v) throws IOException; /** * Writes the specified string to the stream. * - * @param s the string to be written. - * - * @throws IOException Signals that an I/O exception has occurred. + * @param s + * the string to be written. + * @throws IOException + * if an I/O exception has occurred. */ void writeBytes(String s) throws IOException; /** * Writes the specified String to the output stream. * - * @param s the String to be written. - * - * @throws IOException Signals that an I/O exception has occurred. + * @param s + * the String to be written. + * @throws IOException + * if an I/O exception has occurred. */ void writeChars(String s) throws IOException; /** - * Writes 2 bytes to the output stream in - * the modified UTF-8 representation of every character of - * the specified string. - * - * @param s the specified string to be written. + * Writes 2 bytes to the output stream in the modified UTF-8 representation + * of every character of the specified string. * - * @throws IOException Signals that an I/O exception has occurred. + * @param s + * the specified string to be written. + * @throws IOException + * if an I/O exception has occurred. */ void writeUTF(String s) throws IOException; /** - * Flushes the initial position in this stream prior to the - * specified stream position. + * Flushes the initial position in this stream prior to the specified stream + * position. * - * @param pos the position. - * - * @throws IOException Signals that an I/O exception has occurred. + * @param pos + * the position. + * @throws IOException + * if an I/O exception has occurred. */ void flushBefore(long pos) throws IOException; - /** - * Writes a len number of short values from the specified array - * to the stream. - * - * @param s the shorts array to be written. - * @param off the offset in the char array. - * @param len the length of chars to be written. - * - * @throws IOException Signals that an I/O exception has occurred. + * Writes a len number of short values from the specified array to the + * stream. + * + * @param s + * the shorts array to be written. + * @param off + * the offset in the char array. + * @param len + * the length of chars to be written. + * @throws IOException + * if an I/O exception has occurred. */ void writeShorts(short[] s, int off, int len) throws IOException; /** * Writes a len number of chars to the stream. * - * @param c the char array to be written. - * @param off the offset in the char array. - * @param len the length of chars to be written. - * - * @throws IOException Signals that an I/O exception has occurred. + * @param c + * the char array to be written. + * @param off + * the offset in the char array. + * @param len + * the length of chars to be written. + * @throws IOException + * if an I/O exception has occurred. */ void writeChars(char[] c, int off, int len) throws IOException; /** - * Writes a len number of int values from the specified array - * to the stream. - * - * @param i the int array to be written. - * @param off the offset in the char array. - * @param len the length of chars to be written. - * - * @throws IOException Signals that an I/O exception has occurred. + * Writes a len number of integer values from the specified array to the + * stream. + * + * @param i + * the integer array to be written. + * @param off + * the offset in the char array. + * @param len + * the length of chars to be written. + * @throws IOException + * if an I/O exception has occurred. */ void writeInts(int[] i, int off, int len) throws IOException; /** - * Writes a len number of long values from the specified array - * to the stream. - * - * @param l the long array to be written. - * @param off the offset in the char array. - * @param len the length of chars to be written. - * - * @throws IOException Signals that an I/O exception has occurred. + * Writes a len number of long values from the specified array to the + * stream. + * + * @param l + * the long array to be written. + * @param off + * the offset in the char array. + * @param len + * the length of chars to be written. + * @throws IOException + * if an I/O exception has occurred. */ void writeLongs(long[] l, int off, int len) throws IOException; /** - * Writes a len number of float values from the specified array - * to the stream. - * - * @param f the float array to be written. - * @param off the offset in the char array. - * @param len the length of chars to be written. - * - * @throws IOException Signals that an I/O exception has occurred. + * Writes a len number of float values from the specified array to the + * stream. + * + * @param f + * the float array to be written. + * @param off + * the offset in the char array. + * @param len + * the length of chars to be written. + * @throws IOException + * if an I/O exception has occurred. */ void writeFloats(float[] f, int off, int len) throws IOException; /** - * Writes a len number of double values from the specified array - * to the stream. - * - * @param d the double array to be written. - * @param off the offset in the char array. - * @param len the length of chars to be written. - * - * @throws IOException Signals that an I/O exception has occurred. + * Writes a len number of double values from the specified array to the + * stream. + * + * @param d + * the double array to be written. + * @param off + * the offset in the char array. + * @param len + * the length of chars to be written. + * @throws IOException + * if an I/O exception has occurred. */ void writeDoubles(double[] d, int off, int len) throws IOException; /** * Writes a single bit at the current position. * - * @param bit the an int whose least significant bit is to be - * written to the stream. - * - * @throws IOException Signals that an I/O exception has occurred. + * @param bit + * the integer whose least significant bit is to be written to + * the stream. + * @throws IOException + * if an I/O exception has occurred. */ void writeBit(int bit) throws IOException; /** - * Writes a sequence of bits beggining from the current position. - * - * @param bits a long value containing the bits to be written, - * starting with the bit in position numBits - 1 down to the - * least significant bit. - * @param numBits the number of significant bit , - * it can be between 0 and 64. - * - * @throws IOException Signals that an I/O exception has occurred. + * Writes a sequence of bits beginning from the current position. + * + * @param bits + * the long value containing the bits to be written, starting + * with the bit in position numBits - 1 down to the least + * significant bit. + * @param numBits + * the number of significant bit, it can be between 0 and 64. + * @throws IOException + * if an I/O exception has occurred. */ void writeBits(long bits, int numBits) throws IOException; diff --git a/awt/javax/imageio/stream/ImageOutputStreamImpl.java b/awt/javax/imageio/stream/ImageOutputStreamImpl.java index c3d80fa7bee61ff957352335cb10ec6c6881074e..0fef78f1d1a1f71500a07e3b9dfde27af8789724 100644 --- a/awt/javax/imageio/stream/ImageOutputStreamImpl.java +++ b/awt/javax/imageio/stream/ImageOutputStreamImpl.java @@ -18,6 +18,7 @@ * @author Rustem V. Rafikov * @version $Revision: 1.3 $ */ + package javax.imageio.stream; import java.io.IOException; @@ -29,16 +30,19 @@ import java.nio.ByteOrder; */ /** - * The ImageOutputStreamImpl abstract class implements - * the ImageOutputStream interface. + * The ImageOutputStreamImpl abstract class implements the ImageOutputStream + * interface. + * + * @since Android 1.0 */ -public abstract class ImageOutputStreamImpl extends ImageInputStreamImpl - implements ImageOutputStream { +public abstract class ImageOutputStreamImpl extends ImageInputStreamImpl implements + ImageOutputStream { /** * Instantiates a new ImageOutputStreamImpl. */ - public ImageOutputStreamImpl() {} + public ImageOutputStreamImpl() { + } public abstract void write(int b) throws IOException; @@ -62,7 +66,7 @@ public abstract class ImageOutputStreamImpl extends ImageInputStreamImpl } else { } - //-- TODO implement + // -- TODO implement throw new UnsupportedOperationException("Not implemented yet"); } @@ -76,7 +80,7 @@ public abstract class ImageOutputStreamImpl extends ImageInputStreamImpl } else { } - //-- TODO implement + // -- TODO implement throw new UnsupportedOperationException("Not implemented yet"); } @@ -86,7 +90,7 @@ public abstract class ImageOutputStreamImpl extends ImageInputStreamImpl } else { } - //-- TODO implement + // -- TODO implement throw new UnsupportedOperationException("Not implemented yet"); } @@ -108,62 +112,63 @@ public abstract class ImageOutputStreamImpl extends ImageInputStreamImpl } public void writeUTF(String s) throws IOException { - //-- TODO implement + // -- TODO implement throw new UnsupportedOperationException("Not implemented yet"); } public void writeShorts(short[] s, int off, int len) throws IOException { - //-- TODO implement + // -- TODO implement throw new UnsupportedOperationException("Not implemented yet"); } public void writeChars(char[] c, int off, int len) throws IOException { - //-- TODO implement + // -- TODO implement throw new UnsupportedOperationException("Not implemented yet"); } public void writeInts(int[] i, int off, int len) throws IOException { - //-- TODO implement + // -- TODO implement throw new UnsupportedOperationException("Not implemented yet"); } public void writeLongs(long[] l, int off, int len) throws IOException { - //-- TODO implement + // -- TODO implement throw new UnsupportedOperationException("Not implemented yet"); } public void writeFloats(float[] f, int off, int len) throws IOException { - //-- TODO implement + // -- TODO implement throw new UnsupportedOperationException("Not implemented yet"); } public void writeDoubles(double[] d, int off, int len) throws IOException { - //-- TODO implement + // -- TODO implement throw new UnsupportedOperationException("Not implemented yet"); } public void writeBit(int bit) throws IOException { - //-- TODO implement + // -- TODO implement throw new UnsupportedOperationException("Not implemented yet"); } public void writeBits(long bits, int numBits) throws IOException { - //-- TODO implement + // -- TODO implement throw new UnsupportedOperationException("Not implemented yet"); } /** - * Flushes the bits. This method should be called in the write - * methods by subclasses. + * Flushes the bits. This method should be called in the write methods by + * subclasses. * - * @throws IOException Signals that an I/O exception has occurred. + * @throws IOException + * if an I/O exception has occurred. */ protected final void flushBits() throws IOException { if (bitOffset == 0) { return; } - - //-- TODO implement + + // -- TODO implement throw new UnsupportedOperationException("Not implemented yet"); } } diff --git a/awt/javax/imageio/stream/MemoryCacheImageInputStream.java b/awt/javax/imageio/stream/MemoryCacheImageInputStream.java index a3d470b01cd38e1f4c8bc5536c79582002374027..d7fc79139cec3021aa5cd2c7bad5eff5060e1720 100644 --- a/awt/javax/imageio/stream/MemoryCacheImageInputStream.java +++ b/awt/javax/imageio/stream/MemoryCacheImageInputStream.java @@ -15,7 +15,6 @@ * limitations under the License. */ - package javax.imageio.stream; import org.apache.harmony.x.imageio.stream.RandomAccessMemoryCache; @@ -24,22 +23,29 @@ import java.io.IOException; import java.io.InputStream; /** - * The MemoryCacheImageInputStream class implements ImageInputStream - * using a memory buffer for caching the data. + * The MemoryCacheImageInputStream class implements ImageInputStream using a + * memory buffer for caching the data. + * + * @since Android 1.0 */ -public class MemoryCacheImageInputStream extends ImageInputStreamImpl { - - /** The is. */ +public class MemoryCacheImageInputStream extends ImageInputStreamImpl { + + /** + * The is. + */ private InputStream is; - - /** The ramc. */ + + /** + * The ramc. + */ private RandomAccessMemoryCache ramc = new RandomAccessMemoryCache(); /** - * Instantiates a new MemoryCacheImageInputStream - * which reads from the specified InputStream. + * Instantiates a new MemoryCacheImageInputStream which reads from the + * specified InputStream. * - * @param stream the InputStream to be read. + * @param stream + * the InputStream to be read. */ public MemoryCacheImageInputStream(InputStream stream) { if (stream == null) { diff --git a/awt/javax/imageio/stream/MemoryCacheImageOutputStream.java b/awt/javax/imageio/stream/MemoryCacheImageOutputStream.java index 96ded433ae13cbe5ab638a1c9223afa5786fb505..1df40a34227faa3d0bb3298d80b8d328efa1c157 100644 --- a/awt/javax/imageio/stream/MemoryCacheImageOutputStream.java +++ b/awt/javax/imageio/stream/MemoryCacheImageOutputStream.java @@ -15,7 +15,6 @@ * limitations under the License. */ - package javax.imageio.stream; import org.apache.harmony.x.imageio.stream.RandomAccessMemoryCache; @@ -23,24 +22,30 @@ import org.apache.harmony.x.imageio.stream.RandomAccessMemoryCache; import java.io.OutputStream; import java.io.IOException; - /** - * The MemoryCacheImageOutputStream class implements ImageOutputStream - * using a memory buffer for caching the data. + * The MemoryCacheImageOutputStream class implements ImageOutputStream using a + * memory buffer for caching the data. + * + * @since Android 1.0 */ public class MemoryCacheImageOutputStream extends ImageOutputStreamImpl { - - /** The os. */ + + /** + * The os. + */ OutputStream os; - - /** The ramc. */ + + /** + * The ramc. + */ RandomAccessMemoryCache ramc = new RandomAccessMemoryCache(); /** - * Instantiates a new MemoryCacheImageOutputStream - * which writes to the specified OutputStream. + * Instantiates a new MemoryCacheImageOutputStream which writes to the + * specified OutputStream. * - * @param stream the OutputStream. + * @param stream + * the OutputStream. */ public MemoryCacheImageOutputStream(OutputStream stream) { if (stream == null) { @@ -125,6 +130,6 @@ public class MemoryCacheImageOutputStream extends ImageOutputStreamImpl { ramc.getData(os, nBytes, flushedPosition); ramc.freeBefore(newFlushedPosition); - os.flush(); + os.flush(); } } diff --git a/awt/javax/imageio/stream/package.html b/awt/javax/imageio/stream/package.html new file mode 100644 index 0000000000000000000000000000000000000000..6cf53c3c0646f33d54feb631b4fa84657b0c88b7 --- /dev/null +++ b/awt/javax/imageio/stream/package.html @@ -0,0 +1,8 @@ + + +

    + This package contains classes and interfaces for handling images with low-level I/O operations. +

    + @since Android 1.0 + + diff --git a/awt/org/apache/harmony/awt/internal/nls/Messages.java b/awt/org/apache/harmony/awt/internal/nls/Messages.java index 96762c98e90d97816207ad114cddc9f263b3250e..c340358db6157167316f9db42063169f550aa7e1 100644 --- a/awt/org/apache/harmony/awt/internal/nls/Messages.java +++ b/awt/org/apache/harmony/awt/internal/nls/Messages.java @@ -71,7 +71,9 @@ public class Messages { * @return String the message for that key in the system message bundle. */ static public String getString(String msg) { + // BEGIN android-changed return MsgHelp.getString(msg); + // END android-changed } /** @@ -138,6 +140,12 @@ public class Messages { * @return String the message for that key in the system message bundle. */ static public String getString(String msg, Object[] args) { + // BEGIN android-changed return MsgHelp.getString(msg, args); + // END android-changed } + + // BEGIN android-note + // Duplicate code was dropped in favor of using MsgHelp. + // END android-note } diff --git a/awt/org/apache/harmony/beans/internal/nls/Messages.java b/awt/org/apache/harmony/beans/internal/nls/Messages.java index 727c75751b43b9e912efa0474d0f568c89747469..51e8168fa10690982eef09e2792eca1439c6f24c 100644 --- a/awt/org/apache/harmony/beans/internal/nls/Messages.java +++ b/awt/org/apache/harmony/beans/internal/nls/Messages.java @@ -30,8 +30,17 @@ import java.util.Locale; import java.util.MissingResourceException; import java.util.ResourceBundle; -import org.apache.harmony.kernel.vm.VM; -import org.apache.harmony.luni.util.MsgHelp; +// BEGIN android-deleted +/* + * For Android, this module is a separate library and not part of the + * boot classpath, so its resources won't be found on the boot classpath + * as is assumed by MsgHelp.getString(). We instead use a local MsgHelp + * which bottoms out in a call to the useful part of its lower-level + * namesake. + */ +//import org.apache.harmony.kernel.vm.VM; +//import org.apache.harmony.luni.util.MsgHelp; +// END android-deleted /** * This class retrieves strings from a resource bundle and returns them, @@ -49,8 +58,10 @@ import org.apache.harmony.luni.util.MsgHelp; */ public class Messages { - private static final String sResource = - "org.apache.harmony.beans.internal.nls.messages"; //$NON-NLS-1$ + // BEGIN android-deleted + // private static final String sResource = + // "org.apache.harmony.beans.internal.nls.messages"; //$NON-NLS-1$ + // END android-deleted /** * Retrieves a message which has no arguments. @@ -60,7 +71,9 @@ public class Messages { * @return String the message for that key in the system message bundle. */ static public String getString(String msg) { - return MsgHelp.getString(sResource, msg); + // BEGIN android-changed + return MsgHelp.getString(msg); + // END android-changed } /** @@ -127,6 +140,12 @@ public class Messages { * @return String the message for that key in the system message bundle. */ static public String getString(String msg, Object[] args) { - return MsgHelp.getString(sResource, msg, args); + // BEGIN android-changed + return MsgHelp.getString(msg, args); + // END android-changed } + + // BEGIN android-note + // Duplicate code was dropped in favor of using MsgHelp. + // END android-note } diff --git a/awt/org/apache/harmony/beans/internal/nls/MsgHelp.java b/awt/org/apache/harmony/beans/internal/nls/MsgHelp.java new file mode 100644 index 0000000000000000000000000000000000000000..68faabfa34cca39ad180fc02768ba97ddb2a942a --- /dev/null +++ b/awt/org/apache/harmony/beans/internal/nls/MsgHelp.java @@ -0,0 +1,86 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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 implementation is based on the class of the same name in + * org.apache.harmony.luni.util. + */ + +package org.apache.harmony.beans.internal.nls; + +import java.io.IOException; +import java.io.InputStream; +import java.util.logging.Logger; +import java.util.Locale; +import java.util.PropertyResourceBundle; +import java.util.ResourceBundle; +import java.util.MissingResourceException; + +/** + * This class contains helper methods for loading resource bundles and + * formatting external message strings. + */ +public final class MsgHelp { + /** name of the resource for this class */ + private static final String RESOURCE_NAME = + "/org/apache/harmony/beans/internal/nls/messages.properties"; + + /** the resource bundle for this class */ + private static final ResourceBundle THE_BUNDLE; + + static { + ResourceBundle rb = null; + + try { + InputStream in = MsgHelp.class.getResourceAsStream( + RESOURCE_NAME); + rb = new PropertyResourceBundle(in); + } catch (IOException ex) { + Logger.global.warning("Couldn't read resource bundle: " + + ex); + } catch (RuntimeException ex) { + // Shouldn't happen, but deal at least somewhat gracefully. + Logger.global.warning("Couldn't find resource bundle: " + + ex); + } + + THE_BUNDLE = rb; + } + + public static String getString(String msg) { + if (THE_BUNDLE == null) { + return msg; + } + try { + return THE_BUNDLE.getString(msg); + } catch (MissingResourceException e) { + return "Missing message: " + msg; + } + } + + static public String getString(String msg, Object[] args) { + String format = msg; + if (THE_BUNDLE != null) { + try { + format = THE_BUNDLE.getString(msg); + } catch (MissingResourceException e) { + } + } + + return org.apache.harmony.luni.util.MsgHelp.format(format, args); + } +} diff --git a/awt/org/apache/harmony/beans/internal/nls/messages.properties b/awt/resources/org/apache/harmony/beans/internals/nls/messages.properties similarity index 100% rename from awt/org/apache/harmony/beans/internal/nls/messages.properties rename to awt/resources/org/apache/harmony/beans/internals/nls/messages.properties diff --git a/build/jarjar-rules.txt b/build/jarjar-rules.txt new file mode 100644 index 0000000000000000000000000000000000000000..5fdb022251b3bb7a136fe296c82650bfbb4a9257 --- /dev/null +++ b/build/jarjar-rules.txt @@ -0,0 +1,2 @@ +rule org.apache.commons com.android.internal.apache.commons + diff --git a/camera/libcameraservice/Android.mk b/camera/libcameraservice/Android.mk index 4e7d6d23e91624c10310843a92c323d2b88d6258..2dfe659a2e042273966f781c5fc4ada1df9e8e62 100644 --- a/camera/libcameraservice/Android.mk +++ b/camera/libcameraservice/Android.mk @@ -4,12 +4,13 @@ LOCAL_PATH:= $(call my-dir) # Set USE_CAMERA_STUB for non-emulator and non-simulator builds, if you want # the camera service to use the fake camera. For emulator or simulator builds, # we always use the fake camera. -# -ifeq ($(BOARD_CAMERA_LIBRARIES),) -USE_CAMERA_STUB:=true -else + +ifeq ($(USE_CAMERA_STUB),) USE_CAMERA_STUB:=false +ifneq ($(filter sooner generic sim,$(TARGET_DEVICE)),) +USE_CAMERA_STUB:=true endif #libcamerastub +endif ifeq ($(USE_CAMERA_STUB),true) # @@ -51,7 +52,7 @@ ifeq ($(USE_CAMERA_STUB), true) LOCAL_STATIC_LIBRARIES += libcamerastub LOCAL_CFLAGS += -include CameraHardwareStub.h else -LOCAL_SHARED_LIBRARIES += $(BOARD_CAMERA_LIBRARIES) +LOCAL_SHARED_LIBRARIES += libcamera endif include $(BUILD_SHARED_LIBRARY) diff --git a/camera/libcameraservice/CameraService.cpp b/camera/libcameraservice/CameraService.cpp index 5784c4b12b9a5eb7b593b06f92a166987a0ced1d..800ffa48a1949aded8d4e50ff21ef2d160cb2ec4 100644 --- a/camera/libcameraservice/CameraService.cpp +++ b/camera/libcameraservice/CameraService.cpp @@ -1,6 +1,7 @@ /* ** -** Copyright 2008, The Android Open Source Project +** Copyright (C) 2008, The Android Open Source Project +** Copyright (C) 2008 HTC Inc. ** ** Licensed under the Apache License, Version 2.0 (the "License"); ** you may not use this file except in compliance with the License. @@ -15,7 +16,7 @@ ** limitations under the License. */ - +//#define LOG_NDEBUG 0 #define LOG_TAG "CameraService" #include @@ -155,10 +156,22 @@ CameraService::Client::Client(const sp& cameraService, { LOGD("Client E constructor"); mHardware = openCameraHardware(); - mHasFrameCallback = false; + + // Callback is disabled by default + mFrameCallbackFlag = FRAME_CALLBACK_FLAG_NOOP; LOGD("Client X constructor"); } +status_t CameraService::Client::connect(const sp& client) +{ + // remvoe old client + LOGD("connect (new client)"); + Mutex::Autolock _l(mLock); + mCameraClient = client; + mFrameCallbackFlag = FRAME_CALLBACK_FLAG_NOOP; + return NO_ERROR; +} + #if HAVE_ANDROID_OS static void *unregister_surface(void *arg) { @@ -170,7 +183,7 @@ static void *unregister_surface(void *arg) #endif CameraService::Client::~Client() -{ +{ // spin down hardware LOGD("Client E destructor"); if (mSurface != 0) { @@ -179,7 +192,7 @@ CameraService::Client::~Client() // We unregister the buffers in a different thread because binder does // not let us make sychronous transactions in a binder destructor (that // is, upon our reaching a refcount of zero.) - pthread_create(&thr, NULL, + pthread_create(&thr, NULL, unregister_surface, mSurface.get()); pthread_join(thr, NULL); @@ -227,12 +240,12 @@ status_t CameraService::Client::setPreviewDisplay(const sp& surface) return NO_ERROR; } -// tell the service whether to callback with each preview frame -void CameraService::Client::setHasFrameCallback(bool installed) +// set the frame callback flag to affect how the received frames from +// preview are handled. +void CameraService::Client::setFrameCallbackFlag(int frame_callback_flag) { Mutex::Autolock lock(mLock); - mHasFrameCallback = installed; - // If installed is false, mPreviewBuffer will be released in stopPreview(). + mFrameCallbackFlag = frame_callback_flag; } // start preview mode, must call setPreviewDisplay first @@ -250,24 +263,24 @@ status_t CameraService::Client::startPreview() LOGE("mHardware is NULL, returning."); return INVALID_OPERATION; } - + if (mSurface == 0) { LOGE("setPreviewDisplay must be called before startPreview!"); return INVALID_OPERATION; } - + // XXX: This needs to be improved. remove all hardcoded stuff - + int w, h; CameraParameters params(mHardware->getParameters()); params.getPreviewSize(&w, &h); - + mSurface->unregisterBuffers(); #if DEBUG_DUMP_PREVIEW_FRAME_TO_FILE debug_frame_cnt = 0; #endif - + status_t ret = mHardware->startPreview(previewCallback, mCameraService.get()); if (ret == NO_ERROR) { @@ -277,7 +290,7 @@ status_t CameraService::Client::startPreview() } else LOGE("mHardware->startPreview() failed with status %d\n", ret); - + return ret; } @@ -295,7 +308,7 @@ void CameraService::Client::stopPreview() mHardware->stopPreview(); LOGD("stopPreview(), hardware stopped OK"); - + if (mSurface != 0) { mSurface->unregisterBuffers(); } @@ -361,6 +374,7 @@ static void dump_to_file(const char *fname, // preview callback - frame buffer update void CameraService::Client::previewCallback(const sp& mem, void* user) { + LOGV("previewCallback()"); sp client = getClientFromCookie(user); if (client == 0) { return; @@ -395,7 +409,7 @@ void CameraService::Client::previewCallback(const sp& mem, void* user) client->postFrame(mem); #if DEBUG_CLIENT_REFERENCES - //**** if the client's refcount is 1, then we are about to destroy it here, + //**** if the client's refcount is 1, then we are about to destroy it here, // which is bad--print all refcounts. if (client->getStrongCount() == 1) { LOGE("++++++++++++++++ (PREVIEW) THIS WILL CAUSE A LOCKUP!"); @@ -431,7 +445,7 @@ status_t CameraService::Client::takePicture() LOGE("mHardware is NULL, returning."); return INVALID_OPERATION; } - + if (mSurface != NULL) mSurface->unregisterBuffers(); @@ -495,7 +509,7 @@ void CameraService::Client::yuvPictureCallback(const sp& mem, client->postRaw(mem); #if DEBUG_CLIENT_REFERENCES - //**** if the client's refcount is 1, then we are about to destroy it here, + //**** if the client's refcount is 1, then we are about to destroy it here, // which is bad--print all refcounts. if (client->getStrongCount() == 1) { LOGE("++++++++++++++++ (RAW) THIS WILL CAUSE A LOCKUP!"); @@ -532,7 +546,7 @@ void CameraService::Client::jpegPictureCallback(const sp& mem, void *us client->postJpeg(mem); #if DEBUG_CLIENT_REFERENCES - //**** if the client's refcount is 1, then we are about to destroy it here, + //**** if the client's refcount is 1, then we are about to destroy it here, // which is bad--print all refcounts. if (client->getStrongCount() == 1) { LOGE("++++++++++++++++ (JPEG) THIS WILL CAUSE A LOCKUP!"); @@ -615,37 +629,74 @@ void CameraService::Client::postJpeg(const sp& mem) mCameraClient->jpegCallback(mem); } +void CameraService::Client::copyFrameAndPostCopiedFrame(sp heap, size_t offset, size_t size) +{ + LOGV("copyFrameAndPostCopiedFrame"); + // It is necessary to copy out of pmem before sending this to + // the callback. For efficiency, reuse the same MemoryHeapBase + // provided it's big enough. Don't allocate the memory or + // perform the copy if there's no callback. + if (mPreviewBuffer == 0) { + mPreviewBuffer = new MemoryHeapBase(size, 0, NULL); + } else if (size > mPreviewBuffer->virtualSize()) { + mPreviewBuffer.clear(); + mPreviewBuffer = new MemoryHeapBase(size, 0, NULL); + if (mPreviewBuffer == 0) { + LOGE("failed to allocate space for preview buffer"); + return; + } + } + memcpy(mPreviewBuffer->base(), + (uint8_t *)heap->base() + offset, size); + + sp frame = new MemoryBase(mPreviewBuffer, 0, size); + if (frame == 0) { + LOGE("failed to allocate space for frame callback"); + return; + } + mCameraClient->frameCallback(frame); +} + void CameraService::Client::postFrame(const sp& mem) { + LOGV("postFrame"); + if (mem == 0) { + LOGW("mem is a null pointer"); + return; + } + ssize_t offset; size_t size; sp heap = mem->getMemory(&offset, &size); - - sp frame; - { Mutex::Autolock surfaceLock(mSurfaceLock); - if (mSurface != NULL) + if (mSurface != NULL) { mSurface->postBuffer(offset); - } - - // It is necessary to copy out of pmem before sending this to the callback. - // For efficiency, reuse the same MemoryHeapBase provided it's big enough. - // Don't allocate the memory or perform the copy if there's no callback. - if (mHasFrameCallback) { - if (mPreviewBuffer == 0) { - mPreviewBuffer = new MemoryHeapBase(size, 0, NULL); - } else if (size > mPreviewBuffer->virtualSize()) { - mPreviewBuffer.clear(); - mPreviewBuffer = new MemoryHeapBase(size, 0, NULL); } - memcpy(mPreviewBuffer->base(), (uint8_t *)heap->base() + offset, size); - frame = new MemoryBase(mPreviewBuffer, 0, size); } - - // Do not hold the client lock while calling back. - if (frame != 0) { - mCameraClient->frameCallback(frame); + + // Is the callback enabled or not? + if (!(mFrameCallbackFlag & FRAME_CALLBACK_FLAG_ENABLE_MASK)) { + // If the enable bit is off, the copy-out and one-shot bits are ignored + LOGV("frame callback is diabled"); + return; + } + + // Is the received frame copied out or not? + if (mFrameCallbackFlag & FRAME_CALLBACK_FLAG_COPY_OUT_MASK) { + LOGV("frame is copied out"); + copyFrameAndPostCopiedFrame(heap, offset, size); + } else { + LOGV("frame is directly sent out without copying"); + mCameraClient->frameCallback(mem); + } + + // Is this is one-shot only? + if (mFrameCallbackFlag & FRAME_CALLBACK_FLAG_ONE_SHOT_MASK) { + LOGV("One-shot only, thus clear the bits and disable frame callback"); + mFrameCallbackFlag &= ~(FRAME_CALLBACK_FLAG_ONE_SHOT_MASK | + FRAME_CALLBACK_FLAG_COPY_OUT_MASK | + FRAME_CALLBACK_FLAG_ENABLE_MASK); } } @@ -711,7 +762,7 @@ status_t CameraService::onTransact( } status_t err = BnCameraService::onTransact(code, data, reply, flags); - + LOGD("+++ onTransact err %d code %d", err, code); if (err == UNKNOWN_TRANSACTION || err == PERMISSION_DENIED) { diff --git a/camera/libcameraservice/CameraService.h b/camera/libcameraservice/CameraService.h index 683c51b9f6832020d74d764de02b6700855c3448..b225aa9f3449740161b1988b6e9fb2ae941c1323 100644 --- a/camera/libcameraservice/CameraService.h +++ b/camera/libcameraservice/CameraService.h @@ -1,6 +1,7 @@ /* ** -** Copyright 2008, The Android Open Source Project +** Copyright (C) 2008, The Android Open Source Project +** Copyright (C) 2008 HTC Inc. ** ** Licensed under the Apache License, Version 2.0 (the "License"); ** you may not use this file except in compliance with the License. @@ -20,6 +21,8 @@ #include #include +#include + class android::MemoryHeapBase; namespace android { @@ -32,7 +35,7 @@ namespace android { // When enabled, this feature allows you to send an event to the CameraService // so that you can cause all references to the heap object gWeakHeap, defined // below, to be printed. You will also need to set DEBUG_REFS=1 and -// DEBUG_REFS_ENABLED_BY_DEFAULT=0 in libutils/RefBase.cpp. You just have to +// DEBUG_REFS_ENABLED_BY_DEFAULT=0 in libutils/RefBase.cpp. You just have to // set gWeakHeap to the appropriate heap you want to track. #define DEBUG_HEAP_LEAKS 0 @@ -67,11 +70,15 @@ private: public: virtual void disconnect(); + // connect new client with existing camera remote + virtual status_t connect(const sp& client); + // pass the buffered ISurface to the camera service virtual status_t setPreviewDisplay(const sp& surface); - - // tell the service whether to callback with each preview frame - virtual void setHasFrameCallback(bool installed); + + // set the frame callback flag to affect how the received frames from + // preview are handled. + virtual void setFrameCallbackFlag(int frame_callback_flag); // start preview mode, must call setPreviewDisplay first virtual status_t startPreview(); @@ -112,6 +119,7 @@ private: void postRaw(const sp& mem); void postJpeg(const sp& mem); void postFrame(const sp& mem); + void copyFrameAndPostCopiedFrame(sp heap, size_t offset, size_t size); void postError(status_t error); void postAutoFocus(bool focused); @@ -119,20 +127,20 @@ private: mutable Mutex mLock; // mSurfaceLock synchronizes access to mSurface between // setPreviewSurface() and postFrame(). Note that among - // the public methods, all accesses to mSurface are + // the public methods, all accesses to mSurface are // syncrhonized by mLock. However, postFrame() is called - // by the CameraHardwareInterface callback, and needs to + // by the CameraHardwareInterface callback, and needs to // access mSurface. It cannot hold mLock, however, because // stopPreview() may be holding that lock while attempting // top stop preview, and stopPreview itself will block waiting - // for a callback from CameraHardwareInterface. If this + // for a callback from CameraHardwareInterface. If this // happens, it will cause a deadlock. mutable Mutex mSurfaceLock; mutable Condition mReady; sp mCameraService; sp mSurface; sp mPreviewBuffer; - bool mHasFrameCallback; + int mFrameCallbackFlag; // these are immutable once the object is created, // they don't need to be protected by a lock diff --git a/cmds/pm/src/com/android/commands/pm/Pm.java b/cmds/pm/src/com/android/commands/pm/Pm.java index b79ee26e9ea2fbb8d3352591a762b7ba25f64c8b..09a140b021920c9feacda1cc1d89da881c7d2f7f 100644 --- a/cmds/pm/src/com/android/commands/pm/Pm.java +++ b/cmds/pm/src/com/android/commands/pm/Pm.java @@ -16,14 +16,15 @@ package com.android.commands.pm; +import android.content.ComponentName; import android.content.pm.ApplicationInfo; import android.content.pm.IPackageDeleteObserver; import android.content.pm.IPackageInstallObserver; import android.content.pm.IPackageManager; +import android.content.pm.InstrumentationInfo; import android.content.pm.PackageInfo; import android.content.pm.PackageItemInfo; import android.content.pm.PackageManager; -import android.content.pm.PackageParser; import android.content.pm.PermissionGroupInfo; import android.content.pm.PermissionInfo; import android.content.res.AssetManager; @@ -33,8 +34,9 @@ import android.os.RemoteException; import android.os.ServiceManager; import java.io.File; -import java.lang.ref.WeakReference; import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; import java.util.List; import java.util.WeakHashMap; @@ -48,6 +50,9 @@ public final class Pm { private int mNextArg; private String mCurArgData; + private static final String PM_NOT_RUNNING_ERR = + "Error: Could not access the Package Manager. Is the system running?"; + public static void main(String[] args) { new Pm().run(args); } @@ -61,8 +66,7 @@ public final class Pm { mPm = IPackageManager.Stub.asInterface(ServiceManager.getService("package")); if (mPm == null) { - System.err.println("Error Type 1: Could not access the Package Manager!"); - showUsage(); + System.err.println(PM_NOT_RUNNING_ERR); return; } @@ -114,6 +118,11 @@ public final class Pm { /** * Execute the list sub-command. + * + * pm list [package | packages] + * pm list permission-groups + * pm list permissions + * pm list instrumentation */ private void runList() { String type = nextArg(); @@ -128,6 +137,8 @@ public final class Pm { runListPermissionGroups(); } else if ("permissions".equals(type)) { runListPermissions(); + } else if ("instrumentation".equals(type)) { + runListInstrumentation(); } else { System.err.println("Error: unknown list type '" + type + "'"); showUsage(); @@ -173,6 +184,67 @@ public final class Pm { System.out.println(info.packageName); } } catch (RemoteException e) { + System.err.println(e.toString()); + System.err.println(PM_NOT_RUNNING_ERR); + } + } + + /** + * Lists all of the installed instrumentation, or all for a given package + * + * pm list instrumentation [package] [-f] + */ + private void runListInstrumentation() { + int flags = 0; // flags != 0 is only used to request meta-data + boolean showPackage = false; + String targetPackage = null; + + try { + String opt; + while ((opt=nextArg()) != null) { + if (opt.equals("-f")) { + showPackage = true; + } else if (opt.charAt(0) != '-') { + targetPackage = opt; + } else { + System.err.println("Error: Unknown option: " + opt); + showUsage(); + return; + } + } + } catch (RuntimeException ex) { + System.err.println("Error: " + ex.toString()); + showUsage(); + return; + } + + try { + List list = mPm.queryInstrumentation(targetPackage, flags); + + // Sort by target package + Collections.sort(list, new Comparator() { + public int compare(InstrumentationInfo o1, InstrumentationInfo o2) { + return o1.targetPackage.compareTo(o2.targetPackage); + } + }); + + int count = (list != null) ? list.size() : 0; + for (int p = 0; p < count; p++) { + InstrumentationInfo ii = list.get(p); + System.out.print("instrumentation:"); + if (showPackage) { + System.out.print(ii.sourceDir); + System.out.print("="); + } + ComponentName cn = new ComponentName(ii.packageName, ii.name); + System.out.print(cn.flattenToShortString()); + System.out.print(" (target="); + System.out.print(ii.targetPackage); + System.out.println(")"); + } + } catch (RemoteException e) { + System.err.println(e.toString()); + System.err.println(PM_NOT_RUNNING_ERR); } } @@ -190,6 +262,8 @@ public final class Pm { System.out.println(pgi.name); } } catch (RemoteException e) { + System.err.println(e.toString()); + System.err.println(PM_NOT_RUNNING_ERR); } } @@ -274,6 +348,8 @@ public final class Pm { -10000, 10000); } } catch (RemoteException e) { + System.err.println(e.toString()); + System.err.println(PM_NOT_RUNNING_ERR); } } @@ -472,6 +548,9 @@ public final class Pm { case PackageManager.INSTALL_PARSE_FAILED_MANIFEST_EMPTY: s = "INSTALL_PARSE_FAILED_MANIFEST_EMPTY"; break; + case PackageManager.INSTALL_FAILED_OLDER_SDK: + s = "INSTALL_FAILED_OLDER_SDK"; + break; default: s = Integer.toString(result); break; @@ -523,6 +602,8 @@ public final class Pm { } } } catch (RemoteException e) { + System.err.println(e.toString()); + System.err.println(PM_NOT_RUNNING_ERR); } } @@ -575,6 +656,8 @@ public final class Pm { } } } catch (RemoteException e) { + System.err.println(e.toString()); + System.err.println(PM_NOT_RUNNING_ERR); } return obs.result; } @@ -591,6 +674,8 @@ public final class Pm { System.out.println(info.applicationInfo.sourceDir); } } catch (RemoteException e) { + System.err.println(e.toString()); + System.err.println(PM_NOT_RUNNING_ERR); } } @@ -606,7 +691,8 @@ public final class Pm { mResourceCache.put(pii.packageName, res); return res; } catch (RemoteException e) { - System.err.println("Package manager gone!"); + System.err.println(e.toString()); + System.err.println(PM_NOT_RUNNING_ERR); return null; } } @@ -662,6 +748,7 @@ public final class Pm { System.err.println(" pm list packages [-f]"); System.err.println(" pm list permission-groups"); System.err.println(" pm list permissions [-g] [-f] [-d] [-u] [GROUP]"); + System.err.println(" pm list instrumentation [-f] [TARGET-PACKAGE]"); System.err.println(" pm path PACKAGE"); System.err.println(" pm install [-l] [-r] PATH"); System.err.println(" pm uninstall [-k] PACKAGE"); @@ -680,6 +767,10 @@ public final class Pm { System.err.println("the -d option to only list dangerous permissions. Use"); System.err.println("the -u option to list only the permissions users will see."); System.err.println(""); + System.err.println("The list instrumentation command prints all instrumentations,"); + System.err.println("or only those that target a specified package. Use the -f option"); + System.err.println("to see their associated file."); + System.err.println(""); System.err.println("The path command prints the path to the .apk of a package."); System.err.println(""); System.err.println("The install command installs a package to the system. Use"); diff --git a/cmds/svc/src/com/android/commands/svc/DataCommand.java b/cmds/svc/src/com/android/commands/svc/DataCommand.java new file mode 100644 index 0000000000000000000000000000000000000000..72cb86d69914ccc3791c7c39b702a9cc251291e4 --- /dev/null +++ b/cmds/svc/src/com/android/commands/svc/DataCommand.java @@ -0,0 +1,81 @@ +/* + * 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.android.commands.svc; + +import android.os.ServiceManager; +import android.os.RemoteException; +import android.net.IConnectivityManager; +import android.net.ConnectivityManager; +import android.content.Context; +import com.android.internal.telephony.ITelephony; + +public class DataCommand extends Svc.Command { + public DataCommand() { + super("data"); + } + + public String shortHelp() { + return "Control mobile data connectivity"; + } + + public String longHelp() { + return shortHelp() + "\n" + + "\n" + + "usage: svc data [enable|disable]\n" + + " Turn mobile data on or off.\n\n" + + " svc data prefer\n" + + " Set mobile as the preferred data network\n"; + } + + public void run(String[] args) { + boolean validCommand = false; + if (args.length >= 2) { + boolean flag = false; + if ("enable".equals(args[1])) { + flag = true; + validCommand = true; + } else if ("disable".equals(args[1])) { + flag = false; + validCommand = true; + } else if ("prefer".equals(args[1])) { + IConnectivityManager connMgr = + IConnectivityManager.Stub.asInterface(ServiceManager.getService(Context.CONNECTIVITY_SERVICE)); + try { + connMgr.setNetworkPreference(ConnectivityManager.TYPE_MOBILE); + } catch (RemoteException e) { + System.err.println("Failed to set preferred network: " + e); + } + return; + } + if (validCommand) { + ITelephony phoneMgr + = ITelephony.Stub.asInterface(ServiceManager.getService(Context.TELEPHONY_SERVICE)); + try { + if (flag) { + phoneMgr.enableDataConnectivity(); + } else + phoneMgr.disableDataConnectivity(); + } + catch (RemoteException e) { + System.err.println("Mobile data operation failed: " + e); + } + return; + } + } + System.err.println(longHelp()); + } +} \ No newline at end of file diff --git a/cmds/svc/src/com/android/commands/svc/PowerCommand.java b/cmds/svc/src/com/android/commands/svc/PowerCommand.java index 990837f1794b9ebac79a9263779bb444f59d6631..2b54f549f3894b3c17a6186523557d2cb8772a7d 100644 --- a/cmds/svc/src/com/android/commands/svc/PowerCommand.java +++ b/cmds/svc/src/com/android/commands/svc/PowerCommand.java @@ -19,6 +19,8 @@ package com.android.commands.svc; import android.os.IPowerManager; import android.os.ServiceManager; import android.os.RemoteException; +import android.os.BatteryManager; +import android.content.Context; public class PowerCommand extends Svc.Command { public PowerCommand() { @@ -32,7 +34,7 @@ public class PowerCommand extends Svc.Command { public String longHelp() { return shortHelp() + "\n" + "\n" - + "usage: svc power stayon [true|false]\n" + + "usage: svc power stayon [true|false|usb|ac]\n" + " Set the 'keep awake while plugged in' setting.\n"; } @@ -40,18 +42,23 @@ public class PowerCommand extends Svc.Command { fail: { if (args.length >= 2) { if ("stayon".equals(args[1]) && args.length == 3) { - boolean val; + int val; if ("true".equals(args[2])) { - val = true; + val = BatteryManager.BATTERY_PLUGGED_AC | + BatteryManager.BATTERY_PLUGGED_USB; } else if ("false".equals(args[2])) { - val = false; + val = 0; + } else if ("usb".equals(args[2])) { + val = BatteryManager.BATTERY_PLUGGED_USB; + } else if ("ac".equals(args[2])) { + val = BatteryManager.BATTERY_PLUGGED_AC; } else { break fail; } IPowerManager pm - = IPowerManager.Stub.asInterface(ServiceManager.getService("power")); + = IPowerManager.Stub.asInterface(ServiceManager.getService(Context.POWER_SERVICE)); try { pm.setStayOnSetting(val); } diff --git a/cmds/svc/src/com/android/commands/svc/Svc.java b/cmds/svc/src/com/android/commands/svc/Svc.java index ae397a0cf158ca5567dd2be7ffa71478a67146d6..1cd4c0db0ebcc95a14438d7739367a33cd353806 100644 --- a/cmds/svc/src/com/android/commands/svc/Svc.java +++ b/cmds/svc/src/com/android/commands/svc/Svc.java @@ -16,20 +16,6 @@ package com.android.commands.svc; -import android.app.ActivityManagerNative; -import android.app.IActivityManager; -import android.app.IInstrumentationWatcher; -import android.content.ComponentName; -import android.content.Intent; -import android.net.Uri; -import android.os.RemoteException; -import android.os.Bundle; -import android.os.ServiceManager; -import android.view.IWindowManager; - -import java.util.Iterator; -import java.util.Set; - public class Svc { public static abstract class Command { @@ -49,13 +35,6 @@ public class Svc { } public static void main(String[] args) { - if (true) { - for (String a: args) { - System.err.print(a + " "); - } - System.err.println(); - } - if (args.length >= 1) { Command c = lookupCommand(args[0]); if (c != null) { @@ -66,7 +45,7 @@ public class Svc { COMMAND_HELP.run(args); } - private static final Command lookupCommand(String name) { + private static Command lookupCommand(String name) { final int N = COMMANDS.length; for (int i=0; i= 2) { + boolean flag = false; + if ("enable".equals(args[1])) { + flag = true; + validCommand = true; + } else if ("disable".equals(args[1])) { + flag = false; + validCommand = true; + } else if ("prefer".equals(args[1])) { + IConnectivityManager connMgr = + IConnectivityManager.Stub.asInterface(ServiceManager.getService(Context.CONNECTIVITY_SERVICE)); + try { + connMgr.setNetworkPreference(ConnectivityManager.TYPE_WIFI); + } catch (RemoteException e) { + System.err.println("Failed to set preferred network: " + e); + } + return; + } + if (validCommand) { + IWifiManager wifiMgr + = IWifiManager.Stub.asInterface(ServiceManager.getService(Context.WIFI_SERVICE)); + try { + wifiMgr.setWifiEnabled(flag); + } + catch (RemoteException e) { + System.err.println("Wi-Fi operation failed: " + e); + } + return; + } + } + System.err.println(longHelp()); + } +} \ No newline at end of file diff --git a/core/java/android/accounts/AccountMonitor.java b/core/java/android/accounts/AccountMonitor.java index 9bcc1e78f675a4effa7b89ca360fceb7d4897815..f21385eadeb70cf72b220fffddc3083e73b263dd 100644 --- a/core/java/android/accounts/AccountMonitor.java +++ b/core/java/android/accounts/AccountMonitor.java @@ -42,31 +42,42 @@ public class AccountMonitor extends BroadcastReceiver implements ServiceConnecti private final Context mContext; private final AccountMonitorListener mListener; private boolean mClosed = false; + private int pending = 0; // This thread runs in the background and runs the code to update accounts // in the listener. private class AccountUpdater extends Thread { private IBinder mService; - + public AccountUpdater(IBinder service) { mService = service; } - + @Override public void run() { Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); IAccountsService accountsService = IAccountsService.Stub.asInterface(mService); - String[] accounts; - try { - accounts = accountsService.getAccounts(); - } catch (RemoteException e) { - // if the service was killed then the system will restart it and when it does we - // will get another onServiceConnected, at which point we will do a notify. - Log.w("AccountMonitor", "Remote exception when getting accounts", e); - return; - } + String[] accounts = null; + do { + try { + accounts = accountsService.getAccounts(); + } catch (RemoteException e) { + // if the service was killed then the system will restart it and when it does we + // will get another onServiceConnected, at which point we will do a notify. + Log.w("AccountMonitor", "Remote exception when getting accounts", e); + return; + } + + synchronized (AccountMonitor.this) { + --pending; + if (pending == 0) { + break; + } + } + } while (true); + mContext.unbindService(AccountMonitor.this); - + try { mListener.onAccountsUpdated(accounts); } catch (SQLException e) { @@ -76,7 +87,7 @@ public class AccountMonitor extends BroadcastReceiver implements ServiceConnecti } } } - + /** * Initializes the AccountMonitor and initiates a bind to the * AccountsService to get the initial account list. For 1.0, @@ -93,7 +104,7 @@ public class AccountMonitor extends BroadcastReceiver implements ServiceConnecti mContext = context; mListener = listener; - // Register an intent receiver to monitor account changes + // Register a broadcast receiver to monitor account changes IntentFilter intentFilter = new IntentFilter(); intentFilter.addAction(AccountsServiceConstants.LOGIN_ACCOUNTS_CHANGED_ACTION); intentFilter.addAction(Intent.ACTION_DEVICE_STORAGE_OK); // To recover from disk-full. @@ -116,14 +127,27 @@ public class AccountMonitor extends BroadcastReceiver implements ServiceConnecti public void onServiceDisconnected(ComponentName className) { } - private void notifyListener() { - // initiate the bind - if (!mContext.bindService(AccountsServiceConstants.SERVICE_INTENT, this, - Context.BIND_AUTO_CREATE)) { - // This is normal if GLS isn't part of this build. - Log.w("AccountMonitor", - "Couldn't connect to the accounts service (Missing service?)"); + private synchronized void notifyListener() { + if (pending == 0) { + // initiate the bind + if (!mContext.bindService(AccountsServiceConstants.SERVICE_INTENT, + this, Context.BIND_AUTO_CREATE)) { + // This is normal if GLS isn't part of this build. + Log.w("AccountMonitor", + "Couldn't connect to " + + AccountsServiceConstants.SERVICE_INTENT + + " (Missing service?)"); + } + } else { + // already bound. bindService will not trigger another + // call to onServiceConnected, so instead we make sure + // that the existing background thread will call + // getAccounts() after this function returns, by + // incrementing pending. + // + // Yes, this else clause contains only a comment. } + ++pending; } /** diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java index fa310a5cf14ae6952188895ed9804fe1d0b780a1..eafb0488490fd144fa6fac15cbd303dfd93eb894 100644 --- a/core/java/android/app/Activity.java +++ b/core/java/android/app/Activity.java @@ -62,6 +62,7 @@ import android.widget.AdapterView; import com.android.internal.policy.PolicyManager; import java.util.ArrayList; +import java.util.HashMap; /** * An activity is a single, focused thing that the user can do. Almost all @@ -613,7 +614,8 @@ public class Activity extends ContextThemeWrapper private ComponentName mComponent; /*package*/ ActivityInfo mActivityInfo; /*package*/ ActivityThread mMainThread; - private Object mLastNonConfigurationInstance; + /*package*/ Object mLastNonConfigurationInstance; + /*package*/ HashMap mLastNonConfigurationChildInstances; Activity mParent; boolean mCalled; private boolean mResumed; @@ -1379,6 +1381,38 @@ public class Activity extends ContextThemeWrapper return null; } + /** + * Retrieve the non-configuration instance data that was previously + * returned by {@link #onRetainNonConfigurationChildInstances()}. This will + * be available from the initial {@link #onCreate} and + * {@link #onStart} calls to the new instance, allowing you to extract + * any useful dynamic state from the previous instance. + * + *

    Note that the data you retrieve here should only be used + * as an optimization for handling configuration changes. You should always + * be able to handle getting a null pointer back, and an activity must + * still be able to restore itself to its previous state (through the + * normal {@link #onSaveInstanceState(Bundle)} mechanism) even if this + * function returns null. + * + * @return Returns the object previously returned by + * {@link #onRetainNonConfigurationChildInstances()} + */ + HashMap getLastNonConfigurationChildInstances() { + return mLastNonConfigurationChildInstances; + } + + /** + * This method is similar to {@link #onRetainNonConfigurationInstance()} except that + * it should return either a mapping from child activity id strings to arbitrary objects, + * or null. This method is intended to be used by Activity framework subclasses that control a + * set of child activities, such as ActivityGroup. The same guarantees and restrictions apply + * as for {@link #onRetainNonConfigurationInstance()}. The default implementation returns null. + */ + HashMap onRetainNonConfigurationChildInstances() { + return null; + } + public void onLowMemory() { mCalled = true; } @@ -1837,12 +1871,49 @@ public class Activity extends ContextThemeWrapper * Called when the current {@link Window} of the activity gains or loses * focus. This is the best indicator of whether this activity is visible * to the user. + * + *

    Note that this provides information what global focus state, which + * is managed independently of activity lifecycles. As such, while focus + * changes will generally have some relation to lifecycle changes (an + * activity that is stopped will not generally get window focus), you + * should not rely on any particular order between the callbacks here and + * those in the other lifecycle methods such as {@link #onResume}. + * + *

    As a general rule, however, a resumed activity will have window + * focus... unless it has displayed other dialogs or popups that take + * input focus, in which case the activity itself will not have focus + * when the other windows have it. Likewise, the system may display + * system-level windows (such as the status bar notification panel or + * a system alert) which will temporarily take window input focus without + * pausing the foreground activity. * * @param hasFocus Whether the window of this activity has focus. + * + * @see #hasWindowFocus() + * @see #onResume */ public void onWindowFocusChanged(boolean hasFocus) { } + /** + * Returns true if this activity's main window currently has window focus. + * Note that this is not the same as the view itself having focus. + * + * @return True if this activity's main window currently has window focus. + * + * @see #onWindowAttributesChanged(android.view.WindowManager.LayoutParams) + */ + public boolean hasWindowFocus() { + Window w = getWindow(); + if (w != null) { + View d = w.getDecorView(); + if (d != null) { + return d.hasWindowFocus(); + } + } + return false; + } + /** * Called to process key events. You can override this to intercept all * key events before they are dispatched to the window. Be sure to call @@ -2159,6 +2230,15 @@ public class Activity extends ContextThemeWrapper view.showContextMenu(); } + /** + * Programmatically closes the most recently opened context menu, if showing. + * + * @hide pending API council + */ + public void closeContextMenu() { + mWindow.closePanel(Window.FEATURE_CONTEXT_MENU); + } + /** * This hook is called whenever an item in a context menu is selected. The * default implementation simply returns false to have the normal processing @@ -2910,6 +2990,7 @@ public class Activity extends ContextThemeWrapper * @param flags May be {@link PendingIntent#FLAG_ONE_SHOT PendingIntent.FLAG_ONE_SHOT}, * {@link PendingIntent#FLAG_NO_CREATE PendingIntent.FLAG_NO_CREATE}, * {@link PendingIntent#FLAG_CANCEL_CURRENT PendingIntent.FLAG_CANCEL_CURRENT}, + * {@link PendingIntent#FLAG_UPDATE_CURRENT PendingIntent.FLAG_UPDATE_CURRENT}, * or any of the flags as supported by * {@link Intent#fillIn Intent.fillIn()} to control which unspecified parts * of the intent that can be supplied when the actual send happens. @@ -3285,10 +3366,21 @@ public class Activity extends ContextThemeWrapper Application application, Intent intent, ActivityInfo info, CharSequence title, Activity parent, String id, Object lastNonConfigurationInstance, Configuration config) { + attach(context, aThread, instr, token, application, intent, info, title, parent, id, + lastNonConfigurationInstance, null, config); + } + + final void attach(Context context, ActivityThread aThread, Instrumentation instr, IBinder token, + Application application, Intent intent, ActivityInfo info, CharSequence title, + Activity parent, String id, Object lastNonConfigurationInstance, + HashMap lastNonConfigurationChildInstances, Configuration config) { attachBaseContext(context); mWindow = PolicyManager.makeNewWindow(this); mWindow.setCallback(this); + if (info.softInputMode != WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED) { + mWindow.setSoftInputMode(info.softInputMode); + } mUiThread = Thread.currentThread(); mMainThread = aThread; @@ -3302,6 +3394,7 @@ public class Activity extends ContextThemeWrapper mParent = parent; mEmbeddedID = id; mLastNonConfigurationInstance = lastNonConfigurationInstance; + mLastNonConfigurationChildInstances = lastNonConfigurationChildInstances; mWindow.setWindowManager(null, mToken, mComponent.flattenToString()); if (mParent != null) { @@ -3375,6 +3468,10 @@ public class Activity extends ContextThemeWrapper } } + final void performPause() { + onPause(); + } + final void performStop() { if (!mStopped) { if (mWindow != null) { diff --git a/core/java/android/app/ActivityGroup.java b/core/java/android/app/ActivityGroup.java index 96bb47582de0544d762f99dc0807fb15c2e7bae9..f1216f95e7dfb9d69e3087e9df591bca94ba16d2 100644 --- a/core/java/android/app/ActivityGroup.java +++ b/core/java/android/app/ActivityGroup.java @@ -16,14 +16,19 @@ package android.app; +import java.util.HashMap; + import android.content.Intent; import android.os.Bundle; +import android.util.Log; /** * A screen that contains and runs multiple embedded activities. */ public class ActivityGroup extends Activity { + private static final String TAG = "ActivityGroup"; private static final String STATES_KEY = "android:states"; + static final String PARENT_NON_CONFIG_INSTANCE_KEY = "android:parent_non_config_instance"; /** * This field should be made private, so it is hidden from the SDK. @@ -80,6 +85,17 @@ public class ActivityGroup extends Activity { mLocalActivityManager.dispatchDestroy(isFinishing()); } + /** + * Returns a HashMap mapping from child activity ids to the return values + * from calls to their onRetainNonConfigurationInstance methods. + * + * {@hide} + */ + @Override + public HashMap onRetainNonConfigurationChildInstances() { + return mLocalActivityManager.dispatchRetainNonConfigurationInstance(); + } + public Activity getCurrentActivity() { return mLocalActivityManager.getCurrentActivity(); } diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java index 6eb1102949768c9ad044101822a653a6807a30cc..f9b92218c56a97acb3df75155d27c2d498f2e406 100644 --- a/core/java/android/app/ActivityManager.java +++ b/core/java/android/app/ActivityManager.java @@ -29,7 +29,6 @@ import android.os.Parcelable; import android.os.Parcelable.Creator; import android.text.TextUtils; import android.util.Log; - import java.util.List; /** @@ -601,4 +600,75 @@ public class ActivityManager { return null; } } + + /** + * Information you can retrieve about a running process. + */ + public static class RunningAppProcessInfo implements Parcelable { + /** + * The name of the process that this object is associated with + */ + public String processName; + + /** + * The pid of this process; 0 if none + */ + public int pid; + + public String pkgList[]; + + public RunningAppProcessInfo() { + } + + public RunningAppProcessInfo(String pProcessName, int pPid, String pArr[]) { + processName = pProcessName; + pid = pPid; + pkgList = pArr; + } + + public int describeContents() { + return 0; + } + + public void writeToParcel(Parcel dest, int flags) { + dest.writeString(processName); + dest.writeInt(pid); + dest.writeStringArray(pkgList); + } + + public void readFromParcel(Parcel source) { + processName = source.readString(); + pid = source.readInt(); + pkgList = source.readStringArray(); + } + + public static final Creator CREATOR = + new Creator() { + public RunningAppProcessInfo createFromParcel(Parcel source) { + return new RunningAppProcessInfo(source); + } + public RunningAppProcessInfo[] newArray(int size) { + return new RunningAppProcessInfo[size]; + } + }; + + private RunningAppProcessInfo(Parcel source) { + readFromParcel(source); + } + } + + /** + * Returns a list of application processes that are running on the device. + * + * @return Returns a list of RunningAppProcessInfo records, or null if there are no + * running processes (it will not return an empty list). This list ordering is not + * specified. + */ + public List getRunningAppProcesses() { + try { + return ActivityManagerNative.getDefault().getRunningAppProcesses(); + } catch (RemoteException e) { + return null; + } + } } diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java index e6f1b05f870d0bf0ee1aee928bf4d513293f89e8..ae9f3bf15029c2d664531aa4f4cedf94f5d5abe7 100644 --- a/core/java/android/app/ActivityManagerNative.java +++ b/core/java/android/app/ActivityManagerNative.java @@ -387,6 +387,14 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM reply.writeTypedList(list); return true; } + + case GET_RUNNING_APP_PROCESSES_TRANSACTION: { + data.enforceInterface(IActivityManager.descriptor); + List list = getRunningAppProcesses(); + reply.writeNoException(); + reply.writeTypedList(list); + return true; + } case MOVE_TASK_TO_FRONT_TRANSACTION: { data.enforceInterface(IActivityManager.descriptor); @@ -1314,6 +1322,19 @@ class ActivityManagerProxy implements IActivityManager reply.recycle(); return list; } + public List getRunningAppProcesses() + throws RemoteException { + Parcel data = Parcel.obtain(); + Parcel reply = Parcel.obtain(); + data.writeInterfaceToken(IActivityManager.descriptor); + mRemote.transact(GET_RUNNING_APP_PROCESSES_TRANSACTION, data, reply, 0); + reply.readException(); + ArrayList list + = reply.createTypedArrayList(ActivityManager.RunningAppProcessInfo.CREATOR); + data.recycle(); + reply.recycle(); + return list; + } public void moveTaskToFront(int task) throws RemoteException { Parcel data = Parcel.obtain(); diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index d03a76f0ab00c9d24df08bd34462c3d01b26b8b9..3d448a6201abc66c5421621004d72e55da5a22f7 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -220,7 +220,8 @@ public final class ActivityThread { mApplicationInfo = aInfo; mPackageName = aInfo.packageName; mAppDir = aInfo.sourceDir; - mResDir = aInfo.publicSourceDir; + mResDir = aInfo.uid == Process.myUid() ? aInfo.sourceDir + : aInfo.publicSourceDir; mSharedLibraries = aInfo.sharedLibraryFiles; mDataDir = aInfo.dataDir; mDataDirFile = mDataDir != null ? new File(mDataDir) : null; @@ -1057,6 +1058,7 @@ public final class ActivityThread { Activity parent; String embeddedID; Object lastNonConfigurationInstance; + HashMap lastNonConfigurationChildInstances; boolean paused; boolean stopped; boolean hideForNow; @@ -1966,6 +1968,12 @@ public final class ActivityThread { public final Activity startActivityNow(Activity parent, String id, Intent intent, ActivityInfo activityInfo, IBinder token, Bundle state) { + return startActivityNow(parent, id, intent, activityInfo, token, state, null); + } + + public final Activity startActivityNow(Activity parent, String id, + Intent intent, ActivityInfo activityInfo, IBinder token, Bundle state, + Object lastNonConfigurationInstance) { ActivityRecord r = new ActivityRecord(); r.token = token; r.intent = intent; @@ -1973,6 +1981,7 @@ public final class ActivityThread { r.parent = parent; r.embeddedID = id; r.activityInfo = activityInfo; + r.lastNonConfigurationInstance = lastNonConfigurationInstance; if (localLOGV) { ComponentName compname = intent.getComponent(); String name; @@ -2090,9 +2099,11 @@ public final class ActivityThread { Configuration config = new Configuration(mConfiguration); activity.attach(appContext, this, getInstrumentation(), r.token, app, r.intent, r.activityInfo, title, r.parent, r.embeddedID, - r.lastNonConfigurationInstance, config); + r.lastNonConfigurationInstance, r.lastNonConfigurationChildInstances, + config); r.lastNonConfigurationInstance = null; + r.lastNonConfigurationChildInstances = null; activity.mStartedActivity = false; int theme = r.activityInfo.getThemeResource(); if (theme != 0) { @@ -2948,6 +2959,17 @@ public final class ActivityThread { + ": " + e.toString(), e); } } + try { + r.lastNonConfigurationChildInstances + = r.activity.onRetainNonConfigurationChildInstances(); + } catch (Exception e) { + if (!mInstrumentation.onException(r.activity, e)) { + throw new RuntimeException( + "Unable to retain child activities " + + r.intent.getComponent().toShortString() + + ": " + e.toString(), e); + } + } } try { @@ -3225,11 +3247,7 @@ public final class ActivityThread { Locale.setDefault(config.locale); } - if (mSystemContext != null) { - mSystemContext.getResources().updateConfiguration(config, null); - //Log.i(TAG, "Updated system resources " + mSystemContext.getResources() - // + ": " + mSystemContext.getResources().getConfiguration()); - } + Resources.updateSystemConfiguration(config, null); ApplicationContext.ApplicationPackageManager.configurationChanged(); //Log.i(TAG, "Configuration changed in " + currentPackageName()); diff --git a/core/java/android/app/AlarmManager.java b/core/java/android/app/AlarmManager.java index 35c6ac1f891ed69922dcfcd8d92688761c17d5f7..b4c0e314cfb62adb18108ef396b816af09c082b9 100644 --- a/core/java/android/app/AlarmManager.java +++ b/core/java/android/app/AlarmManager.java @@ -71,17 +71,13 @@ public class AlarmManager */ public static final int ELAPSED_REALTIME = 3; - private static IAlarmManager mService; + private final IAlarmManager mService; - static { - mService = IAlarmManager.Stub.asInterface( - ServiceManager.getService(Context.ALARM_SERVICE)); - } - /** * package private on purpose */ - AlarmManager() { + AlarmManager(IAlarmManager service) { + mService = service; } /** @@ -97,7 +93,7 @@ public class AlarmManager * this one. * *

    - * The alarm is an intent broadcast that goes to an intent receiver that + * The alarm is an intent broadcast that goes to a broadcast receiver that * you registered with {@link android.content.Context#registerReceiver} * or through the <receiver> tag in an AndroidManifest.xml file. * @@ -188,6 +184,72 @@ public class AlarmManager } } + /** + * Available inexact recurrence intervals recognized by + * {@link #setInexactRepeating(int, long, long, PendingIntent)} + */ + public static final long INTERVAL_FIFTEEN_MINUTES = 15 * 60 * 1000; + public static final long INTERVAL_HALF_HOUR = 2*INTERVAL_FIFTEEN_MINUTES; + public static final long INTERVAL_HOUR = 2*INTERVAL_HALF_HOUR; + public static final long INTERVAL_HALF_DAY = 12*INTERVAL_HOUR; + public static final long INTERVAL_DAY = 2*INTERVAL_HALF_DAY; + + /** + * Schedule a repeating alarm that has inexact trigger time requirements; + * for example, an alarm that repeats every hour, but not necessarily at + * the top of every hour. These alarms are more power-efficient than + * the strict recurrences supplied by {@link #setRepeating}, since the + * system can adjust alarms' phase to cause them to fire simultaneously, + * avoiding waking the device from sleep more than necessary. + * + *

    Your alarm's first trigger will not be before the requested time, + * but it might not occur for almost a full interval after that time. In + * addition, while the overall period of the repeating alarm will be as + * requested, the time between any two successive firings of the alarm + * may vary. If your application demands very low jitter, use + * {@link #setRepeating} instead. + * + * @param type One of ELAPSED_REALTIME, ELAPSED_REALTIME_WAKEUP}, RTC or + * RTC_WAKEUP. + * @param triggerAtTime Time the alarm should first go off, using the + * appropriate clock (depending on the alarm type). This + * is inexact: the alarm will not fire before this time, + * but there may be a delay of almost an entire alarm + * interval before the first invocation of the alarm. + * @param interval Interval between subsequent repeats of the alarm. If + * this is one of INTERVAL_FIFTEEN_MINUTES, INTERVAL_HALF_HOUR, + * INTERVAL_HOUR, INTERVAL_HALF_DAY, or INTERVAL_DAY then the + * alarm will be phase-aligned with other alarms to reduce + * the number of wakeups. Otherwise, the alarm will be set + * as though the application had called {@link #setRepeating}. + * @param operation Action to perform when the alarm goes off; + * typically comes from {@link PendingIntent#getBroadcast + * IntentSender.getBroadcast()}. + * + * @see android.os.Handler + * @see #set + * @see #cancel + * @see android.content.Context#sendBroadcast + * @see android.content.Context#registerReceiver + * @see android.content.Intent#filterEquals + * @see #ELAPSED_REALTIME + * @see #ELAPSED_REALTIME_WAKEUP + * @see #RTC + * @see #RTC_WAKEUP + * @see #INTERVAL_FIFTEEN_MINUTES + * @see #INTERVAL_HALF_HOUR + * @see #INTERVAL_HOUR + * @see #INTERVAL_HALF_DAY + * @see #INTERVAL_DAY + */ + public void setInexactRepeating(int type, long triggerAtTime, long interval, + PendingIntent operation) { + try { + mService.setInexactRepeating(type, triggerAtTime, interval, operation); + } catch (RemoteException ex) { + } + } + /** * Remove any alarms with a matching {@link Intent}. * Any alarm, of any type, whose Intent matches this one (as defined by diff --git a/core/java/android/app/AlertDialog.java b/core/java/android/app/AlertDialog.java index cc80ba404f3030c4bbf1ab80686f37758fd53955..a6981a5c959993704bec8b867114cbcf8f21b904 100644 --- a/core/java/android/app/AlertDialog.java +++ b/core/java/android/app/AlertDialog.java @@ -25,6 +25,7 @@ import android.os.Message; import android.view.KeyEvent; import android.view.View; import android.widget.AdapterView; +import android.widget.Button; import android.widget.ListAdapter; import android.widget.ListView; @@ -59,6 +60,29 @@ public class AlertDialog extends Dialog implements DialogInterface { setOnCancelListener(cancelListener); mAlert = new AlertController(context, this, getWindow()); } + + /** + * Gets one of the buttons used in the dialog. + *

    + * If a button does not exist in the dialog, null will be returned. + * + * @param whichButton The identifier of the button that should be returned. + * For example, this can be + * {@link DialogInterface#BUTTON_POSITIVE}. + * @return The button from the dialog, or null if a button does not exist. + */ + public Button getButton(int whichButton) { + return mAlert.getButton(whichButton); + } + + /** + * Gets the list view used in the dialog. + * + * @return The {@link ListView} from the dialog. + */ + public ListView getListView() { + return mAlert.getListView(); + } @Override public void setTitle(CharSequence title) { @@ -83,44 +107,115 @@ public class AlertDialog extends Dialog implements DialogInterface { public void setView(View view) { mAlert.setView(view); } + + /** + * Set the view to display in that dialog, specifying the spacing to appear around that + * view. + * + * @param view The view to show in the content area of the dialog + * @param viewSpacingLeft Extra space to appear to the left of {@code view} + * @param viewSpacingTop Extra space to appear above {@code view} + * @param viewSpacingRight Extra space to appear to the right of {@code view} + * @param viewSpacingBottom Extra space to appear below {@code view} + */ + public void setView(View view, int viewSpacingLeft, int viewSpacingTop, int viewSpacingRight, + int viewSpacingBottom) { + mAlert.setView(view, viewSpacingLeft, viewSpacingTop, viewSpacingRight, viewSpacingBottom); + } - public void setButton(CharSequence text, Message msg) { - mAlert.setButton(text, msg); + /** + * Set a message to be sent when a button is pressed. + * + * @param whichButton Which button to set the message for, can be one of + * {@link DialogInterface#BUTTON_POSITIVE}, + * {@link DialogInterface#BUTTON_NEGATIVE}, or + * {@link DialogInterface#BUTTON_NEUTRAL} + * @param text The text to display in positive button. + * @param msg The {@link Message} to be sent when clicked. + */ + public void setButton(int whichButton, CharSequence text, Message msg) { + mAlert.setButton(whichButton, text, null, msg); + } + + /** + * Set a listener to be invoked when the positive button of the dialog is pressed. + * + * @param whichButton Which button to set the listener on, can be one of + * {@link DialogInterface#BUTTON_POSITIVE}, + * {@link DialogInterface#BUTTON_NEGATIVE}, or + * {@link DialogInterface#BUTTON_NEUTRAL} + * @param text The text to display in positive button. + * @param listener The {@link DialogInterface.OnClickListener} to use. + */ + public void setButton(int whichButton, CharSequence text, OnClickListener listener) { + mAlert.setButton(whichButton, text, listener, null); } + /** + * @deprecated Use {@link #setButton(int, CharSequence, Message)} with + * {@link DialogInterface#BUTTON_POSITIVE}. + */ + @Deprecated + public void setButton(CharSequence text, Message msg) { + setButton(BUTTON_POSITIVE, text, msg); + } + + /** + * @deprecated Use {@link #setButton(int, CharSequence, Message)} with + * {@link DialogInterface#BUTTON_NEGATIVE}. + */ + @Deprecated public void setButton2(CharSequence text, Message msg) { - mAlert.setButton2(text, msg); + setButton(BUTTON_NEGATIVE, text, msg); } + /** + * @deprecated Use {@link #setButton(int, CharSequence, Message)} with + * {@link DialogInterface#BUTTON_NEUTRAL}. + */ + @Deprecated public void setButton3(CharSequence text, Message msg) { - mAlert.setButton3(text, msg); + setButton(BUTTON_NEUTRAL, text, msg); } /** * Set a listener to be invoked when button 1 of the dialog is pressed. + * * @param text The text to display in button 1. * @param listener The {@link DialogInterface.OnClickListener} to use. + * @deprecated Use + * {@link #setButton(int, CharSequence, android.content.DialogInterface.OnClickListener)} + * with {@link DialogInterface#BUTTON_POSITIVE} */ + @Deprecated public void setButton(CharSequence text, final OnClickListener listener) { - mAlert.setButton(text, listener); + setButton(BUTTON_POSITIVE, text, listener); } /** * Set a listener to be invoked when button 2 of the dialog is pressed. * @param text The text to display in button 2. * @param listener The {@link DialogInterface.OnClickListener} to use. + * @deprecated Use + * {@link #setButton(int, CharSequence, android.content.DialogInterface.OnClickListener)} + * with {@link DialogInterface#BUTTON_NEGATIVE} */ + @Deprecated public void setButton2(CharSequence text, final OnClickListener listener) { - mAlert.setButton2(text, listener); + setButton(BUTTON_NEGATIVE, text, listener); } /** * Set a listener to be invoked when button 3 of the dialog is pressed. * @param text The text to display in button 3. * @param listener The {@link DialogInterface.OnClickListener} to use. + * @deprecated Use + * {@link #setButton(int, CharSequence, android.content.DialogInterface.OnClickListener)} + * with {@link DialogInterface#BUTTON_POSITIVE} */ + @Deprecated public void setButton3(CharSequence text, final OnClickListener listener) { - mAlert.setButton3(text, listener); + setButton(BUTTON_NEUTRAL, text, listener); } /** @@ -170,6 +265,8 @@ public class AlertDialog extends Dialog implements DialogInterface { /** * Set the title using the given resource id. + * + * @return This Builder object to allow for chaining of calls to set methods */ public Builder setTitle(int titleId) { P.mTitle = P.mContext.getText(titleId); @@ -178,6 +275,8 @@ public class AlertDialog extends Dialog implements DialogInterface { /** * Set the title displayed in the {@link Dialog}. + * + * @return This Builder object to allow for chaining of calls to set methods */ public Builder setTitle(CharSequence title) { P.mTitle = title; @@ -192,6 +291,8 @@ public class AlertDialog extends Dialog implements DialogInterface { * via the other methods. * * @param customTitleView The custom view to use as the title. + * + * @return This Builder object to allow for chaining of calls to set methods */ public Builder setCustomTitle(View customTitleView) { P.mCustomTitleView = customTitleView; @@ -200,6 +301,8 @@ public class AlertDialog extends Dialog implements DialogInterface { /** * Set the message to display using the given resource id. + * + * @return This Builder object to allow for chaining of calls to set methods */ public Builder setMessage(int messageId) { P.mMessage = P.mContext.getText(messageId); @@ -208,6 +311,8 @@ public class AlertDialog extends Dialog implements DialogInterface { /** * Set the message to display. + * + * @return This Builder object to allow for chaining of calls to set methods */ public Builder setMessage(CharSequence message) { P.mMessage = message; @@ -216,6 +321,8 @@ public class AlertDialog extends Dialog implements DialogInterface { /** * Set the resource id of the {@link Drawable} to be used in the title. + * + * @return This Builder object to allow for chaining of calls to set methods */ public Builder setIcon(int iconId) { P.mIconId = iconId; @@ -224,6 +331,8 @@ public class AlertDialog extends Dialog implements DialogInterface { /** * Set the {@link Drawable} to be used in the title. + * + * @return This Builder object to allow for chaining of calls to set methods */ public Builder setIcon(Drawable icon) { P.mIcon = icon; @@ -234,6 +343,8 @@ public class AlertDialog extends Dialog implements DialogInterface { * Set a listener to be invoked when the positive button of the dialog is pressed. * @param textId The resource id of the text to display in the positive button * @param listener The {@link DialogInterface.OnClickListener} to use. + * + * @return This Builder object to allow for chaining of calls to set methods */ public Builder setPositiveButton(int textId, final OnClickListener listener) { P.mPositiveButtonText = P.mContext.getText(textId); @@ -245,6 +356,8 @@ public class AlertDialog extends Dialog implements DialogInterface { * Set a listener to be invoked when the positive button of the dialog is pressed. * @param text The text to display in the positive button * @param listener The {@link DialogInterface.OnClickListener} to use. + * + * @return This Builder object to allow for chaining of calls to set methods */ public Builder setPositiveButton(CharSequence text, final OnClickListener listener) { P.mPositiveButtonText = text; @@ -256,6 +369,8 @@ public class AlertDialog extends Dialog implements DialogInterface { * Set a listener to be invoked when the negative button of the dialog is pressed. * @param textId The resource id of the text to display in the negative button * @param listener The {@link DialogInterface.OnClickListener} to use. + * + * @return This Builder object to allow for chaining of calls to set methods */ public Builder setNegativeButton(int textId, final OnClickListener listener) { P.mNegativeButtonText = P.mContext.getText(textId); @@ -267,6 +382,8 @@ public class AlertDialog extends Dialog implements DialogInterface { * Set a listener to be invoked when the negative button of the dialog is pressed. * @param text The text to display in the negative button * @param listener The {@link DialogInterface.OnClickListener} to use. + * + * @return This Builder object to allow for chaining of calls to set methods */ public Builder setNegativeButton(CharSequence text, final OnClickListener listener) { P.mNegativeButtonText = text; @@ -278,6 +395,8 @@ public class AlertDialog extends Dialog implements DialogInterface { * Set a listener to be invoked when the neutral button of the dialog is pressed. * @param textId The resource id of the text to display in the neutral button * @param listener The {@link DialogInterface.OnClickListener} to use. + * + * @return This Builder object to allow for chaining of calls to set methods */ public Builder setNeutralButton(int textId, final OnClickListener listener) { P.mNeutralButtonText = P.mContext.getText(textId); @@ -289,6 +408,8 @@ public class AlertDialog extends Dialog implements DialogInterface { * Set a listener to be invoked when the neutral button of the dialog is pressed. * @param text The text to display in the neutral button * @param listener The {@link DialogInterface.OnClickListener} to use. + * + * @return This Builder object to allow for chaining of calls to set methods */ public Builder setNeutralButton(CharSequence text, final OnClickListener listener) { P.mNeutralButtonText = text; @@ -298,6 +419,8 @@ public class AlertDialog extends Dialog implements DialogInterface { /** * Sets whether the dialog is cancelable or not default is true. + * + * @return This Builder object to allow for chaining of calls to set methods */ public Builder setCancelable(boolean cancelable) { P.mCancelable = cancelable; @@ -307,6 +430,8 @@ public class AlertDialog extends Dialog implements DialogInterface { /** * Sets the callback that will be called if the dialog is canceled. * @see #setCancelable(boolean) + * + * @return This Builder object to allow for chaining of calls to set methods */ public Builder setOnCancelListener(OnCancelListener onCancelListener) { P.mOnCancelListener = onCancelListener; @@ -315,6 +440,8 @@ public class AlertDialog extends Dialog implements DialogInterface { /** * Sets the callback that will be called if a key is dispatched to the dialog. + * + * @return This Builder object to allow for chaining of calls to set methods */ public Builder setOnKeyListener(OnKeyListener onKeyListener) { P.mOnKeyListener = onKeyListener; @@ -324,6 +451,8 @@ public class AlertDialog extends Dialog implements DialogInterface { /** * Set a list of items to be displayed in the dialog as the content, you will be notified of the * selected item via the supplied listener. This should be an array type i.e. R.array.foo + * + * @return This Builder object to allow for chaining of calls to set methods */ public Builder setItems(int itemsId, final OnClickListener listener) { P.mItems = P.mContext.getResources().getTextArray(itemsId); @@ -334,6 +463,8 @@ public class AlertDialog extends Dialog implements DialogInterface { /** * Set a list of items to be displayed in the dialog as the content, you will be notified of the * selected item via the supplied listener. + * + * @return This Builder object to allow for chaining of calls to set methods */ public Builder setItems(CharSequence[] items, final OnClickListener listener) { P.mItems = items; @@ -348,6 +479,8 @@ public class AlertDialog extends Dialog implements DialogInterface { * * @param adapter The {@link ListAdapter} to supply the list of items * @param listener The listener that will be called when an item is clicked. + * + * @return This Builder object to allow for chaining of calls to set methods */ public Builder setAdapter(final ListAdapter adapter, final OnClickListener listener) { P.mAdapter = adapter; @@ -364,6 +497,8 @@ public class AlertDialog extends Dialog implements DialogInterface { * @param listener The listener that will be called when an item is clicked. * @param labelColumn The column name on the cursor containing the string to display * in the label. + * + * @return This Builder object to allow for chaining of calls to set methods */ public Builder setCursor(final Cursor cursor, final OnClickListener listener, String labelColumn) { @@ -388,6 +523,8 @@ public class AlertDialog extends Dialog implements DialogInterface { * @param listener notified when an item on the list is clicked. The dialog will not be * dismissed when an item is clicked. It will only be dismissed if clicked on a * button, if no buttons are supplied it's up to the user to dismiss the dialog. + * + * @return This Builder object to allow for chaining of calls to set methods */ public Builder setMultiChoiceItems(int itemsId, boolean[] checkedItems, final OnMultiChoiceClickListener listener) { @@ -412,6 +549,8 @@ public class AlertDialog extends Dialog implements DialogInterface { * @param listener notified when an item on the list is clicked. The dialog will not be * dismissed when an item is clicked. It will only be dismissed if clicked on a * button, if no buttons are supplied it's up to the user to dismiss the dialog. + * + * @return This Builder object to allow for chaining of calls to set methods */ public Builder setMultiChoiceItems(CharSequence[] items, boolean[] checkedItems, final OnMultiChoiceClickListener listener) { @@ -438,6 +577,8 @@ public class AlertDialog extends Dialog implements DialogInterface { * @param listener notified when an item on the list is clicked. The dialog will not be * dismissed when an item is clicked. It will only be dismissed if clicked on a * button, if no buttons are supplied it's up to the user to dismiss the dialog. + * + * @return This Builder object to allow for chaining of calls to set methods */ public Builder setMultiChoiceItems(Cursor cursor, String isCheckedColumn, String labelColumn, final OnMultiChoiceClickListener listener) { @@ -461,6 +602,8 @@ public class AlertDialog extends Dialog implements DialogInterface { * @param listener notified when an item on the list is clicked. The dialog will not be * dismissed when an item is clicked. It will only be dismissed if clicked on a * button, if no buttons are supplied it's up to the user to dismiss the dialog. + * + * @return This Builder object to allow for chaining of calls to set methods */ public Builder setSingleChoiceItems(int itemsId, int checkedItem, final OnClickListener listener) { @@ -484,6 +627,8 @@ public class AlertDialog extends Dialog implements DialogInterface { * @param listener notified when an item on the list is clicked. The dialog will not be * dismissed when an item is clicked. It will only be dismissed if clicked on a * button, if no buttons are supplied it's up to the user to dismiss the dialog. + * + * @return This Builder object to allow for chaining of calls to set methods */ public Builder setSingleChoiceItems(Cursor cursor, int checkedItem, String labelColumn, final OnClickListener listener) { @@ -506,6 +651,8 @@ public class AlertDialog extends Dialog implements DialogInterface { * @param listener notified when an item on the list is clicked. The dialog will not be * dismissed when an item is clicked. It will only be dismissed if clicked on a * button, if no buttons are supplied it's up to the user to dismiss the dialog. + * + * @return This Builder object to allow for chaining of calls to set methods */ public Builder setSingleChoiceItems(CharSequence[] items, int checkedItem, final OnClickListener listener) { P.mItems = items; @@ -526,6 +673,8 @@ public class AlertDialog extends Dialog implements DialogInterface { * @param listener notified when an item on the list is clicked. The dialog will not be * dismissed when an item is clicked. It will only be dismissed if clicked on a * button, if no buttons are supplied it's up to the user to dismiss the dialog. + * + * @return This Builder object to allow for chaining of calls to set methods */ public Builder setSingleChoiceItems(ListAdapter adapter, int checkedItem, final OnClickListener listener) { P.mAdapter = adapter; @@ -540,6 +689,8 @@ public class AlertDialog extends Dialog implements DialogInterface { * * @param listener The listener to be invoked. * @see AdapterView#setOnItemSelectedListener(android.widget.AdapterView.OnItemSelectedListener) + * + * @return This Builder object to allow for chaining of calls to set methods */ public Builder setOnItemSelectedListener(final AdapterView.OnItemSelectedListener listener) { P.mOnItemSelectedListener = listener; @@ -549,9 +700,44 @@ public class AlertDialog extends Dialog implements DialogInterface { /** * Set a custom view to be the contents of the Dialog. If the supplied view is an instance * of a {@link ListView} the light background will be used. + * + * @param view The view to use as the contents of the Dialog. + * + * @return This Builder object to allow for chaining of calls to set methods */ public Builder setView(View view) { P.mView = view; + P.mViewSpacingSpecified = false; + return this; + } + + /** + * Set a custom view to be the contents of the Dialog, specifying the + * spacing to appear around that view. If the supplied view is an + * instance of a {@link ListView} the light background will be used. + * + * @param view The view to use as the contents of the Dialog. + * @param viewSpacingLeft Spacing between the left edge of the view and + * the dialog frame + * @param viewSpacingTop Spacing between the top edge of the view and + * the dialog frame + * @param viewSpacingRight Spacing between the right edge of the view + * and the dialog frame + * @param viewSpacingBottom Spacing between the bottom edge of the view + * and the dialog frame + * @return This Builder object to allow for chaining of calls to set + * methods + * + * @hide pending API review + */ + public Builder setView(View view, int viewSpacingLeft, int viewSpacingTop, + int viewSpacingRight, int viewSpacingBottom) { + P.mView = view; + P.mViewSpacingSpecified = true; + P.mViewSpacingLeft = viewSpacingLeft; + P.mViewSpacingTop = viewSpacingTop; + P.mViewSpacingRight = viewSpacingRight; + P.mViewSpacingBottom = viewSpacingBottom; return this; } @@ -560,7 +746,8 @@ public class AlertDialog extends Dialog implements DialogInterface { * contents is. * * @param useInverseBackground Whether to use the inverse background - * @return This Builder object to allow for chaining of sets. + * + * @return This Builder object to allow for chaining of calls to set methods */ public Builder setInverseBackgroundForced(boolean useInverseBackground) { P.mForceInverseBackground = useInverseBackground; diff --git a/core/java/android/app/ApplicationContext.java b/core/java/android/app/ApplicationContext.java index 342ffcf962e5f55ca89aa728cd1143cd8b8e00f3..0e41ae6f2faf33e9bcaa54670381f6fef921da74 100644 --- a/core/java/android/app/ApplicationContext.java +++ b/core/java/android/app/ApplicationContext.java @@ -87,6 +87,7 @@ import android.util.Log; import android.view.ContextThemeWrapper; import android.view.LayoutInflater; import android.view.WindowManagerImpl; +import android.view.inputmethod.InputMethodManager; import com.android.internal.policy.PolicyManager; @@ -104,6 +105,8 @@ import java.util.List; import java.util.Map; import java.util.Map.Entry; +import org.xmlpull.v1.XmlPullParserException; + class ReceiverRestrictedContext extends ContextWrapper { ReceiverRestrictedContext(Context base) { super(base); @@ -139,12 +142,12 @@ class ReceiverRestrictedContext extends ContextWrapper { * Common implementation of Context API, which Activity and other application * classes inherit. */ -@SuppressWarnings({"EmptyCatchBlock"}) class ApplicationContext extends Context { private final static String TAG = "ApplicationContext"; private final static boolean DEBUG_ICONS = false; private static final Object sSync = new Object(); + private static AlarmManager sAlarmManager; private static PowerManager sPowerManager; private static ConnectivityManager sConnectivityManager; private static WifiManager sWifiManager; @@ -288,12 +291,15 @@ class ApplicationContext extends Context { } throw new RuntimeException("Not supported in system context"); } + + private static File makeBackupFile(File prefsFile) { + return new File(prefsFile.getPath() + ".bak"); + } @Override public SharedPreferences getSharedPreferences(String name, int mode) { - File f; - f = makeFilename(getPreferencesDir(), name + ".xml"); SharedPreferencesImpl sp; + File f = makeFilename(getPreferencesDir(), name + ".xml"); synchronized (sSharedPrefs) { sp = sSharedPrefs.get(f); if (sp != null && !sp.hasFileChanged()) { @@ -301,15 +307,27 @@ class ApplicationContext extends Context { return sp; } } + + FileInputStream str = null; + File backup = makeBackupFile(f); + if (backup.exists()) { + f.delete(); + backup.renameTo(f); + } Map map = null; - try { - FileInputStream str = new FileInputStream(f); - map = XmlUtils.readMapXml(str); - str.close(); - } catch (org.xmlpull.v1.XmlPullParserException e) { - } catch (java.io.FileNotFoundException e) { - } catch (java.io.IOException e) { + if (f.exists()) { + try { + str = new FileInputStream(f); + map = XmlUtils.readMapXml(str); + str.close(); + } catch (org.xmlpull.v1.XmlPullParserException e) { + Log.w(TAG, "getSharedPreferences", e); + } catch (FileNotFoundException e) { + Log.w(TAG, "getSharedPreferences", e); + } catch (IOException e) { + Log.w(TAG, "getSharedPreferences", e); + } } synchronized (sSharedPrefs) { @@ -350,7 +368,7 @@ class ApplicationContext extends Context { File f = makeFilename(getFilesDir(), name); try { FileOutputStream fos = new FileOutputStream(f, append); - setFilePermissionsFromMode(f.toString(), mode, 0); + setFilePermissionsFromMode(f.getPath(), mode, 0); return fos; } catch (FileNotFoundException e) { } @@ -358,11 +376,11 @@ class ApplicationContext extends Context { File parent = f.getParentFile(); parent.mkdir(); FileUtils.setPermissions( - parent.toString(), + parent.getPath(), FileUtils.S_IRWXU|FileUtils.S_IRWXG|FileUtils.S_IXOTH, -1, -1); FileOutputStream fos = new FileOutputStream(f, append); - setFilePermissionsFromMode(f.toString(), mode, 0); + setFilePermissionsFromMode(f.getPath(), mode, 0); return fos; } @@ -378,6 +396,16 @@ class ApplicationContext extends Context { if (mFilesDir == null) { mFilesDir = new File(getDataDirFile(), "files"); } + if (!mFilesDir.exists()) { + if(!mFilesDir.mkdirs()) { + Log.w(TAG, "Unable to create files directory"); + return null; + } + FileUtils.setPermissions( + mFilesDir.getPath(), + FileUtils.S_IRWXU|FileUtils.S_IRWXG|FileUtils.S_IXOTH, + -1, -1); + } return mFilesDir; } } @@ -394,7 +422,7 @@ class ApplicationContext extends Context { return null; } FileUtils.setPermissions( - mCacheDir.toString(), + mCacheDir.getPath(), FileUtils.S_IRWXU|FileUtils.S_IRWXG|FileUtils.S_IXOTH, -1, -1); } @@ -418,14 +446,14 @@ class ApplicationContext extends Context { public SQLiteDatabase openOrCreateDatabase(String name, int mode, CursorFactory factory) { File dir = getDatabasesDir(); if (!dir.isDirectory() && dir.mkdir()) { - FileUtils.setPermissions(dir.toString(), + FileUtils.setPermissions(dir.getPath(), FileUtils.S_IRWXU|FileUtils.S_IRWXG|FileUtils.S_IXOTH, -1, -1); } File f = makeFilename(dir, name); SQLiteDatabase db = SQLiteDatabase.openOrCreateDatabase(f, factory); - setFilePermissionsFromMode(f.toString(), mode, 0); + setFilePermissionsFromMode(f.getPath(), mode, 0); return db; } @@ -844,7 +872,7 @@ class ApplicationContext extends Context { } else if (ACTIVITY_SERVICE.equals(name)) { return getActivityManager(); } else if (ALARM_SERVICE.equals(name)) { - return new AlarmManager(); + return getAlarmManager(); } else if (POWER_SERVICE.equals(name)) { return getPowerManager(); } else if (CONNECTIVITY_SERVICE.equals(name)) { @@ -878,6 +906,8 @@ class ApplicationContext extends Context { return getTelephonyManager(); } else if (CLIPBOARD_SERVICE.equals(name)) { return getClipboardManager(); + } else if (INPUT_METHOD_SERVICE.equals(name)) { + return InputMethodManager.getInstance(this); } return null; @@ -893,6 +923,17 @@ class ApplicationContext extends Context { return mActivityManager; } + private AlarmManager getAlarmManager() { + synchronized (sSync) { + if (sAlarmManager == null) { + IBinder b = ServiceManager.getService(ALARM_SERVICE); + IAlarmManager service = IAlarmManager.Stub.asInterface(b); + sAlarmManager = new AlarmManager(service); + } + } + return sAlarmManager; + } + private PowerManager getPowerManager() { synchronized (sSync) { if (sPowerManager == null) { @@ -1299,7 +1340,7 @@ class ApplicationContext extends Context { File file = makeFilename(getDataDirFile(), name); if (!file.exists()) { file.mkdir(); - setFilePermissionsFromMode(file.toString(), mode, + setFilePermissionsFromMode(file.getPath(), mode, FileUtils.S_IRWXU|FileUtils.S_IRWXG|FileUtils.S_IXOTH); } return file; @@ -1636,6 +1677,20 @@ class ApplicationContext extends Context { throw new RuntimeException("Package manager has died", e); } } + + @Override + public int getUidForSharedUser(String sharedUserName) + throws NameNotFoundException { + try { + int uid = mPM.getUidForSharedUser(sharedUserName); + if(uid != -1) { + return uid; + } + } catch (RemoteException e) { + throw new RuntimeException("Package manager has died", e); + } + throw new NameNotFoundException("No shared userid for user:"+sharedUserName); + } @Override public List getInstalledPackages(int flags) { @@ -1899,7 +1954,9 @@ class ApplicationContext extends Context { if (app.packageName.equals("system")) { return mContext.mMainThread.getSystemContext().getResources(); } - Resources r = mContext.mMainThread.getTopLevelResources(app.publicSourceDir); + Resources r = mContext.mMainThread.getTopLevelResources( + app.uid == Process.myUid() ? app.sourceDir + : app.publicSourceDir); if (r != null) { return r; } @@ -2341,6 +2398,7 @@ class ApplicationContext extends Context { private static final class SharedPreferencesImpl implements SharedPreferences { private final File mFile; + private final File mBackupFile; private final int mMode; private Map mMap; private final FileStatus mFileStatus = new FileStatus(); @@ -2351,6 +2409,7 @@ class ApplicationContext extends Context { SharedPreferencesImpl( File file, int mode, Map initialContents) { mFile = file; + mBackupFile = makeBackupFile(file); mMode = mode; mMap = initialContents != null ? initialContents : new HashMap(); if (FileUtils.getFileStatus(file.getPath(), mFileStatus)) { @@ -2544,30 +2603,68 @@ class ApplicationContext extends Context { public Editor edit() { return new EditorImpl(); } + + private FileOutputStream createFileOutputStream(File file) { + FileOutputStream str = null; + try { + str = new FileOutputStream(file); + } catch (FileNotFoundException e) { + File parent = file.getParentFile(); + if (!parent.mkdir()) { + Log.e(TAG, "Couldn't create directory for SharedPreferences file " + file); + return null; + } + FileUtils.setPermissions( + parent.getPath(), + FileUtils.S_IRWXU|FileUtils.S_IRWXG|FileUtils.S_IXOTH, + -1, -1); + try { + str = new FileOutputStream(file); + } catch (FileNotFoundException e2) { + Log.e(TAG, "Couldn't create SharedPreferences file " + file, e2); + } + } + return str; + } private boolean writeFileLocked() { + // Rename the current file so it may be used as a backup during the next read + if (mFile.exists()) { + if (!mFile.renameTo(mBackupFile)) { + Log.e(TAG, "Couldn't rename file " + mFile + " to backup file " + mBackupFile); + } + } + + // Attempt to write the file, delete the backup and return true as atomically as + // possible. If any exception occurs, delete the new file; next time we will restore + // from the backup. try { - FileOutputStream str; - try { - str = new FileOutputStream(mFile); - } catch (Exception e) { - File parent = mFile.getParentFile(); - parent.mkdir(); - FileUtils.setPermissions( - parent.toString(), - FileUtils.S_IRWXU|FileUtils.S_IRWXG|FileUtils.S_IXOTH, - -1, -1); - str = new FileOutputStream(mFile); + FileOutputStream str = createFileOutputStream(mFile); + if (str == null) { + return false; } XmlUtils.writeMapXml(mMap, str); str.close(); - setFilePermissionsFromMode(mFile.toString(), mMode, 0); + setFilePermissionsFromMode(mFile.getPath(), mMode, 0); if (FileUtils.getFileStatus(mFile.getPath(), mFileStatus)) { mTimestamp = mFileStatus.mtime; } - } catch (org.xmlpull.v1.XmlPullParserException e) { - } catch (java.io.FileNotFoundException e) { - } catch (java.io.IOException e) { + + // Writing was successful, delete the backup file + if (!mBackupFile.delete()) { + Log.e(TAG, "Couldn't delete new backup file " + mBackupFile); + } + return true; + } catch (XmlPullParserException e) { + Log.w(TAG, "writeFileLocked: Got exception:", e); + } catch (IOException e) { + Log.w(TAG, "writeFileLocked: Got exception:", e); + } + // Clean up an unsuccessfully written file + if (mFile.exists()) { + if (!mFile.delete()) { + Log.e(TAG, "Couldn't clean up partially-written file " + mFile); + } } return false; } diff --git a/core/java/android/app/DatePickerDialog.java b/core/java/android/app/DatePickerDialog.java index 7450559dcd88c3361803378da6ab0f192c321b27..ee5e0d5b577ca10c675e03d841273114acb684de 100644 --- a/core/java/android/app/DatePickerDialog.java +++ b/core/java/android/app/DatePickerDialog.java @@ -20,8 +20,8 @@ import android.content.Context; import android.content.DialogInterface; import android.content.DialogInterface.OnClickListener; import android.os.Bundle; -import android.pim.DateFormat; import android.text.TextUtils.TruncateAt; +import android.text.format.DateFormat; import android.view.LayoutInflater; import android.view.View; import android.widget.DatePicker; @@ -107,7 +107,7 @@ public class DatePickerDialog extends AlertDialog implements OnClickListener, DateFormatSymbols symbols = new DateFormatSymbols(); mWeekDays = symbols.getShortWeekdays(); - mDateFormat = DateFormat.getLongDateFormat(context); + mDateFormat = DateFormat.getMediumDateFormat(context); mCalendar = Calendar.getInstance(); updateTitle(mInitialYear, mInitialMonth, mInitialDay); diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java index 2de21ed825570b0c13ff2c35338a0b49a427b511..353500e923459210aea7b38d1d27fdaa2661f53f 100644 --- a/core/java/android/app/IActivityManager.java +++ b/core/java/android/app/IActivityManager.java @@ -213,6 +213,9 @@ public interface IActivityManager extends IInterface { * SIGUSR1 is delivered. All others are ignored. */ public void signalPersistentProcesses(int signal) throws RemoteException; + // Retrieve running application processes in the system + public List getRunningAppProcesses() + throws RemoteException; /** Information you can retrieve about a particular application. */ public static class ContentProviderHolder implements Parcelable { @@ -350,4 +353,5 @@ public interface IActivityManager extends IInterface { int KILL_PIDS_FOR_MEMORY_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+79; int GET_SERVICES_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+80; int REPORT_PSS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+81; + int GET_RUNNING_APP_PROCESSES_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+82; } diff --git a/core/java/android/app/IAlarmManager.aidl b/core/java/android/app/IAlarmManager.aidl index c7f20b9bda7e4057aa250f28dfd89ce6a967d232..cb42236f413c03cd4a05d3b5394a61fc7ee4dd95 100755 --- a/core/java/android/app/IAlarmManager.aidl +++ b/core/java/android/app/IAlarmManager.aidl @@ -26,6 +26,7 @@ import android.app.PendingIntent; interface IAlarmManager { void set(int type, long triggerAtTime, in PendingIntent operation); void setRepeating(int type, long triggerAtTime, long interval, in PendingIntent operation); + void setInexactRepeating(int type, long triggerAtTime, long interval, in PendingIntent operation); void setTimeZone(String zone); void remove(in PendingIntent operation); } diff --git a/core/java/android/app/Instrumentation.java b/core/java/android/app/Instrumentation.java index f80c947efe2e477c31d4bdca880676ab7913e2da..17618ff26fd4a223df550f038cdf0521927785b3 100644 --- a/core/java/android/app/Instrumentation.java +++ b/core/java/android/app/Instrumentation.java @@ -40,6 +40,7 @@ import android.view.KeyEvent; import android.view.MotionEvent; import android.view.ViewConfiguration; import android.view.Window; +import android.view.inputmethod.InputMethodManager; import java.io.File; import java.util.ArrayList; @@ -1262,7 +1263,7 @@ public class Instrumentation { * @param activity The activity being paused. */ public void callActivityOnPause(Activity activity) { - activity.onPause(); + activity.performPause(); } /* @@ -1392,8 +1393,8 @@ public class Instrumentation { * if there was no Activity found to run the given Intent. * * @param who The Context from which the activity is being started. - * @param whoThread The main thread of the Context from which the activity - * is being started. + * @param contextThread The main thread of the Context from which the activity + * is being started. * @param token Internal token identifying to the system who is starting * the activity; may be null. * @param target Which activity is perform the start (and thus receiving @@ -1416,8 +1417,9 @@ public class Instrumentation { * {@hide} */ public ActivityResult execStartActivity( - Context who, IApplicationThread whoThread, IBinder token, Activity target, + Context who, IBinder contextThread, IBinder token, Activity target, Intent intent, int requestCode) { + IApplicationThread whoThread = (IApplicationThread) contextThread; if (mActivityMonitors != null) { synchronized (mSync) { final int N = mActivityMonitors.size(); diff --git a/core/java/android/app/LocalActivityManager.java b/core/java/android/app/LocalActivityManager.java index 12e70e31b3e2b5cf5e60a1a9ef5e7dbf095b5fa3..a24fcae26639cc48854f63b4a76f605821868faa 100644 --- a/core/java/android/app/LocalActivityManager.java +++ b/core/java/android/app/LocalActivityManager.java @@ -22,9 +22,6 @@ import android.os.Binder; import android.os.Bundle; import android.util.Config; import android.util.Log; -import android.view.View; -import android.view.ViewGroup; -import android.view.ViewParent; import android.view.Window; import java.util.ArrayList; @@ -114,13 +111,21 @@ public class LocalActivityManager { } if (r.curState == INITIALIZING) { + // Get the lastNonConfigurationInstance for the activity + HashMap lastNonConfigurationInstances = + mParent.getLastNonConfigurationChildInstances(); + Object instance = null; + if (lastNonConfigurationInstances != null) { + instance = lastNonConfigurationInstances.get(r.id); + } + // We need to have always created the activity. if (localLOGV) Log.v(TAG, r.id + ": starting " + r.intent); if (r.activityInfo == null) { r.activityInfo = mActivityThread.resolveActivityInfo(r.intent); } r.activity = mActivityThread.startActivityNow( - mParent, r.id, r.intent, r.activityInfo, r, r.instanceState); + mParent, r.id, r.intent, r.activityInfo, r, r.instanceState, instance); if (r.activity == null) { return; } @@ -288,7 +293,6 @@ public class LocalActivityManager { // It's a brand new world. mActivities.put(id, r); mActivityArray.add(r); - } else if (r.activityInfo != null) { // If the new activity is the same as the current one, then // we may be able to reuse it. @@ -568,6 +572,32 @@ public class LocalActivityManager { moveToState(r, CREATED); } } + + /** + * Call onRetainNonConfigurationInstance on each child activity and store the + * results in a HashMap by id. Only construct the HashMap if there is a non-null + * object to store. Note that this does not support nested ActivityGroups. + * + * {@hide} + */ + public HashMap dispatchRetainNonConfigurationInstance() { + HashMap instanceMap = null; + + final int N = mActivityArray.size(); + for (int i=0; i(); + } + instanceMap.put(r.id, instance); + } + } + } + return instanceMap; + } /** * Remove all activities from this LocalActivityManager, performing an diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java index cc5638589df385cd66e8be90fa89f8fd297e1852..ea67cdbd474385a4c9b7d5ed0dfd09eabdac9378 100644 --- a/core/java/android/app/Notification.java +++ b/core/java/android/app/Notification.java @@ -25,9 +25,9 @@ import android.media.AudioManager; import android.net.Uri; import android.os.Parcel; import android.os.Parcelable; -import android.pim.DateFormat; -import android.pim.DateUtils; import android.text.TextUtils; +import android.text.format.DateFormat; +import android.text.format.DateUtils; import android.widget.RemoteViews; /** diff --git a/core/java/android/app/PendingIntent.java b/core/java/android/app/PendingIntent.java index ba8490379a2c260d0eb6f8302eb9edb94229ef8e..b59e9dc435499eaa465abe931764e93d4b051b53 100644 --- a/core/java/android/app/PendingIntent.java +++ b/core/java/android/app/PendingIntent.java @@ -73,9 +73,22 @@ public final class PendingIntent implements Parcelable { * {@link #getService}: if the described PendingIntent already exists, * the current one is canceled before generating a new one. You can use * this to retrieve a new PendingIntent when you are only changing the - * extra data in the Intent. + * extra data in the Intent; by canceling the previous pending intent, + * this ensures that only entities given the new data will be able to + * launch it. If this assurance is not an issue, consider + * {@link #FLAG_UPDATE_CURRENT}. */ public static final int FLAG_CANCEL_CURRENT = 1<<28; + /** + * Flag for use with {@link #getActivity}, {@link #getBroadcast}, and + * {@link #getService}: if the described PendingIntent already exists, + * then keep it but its replace its extra data with what is in this new + * Intent. This can be used if you are creating intents where only the + * extras change, and don't care that any entities that received your + * previous PendingIntent will be able to launch it with your new + * extras even if they are not explicitly given to it. + */ + public static final int FLAG_UPDATE_CURRENT = 1<<27; /** * Exception thrown when trying to send through a PendingIntent that @@ -161,7 +174,8 @@ public final class PendingIntent implements Parcelable { * not used). * @param intent Intent of the activity to be launched. * @param flags May be {@link #FLAG_ONE_SHOT}, {@link #FLAG_NO_CREATE}, - * {@link #FLAG_CANCEL_CURRENT}, or any of the flags as supported by + * {@link #FLAG_CANCEL_CURRENT}, {@link #FLAG_UPDATE_CURRENT}, + * or any of the flags as supported by * {@link Intent#fillIn Intent.fillIn()} to control which unspecified parts * of the intent that can be supplied when the actual send happens. * @@ -195,7 +209,8 @@ public final class PendingIntent implements Parcelable { * not used). * @param intent The Intent to be broadcast. * @param flags May be {@link #FLAG_ONE_SHOT}, {@link #FLAG_NO_CREATE}, - * {@link #FLAG_CANCEL_CURRENT}, or any of the flags as supported by + * {@link #FLAG_CANCEL_CURRENT}, {@link #FLAG_UPDATE_CURRENT}, + * or any of the flags as supported by * {@link Intent#fillIn Intent.fillIn()} to control which unspecified parts * of the intent that can be supplied when the actual send happens. * @@ -230,7 +245,8 @@ public final class PendingIntent implements Parcelable { * not used). * @param intent An Intent describing the service to be started. * @param flags May be {@link #FLAG_ONE_SHOT}, {@link #FLAG_NO_CREATE}, - * {@link #FLAG_CANCEL_CURRENT}, or any of the flags as supported by + * {@link #FLAG_CANCEL_CURRENT}, {@link #FLAG_UPDATE_CURRENT}, + * or any of the flags as supported by * {@link Intent#fillIn Intent.fillIn()} to control which unspecified parts * of the intent that can be supplied when the actual send happens. * diff --git a/core/java/android/app/ProgressDialog.java b/core/java/android/app/ProgressDialog.java index 8b60cfab699dcf099217a7ae4eec94d6c1f0e9e4..c87e3982b7badf95e379caf023d77490ebc551f6 100644 --- a/core/java/android/app/ProgressDialog.java +++ b/core/java/android/app/ProgressDialog.java @@ -262,7 +262,7 @@ public class ProgressDialog extends AlertDialog { } public void setIndeterminate(boolean indeterminate) { - if (mHasStarted && (isIndeterminate() != indeterminate)) { + if (mProgress != null) { mProgress.setIndeterminate(indeterminate); } else { mIndeterminate = indeterminate; diff --git a/core/java/android/app/SearchDialog.java b/core/java/android/app/SearchDialog.java index 5f3f9eff0f643ce3b2e78a756a094aa46b430af0..2ce2db996b89d483cf61fb1cf29f7e6cdfca4a45 100644 --- a/core/java/android/app/SearchDialog.java +++ b/core/java/android/app/SearchDialog.java @@ -16,11 +16,14 @@ package android.app; +import android.content.ActivityNotFoundException; import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; +import android.content.pm.PackageManager; +import android.content.pm.ResolveInfo; import android.content.res.Configuration; import android.content.res.Resources; import android.content.res.Resources.NotFoundException; @@ -48,10 +51,12 @@ import android.view.WindowManager; import android.view.View.OnFocusChangeListener; import android.view.animation.Animation; import android.view.animation.AnimationUtils; +import android.view.inputmethod.InputMethodManager; +import android.view.inputmethod.EditorInfo; import android.widget.AdapterView; -import android.widget.Button; import android.widget.CursorAdapter; import android.widget.EditText; +import android.widget.ImageButton; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.ListAdapter; @@ -62,6 +67,7 @@ import android.widget.WrapperListAdapter; import android.widget.AdapterView.OnItemClickListener; import android.widget.AdapterView.OnItemSelectedListener; +import java.util.List; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.atomic.AtomicLong; @@ -100,7 +106,7 @@ public class SearchDialog extends Dialog { private TextView mBadgeLabel; private LinearLayout mSearchEditLayout; private EditText mSearchTextField; - private Button mGoButton; + private ImageButton mGoButton; private ListView mSuggestionsList; private ViewTreeObserver mViewTreeObserver = null; @@ -130,14 +136,14 @@ public class SearchDialog extends Dialog { private String mSuggestionAction = null; private Uri mSuggestionData = null; private String mSuggestionQuery = null; - + /** * Constructor - fires it up and makes it look like the search UI. * * @param context Application Context we can use for system acess */ public SearchDialog(Context context) { - super(context, com.android.internal.R.style.Theme_Translucent); + super(context, com.android.internal.R.style.Theme_SearchBar); } /** @@ -149,21 +155,15 @@ public class SearchDialog extends Dialog { super.onCreate(savedInstanceState); Window theWindow = getWindow(); - theWindow.requestFeature(Window.FEATURE_NO_TITLE); - theWindow.setFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND, - WindowManager.LayoutParams.FLAG_DIM_BEHIND); theWindow.setGravity(Gravity.TOP|Gravity.FILL_HORIZONTAL); setContentView(com.android.internal.R.layout.search_bar); - // Note: theWindow.setBackgroundDrawable(null) does not work here - you get blackness - theWindow.setBackgroundDrawableResource(android.R.color.transparent); - theWindow.setLayout(ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT); WindowManager.LayoutParams lp = theWindow.getAttributes(); - lp.dimAmount = 0.5f; lp.setTitle("Search Dialog"); + lp.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE; theWindow.setAttributes(lp); // get the view elements for local access @@ -171,14 +171,14 @@ public class SearchDialog extends Dialog { mBadgeLabel = (TextView) findViewById(com.android.internal.R.id.search_badge); mSearchEditLayout = (LinearLayout)findViewById(com.android.internal.R.id.search_edit_frame); mSearchTextField = (EditText) findViewById(com.android.internal.R.id.search_src_text); - mGoButton = (Button) findViewById(com.android.internal.R.id.search_go_btn); + mGoButton = (ImageButton) findViewById(com.android.internal.R.id.search_go_btn); mSuggestionsList = (ListView) findViewById(com.android.internal.R.id.search_suggest_list); // attach listeners mSearchTextField.addTextChangedListener(mTextWatcher); mSearchTextField.setOnKeyListener(mTextKeyListener); mGoButton.setOnClickListener(mGoButtonClickListener); - mGoButton.setOnKeyListener(mGoButtonKeyListener); + mGoButton.setOnKeyListener(mButtonsKeyListener); mSuggestionsList.setOnItemClickListener(mSuggestionsListItemClickListener); mSuggestionsList.setOnKeyListener(mSuggestionsKeyListener); mSuggestionsList.setOnFocusChangeListener(mSuggestFocusListener); @@ -241,6 +241,7 @@ public class SearchDialog extends Dialog { if (mSuggestionsList != null) { mSuggestionsList.setVisibility(View.GONE); // prevent any flicker if was visible } + super.show(); setupSearchableInfo(); @@ -266,6 +267,17 @@ public class SearchDialog extends Dialog { initialQuery = ""; // This forces the preload to happen, triggering suggestions } mSearchTextField.setText(initialQuery); + + // If it is not for global search, that means the search dialog is + // launched to input a web address. + if (!globalSearch) { + mSearchTextField.setRawInputType(EditorInfo.TYPE_CLASS_TEXT + | EditorInfo.TYPE_TEXT_VARIATION_URI); + } else { + mSearchTextField.setRawInputType(EditorInfo.TYPE_CLASS_TEXT + | EditorInfo.TYPE_TEXT_VARIATION_NORMAL); + } + if (selectInitialQuery) { mSearchTextField.selectAll(); } else { @@ -424,7 +436,6 @@ public class SearchDialog extends Dialog { public void onConfigurationChanged(Configuration newConfig) { if (isShowing()) { // Redraw (resources may have changed) - updateSearchButton(); updateSearchBadge(); updateQueryHint(); } @@ -439,7 +450,6 @@ public class SearchDialog extends Dialog { mActivityContext = mSearchable.getActivityContext(getContext()); mProviderContext = mSearchable.getProviderContext(getContext(), mActivityContext); - updateSearchButton(); updateSearchBadge(); updateQueryHint(); } @@ -458,18 +468,6 @@ public class SearchDialog extends Dialog { cancel(); } - /** - * Update the text in the search button - */ - private void updateSearchButton() { - int textId = mSearchable.getSearchButtonText(); - if (textId == 0) { - textId = com.android.internal.R.string.search_go; - } - String goText = mActivityContext.getResources().getString(textId); - mGoButton.setText(goText); - } - /** * Setup the search "Badge" if request by mode flags. */ @@ -1031,9 +1029,10 @@ public class SearchDialog extends Dialog { } /** - * React to typing in the GO button by refocusing to EditText. Continue typing the query. + * React to typing in the GO search button by refocusing to EditText. + * Continue typing the query. */ - View.OnKeyListener mGoButtonKeyListener = new View.OnKeyListener() { + View.OnKeyListener mButtonsKeyListener = new View.OnKeyListener() { public boolean onKey(View v, int keyCode, KeyEvent event) { // also guard against possible race conditions (late arrival after dismiss) if (mSearchable != null) { @@ -1054,7 +1053,7 @@ public class SearchDialog extends Dialog { } } }; - + /** * React to the user typing "enter" or other hardwired keys while typing in the search box. * This handles these special keys while the edit box has focus. diff --git a/core/java/android/app/SearchManager.java b/core/java/android/app/SearchManager.java index 01babc45bd437abb49d72538349ae4ce22382952..5f25b906016771e03ae078f37c051c2b402e29ad 100644 --- a/core/java/android/app/SearchManager.java +++ b/core/java/android/app/SearchManager.java @@ -48,6 +48,7 @@ import android.view.KeyEvent; *

  • Action Keys *
  • Searchability Metadata *
  • Passing Search Context + *
  • Protecting User Privacy * * * @@ -578,7 +579,7 @@ import android.view.KeyEvent; * file. Each element defines one of the keycodes you are interested in, * defines the conditions under which they are sent, and provides details * on how to communicate the action key event back to your searchable activity.
  • - *
  • In your intent receiver, if you wish, you can check for action keys by checking the + *
  • In your broadcast receiver, if you wish, you can check for action keys by checking the * extras field of the {@link android.content.Intent Intent}.
  • * * @@ -974,6 +975,36 @@ import android.view.KeyEvent; * appData.get...(); * appData.get...(); * } + * + * + *

    Protecting User Privacy

    + * + *

    Many users consider their activities on the phone, including searches, to be private + * information. Applications that implement search should take steps to protect users' privacy + * wherever possible. This section covers two areas of concern, but you should consider your search + * design carefully and take any additional steps necessary. + * + *

    Don't send personal information to servers, and if you do, don't log it. + * "Personal information" is information that can personally identify your users, such as name, + * email address or billing information, or other data which can be reasonably linked to such + * information. If your application implements search with the assistance of a server, try to + * avoid sending personal information with your searches. For example, if you are searching for + * businesses near a zip code, you don't need to send the user ID as well - just send the zip code + * to the server. If you do need to send personal information, you should take steps to avoid + * logging it. If you must log it, you should protect that data very carefully, and erase it as + * soon as possible. + * + *

    Provide the user with a way to clear their search history. The Search Manager helps + * your application provide context-specific suggestions. Sometimes these suggestions are based + * on previous searches, or other actions taken by the user in an earlier session. A user may not + * wish for previous searches to be revealed to other users, for instance if they share their phone + * with a friend. If your application provides suggestions that can reveal previous activities, + * you should implement a "Clear History" menu, preference, or button. If you are using + * {@link android.provider.SearchRecentSuggestions}, you can simply call its + * {@link android.provider.SearchRecentSuggestions#clearHistory() clearHistory()} method from + * your "Clear History" UI. If you are implementing your own form of recent suggestions, you'll + * need to provide a similar a "clear history" API in your provider, and call it from your + * "Clear History" UI. */ public class SearchManager implements DialogInterface.OnDismissListener, DialogInterface.OnCancelListener @@ -1008,6 +1039,16 @@ public class SearchManager * activity that launched the search. */ public final static String APP_DATA = "app_data"; + + /** + * Intent app_data bundle key: Use this key with the bundle from + * {@link android.content.Intent#getBundleExtra + * content.Intent.getBundleExtra(APP_DATA)} to obtain the source identifier + * set by the activity that launched the search. + * + * @hide + */ + public final static String SOURCE = "source"; /** * Intent extra data key: Use this key with Intent.ACTION_SEARCH and diff --git a/core/java/android/app/Service.java b/core/java/android/app/Service.java index 28b06153a56f56aab3c64892505296fef9a7a32b..6c08e750c7d7af28409ef4d4d38b208eed103fb1 100644 --- a/core/java/android/app/Service.java +++ b/core/java/android/app/Service.java @@ -163,7 +163,6 @@ public abstract class Service extends ContextWrapper implements ComponentCallbac /** * Called by the system when the service is first created. Do not call this method directly. - * If you override this method, be sure to call super.onCreate(). */ public void onCreate() { } @@ -172,7 +171,6 @@ public abstract class Service extends ContextWrapper implements ComponentCallbac * Called by the system every time a client explicitly starts the service by calling * {@link android.content.Context#startService}, providing the arguments it supplied and a * unique integer token representing the start request. Do not call this method directly. - * If you override this method, be sure to call super.onStart(). * * @param intent The Intent supplied to {@link android.content.Context#startService}, * as given. @@ -189,7 +187,6 @@ public abstract class Service extends ContextWrapper implements ComponentCallbac * service should clean up an resources it holds (threads, registered * receivers, etc) at this point. Upon return, there will be no more calls * in to this Service object and it is effectively dead. Do not call this method directly. - * If you override this method, be sure to call super.onDestroy(). */ public void onDestroy() { } @@ -375,4 +372,3 @@ public abstract class Service extends ContextWrapper implements ComponentCallbac private Application mApplication = null; private IActivityManager mActivityManager = null; } - diff --git a/core/java/android/app/TimePickerDialog.java b/core/java/android/app/TimePickerDialog.java index 107532e79bbf0a1ed98a8314d8d0d5d97e0d365a..002b01f69eec398d38bffd1a1893ccf42dcdd80b 100644 --- a/core/java/android/app/TimePickerDialog.java +++ b/core/java/android/app/TimePickerDialog.java @@ -20,7 +20,7 @@ import android.content.Context; import android.content.DialogInterface; import android.content.DialogInterface.OnClickListener; import android.os.Bundle; -import android.pim.DateFormat; +import android.text.format.DateFormat; import android.view.LayoutInflater; import android.view.View; import android.widget.TimePicker; diff --git a/core/java/android/bluetooth/BluetoothA2dp.java b/core/java/android/bluetooth/BluetoothA2dp.java new file mode 100644 index 0000000000000000000000000000000000000000..d6ea889e8c91200e4d461852297b940c55e0b545 --- /dev/null +++ b/core/java/android/bluetooth/BluetoothA2dp.java @@ -0,0 +1,181 @@ +/* + * 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 android.bluetooth; + +import android.annotation.SdkConstant; +import android.annotation.SdkConstant.SdkConstantType; +import android.server.BluetoothA2dpService; +import android.content.Context; +import android.os.ServiceManager; +import android.os.RemoteException; +import android.os.IBinder; +import android.util.Log; + +import java.util.List; + +/** + * Public API for controlling the Bluetooth A2DP Profile Service. + * + * BluetoothA2dp is a proxy object for controlling the Bluetooth A2DP + * Service via IPC. + * + * Creating a BluetoothA2dp object will initiate a binding with the + * BluetoothHeadset service. Users of this object should call close() when they + * are finished, so that this proxy object can unbind from the service. + * + * Currently the BluetoothA2dp service runs in the system server and this + * proxy object will be immediately bound to the service on construction. + * However this may change in future releases, and error codes such as + * BluetoothError.ERROR_IPC_NOT_READY will be returned from this API when the + * proxy object is not yet attached. + * + * Currently this class provides methods to connect to A2DP audio sinks. + * + * @hide + */ +public class BluetoothA2dp { + private static final String TAG = "BluetoothA2dp"; + + /** int extra for SINK_STATE_CHANGED_ACTION */ + public static final String SINK_STATE = + "android.bluetooth.a2dp.intent.SINK_STATE"; + /** int extra for SINK_STATE_CHANGED_ACTION */ + public static final String SINK_PREVIOUS_STATE = + "android.bluetooth.a2dp.intent.SINK_PREVIOUS_STATE"; + + /** Indicates the state of an A2DP audio sink has changed. + * This intent will always contain SINK_STATE, SINK_PREVIOUS_STATE and + * BluetoothIntent.ADDRESS extras. + */ + @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) + public static final String SINK_STATE_CHANGED_ACTION = + "android.bluetooth.a2dp.intent.action.SINK_STATE_CHANGED"; + + public static final int STATE_DISCONNECTED = 0; + public static final int STATE_CONNECTING = 1; + public static final int STATE_CONNECTED = 2; + public static final int STATE_DISCONNECTING = 3; + /** Playing implies connected */ + public static final int STATE_PLAYING = 4; + + private final IBluetoothA2dp mService; + private final Context mContext; + + /** + * Create a BluetoothA2dp proxy object for interacting with the local + * Bluetooth A2DP service. + * @param c Context + */ + public BluetoothA2dp(Context c) { + mContext = c; + IBinder b = ServiceManager.getService(BluetoothA2dpService.BLUETOOTH_A2DP_SERVICE); + if (b == null) { + throw new RuntimeException("Bluetooth A2DP service not available!"); + } + mService = IBluetoothA2dp.Stub.asInterface(b); + } + + /** Initiate a connection to an A2DP sink. + * Listen for A2DP_SINK_STATE_CHANGED_ACTION to find out when the + * connection is completed. + * @param address Remote BT address. + * @return Result code, negative indicates an immediate error. + * @hide + */ + public int connectSink(String address) { + try { + return mService.connectSink(address); + } catch (RemoteException e) { + Log.w(TAG, "", e); + return BluetoothError.ERROR_IPC; + } + } + + /** Initiate disconnect from an A2DP sink. + * Listen for A2DP_SINK_STATE_CHANGED_ACTION to find out when + * disconnect is completed. + * @param address Remote BT address. + * @return Result code, negative indicates an immediate error. + * @hide + */ + public int disconnectSink(String address) { + try { + return mService.disconnectSink(address); + } catch (RemoteException e) { + Log.w(TAG, "", e); + return BluetoothError.ERROR_IPC; + } + } + + /** Check if a specified A2DP sink is connected. + * @param address Remote BT address. + * @return True if connected (or playing), false otherwise and on error. + * @hide + */ + public boolean isSinkConnected(String address) { + int state = getSinkState(address); + return state == STATE_CONNECTED || state == STATE_PLAYING; + } + + /** Check if any A2DP sink is connected. + * @return a List of connected A2DP sinks, or null on error. + * @hide + */ + public List listConnectedSinks() { + try { + return mService.listConnectedSinks(); + } catch (RemoteException e) { + Log.w(TAG, "", e); + return null; + } + } + + /** Get the state of an A2DP sink + * @param address Remote BT address. + * @return State code, or negative on error + * @hide + */ + public int getSinkState(String address) { + try { + return mService.getSinkState(address); + } catch (RemoteException e) { + Log.w(TAG, "", e); + return BluetoothError.ERROR_IPC; + } + } + + /** Helper for converting a state to a string. + * For debug use only - strings are not internationalized. + * @hide + */ + public static String stateToString(int state) { + switch (state) { + case STATE_DISCONNECTED: + return "disconnected"; + case STATE_CONNECTING: + return "connecting"; + case STATE_CONNECTED: + return "connected"; + case STATE_DISCONNECTING: + return "disconnecting"; + case STATE_PLAYING: + return "playing"; + default: + return ""; + } + } +} diff --git a/core/java/android/bluetooth/BluetoothClass.java b/core/java/android/bluetooth/BluetoothClass.java new file mode 100644 index 0000000000000000000000000000000000000000..88ce18b45773e10a42db71b5441b24df8b8d2640 --- /dev/null +++ b/core/java/android/bluetooth/BluetoothClass.java @@ -0,0 +1,191 @@ +/* + * 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 android.bluetooth; + +/** + * The Android Bluetooth API is not finalized, and *will* change. Use at your + * own risk. + * + * Static helper methods and constants to decode the device class bit vector + * returned by the Bluetooth API. + * + * The Android Bluetooth API returns a 32-bit integer to represent the class. + * The format of these bits is defined at + * http://www.bluetooth.org/Technical/AssignedNumbers/baseband.htm + * (login required). This class provides static helper methods and constants to + * determine what Service Class(es) and Device Class are encoded in the 32-bit + * class. + * + * Devices typically have zero or more service classes, and exactly one device + * class. The device class is encoded as a major and minor device class, the + * minor being a subset of the major. + * + * Class is useful to describe a device (for example to show an icon), + * but does not reliably describe what profiles a device supports. To determine + * profile support you usually need to perform SDP queries. + * + * Each of these helper methods takes the 32-bit integer class as an argument. + * + * @hide + */ +public class BluetoothClass { + /** Indicates the Bluetooth API could not retrieve the class */ + public static final int ERROR = 0xFF000000; + + /** Every Bluetooth device has zero or more service classes */ + public static class Service { + public static final int BITMASK = 0xFFE000; + + public static final int LIMITED_DISCOVERABILITY = 0x002000; + public static final int POSITIONING = 0x010000; + public static final int NETWORKING = 0x020000; + public static final int RENDER = 0x040000; + public static final int CAPTURE = 0x080000; + public static final int OBJECT_TRANSFER = 0x100000; + public static final int AUDIO = 0x200000; + public static final int TELEPHONY = 0x400000; + public static final int INFORMATION = 0x800000; + + /** Returns true if the given class supports the given Service Class. + * A bluetooth device can claim to support zero or more service classes. + * @param btClass The bluetooth class. + * @param serviceClass The service class constant to test for. For + * example, Service.AUDIO. Must be one of the + * Service.FOO constants. + * @return True if the service class is supported. + */ + public static boolean hasService(int btClass, int serviceClass) { + if (btClass == ERROR) { + return false; + } + return ((btClass & Service.BITMASK & serviceClass) != 0); + } + } + + /** Every Bluetooth device has exactly one device class, comprimised of + * major and minor components. We have not included the minor classes for + * major classes: NETWORKING, PERIPHERAL and IMAGING yet because they work + * a little differently. */ + public static class Device { + public static final int BITMASK = 0x1FFC; + + public static class Major { + public static final int BITMASK = 0x1F00; + + public static final int MISC = 0x0000; + public static final int COMPUTER = 0x0100; + public static final int PHONE = 0x0200; + public static final int NETWORKING = 0x0300; + public static final int AUDIO_VIDEO = 0x0400; + public static final int PERIPHERAL = 0x0500; + public static final int IMAGING = 0x0600; + public static final int WEARABLE = 0x0700; + public static final int TOY = 0x0800; + public static final int HEALTH = 0x0900; + public static final int UNCATEGORIZED = 0x1F00; + + /** Returns the Major Device Class component of a bluetooth class. + * Values returned from this function can be compared with the constants + * Device.Major.FOO. A bluetooth device can only be associated + * with one major class. + */ + public static int getDeviceMajor(int btClass) { + if (btClass == ERROR) { + return ERROR; + } + return (btClass & Device.Major.BITMASK); + } + } + + // Devices in the COMPUTER major class + public static final int COMPUTER_UNCATEGORIZED = 0x0100; + public static final int COMPUTER_DESKTOP = 0x0104; + public static final int COMPUTER_SERVER = 0x0108; + public static final int COMPUTER_LAPTOP = 0x010C; + public static final int COMPUTER_HANDHELD_PC_PDA = 0x0110; + public static final int COMPUTER_PALM_SIZE_PC_PDA = 0x0114; + public static final int COMPUTER_WEARABLE = 0x0118; + + // Devices in the PHONE major class + public static final int PHONE_UNCATEGORIZED = 0x0200; + public static final int PHONE_CELLULAR = 0x0204; + public static final int PHONE_CORDLESS = 0x0208; + public static final int PHONE_SMART = 0x020C; + public static final int PHONE_MODEM_OR_GATEWAY = 0x0210; + public static final int PHONE_ISDN = 0x0214; + + // Minor classes for the AUDIO_VIDEO major class + public static final int AUDIO_VIDEO_UNCATEGORIZED = 0x0400; + public static final int AUDIO_VIDEO_WEARABLE_HEADSET = 0x0404; + public static final int AUDIO_VIDEO_HANDSFREE = 0x0408; + //public static final int AUDIO_VIDEO_RESERVED = 0x040C; + public static final int AUDIO_VIDEO_MICROPHONE = 0x0410; + public static final int AUDIO_VIDEO_LOUDSPEAKER = 0x0414; + public static final int AUDIO_VIDEO_HEADPHONES = 0x0418; + public static final int AUDIO_VIDEO_PORTABLE_AUDIO = 0x041C; + public static final int AUDIO_VIDEO_CAR_AUDIO = 0x0420; + public static final int AUDIO_VIDEO_SET_TOP_BOX = 0x0424; + public static final int AUDIO_VIDEO_HIFI_AUDIO = 0x0428; + public static final int AUDIO_VIDEO_VCR = 0x042C; + public static final int AUDIO_VIDEO_VIDEO_CAMERA = 0x0430; + public static final int AUDIO_VIDEO_CAMCORDER = 0x0434; + public static final int AUDIO_VIDEO_VIDEO_MONITOR = 0x0438; + public static final int AUDIO_VIDEO_VIDEO_DISPLAY_AND_LOUDSPEAKER = 0x043C; + public static final int AUDIO_VIDEO_VIDEO_CONFERENCING = 0x0440; + //public static final int AUDIO_VIDEO_RESERVED = 0x0444; + public static final int AUDIO_VIDEO_VIDEO_GAMING_TOY = 0x0448; + + // Devices in the WEARABLE major class + public static final int WEARABLE_UNCATEGORIZED = 0x0700; + public static final int WEARABLE_WRIST_WATCH = 0x0704; + public static final int WEARABLE_PAGER = 0x0708; + public static final int WEARABLE_JACKET = 0x070C; + public static final int WEARABLE_HELMET = 0x0710; + public static final int WEARABLE_GLASSES = 0x0714; + + // Devices in the TOY major class + public static final int TOY_UNCATEGORIZED = 0x0800; + public static final int TOY_ROBOT = 0x0804; + public static final int TOY_VEHICLE = 0x0808; + public static final int TOY_DOLL_ACTION_FIGURE = 0x080C; + public static final int TOY_CONTROLLER = 0x0810; + public static final int TOY_GAME = 0x0814; + + // Devices in the HEALTH major class + public static final int HEALTH_UNCATEGORIZED = 0x0900; + public static final int HEALTH_BLOOD_PRESSURE = 0x0904; + public static final int HEALTH_THERMOMETER = 0x0908; + public static final int HEALTH_WEIGHING = 0x090C; + public static final int HEALTH_GLUCOSE = 0x0910; + public static final int HEALTH_PULSE_OXIMETER = 0x0914; + public static final int HEALTH_PULSE_RATE = 0x0918; + public static final int HEALTH_DATA_DISPLAY = 0x091C; + + /** Returns the Device Class component of a bluetooth class. This includes + * both the major and minor device components. Values returned from this + * function can be compared with the constants Device.FOO. A bluetooth + * device can only be associated with one device class. + */ + public static int getDevice(int btClass) { + if (btClass == ERROR) { + return ERROR; + } + return (btClass & Device.BITMASK); + } + } +} + diff --git a/core/java/android/bluetooth/BluetoothDevice.java b/core/java/android/bluetooth/BluetoothDevice.java index 0b24db662cac6d22f2521ec9e468071534161a8a..d1f71c55f05a3dc45a34368547eed8c5e8c01f33 100644 --- a/core/java/android/bluetooth/BluetoothDevice.java +++ b/core/java/android/bluetooth/BluetoothDevice.java @@ -514,7 +514,7 @@ public class BluetoothDevice { try { return mService.getRemoteClass(address); } catch (RemoteException e) {Log.e(TAG, "", e);} - return DeviceClass.CLASS_UNKNOWN; + return BluetoothClass.ERROR; } public byte[] getRemoteFeatures(String address) { try { diff --git a/core/java/android/bluetooth/BluetoothError.java b/core/java/android/bluetooth/BluetoothError.java new file mode 100644 index 0000000000000000000000000000000000000000..2554bead0ca2889e9c2f711c4eb7577177387da6 --- /dev/null +++ b/core/java/android/bluetooth/BluetoothError.java @@ -0,0 +1,42 @@ +/* + * 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 android.bluetooth; + +/** + * Bluetooth API error codes. + * + * Errors are always negative. + * + * @hide + */ +public class BluetoothError { + /** No error */ + public static final int SUCCESS = 0; + + /** Generic error */ + public static final int ERROR = -1000; + + /** Bluetooth currently disabled */ + public static final int ERROR_DISABLED = -1001; + + /** IPC is not ready, for example service is not yet bound */ + public static final int ERROR_IPC_NOT_READY = -1011; + + /** Some other IPC error, for example a RemoteException */ + public static final int ERROR_IPC = -1012; + +} diff --git a/core/java/android/bluetooth/BluetoothHeadset.java b/core/java/android/bluetooth/BluetoothHeadset.java index 90db39bc547f855f4ad208abe0a71cf688b340aa..905173e34083e40814ee691fa60e689081a226a0 100644 --- a/core/java/android/bluetooth/BluetoothHeadset.java +++ b/core/java/android/bluetooth/BluetoothHeadset.java @@ -28,35 +28,36 @@ import android.util.Log; * The Android Bluetooth API is not finalized, and *will* change. Use at your * own risk. * - * Public API for controlling the Bluetooth Headset Service. + * Public API for controlling the Bluetooth Headset Service. This includes both + * Bluetooth Headset and Handsfree (v1.5) profiles. The Headset service will + * attempt a handsfree connection first, and fall back to headset. * * BluetoothHeadset is a proxy object for controlling the Bluetooth Headset - * Service. + * Service via IPC. * * Creating a BluetoothHeadset object will create a binding with the * BluetoothHeadset service. Users of this object should call close() when they * are finished with the BluetoothHeadset, so that this proxy object can unbind * from the service. * - * BlueoothHeadset objects are not guarenteed to be connected to the - * BluetoothHeadsetService at all times. Calls on this object while not - * connected to the service will result in default error return values. Even - * after object construction, there is a short delay (~10ms) before this proxy - * object is actually connected to the Service. + * This BluetoothHeadset object is not immediately bound to the + * BluetoothHeadset service. Use the ServiceListener interface to obtain a + * notification when it is bound, this is especially important if you wish to + * immediately call methods on BluetootHeadset after construction. * * Android only supports one connected Bluetooth Headset at a time. * - * Note that in this context, Headset includes both Bluetooth Headset's and - * Handsfree devices. - * * @hide */ public class BluetoothHeadset { - private final static String TAG = "BluetoothHeadset"; + private static final String TAG = "BluetoothHeadset"; + private static final boolean DBG = false; - private final Context mContext; private IBluetoothHeadset mService; + private final Context mContext; + private final ServiceListener mServiceListener; + private ConnectHeadsetCallback mConnectHeadsetCallback; /** There was an error trying to obtain the state */ public static final int STATE_ERROR = -1; @@ -72,25 +73,44 @@ public class BluetoothHeadset { /** Connection cancelled before completetion. */ public static final int RESULT_CANCELLED = 2; - private ServiceConnection mConnection = new ServiceConnection() { - public void onServiceConnected(ComponentName className, IBinder service) { - mService = IBluetoothHeadset.Stub.asInterface(service); - Log.i(TAG, "Proxy object is now connected to Bluetooth Headset Service"); - } - public void onServiceDisconnected(ComponentName className) { - mService = null; - } - }; + /** + * An interface for notifying BluetoothHeadset IPC clients when they have + * been connected to the BluetoothHeadset service. + */ + public interface ServiceListener { + /** + * Called to notify the client when this proxy object has been + * connected to the BluetoothHeadset service. Clients must wait for + * this callback before making IPC calls on the BluetoothHeadset + * service. + */ + public void onServiceConnected(); + + /** + * Called to notify the client that this proxy object has been + * disconnected from the BluetoothHeadset service. Clients must not + * make IPC calls on the BluetoothHeadset service after this callback. + * This callback will currently only occur if the application hosting + * the BluetoothHeadset service, but may be called more often in future. + */ + public void onServiceDisconnected(); + } + + /** + * Interface for connectHeadset() callback. + * This callback can occur in the Binder thread. + */ + public interface ConnectHeadsetCallback { + public void onConnectHeadsetResult(String address, int resultCode); + } /** * Create a BluetoothHeadset proxy object. - * Remeber to call close() when you are done with this object, so that it - * can unbind from the BluetoothHeadsetService. */ - public BluetoothHeadset(Context context) { + public BluetoothHeadset(Context context, ServiceListener l) { mContext = context; - if (!context.bindService( - new Intent(IBluetoothHeadset.class.getName()), mConnection, 0)) { + mServiceListener = l; + if (!context.bindService(new Intent(IBluetoothHeadset.class.getName()), mConnection, 0)) { Log.e(TAG, "Could not bind to Bluetooth Headset Service"); } } @@ -126,6 +146,9 @@ public class BluetoothHeadset { try { return mService.getState(); } catch (RemoteException e) {Log.e(TAG, e.toString());} + } else { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable())); } return BluetoothHeadset.STATE_ERROR; } @@ -141,6 +164,9 @@ public class BluetoothHeadset { try { return mService.getHeadsetAddress(); } catch (RemoteException e) {Log.e(TAG, e.toString());} + } else { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable())); } return null; } @@ -150,20 +176,29 @@ public class BluetoothHeadset { * This call does not block. Fails if a headset is already connecting * or connected. * Will connect to the last connected headset if address is null. + * onConnectHeadsetResult() of your ConnectHeadsetCallback will be called + * on completition. * @param address The Bluetooth Address to connect to, or null to connect * to the last connected headset. - * @param callback A callback with onCreateBondingResult() defined, or - * null. + * @param callback Callback on result. Not called if false is returned. Can + * be null. + * to the last connected headset. * @return False if there was a problem initiating the connection * procedure, and your callback will not be used. True if * the connection procedure was initiated, in which case * your callback is guarenteed to be called. */ - public boolean connectHeadset(String address, IBluetoothHeadsetCallback callback) { + public boolean connectHeadset(String address, ConnectHeadsetCallback callback) { if (mService != null) { try { - return mService.connectHeadset(address, callback); + if (mService.connectHeadset(address, mHeadsetCallback)) { + mConnectHeadsetCallback = callback; + return true; + } } catch (RemoteException e) {Log.e(TAG, e.toString());} + } else { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable())); } return false; } @@ -178,6 +213,9 @@ public class BluetoothHeadset { try { return mService.isConnected(address); } catch (RemoteException e) {Log.e(TAG, e.toString());} + } else { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable())); } return false; } @@ -191,8 +229,72 @@ public class BluetoothHeadset { if (mService != null) { try { mService.disconnectHeadset(); + return true; + } catch (RemoteException e) {Log.e(TAG, e.toString());} + } else { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable())); + } + return false; + } + + /** + * Start BT Voice Recognition mode, and set up Bluetooth audio path. + * Returns false if there is no headset connected, or if the + * connected headset does not support voice recognition, or on + * error. + */ + public boolean startVoiceRecognition() { + if (mService != null) { + try { + return mService.startVoiceRecognition(); + } catch (RemoteException e) {Log.e(TAG, e.toString());} + } else { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable())); + } + return false; + } + + /** + * Stop BT Voice Recognition mode, and shut down Bluetooth audio path. + * Returns false if there is no headset connected, or the connected + * headset is not in voice recognition mode, or on error. + */ + public boolean stopVoiceRecognition() { + if (mService != null) { + try { + return mService.stopVoiceRecognition(); } catch (RemoteException e) {Log.e(TAG, e.toString());} + } else { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable())); } return false; } + + private ServiceConnection mConnection = new ServiceConnection() { + public void onServiceConnected(ComponentName className, IBinder service) { + if (DBG) Log.d(TAG, "Proxy object connected"); + mService = IBluetoothHeadset.Stub.asInterface(service); + if (mServiceListener != null) { + mServiceListener.onServiceConnected(); + } + } + public void onServiceDisconnected(ComponentName className) { + if (DBG) Log.d(TAG, "Proxy object disconnected"); + mService = null; + if (mServiceListener != null) { + mServiceListener.onServiceDisconnected(); + } + } + }; + + private IBluetoothHeadsetCallback mHeadsetCallback = new IBluetoothHeadsetCallback.Stub() { + public void onConnectHeadsetResult(String address, int resultCode) { + if (mConnectHeadsetCallback != null) { + mConnectHeadsetCallback.onConnectHeadsetResult(address, resultCode); + } + } + }; } diff --git a/core/java/android/bluetooth/DeviceClass.java b/core/java/android/bluetooth/DeviceClass.java deleted file mode 100644 index 36035ca4db0ce4b56a2d856768d425412bc5b2d5..0000000000000000000000000000000000000000 --- a/core/java/android/bluetooth/DeviceClass.java +++ /dev/null @@ -1,131 +0,0 @@ -/* - * 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 android.bluetooth; - -/** - * The Android Bluetooth API is not finalized, and *will* change. Use at your - * own risk. - * - * Static helper methods and constants to decode the device class bit vector - * returned by the Bluetooth API. - * - * The Android Bluetooth API returns a 32-bit integer to represent the device - * class. This is actually a bit vector, the format defined at - * http://www.bluetooth.org/Technical/AssignedNumbers/baseband.htm - * (login required). This class provides static helper methods and constants to - * determine what Service Class(es), Major Class, and Minor Class are encoded - * in a 32-bit device class. - * - * Each of the helper methods takes the 32-bit integer device class as an - * argument. - * - * @hide - */ -public class DeviceClass { - - // Baseband class information - // See http://www.bluetooth.org/Technical/AssignedNumbers/baseband.htm - - public static final int SERVICE_CLASS_BITMASK = 0xFFE000; - public static final int SERVICE_CLASS_LIMITED_DISCOVERABILITY = 0x002000; - public static final int SERVICE_CLASS_POSITIONING = 0x010000; - public static final int SERVICE_CLASS_NETWORKING = 0x020000; - public static final int SERVICE_CLASS_RENDER = 0x040000; - public static final int SERVICE_CLASS_CAPTURE = 0x080000; - public static final int SERVICE_CLASS_OBJECT_TRANSFER = 0x100000; - public static final int SERVICE_CLASS_AUDIO = 0x200000; - public static final int SERVICE_CLASS_TELEPHONY = 0x400000; - public static final int SERVICE_CLASS_INFORMATION = 0x800000; - - public static final int MAJOR_CLASS_BITMASK = 0x001F00; - public static final int MAJOR_CLASS_MISC = 0x000000; - public static final int MAJOR_CLASS_COMPUTER = 0x000100; - public static final int MAJOR_CLASS_PHONE = 0x000200; - public static final int MAJOR_CLASS_NETWORKING = 0x000300; - public static final int MAJOR_CLASS_AUDIO_VIDEO = 0x000400; - public static final int MAJOR_CLASS_PERIPHERAL = 0x000500; - public static final int MAJOR_CLASS_IMAGING = 0x000600; - public static final int MAJOR_CLASS_WEARABLE = 0x000700; - public static final int MAJOR_CLASS_TOY = 0x000800; - public static final int MAJOR_CLASS_MEDICAL = 0x000900; - public static final int MAJOR_CLASS_UNCATEGORIZED = 0x001F00; - - // Minor classes for the AUDIO_VIDEO major class - public static final int MINOR_CLASS_AUDIO_VIDEO_BITMASK = 0x0000FC; - public static final int MINOR_CLASS_AUDIO_VIDEO_UNCATEGORIZED = 0x000000; - public static final int MINOR_CLASS_AUDIO_VIDEO_HEADSET = 0x000004; - public static final int MINOR_CLASS_AUDIO_VIDEO_HANDSFREE = 0x000008; - public static final int MINOR_CLASS_AUDIO_VIDEO_MICROPHONE = 0x000010; - public static final int MINOR_CLASS_AUDIO_VIDEO_LOUDSPEAKER = 0x000014; - public static final int MINOR_CLASS_AUDIO_VIDEO_HEADPHONES = 0x000018; - public static final int MINOR_CLASS_AUDIO_VIDEO_PORTABLE_AUDIO = 0x00001C; - public static final int MINOR_CLASS_AUDIO_VIDEO_CAR_AUDIO = 0x000020; - public static final int MINOR_CLASS_AUDIO_VIDEO_SET_TOP_BOX = 0x000024; - public static final int MINOR_CLASS_AUDIO_VIDEO_HIFI_AUDIO = 0x000028; - public static final int MINOR_CLASS_AUDIO_VIDEO_VCR = 0x00002C; - public static final int MINOR_CLASS_AUDIO_VIDEO_VIDEO_CAMERA = 0x000030; - public static final int MINOR_CLASS_AUDIO_VIDEO_CAMCORDER = 0x000034; - public static final int MINOR_CLASS_AUDIO_VIDEO_VIDEO_MONITOR = 0x000038; - public static final int MINOR_CLASS_AUDIO_VIDEO_VIDEO_DISPLAY_AND_LOUDSPEAKER = 0x00003C; - public static final int MINOR_CLASS_AUDIO_VIDEO_VIDEO_CONFERENCING = 0x000040; - public static final int MINOR_CLASS_AUDIO_VIDEO_VIDEO_GAMING_TOY = 0x000048; - - // Indicates the Bluetooth API could not retrieve the class - public static final int CLASS_UNKNOWN = 0xFF000000; - - /** Returns true if the given device class supports the given Service Class. - * A bluetooth device can claim to support zero or more service classes. - * @param deviceClass The bluetooth device class. - * @param serviceClassType The service class constant to test for. For - * example, DeviceClass.SERVICE_CLASS_AUDIO. This - * must be one of the SERVICE_CLASS_xxx constants, - * results of this function are undefined - * otherwise. - * @return If the deviceClass claims to support the serviceClassType. - */ - public static boolean hasServiceClass(int deviceClass, int serviceClassType) { - if (deviceClass == CLASS_UNKNOWN) { - return false; - } - return ((deviceClass & SERVICE_CLASS_BITMASK & serviceClassType) != 0); - } - - /** Returns the Major Class of a bluetooth device class. - * Values returned from this function can be compared with the constants - * MAJOR_CLASS_xxx. A bluetooth device can only be associated - * with one major class. - */ - public static int getMajorClass(int deviceClass) { - if (deviceClass == CLASS_UNKNOWN) { - return CLASS_UNKNOWN; - } - return (deviceClass & MAJOR_CLASS_BITMASK); - } - - /** Returns the Minor Class of a bluetooth device class. - * Values returned from this function can be compared with the constants - * MINOR_CLASS_xxx_yyy, where xxx is the Major Class. A bluetooth - * device can only be associated with one minor class within its major - * class. - */ - public static int getMinorClass(int deviceClass) { - if (deviceClass == CLASS_UNKNOWN) { - return CLASS_UNKNOWN; - } - return (deviceClass & MINOR_CLASS_AUDIO_VIDEO_BITMASK); - } -} diff --git a/core/java/android/bluetooth/IBluetoothA2dp.aidl b/core/java/android/bluetooth/IBluetoothA2dp.aidl new file mode 100644 index 0000000000000000000000000000000000000000..7e0226d2fd9a6020a9533211e11d1df0e43f7aaa --- /dev/null +++ b/core/java/android/bluetooth/IBluetoothA2dp.aidl @@ -0,0 +1,29 @@ +/* + * 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 android.bluetooth; + +/** + * System private API for Bluetooth A2DP service + * + * {@hide} + */ +interface IBluetoothA2dp { + int connectSink(in String address); + int disconnectSink(in String address); + List listConnectedSinks(); + int getSinkState(in String address); +} diff --git a/core/java/android/bluetooth/IBluetoothHeadset.aidl b/core/java/android/bluetooth/IBluetoothHeadset.aidl index 7b6030b1cf6574c4bff1b63a0582f20edfd748da..564861ff4c7743e90bc44eadec14162d83d7da5f 100644 --- a/core/java/android/bluetooth/IBluetoothHeadset.aidl +++ b/core/java/android/bluetooth/IBluetoothHeadset.aidl @@ -36,7 +36,11 @@ interface IBluetoothHeadset { // returns true boolean connectHeadset(in String address, in IBluetoothHeadsetCallback callback); + void disconnectHeadset(); + boolean isConnected(in String address); - void disconnectHeadset(); + boolean startVoiceRecognition(); + + boolean stopVoiceRecognition(); } diff --git a/core/java/android/bluetooth/package.html b/core/java/android/bluetooth/package.html index ccd8fecaf8202eeeb8ee99ee0fd000e992441192..79abf0cb4a04635b7c3f4896aa13b370a79c58de 100644 --- a/core/java/android/bluetooth/package.html +++ b/core/java/android/bluetooth/package.html @@ -9,6 +9,5 @@ query the SDP database of other Bluetooth devices, establish RFCOMM channels/sockets on Android, and connect to specified sockets on other devices.

    Remember, not all Android devices are guaranteed to have Bluetooth functionality.

    -{@hide} diff --git a/core/java/android/content/AbstractTableMerger.java b/core/java/android/content/AbstractTableMerger.java index 56e5d4a7fbc659e3d7d79428a67d934a35710118..e1a484e3363dae82ab8e6e15f533bbfcd99cddd0 100644 --- a/core/java/android/content/AbstractTableMerger.java +++ b/core/java/android/content/AbstractTableMerger.java @@ -548,7 +548,8 @@ public abstract class AbstractTableMerger long numDeletedEntries = 0; if (mDeletedTable != null) { Cursor deletedCursor = mDb.query(mDeletedTable, - syncIdAndVersionProjection, _SYNC_ACCOUNT + "=?", accountSelectionArgs, + syncIdAndVersionProjection, + _SYNC_ACCOUNT + "=? AND " + _SYNC_ID + " IS NOT NULL", accountSelectionArgs, null, null, mDeletedTable + "." + _SYNC_ID); numDeletedEntries = deletedCursor.getCount(); diff --git a/core/java/android/content/AsyncQueryHandler.java b/core/java/android/content/AsyncQueryHandler.java index 48f1bc7023688cea14520033d61276a63b2b3c89..2d651a756111ca29bb11ec5fdd6961bc8f5311a2 100644 --- a/core/java/android/content/AsyncQueryHandler.java +++ b/core/java/android/content/AsyncQueryHandler.java @@ -24,6 +24,8 @@ import android.os.Looper; import android.os.Message; import android.util.Log; +import java.lang.ref.WeakReference; + /** * A helper class to help make handling asynchronous {@link ContentResolver} * queries easier. @@ -37,7 +39,7 @@ public abstract class AsyncQueryHandler extends Handler { private static final int EVENT_ARG_UPDATE = 3; private static final int EVENT_ARG_DELETE = 4; - /* package */ ContentResolver mResolver; + /* package */ final WeakReference mResolver; private static Looper sLooper = null; @@ -62,18 +64,26 @@ public abstract class AsyncQueryHandler extends Handler { @Override public void handleMessage(Message msg) { + final ContentResolver resolver = mResolver.get(); + if (resolver == null) return; + WorkerArgs args = (WorkerArgs) msg.obj; int token = msg.what; int event = msg.arg1; - + switch (event) { case EVENT_ARG_QUERY: Cursor cursor; try { - cursor = mResolver.query(args.uri, args.projection, + cursor = resolver.query(args.uri, args.projection, args.selection, args.selectionArgs, args.orderBy); + // Calling getCount() causes the cursor window to be filled, + // which will make the first access on the main thread a lot faster. + if (cursor != null) { + cursor.getCount(); + } } catch (Exception e) { cursor = null; } @@ -82,18 +92,16 @@ public abstract class AsyncQueryHandler extends Handler { break; case EVENT_ARG_INSERT: - args.result = mResolver.insert(args.uri, args.values); + args.result = resolver.insert(args.uri, args.values); break; case EVENT_ARG_UPDATE: - int r = mResolver.update(args.uri, args.values, args.selection, + args.result = resolver.update(args.uri, args.values, args.selection, args.selectionArgs); - args.result = new Integer(r); break; case EVENT_ARG_DELETE: - int r2 = mResolver.delete(args.uri, args.selection, args.selectionArgs); - args.result = new Integer(r2); + args.result = resolver.delete(args.uri, args.selection, args.selectionArgs); break; } @@ -115,7 +123,7 @@ public abstract class AsyncQueryHandler extends Handler { public AsyncQueryHandler(ContentResolver cr) { super(); - mResolver = cr; + mResolver = new WeakReference(cr); synchronized (AsyncQueryHandler.class) { if (sLooper == null) { HandlerThread thread = new HandlerThread("AsyncQueryWorker"); diff --git a/core/java/android/content/BroadcastReceiver.java b/core/java/android/content/BroadcastReceiver.java index 6a6f4f960fb0d8a7ed2664eabe7da59a7ce88f62..cd92002b72ada65aa1183aa0e67cc94db3476405 100644 --- a/core/java/android/content/BroadcastReceiver.java +++ b/core/java/android/content/BroadcastReceiver.java @@ -327,7 +327,7 @@ public abstract class BroadcastReceiver { * current broadcast; only works with broadcasts sent through * {@link Context#sendOrderedBroadcast(Intent, String) * Context.sendOrderedBroadcast}. This will prevent - * any other intent receivers from receiving the broadcast. It will still + * any other broadcast receivers from receiving the broadcast. It will still * call {@link #onReceive} of the BroadcastReceiver that the caller of * {@link Context#sendOrderedBroadcast(Intent, String) * Context.sendOrderedBroadcast} passed in. diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java index 00a6d316886c33909837e17a631ad7c1da907d44..6da00dfb30f69bd6018144dca6e01940f16d66b8 100644 --- a/core/java/android/content/Context.java +++ b/core/java/android/content/Context.java @@ -982,10 +982,10 @@ public abstract class Context { String profileFile, Bundle arguments); /** - * Return the handle to a system-level service by name. The class of the - * returned object varies by the requested name. Currently available names + * Return the handle to a system-level service by name. The class of the + * returned object varies by the requested name. Currently available names * are: - * + * *
    *
    {@link #WINDOW_SERVICE} ("window") *
    The top-level window manager in which you can place custom @@ -1021,6 +1021,9 @@ public abstract class Context { *
    {@link #WIFI_SERVICE} ("wifi") *
    A {@link android.net.wifi.WifiManager WifiManager} for management of * Wi-Fi connectivity. + *
    {@link #INPUT_METHOD_SERVICE} ("input_method") + *
    An {@link android.view.inputmethod.InputMethodManager InputMethodManager} + * for management of input methods. *
    * *

    Note: System services obtained via this API may be closely associated with @@ -1029,9 +1032,9 @@ public abstract class Context { * Services, Providers, etc.) * * @param name The name of the desired service. - * + * * @return The service or null if the name does not exist. - * + * * @see #WINDOW_SERVICE * @see android.view.WindowManager * @see #LAYOUT_INFLATER_SERVICE @@ -1062,6 +1065,8 @@ public abstract class Context { * @see android.media.AudioManager * @see #TELEPHONY_SERVICE * @see android.internal.TelephonyManager + * @see #INPUT_METHOD_SERVICE + * @see android.view.inputmethod.InputMethodManager */ public abstract Object getSystemService(String name); @@ -1234,6 +1239,15 @@ public abstract class Context { */ public static final String CLIPBOARD_SERVICE = "clipboard"; + /** + * Use with {@link #getSystemService} to retrieve a + * {@link android.view.inputmethod.InputMethodManager} for accessing input + * methods. + * + * @see #getSystemService + */ + public static final String INPUT_METHOD_SERVICE = "input_method"; + /** * Determine whether the given permission is allowed for a particular * process and user ID running in the system. diff --git a/core/java/android/content/DefaultDataHandler.java b/core/java/android/content/DefaultDataHandler.java index 7dc71b838d3ee69e06ddce78e21b7caecc3f8c90..863c9f6f144dfcf1b7f3e5d31d0fd07ba952a659 100644 --- a/core/java/android/content/DefaultDataHandler.java +++ b/core/java/android/content/DefaultDataHandler.java @@ -28,42 +28,47 @@ import java.io.InputStream; import java.util.Stack; /** - * insert default data from InputStream, should be in XML format: - * if the provider syncs data to the server, the imported data will be synced to the server - * Samples: - * insert one row - * - * - * - * - * - * delete, it must be in order of uri, select and arg - * + * Inserts default data from InputStream, should be in XML format. + * If the provider syncs data to the server, the imported data will be synced to the server. + *

    Samples:

    + *
    + * Insert one row: + *
    + * <row uri="content://contacts/people">
    + *  <Col column = "name" value = "foo feebe "/>
    + *  <Col column = "addr" value = "Tx"/>
    + * </row>
    + *
    + * Delete, it must be in order of uri, select, and arg: + *
    + * <del uri="content://contacts/people" select="name=? and addr=?" 
    + *  arg1 = "foo feebe" arg2 ="Tx"/>
    + *
    + * Use first row's uri to insert into another table, + * content://contacts/people/1/phones: + *
    + * <row uri="content://contacts/people">
    + *  <col column = "name" value = "foo feebe"/>
    + *  <col column = "addr" value = "Tx"/>
    + *  <row postfix="phones">
    + *    <col column="number" value="512-514-6535"/>
    + *  </row>
    + *  <row postfix="phones">
    + *    <col column="cell" value="512-514-6535"/>
    + *  </row>  
    + * </row>
    + *
    + * Insert multiple rows in to same table and same attributes: + *
    + * <row uri="content://contacts/people" >
    + *  <row>
    + *   <col column= "name" value = "foo feebe"/>
    + *   <col column= "addr" value = "Tx"/>
    + *  </row>
    + *  <row>
    + *  </row>
    + * </row>
    * - * use first row's uri to insert into another table - * content://contacts/people/1/phones - * - * - * - * - * - * - * - * - * - * - * - * insert multiple rows in to same table and same attributes: - * - * - * - * - * - * - * - * - * * @hide */ public class DefaultDataHandler implements ContentInsertHandler { diff --git a/core/java/android/content/DialogInterface.java b/core/java/android/content/DialogInterface.java index fc94aa6788fd5f88156d785b0d638d3d833318e7..4afa2946176a56b0503e5779cb0555feae1d74fc 100644 --- a/core/java/android/content/DialogInterface.java +++ b/core/java/android/content/DialogInterface.java @@ -22,10 +22,39 @@ import android.view.KeyEvent; * */ public interface DialogInterface { - public static final int BUTTON1 = -1; - public static final int BUTTON2 = -2; - public static final int BUTTON3 = -3; + /** + * The identifier for the positive button. + */ + public static final int BUTTON_POSITIVE = -1; + + /** + * The identifier for the negative button. + */ + public static final int BUTTON_NEGATIVE = -2; + /** + * The identifier for the neutral button. + */ + public static final int BUTTON_NEUTRAL = -3; + + /** + * @deprecated Use {@link #BUTTON_POSITIVE} + */ + @Deprecated + public static final int BUTTON1 = BUTTON_POSITIVE; + + /** + * @deprecated Use {@link #BUTTON_NEGATIVE} + */ + @Deprecated + public static final int BUTTON2 = BUTTON_NEGATIVE; + + /** + * @deprecated Use {@link #BUTTON_NEUTRAL} + */ + @Deprecated + public static final int BUTTON3 = BUTTON_NEUTRAL; + public void cancel(); public void dismiss(); @@ -71,9 +100,11 @@ public interface DialogInterface { * This method will be invoked when a button in the dialog is clicked. * * @param dialog The dialog that received the click. - * @param which The button that was clicked, i.e. BUTTON1 or BUTTON2 or - * the position of the item clicked. + * @param which The button that was clicked (e.g. + * {@link DialogInterface#BUTTON1}) or the position + * of the item clicked. */ + /* TODO: Change to use BUTTON_POSITIVE after API council */ public void onClick(DialogInterface dialog, int which); } diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java index c76158c1adb0658e12cdb509ffcac5cdc03b8cd6..4a92b4c8fb7f5ea3df26a13b962f3152bb982fa2 100644 --- a/core/java/android/content/Intent.java +++ b/core/java/android/content/Intent.java @@ -33,7 +33,6 @@ import android.os.Parcel; import android.os.Parcelable; import android.util.AttributeSet; import android.util.Log; -import android.util.TypedValue; import com.android.internal.util.XmlUtils; import java.io.IOException; @@ -542,23 +541,8 @@ import java.util.Set; *

    Flags

    * *

    These are the possible flags that can be used in the Intent via - * {@link #setFlags} and {@link #addFlags}. - * - *

      - *
    • {@link #FLAG_GRANT_READ_URI_PERMISSION} - *
    • {@link #FLAG_GRANT_WRITE_URI_PERMISSION} - *
    • {@link #FLAG_FROM_BACKGROUND} - *
    • {@link #FLAG_DEBUG_LOG_RESOLUTION} - *
    • {@link #FLAG_ACTIVITY_NO_HISTORY} - *
    • {@link #FLAG_ACTIVITY_SINGLE_TOP} - *
    • {@link #FLAG_ACTIVITY_NEW_TASK} - *
    • {@link #FLAG_ACTIVITY_MULTIPLE_TASK} - *
    • {@link #FLAG_ACTIVITY_FORWARD_RESULT} - *
    • {@link #FLAG_ACTIVITY_PREVIOUS_IS_TOP} - *
    • {@link #FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS} - *
    • {@link #FLAG_ACTIVITY_BROUGHT_TO_FRONT} - *
    • {@link #FLAG_RECEIVER_REGISTERED_ONLY} - *
    + * {@link #setFlags} and {@link #addFlags}. See {@link #setFlags} for a list + * of all possible flags. */ public class Intent implements Parcelable { // --------------------------------------------------------------------- @@ -573,6 +557,7 @@ public class Intent implements Parcelable { */ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) public static final String ACTION_MAIN = "android.intent.action.MAIN"; + /** * Activity Action: Display the data to the user. This is the most common * action performed on data -- it is the generic action you can use on @@ -586,11 +571,13 @@ public class Intent implements Parcelable { */ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) public static final String ACTION_VIEW = "android.intent.action.VIEW"; + /** * A synonym for {@link #ACTION_VIEW}, the "standard" action that is * performed on a piece of data. */ public static final String ACTION_DEFAULT = ACTION_VIEW; + /** * Used to indicate that some piece of data should be attached to some other * place. For example, image data could be attached to a contact. It is up @@ -601,6 +588,7 @@ public class Intent implements Parcelable { */ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) public static final String ACTION_ATTACH_DATA = "android.intent.action.ATTACH_DATA"; + /** * Activity Action: Provide explicit editable access to the given data. *

    Input: {@link #getData} is URI of data to be edited. @@ -608,6 +596,7 @@ public class Intent implements Parcelable { */ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) public static final String ACTION_EDIT = "android.intent.action.EDIT"; + /** * Activity Action: Pick an existing item, or insert a new item, and then edit it. *

    Input: {@link #getType} is the desired MIME type of the item to create or edit. @@ -618,6 +607,7 @@ public class Intent implements Parcelable { */ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) public static final String ACTION_INSERT_OR_EDIT = "android.intent.action.INSERT_OR_EDIT"; + /** * Activity Action: Pick an item from the data, returning what was selected. *

    Input: {@link #getData} is URI containing a directory of data @@ -626,13 +616,15 @@ public class Intent implements Parcelable { */ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) public static final String ACTION_PICK = "android.intent.action.PICK"; + /** * Activity Action: Creates a shortcut. - *

    Input: Nothing. + *

    Input: Nothing.

    *

    Output: An Intent representing the shortcut. The intent must contain three * extras: SHORTCUT_INTENT (value: Intent), SHORTCUT_NAME (value: String), * and SHORTCUT_ICON (value: Bitmap) or SHORTCUT_ICON_RESOURCE - * (value: ShortcutIconResource). + * (value: ShortcutIconResource).

    + * * @see #EXTRA_SHORTCUT_INTENT * @see #EXTRA_SHORTCUT_NAME * @see #EXTRA_SHORTCUT_ICON @@ -670,10 +662,12 @@ public class Intent implements Parcelable { "android.intent.extra.shortcut.ICON_RESOURCE"; /** - * Represents a shortcut icon resource. + * Represents a shortcut/live folder icon resource. * * @see Intent#ACTION_CREATE_SHORTCUT * @see Intent#EXTRA_SHORTCUT_ICON_RESOURCE + * @see android.provider.LiveFolders#ACTION_CREATE_LIVE_FOLDER + * @see android.provider.LiveFolders#EXTRA_LIVE_FOLDER_ICON */ public static class ShortcutIconResource implements Parcelable { /** @@ -972,10 +966,13 @@ public class Intent implements Parcelable { public static final String ACTION_SEARCH = "android.intent.action.SEARCH"; /** * Activity Action: Perform a web search. - *

    Input: {@link #getData} is URI of data. If it is a url - * starts with http or https, the site will be opened. If it is plain text, - * Google search will be applied. - *

    Output: nothing. + *

    + * Input: {@link android.app.SearchManager#QUERY + * getStringExtra(SearchManager.QUERY)} is the text to search for. If it is + * a url starts with http or https, the site will be opened. If it is plain + * text, Google search will be applied. + *

    + * Output: nothing. */ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) public static final String ACTION_WEB_SEARCH = "android.intent.action.WEB_SEARCH"; @@ -1027,7 +1024,7 @@ public class Intent implements Parcelable { */ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) public static final String ACTION_VOICE_COMMAND = "android.intent.action.VOICE_COMMAND"; - + // --------------------------------------------------------------------- // --------------------------------------------------------------------- // Standard intent broadcast actions (see action variable). @@ -1318,6 +1315,14 @@ public class Intent implements Parcelable { @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) public static final String ACTION_GTALK_SERVICE_DISCONNECTED = "android.intent.action.GTALK_DISCONNECTED"; + + /** + * Broadcast Action: An input method has been changed. + * {@hide pending API Council approval} + */ + @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) + public static final String ACTION_INPUT_METHOD_CHANGED = + "android.intent.action.INPUT_METHOD_CHANGED"; /** *

    Broadcast Action: The user has switched the phone into or out of Airplane Mode. One or @@ -1644,6 +1649,15 @@ public class Intent implements Parcelable { */ public static final String EXTRA_ALARM_COUNT = "android.intent.extra.ALARM_COUNT"; + /** + * Used as an int extra field in {@link android.content.Intent#ACTION_VOICE_COMMAND} + * intents to request which audio route the voice command should prefer. + * The value should be a route from {@link android.media.AudioManager}, for + * example ROUTE_BLUETOOTH_SCO. Providing this value is optional. + * {@hide pending API Council approval} + */ + public static final String EXTRA_AUDIO_ROUTE = "android.intent.extra.AUDIO_ROUTE"; + // --------------------------------------------------------------------- // --------------------------------------------------------------------- // Intent flags (see mFlags variable). @@ -1671,7 +1685,10 @@ public class Intent implements Parcelable { public static final int FLAG_DEBUG_LOG_RESOLUTION = 0x00000008; /** - * If set, the new activity is not kept in the history stack. + * If set, the new activity is not kept in the history stack. As soon as + * the user navigates away from it, the activity is finished. This may also + * be set with the {@link android.R.styleable#AndroidManifestActivity_noHistory + * noHistory} attribute. */ public static final int FLAG_ACTIVITY_NO_HISTORY = 0x40000000; /** @@ -1794,9 +1811,33 @@ public class Intent implements Parcelable { */ public static final int FLAG_ACTIVITY_RESET_TASK_IF_NEEDED = 0x00200000; /** - * If set, this activity is being launched from history (longpress home key). + * This flag is not normally set by application code, but set for you by + * the system if this activity is being launched from history + * (longpress home key). */ public static final int FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY = 0x00100000; + /** + * If set, this marks a point in the task's activity stack that should + * be cleared when the task is reset. That is, the next time the task + * is broad to the foreground with + * {@link #FLAG_ACTIVITY_RESET_TASK_IF_NEEDED} (typically as a result of + * the user re-launching it from home), this activity and all on top of + * it will be finished so that the user does not return to them, but + * instead returns to whatever activity preceeded it. + * + *

    This is useful for cases where you have a logical break in your + * application. For example, an e-mail application may have a command + * to view an attachment, which launches an image view activity to + * display it. This activity should be part of the e-mail application's + * task, since it is a part of the task the user is involved in. However, + * if the user leaves that task, and later selects the e-mail app from + * home, we may like them to return to the conversation they were + * viewing, not the picture attachment, since that is confusing. By + * setting this flag when launching the image viewer, that viewer and + * any activities it starts will be removed the next time the user returns + * to mail. + */ + public static final int FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET = 0x00080000; /** * If set, when sending a broadcast only registered receivers will be @@ -3724,6 +3765,30 @@ public class Intent implements Parcelable { return this; } + /** + * Completely replace the extras in the Intent with the extras in the + * given Intent. + * + * @param src The exact extras contained in this Intent are copied + * into the target intent, replacing any that were previously there. + */ + public Intent replaceExtras(Intent src) { + mExtras = src.mExtras != null ? new Bundle(src.mExtras) : null; + return this; + } + + /** + * Completely replace the extras in the Intent with the given Bundle of + * extras. + * + * @param extras The new set of extras in the Intent, or null to erase + * all extras. + */ + public Intent replaceExtras(Bundle extras) { + mExtras = extras != null ? new Bundle(extras) : null; + return this; + } + /** * Remove extended data from the intent. * @@ -3762,14 +3827,17 @@ public class Intent implements Parcelable { * @see #FLAG_GRANT_WRITE_URI_PERMISSION * @see #FLAG_DEBUG_LOG_RESOLUTION * @see #FLAG_FROM_BACKGROUND - * @see #FLAG_ACTIVITY_RESET_TASK_IF_NEEDED * @see #FLAG_ACTIVITY_BROUGHT_TO_FRONT + * @see #FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET * @see #FLAG_ACTIVITY_CLEAR_TOP * @see #FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS * @see #FLAG_ACTIVITY_FORWARD_RESULT + * @see #FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY * @see #FLAG_ACTIVITY_MULTIPLE_TASK * @see #FLAG_ACTIVITY_NEW_TASK * @see #FLAG_ACTIVITY_NO_HISTORY + * @see #FLAG_ACTIVITY_PREVIOUS_IS_TOP + * @see #FLAG_ACTIVITY_RESET_TASK_IF_NEEDED * @see #FLAG_ACTIVITY_SINGLE_TOP * @see #FLAG_RECEIVER_REGISTERED_ONLY */ @@ -4334,7 +4402,11 @@ public class Intent implements Parcelable { XmlUtils.skipCurrentTag(parser); } else if (nodeName.equals("extra")) { - parseExtra(resources, intent, parser, attrs); + if (intent.mExtras == null) { + intent.mExtras = new Bundle(); + } + resources.parseBundleExtra("extra", attrs, intent.mExtras); + XmlUtils.skipCurrentTag(parser); } else { XmlUtils.skipCurrentTag(parser); @@ -4343,49 +4415,4 @@ public class Intent implements Parcelable { return intent; } - - private static void parseExtra(Resources resources, Intent intent, XmlPullParser parser, - AttributeSet attrs) throws XmlPullParserException, IOException { - TypedArray sa = resources.obtainAttributes(attrs, - com.android.internal.R.styleable.IntentExtra); - - String name = sa.getString( - com.android.internal.R.styleable.IntentExtra_name); - if (name == null) { - sa.recycle(); - throw new RuntimeException( - " requires an android:name attribute at " - + parser.getPositionDescription()); - } - - TypedValue v = sa.peekValue( - com.android.internal.R.styleable.IntentExtra_value); - if (v != null) { - if (v.type == TypedValue.TYPE_STRING) { - CharSequence cs = v.coerceToString(); - intent.putExtra(name, cs != null ? cs.toString() : null); - } else if (v.type == TypedValue.TYPE_INT_BOOLEAN) { - intent.putExtra(name, v.data != 0); - } else if (v.type >= TypedValue.TYPE_FIRST_INT - && v.type <= TypedValue.TYPE_LAST_INT) { - intent.putExtra(name, v.data); - } else if (v.type == TypedValue.TYPE_FLOAT) { - intent.putExtra(name, v.getFloat()); - } else { - sa.recycle(); - throw new RuntimeException( - " only supports string, integer, float, color, and boolean at " - + parser.getPositionDescription()); - } - } else { - sa.recycle(); - throw new RuntimeException( - " requires an android:value or android:resource attribute at " - + parser.getPositionDescription()); - } - - sa.recycle(); - - XmlUtils.skipCurrentTag(parser); - } } diff --git a/core/java/android/content/SyncManager.java b/core/java/android/content/SyncManager.java index 2bf84e78e0a0892f64455206ba90e658bc170bed..6bc3774859b0db9d31e9c6ba8f3e6c248d1edde6 100644 --- a/core/java/android/content/SyncManager.java +++ b/core/java/android/content/SyncManager.java @@ -50,14 +50,14 @@ import android.os.RemoteException; import android.os.ServiceManager; import android.os.SystemClock; import android.os.SystemProperties; -import android.pim.DateUtils; -import android.pim.Time; import android.preference.Preference; import android.preference.PreferenceGroup; import android.provider.Sync; import android.provider.Settings; import android.provider.Sync.History; import android.text.TextUtils; +import android.text.format.DateUtils; +import android.text.format.Time; import android.util.Config; import android.util.EventLog; import android.util.Log; @@ -1484,7 +1484,8 @@ class SyncManager { // skip the sync if it isn't a force and the settings are off for this provider final boolean force = syncOperation.extras.getBoolean( ContentResolver.SYNC_EXTRAS_FORCE, false); - if (!force && (!syncSettings.getListenForNetworkTickles() + if (!force && (!syncSettings.getBackgroundData() + || !syncSettings.getListenForNetworkTickles() || !syncSettings.getSyncProviderAutomatically( syncOperation.authority))) { if (isLoggable) { diff --git a/core/java/android/content/pm/ActivityInfo.java b/core/java/android/content/pm/ActivityInfo.java index f577d2df687371f21d934612b8e4e8fe409adef9..85d877a070170a5006465d77caaf2859fb3a098c 100644 --- a/core/java/android/content/pm/ActivityInfo.java +++ b/core/java/android/content/pm/ActivityInfo.java @@ -119,13 +119,20 @@ public class ActivityInfo extends ComponentInfo * {@link android.R.attr#allowTaskReparenting} attribute. */ public static final int FLAG_ALLOW_TASK_REPARENTING = 0x0040; + /** + * Bit in {@link #flags} indicating that, when the user navigates away + * from an activity, it should be finished. + * Set from the + * {@link android.R.attr#noHistory} attribute. + */ + public static final int FLAG_NO_HISTORY = 0x0080; /** * Options that have been set in the activity declaration in the * manifest: {@link #FLAG_MULTIPROCESS}, * {@link #FLAG_FINISH_ON_TASK_LAUNCH}, {@link #FLAG_CLEAR_TASK_ON_LAUNCH}, * {@link #FLAG_ALWAYS_RETAIN_TASK_STATE}, * {@link #FLAG_STATE_NOT_NEEDED}, {@link #FLAG_EXCLUDE_FROM_RECENTS}, - * {@link #FLAG_ALLOW_TASK_REPARENTING}. + * {@link #FLAG_ALLOW_TASK_REPARENTING}, {@link #FLAG_NO_HISTORY}. */ public int flags; @@ -247,6 +254,16 @@ public class ActivityInfo extends ComponentInfo */ public int configChanges; + /** + * The desired soft input mode for this activity's main window. + * Set from the {@link android.R.attr#windowSoftInputMode} attribute + * in the activity's manifest. May be any of the same values allowed + * for {@link android.view.WindowManager.LayoutParams#softInputMode + * WindowManager.LayoutParams.softInputMode}. If 0 (unspecified), + * the mode from the theme will be used. + */ + public int softInputMode; + public ActivityInfo() { } @@ -260,6 +277,7 @@ public class ActivityInfo extends ComponentInfo flags = orig.flags; screenOrientation = orig.screenOrientation; configChanges = orig.configChanges; + softInputMode = orig.softInputMode; } /** @@ -280,9 +298,10 @@ public class ActivityInfo extends ComponentInfo + " targetActivity=" + targetActivity); pw.println(prefix + "launchMode=" + launchMode + " flags=0x" + Integer.toHexString(flags) - + " theme=0x" + Integer.toHexString(theme) - + " orien=" + screenOrientation - + " configChanges=0x" + Integer.toHexString(configChanges)); + + " theme=0x" + Integer.toHexString(theme)); + pw.println(prefix + "screenOrientation=" + screenOrientation + + " configChanges=0x" + Integer.toHexString(configChanges) + + " softInputMode=0x" + Integer.toHexString(softInputMode)); super.dumpBack(pw, prefix); } @@ -306,6 +325,7 @@ public class ActivityInfo extends ComponentInfo dest.writeInt(flags); dest.writeInt(screenOrientation); dest.writeInt(configChanges); + dest.writeInt(softInputMode); } public static final Parcelable.Creator CREATOR @@ -328,5 +348,6 @@ public class ActivityInfo extends ComponentInfo flags = source.readInt(); screenOrientation = source.readInt(); configChanges = source.readInt(); + softInputMode = source.readInt(); } } diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java index 22d01dcb0178ef64cbf93e298322e1f1ed0521c0..8d727ed9d0b4361d73ba16562cb8d4cd56f4b9bc 100644 --- a/core/java/android/content/pm/ApplicationInfo.java +++ b/core/java/android/content/pm/ApplicationInfo.java @@ -112,6 +112,13 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { * android:allowClearUserData} of the <application> tag. */ public static final int FLAG_ALLOW_CLEAR_USER_DATA = 1<<6; + + + /** + * Value for {@link #flags}: default value for the corresponding ActivityInfo flag. + * {@hide} + */ + public static final int FLAG_UPDATED_SYSTEM_APP = 1<<7; /** * Flags associated with the application. Any combination of @@ -195,7 +202,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { sb = ab.packageName; } - return sCollator.compare(sa, sb); + return sCollator.compare(sa.toString(), sb.toString()); } private final Collator sCollator = Collator.getInstance(); diff --git a/core/java/android/content/pm/ConfigurationInfo.java b/core/java/android/content/pm/ConfigurationInfo.java new file mode 100755 index 0000000000000000000000000000000000000000..9115225c4415ea41ffbc21643d1b17ba7f712008 --- /dev/null +++ b/core/java/android/content/pm/ConfigurationInfo.java @@ -0,0 +1,120 @@ +/* + * 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 android.content.pm; + +import android.content.res.Configuration; +import android.os.Parcel; +import android.os.Parcelable; + +/** + * Information you can retrieve about hardware configuration preferences + * declared by an application. This corresponds to information collected from the + * AndroidManifest.xml's <uses-configuration> tags. + */ +public class ConfigurationInfo implements Parcelable { + /** + * The kind of touch screen attached to the device. + * One of: {@link android.content.res.Configuration#TOUCHSCREEN_NOTOUCH}, + * {@link android.content.res.Configuration#TOUCHSCREEN_STYLUS}, + * {@link android.content.res.Configuration#TOUCHSCREEN_FINGER}. + */ + public int reqTouchScreen; + + /** + * Application's input method preference. + * One of: {@link android.content.res.Configuration#KEYBOARD_UNDEFINED}, + * {@link android.content.res.Configuration#KEYBOARD_NOKEYS}, + * {@link android.content.res.Configuration#KEYBOARD_QWERTY}, + * {@link android.content.res.Configuration#KEYBOARD_12KEY} + */ + public int reqKeyboardType; + + /** + * A flag indicating whether any keyboard is available. + * one of: {@link android.content.res.Configuration#NAVIGATION_UNDEFINED}, + * {@link android.content.res.Configuration#NAVIGATION_DPAD}, + * {@link android.content.res.Configuration#NAVIGATION_TRACKBALL}, + * {@link android.content.res.Configuration#NAVIGATION_WHEEL} + */ + public int reqNavigation; + + /** + * Value for {@link #reqInputFeatures}: if set, indicates that the application + * requires a hard keyboard + */ + public static final int INPUT_FEATURE_HARD_KEYBOARD = 0x00000001; + + /** + * Value for {@link #reqInputFeatures}: if set, indicates that the application + * requires a hard keyboard + */ + public static final int INPUT_FEATURE_FIVE_WAY_NAV = 0x00000002; + + /** + * Flags associated with the application. Any combination of + * {@link #INPUT_FEATURE_HARD_KEYBOARD}, + * {@link #INPUT_FEATURE_FIVE_WAY_NAV} + */ + public int reqInputFeatures = 0; + + public ConfigurationInfo() { + } + + public ConfigurationInfo(ConfigurationInfo orig) { + reqTouchScreen = orig.reqTouchScreen; + reqKeyboardType = orig.reqKeyboardType; + reqNavigation = orig.reqNavigation; + reqInputFeatures = orig.reqInputFeatures; + } + + public String toString() { + return "ApplicationHardwarePreferences{" + + Integer.toHexString(System.identityHashCode(this)) + + ", touchscreen = " + reqTouchScreen + "}" + + ", inputMethod = " + reqKeyboardType + "}" + + ", navigation = " + reqNavigation + "}" + + ", reqInputFeatures = " + reqInputFeatures + "}"; + } + + public int describeContents() { + return 0; + } + + public void writeToParcel(Parcel dest, int parcelableFlags) { + dest.writeInt(reqTouchScreen); + dest.writeInt(reqKeyboardType); + dest.writeInt(reqNavigation); + dest.writeInt(reqInputFeatures); + } + + public static final Creator CREATOR = + new Creator() { + public ConfigurationInfo createFromParcel(Parcel source) { + return new ConfigurationInfo(source); + } + public ConfigurationInfo[] newArray(int size) { + return new ConfigurationInfo[size]; + } + }; + + private ConfigurationInfo(Parcel source) { + reqTouchScreen = source.readInt(); + reqKeyboardType = source.readInt(); + reqNavigation = source.readInt(); + reqInputFeatures = source.readInt(); + } +} diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl index c79655d4abdbe7dfda8da23564fb75da308134e0..fdb2a2f4a3b6deb14e0c67309dc56323b4cb0255 100644 --- a/core/java/android/content/pm/IPackageManager.aidl +++ b/core/java/android/content/pm/IPackageManager.aidl @@ -76,6 +76,8 @@ interface IPackageManager { String getNameForUid(int uid); + int getUidForSharedUser(String sharedUserName); + ResolveInfo resolveIntent(in Intent intent, String resolvedType, int flags); List queryIntentActivities(in Intent intent, diff --git a/core/java/android/content/pm/InstrumentationInfo.java b/core/java/android/content/pm/InstrumentationInfo.java index e6745dac43de847093675f64e77db48298d79a4e..30ca002d23ad45a3d8c19ee709a278addb33a108 100644 --- a/core/java/android/content/pm/InstrumentationInfo.java +++ b/core/java/android/content/pm/InstrumentationInfo.java @@ -73,6 +73,7 @@ public class InstrumentationInfo extends PackageItemInfo implements Parcelable { dest.writeString(publicSourceDir); dest.writeString(dataDir); dest.writeInt((handleProfiling == false) ? 0 : 1); + dest.writeInt((functionalTest == false) ? 0 : 1); } public static final Parcelable.Creator CREATOR @@ -92,5 +93,6 @@ public class InstrumentationInfo extends PackageItemInfo implements Parcelable { publicSourceDir = source.readString(); dataDir = source.readString(); handleProfiling = source.readInt() != 0; + functionalTest = source.readInt() != 0; } } diff --git a/core/java/android/content/pm/PackageInfo.java b/core/java/android/content/pm/PackageInfo.java index 7d694c78818a36901dedd6beca3740352c569e8d..994afc8381ff1effccadaf2f57c251a05152ca56 100644 --- a/core/java/android/content/pm/PackageInfo.java +++ b/core/java/android/content/pm/PackageInfo.java @@ -103,6 +103,15 @@ public class PackageInfo implements Parcelable { * in if the flag {@link PackageManager#GET_SIGNATURES} was set. */ public Signature[] signatures; + + /** + * Application specified preferred configuration + * {@link android.R.styleable#AndroidManifestUsesConfiguration + * <uses-configuration>} tags included under <manifest>, + * or null if there were none. This is only filled in if the flag + * {@link PackageManager#GET_CONFIGURATIONS} was set. + */ + public ConfigurationInfo[] configPreferences; public PackageInfo() { } @@ -136,6 +145,7 @@ public class PackageInfo implements Parcelable { dest.writeTypedArray(permissions, parcelableFlags); dest.writeStringArray(requestedPermissions); dest.writeTypedArray(signatures, parcelableFlags); + dest.writeTypedArray(configPreferences, parcelableFlags); } public static final Parcelable.Creator CREATOR @@ -166,5 +176,6 @@ public class PackageInfo implements Parcelable { permissions = source.createTypedArray(PermissionInfo.CREATOR); requestedPermissions = source.createStringArray(); signatures = source.createTypedArray(Signature.CREATOR); + configPreferences = source.createTypedArray(ConfigurationInfo.CREATOR); } } diff --git a/core/java/android/content/pm/PackageItemInfo.java b/core/java/android/content/pm/PackageItemInfo.java index 406a3eb6963191975dae4fdfe0c1124e6a56f0a7..46e7ca43b973f193c45b46a3eea259263a26c360 100644 --- a/core/java/android/content/pm/PackageItemInfo.java +++ b/core/java/android/content/pm/PackageItemInfo.java @@ -90,7 +90,10 @@ public class PackageItemInfo { return label; } } - return name; + if(name != null) { + return name; + } + return packageName; } /** @@ -179,7 +182,7 @@ public class PackageItemInfo { if (sa == null) sa = aa.name; CharSequence sb = ab.loadLabel(mPM); if (sb == null) sb = ab.name; - return sCollator.compare(sa, sb); + return sCollator.compare(sa.toString(), sb.toString()); } private final Collator sCollator = Collator.getInstance(); diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java index db00a9ab365e55b71d6004ca4be40b9b3d2f5bf6..a5445507a043802febb1724654af59d4bce6ee8a 100644 --- a/core/java/android/content/pm/PackageManager.java +++ b/core/java/android/content/pm/PackageManager.java @@ -148,6 +148,21 @@ public abstract class PackageManager { * {@link PackageInfo#permissions}. */ public static final int GET_PERMISSIONS = 0x00001000; + + /** + * Flag parameter to retrieve all applications(even uninstalled ones) with data directories. + * This state could have resulted if applications have been deleted with flag + * DONT_DELETE_DATA + * with a possibility of being replaced or reinstalled in future + */ + public static final int GET_UNINSTALLED_PACKAGES = 0x00002000; + + /** + * {@link PackageInfo} flag: return information about + * hardware preferences + * {@link PackageInfo#configPreferences} + */ + public static final int GET_CONFIGURATIONS = 0x00004000; /** * Permission check result: this is returned by {@link #checkPermission} @@ -427,16 +442,38 @@ public abstract class PackageManager { * * @param packageName The full name (i.e. com.google.apps.contacts) of the * desired package. - * @param flags Optional flags to control what information is returned. If - * 0, none of the optional information is returned. - * - * @return Returns a PackageInfo containing information about the package. - * + + * @param flags Additional option flags. Use any combination of + * {@link #GET_ACTIVITIES}, + * {@link #GET_GIDS}, + * {@link #GET_CONFIGURATIONS}, + * {@link #GET_INSTRUMENTATION}, + * {@link #GET_PERMISSIONS}, + * {@link #GET_PROVIDERS}, + * {@link #GET_RECEIVERS}, + * {@link #GET_SERVICES}, + * {@link #GET_SIGNATURES}, + * {@link #GET_UNINSTALLED_PACKAGES} to modify the data returned. + * + * @return Returns a PackageInfo object containing information about the package. + * If flag GET_UNINSTALLED_PACKAGES is set and if the package is not + * found in the list of installed applications, the package information is + * retrieved from the list of uninstalled applications(which includes + * installed applications as well as applications + * with data directory ie applications which had been + * deleted with DONT_DELTE_DATA flag set). + * * @see #GET_ACTIVITIES + * @see #GET_GIDS + * @see #GET_CONFIGURATIONS + * @see #GET_INSTRUMENTATION + * @see #GET_PERMISSIONS + * @see #GET_PROVIDERS * @see #GET_RECEIVERS * @see #GET_SERVICES - * @see #GET_INSTRUMENTATION * @see #GET_SIGNATURES + * @see #GET_UNINSTALLED_PACKAGES + * */ public abstract PackageInfo getPackageInfo(String packageName, int flags) throws NameNotFoundException; @@ -530,10 +567,23 @@ public abstract class PackageManager { * * @param packageName The full name (i.e. com.google.apps.contacts) of an * application. - * @param flags Additional option flags. Currently should always be 0. - * - * @return {@link ApplicationInfo} containing information about the - * application. + * @param flags Additional option flags. Use any combination of + * {@link #GET_META_DATA}, {@link #GET_SHARED_LIBRARY_FILES}, + * {@link #GET_UNINSTALLED_PACKAGES} to modify the data returned. + * + * @return {@link ApplicationInfo} Returns ApplicationInfo object containing + * information about the package. + * If flag GET_UNINSTALLED_PACKAGES is set and if the package is not + * found in the list of installed applications, + * the application information is retrieved from the + * list of uninstalled applications(which includes + * installed applications as well as applications + * with data directory ie applications which had been + * deleted with DONT_DELTE_DATA flag set). + * + * @see #GET_META_DATA + * @see #GET_SHARED_LIBRARY_FILES + * @see #GET_UNINSTALLED_PACKAGES */ public abstract ApplicationInfo getApplicationInfo(String packageName, int flags) throws NameNotFoundException; @@ -548,11 +598,15 @@ public abstract class PackageManager { * @param className The full name (i.e. * com.google.apps.contacts.ContactsList) of an Activity * class. - * @param flags Additional option flags. Usually 0. + * @param flags Additional option flags. Use any combination of + * {@link #GET_META_DATA}, {@link #GET_SHARED_LIBRARY_FILES}, + * to modify the data (in ApplicationInfo) returned. * * @return {@link ActivityInfo} containing information about the activity. * * @see #GET_INTENT_FILTERS + * @see #GET_META_DATA + * @see #GET_SHARED_LIBRARY_FILES */ public abstract ActivityInfo getActivityInfo(ComponentName className, int flags) throws NameNotFoundException; @@ -567,11 +621,15 @@ public abstract class PackageManager { * @param className The full name (i.e. * com.google.apps.contacts.CalendarAlarm) of a Receiver * class. - * @param flags Additional option flags. Usually 0. + * @param flags Additional option flags. Use any combination of + * {@link #GET_META_DATA}, {@link #GET_SHARED_LIBRARY_FILES}, + * to modify the data returned. * * @return {@link ActivityInfo} containing information about the receiver. * * @see #GET_INTENT_FILTERS + * @see #GET_META_DATA + * @see #GET_SHARED_LIBRARY_FILES */ public abstract ActivityInfo getReceiverInfo(ComponentName className, int flags) throws NameNotFoundException; @@ -586,9 +644,14 @@ public abstract class PackageManager { * @param className The full name (i.e. * com.google.apps.media.BackgroundPlayback) of a Service * class. - * @param flags Additional option flags. Currently should always be 0. + * @param flags Additional option flags. Use any combination of + * {@link #GET_META_DATA}, {@link #GET_SHARED_LIBRARY_FILES}, + * to modify the data returned. * * @return ServiceInfo containing information about the service. + * + * @see #GET_META_DATA + * @see #GET_SHARED_LIBRARY_FILES */ public abstract ServiceInfo getServiceInfo(ComponentName className, int flags) throws NameNotFoundException; @@ -597,18 +660,36 @@ public abstract class PackageManager { * Return a List of all packages that are installed * on the device. * - * @param flags Optional flags to control what information is returned. If - * 0, none of the optional information is returned. + * @param flags Additional option flags. Use any combination of + * {@link #GET_ACTIVITIES}, + * {@link #GET_GIDS}, + * {@link #GET_CONFIGURATIONS}, + * {@link #GET_INSTRUMENTATION}, + * {@link #GET_PERMISSIONS}, + * {@link #GET_PROVIDERS}, + * {@link #GET_RECEIVERS}, + * {@link #GET_SERVICES}, + * {@link #GET_SIGNATURES}, + * {@link #GET_UNINSTALLED_PACKAGES} to modify the data returned. * * @return A List of PackageInfo objects, one for each package that is * installed on the device. In the unlikely case of there being no - * installed packages, an empty list is returned. + * installed packages, an empty list is returned. + * If flag GET_UNINSTALLED_PACKAGES is set, a list of all + * applications including those deleted with DONT_DELETE_DATA + * (partially installed apps with data directory) will be returned. * * @see #GET_ACTIVITIES + * @see #GET_GIDS + * @see #GET_CONFIGURATIONS + * @see #GET_INSTRUMENTATION + * @see #GET_PERMISSIONS + * @see #GET_PROVIDERS * @see #GET_RECEIVERS * @see #GET_SERVICES - * @see #GET_INSTRUMENTATION * @see #GET_SIGNATURES + * @see #GET_UNINSTALLED_PACKAGES + * */ public abstract List getInstalledPackages(int flags); @@ -731,16 +812,42 @@ public abstract class PackageManager { * user id is not currently assigned. */ public abstract String getNameForUid(int uid); + + /** + * Return the user id associated with a shared user name. Multiple + * applications can specify a shared user name in their manifest and thus + * end up using a common uid. This might be used for new applications + * that use an existing shared user name and need to know the uid of the + * shared user. + * + * @param sharedUserName The shared user name whose uid is to be retrieved. + * @return Returns the uid associated with the shared user, or NameNotFoundException + * if the shared user name is not being used by any installed packages + * @hide + */ + public abstract int getUidForSharedUser(String sharedUserName) + throws NameNotFoundException; /** * Return a List of all application packages that are installed on the - * device. - * - * @param flags Additional option flags. Currently should always be 0. + * device. If flag GET_UNINSTALLED_PACKAGES has been set, a list of all + * applications including those deleted with DONT_DELETE_DATA(partially + * installed apps with data directory) will be returned. + * + * @param flags Additional option flags. Use any combination of + * {@link #GET_META_DATA}, {@link #GET_SHARED_LIBRARY_FILES}, + * {link #GET_UNINSTALLED_PACKAGES} to modify the data returned. * * @return A List of ApplicationInfo objects, one for each application that * is installed on the device. In the unlikely case of there being - * no installed applications, an empty list is returned. + * no installed applications, an empty list is returned. + * If flag GET_UNINSTALLED_PACKAGES is set, a list of all + * applications including those deleted with DONT_DELETE_DATA + * (partially installed apps with data directory) will be returned. + * + * @see #GET_META_DATA + * @see #GET_SHARED_LIBRARY_FILES + * @see #GET_UNINSTALLED_PACKAGES */ public abstract List getInstalledApplications(int flags); @@ -1139,17 +1246,30 @@ public abstract class PackageManager { * in a package archive file * * @param archiveFilePath The path to the archive file - * @param flags Optional flags to control what information is returned. If - * 0, none of the optional information is returned. + * @param flags Additional option flags. Use any combination of + * {@link #GET_ACTIVITIES}, + * {@link #GET_GIDS}, + * {@link #GET_CONFIGURATIONS}, + * {@link #GET_INSTRUMENTATION}, + * {@link #GET_PERMISSIONS}, + * {@link #GET_PROVIDERS}, + * {@link #GET_RECEIVERS}, + * {@link #GET_SERVICES}, + * {@link #GET_SIGNATURES}, to modify the data returned. * * @return Returns the information about the package. Returns * null if the package could not be successfully parsed. * * @see #GET_ACTIVITIES + * @see #GET_GIDS + * @see #GET_CONFIGURATIONS + * @see #GET_INSTRUMENTATION + * @see #GET_PERMISSIONS + * @see #GET_PROVIDERS * @see #GET_RECEIVERS * @see #GET_SERVICES - * @see #GET_INSTRUMENTATION * @see #GET_SIGNATURES + * */ public PackageInfo getPackageArchiveInfo(String archiveFilePath, int flags) { PackageParser packageParser = new PackageParser(archiveFilePath); @@ -1314,16 +1434,28 @@ public abstract class PackageManager { * first package on the list is the most preferred, the last is the * least preferred. * - * @param flags Optional flags to control what information is returned. If - * 0, none of the optional information is returned. + * @param flags Additional option flags. Use any combination of + * {@link #GET_ACTIVITIES}, + * {@link #GET_GIDS}, + * {@link #GET_CONFIGURATIONS}, + * {@link #GET_INSTRUMENTATION}, + * {@link #GET_PERMISSIONS}, + * {@link #GET_PROVIDERS}, + * {@link #GET_RECEIVERS}, + * {@link #GET_SERVICES}, + * {@link #GET_SIGNATURES}, to modify the data returned. * * @return Returns a list of PackageInfo objects describing each * preferred application, in order of preference. * * @see #GET_ACTIVITIES + * @see #GET_GIDS + * @see #GET_CONFIGURATIONS + * @see #GET_INSTRUMENTATION + * @see #GET_PERMISSIONS + * @see #GET_PROVIDERS * @see #GET_RECEIVERS * @see #GET_SERVICES - * @see #GET_INSTRUMENTATION * @see #GET_SIGNATURES */ public abstract List getPreferredPackages(int flags); diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java index 5a902614308e19306f0d135acdfbac7efc2b15cf..e08f1d154dc2e42507c1037748e4ccc3f9b6dd68 100644 --- a/core/java/android/content/pm/PackageParser.java +++ b/core/java/android/content/pm/PackageParser.java @@ -23,6 +23,7 @@ import android.content.ComponentName; import android.content.Intent; import android.content.IntentFilter; import android.content.res.AssetManager; +import android.content.res.Configuration; import android.content.res.Resources; import android.content.res.TypedArray; import android.content.res.XmlResourceParser; @@ -104,6 +105,15 @@ public class PackageParser { if ((flags&PackageManager.GET_GIDS) != 0) { pi.gids = gids; } + if ((flags&PackageManager.GET_CONFIGURATIONS) != 0) { + int N = p.configPreferences.size(); + if (N > 0) { + pi.configPreferences = new ConfigurationInfo[N]; + for (int i=0; i 0) { @@ -245,18 +255,24 @@ public class PackageParser { XmlResourceParser parser = null; AssetManager assmgr = null; + boolean assetError = true; try { assmgr = new AssetManager(); - assmgr.addAssetPath(mArchiveSourcePath); - parser = assmgr.openXmlResourceParser("AndroidManifest.xml"); + if(assmgr.addAssetPath(mArchiveSourcePath) != 0) { + parser = assmgr.openXmlResourceParser("AndroidManifest.xml"); + assetError = false; + } else { + Log.w(TAG, "Failed adding asset path:"+mArchiveSourcePath); + } } catch (Exception e) { - if (assmgr != null) assmgr.close(); Log.w(TAG, "Unable to read AndroidManifest.xml of " + mArchiveSourcePath, e); + } + if(assetError) { + if (assmgr != null) assmgr.close(); mParseError = PackageManager.INSTALL_PARSE_FAILED_BAD_MANIFEST; return null; } - String[] errorText = new String[1]; Package pkg = null; Exception errorException = null; @@ -626,7 +642,35 @@ public class PackageParser { XmlUtils.skipCurrentTag(parser); - } else if (tagName.equals("uses-sdk")) { + } else if (tagName.equals("uses-configuration")) { + ConfigurationInfo cPref = new ConfigurationInfo(); + sa = res.obtainAttributes(attrs, + com.android.internal.R.styleable.AndroidManifestUsesConfiguration); + cPref.reqTouchScreen = sa.getInt( + com.android.internal.R.styleable.AndroidManifestUsesConfiguration_reqTouchScreen, + Configuration.TOUCHSCREEN_UNDEFINED); + cPref.reqKeyboardType = sa.getInt( + com.android.internal.R.styleable.AndroidManifestUsesConfiguration_reqKeyboardType, + Configuration.KEYBOARD_UNDEFINED); + if (sa.getBoolean( + com.android.internal.R.styleable.AndroidManifestUsesConfiguration_reqHardKeyboard, + false)) { + cPref.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_HARD_KEYBOARD; + } + cPref.reqNavigation = sa.getInt( + com.android.internal.R.styleable.AndroidManifestUsesConfiguration_reqNavigation, + Configuration.NAVIGATION_UNDEFINED); + if (sa.getBoolean( + com.android.internal.R.styleable.AndroidManifestUsesConfiguration_reqFiveWayNav, + false)) { + cPref.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_FIVE_WAY_NAV; + } + sa.recycle(); + pkg.configPreferences.add(cPref); + + XmlUtils.skipCurrentTag(parser); + + } else if (tagName.equals("uses-sdk")) { if (mSdkVersion > 0) { sa = res.obtainAttributes(attrs, com.android.internal.R.styleable.AndroidManifestUsesSdk); @@ -650,6 +694,10 @@ public class PackageParser { if (parseInstrumentation(pkg, res, parser, attrs, outError) == null) { return null; } + } else if (tagName.equals("eat-comment")) { + // Just skip this tag + XmlUtils.skipCurrentTag(parser); + continue; } else if (RIGID_PARSER) { outError[0] = "Bad element under : " + parser.getName(); @@ -1038,11 +1086,6 @@ public class PackageParser { if (outError[0] != null) { mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; return false; - } else if (ai.processName != null && !ai.processName.equals(ai.packageName) - && ai.className != null) { - Log.w(TAG, "In package " + ai.packageName - + " specifies both a name and a process; ignoring the process"); - ai.processName = null; } final int innerDepth = parser.getDepth(); @@ -1257,6 +1300,12 @@ public class PackageParser { a.info.flags |= ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH; } + if (sa.getBoolean( + com.android.internal.R.styleable.AndroidManifestActivity_noHistory, + false)) { + a.info.flags |= ActivityInfo.FLAG_NO_HISTORY; + } + if (sa.getBoolean( com.android.internal.R.styleable.AndroidManifestActivity_alwaysRetainTaskState, false)) { @@ -1291,6 +1340,9 @@ public class PackageParser { a.info.configChanges = sa.getInt( com.android.internal.R.styleable.AndroidManifestActivity_configChanges, 0); + a.info.softInputMode = sa.getInt( + com.android.internal.R.styleable.AndroidManifestActivity_windowSoftInputMode, + 0); } else { a.info.launchMode = ActivityInfo.LAUNCH_MULTIPLE; a.info.configChanges = 0; @@ -2002,6 +2054,12 @@ public class PackageParser { // Additional data supplied by callers. public Object mExtras; + + /* + * Applications hardware preferences + */ + public final ArrayList configPreferences = + new ArrayList(); public Package(String _name) { packageName = _name; @@ -2031,7 +2089,7 @@ public class PackageParser { metaData = clone.metaData; } } - + public final static class Permission extends Component { public final PermissionInfo info; public boolean tree; diff --git a/core/java/android/content/res/ColorStateList.java b/core/java/android/content/res/ColorStateList.java index ee88c899abe5cf9a195903ebdf8dfc5110a75808..4b1e67843608c0d9246a662d61c825e3f4fd763a 100644 --- a/core/java/android/content/res/ColorStateList.java +++ b/core/java/android/content/res/ColorStateList.java @@ -16,6 +16,10 @@ package android.content.res; +import com.google.android.collect.Lists; + +import com.android.internal.util.ArrayUtils; + import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; @@ -30,8 +34,6 @@ import java.io.IOException; import java.lang.ref.WeakReference; import java.util.Arrays; -import com.android.internal.util.ArrayUtils; - /** * * Lets you map {@link android.view.View} state sets to colors. diff --git a/core/java/android/content/res/Configuration.java b/core/java/android/content/res/Configuration.java index 78a90de6c7110f5db74b6ba044b4cbcc3d9d6642..7e4b7ac1803cdd6ea366e483aaf10e3a54b09e1c 100644 --- a/core/java/android/content/res/Configuration.java +++ b/core/java/android/content/res/Configuration.java @@ -34,6 +34,12 @@ public final class Configuration implements Parcelable, Comparable

      + *
    • {@link TypedValue#TYPE_STRING}: + * {@link Bundle#putCharSequence Bundle.putCharSequence()} + *
    • {@link TypedValue#TYPE_INT_BOOLEAN}: + * {@link Bundle#putCharSequence Bundle.putBoolean()} + *
    • {@link TypedValue#TYPE_FIRST_INT}-{@link TypedValue#TYPE_LAST_INT}: + * {@link Bundle#putCharSequence Bundle.putBoolean()} + *
    • {@link TypedValue#TYPE_FLOAT}: + * {@link Bundle#putCharSequence Bundle.putFloat()} + *
    + * + * @param tagName The name of the tag these attributes come from; this is + * only used for reporting error messages. + * @param attrs The attributes from which to retrieve the name/value pair. + * @param outBundle The Bundle in which to place the parsed value. + * @throws XmlPullParserException If the attributes are not valid. + */ + public void parseBundleExtra(String tagName, AttributeSet attrs, + Bundle outBundle) throws XmlPullParserException { + TypedArray sa = obtainAttributes(attrs, + com.android.internal.R.styleable.Extra); + + String name = sa.getString( + com.android.internal.R.styleable.Extra_name); + if (name == null) { + sa.recycle(); + throw new XmlPullParserException("<" + tagName + + "> requires an android:name attribute at " + + attrs.getPositionDescription()); + } + + TypedValue v = sa.peekValue( + com.android.internal.R.styleable.Extra_value); + if (v != null) { + if (v.type == TypedValue.TYPE_STRING) { + CharSequence cs = v.coerceToString(); + outBundle.putCharSequence(name, cs); + } else if (v.type == TypedValue.TYPE_INT_BOOLEAN) { + outBundle.putBoolean(name, v.data != 0); + } else if (v.type >= TypedValue.TYPE_FIRST_INT + && v.type <= TypedValue.TYPE_LAST_INT) { + outBundle.putInt(name, v.data); + } else if (v.type == TypedValue.TYPE_FLOAT) { + outBundle.putFloat(name, v.getFloat()); + } else { + sa.recycle(); + throw new XmlPullParserException("<" + tagName + + "> only supports string, integer, float, color, and boolean at " + + attrs.getPositionDescription()); + } + } else { + sa.recycle(); + throw new XmlPullParserException("<" + tagName + + "> requires an android:value or android:resource attribute at " + + attrs.getPositionDescription()); + } + + sa.recycle(); + } + /** * Retrieve underlying AssetManager storage for these resources. */ diff --git a/core/java/android/content/res/StringBlock.java b/core/java/android/content/res/StringBlock.java index da32cc82c81f53508f889eeac4848a035c835f45..3df770889d66fbd94022bd3980b3daebc0669422 100644 --- a/core/java/android/content/res/StringBlock.java +++ b/core/java/android/content/res/StringBlock.java @@ -96,6 +96,7 @@ final class StringBlock { mStyleIDs.subId = nativeIndexOfString(mNative, "sub"); mStyleIDs.strikeId = nativeIndexOfString(mNative, "strike"); mStyleIDs.listItemId = nativeIndexOfString(mNative, "li"); + mStyleIDs.marqueeId = nativeIndexOfString(mNative, "marquee"); if (localLOGV) Log.v(TAG, "BoldId=" + mStyleIDs.boldId + ", ItalicId=" + mStyleIDs.italicId @@ -127,6 +128,7 @@ final class StringBlock { private int supId; private int strikeId; private int listItemId; + private int marqueeId; } private CharSequence applyStyles(String str, int[] style, StyleIDs ids) { @@ -179,6 +181,10 @@ final class StringBlock { buffer.setSpan(new BulletSpan(10), style[i+1], style[i+2]+1, Spannable.SPAN_PARAGRAPH); + } else if (type == ids.marqueeId) { + buffer.setSpan(TextUtils.TruncateAt.MARQUEE, + style[i+1], style[i+2]+1, + Spannable.SPAN_INCLUSIVE_INCLUSIVE); } else { String tag = nativeGetString(mNative, type); @@ -216,6 +222,15 @@ final class StringBlock { style[i+1], style[i+2]+1, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); } + } else if (tag.startsWith("a;")) { + String sub; + + sub = subtag(tag, ";href="); + if (sub != null) { + buffer.setSpan(new URLSpan(sub), + style[i+1], style[i+2]+1, + Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); + } } } diff --git a/core/java/android/database/AbstractCursor.java b/core/java/android/database/AbstractCursor.java index e81f7f81fd06d646a0c0c163fa2aad5169c91f14..76f0860b9d36d8ee5adab81dc62051164516d28b 100644 --- a/core/java/android/database/AbstractCursor.java +++ b/core/java/android/database/AbstractCursor.java @@ -21,6 +21,10 @@ import android.net.Uri; import android.util.Config; import android.util.Log; import android.os.Bundle; +import android.os.Handler; +import android.os.HandlerThread; +import android.os.Looper; +import android.os.Message; import java.lang.ref.WeakReference; import java.lang.UnsupportedOperationException; @@ -457,9 +461,24 @@ public abstract class AbstractCursor implements CrossProcessCursor { mContentObservable.unregisterObserver(observer); } } - + + /** + * @hide pending API council approval + */ + protected void notifyDataSetChange() { + mDataSetObservable.notifyChanged(); + } + + /** + * @hide pending API council approval + */ + protected DataSetObservable getDataSetObservable() { + return mDataSetObservable; + + } public void registerDataSetObserver(DataSetObserver observer) { mDataSetObservable.registerObserver(observer); + } public void unregisterDataSetObserver(DataSetObserver observer) { diff --git a/core/java/android/database/AbstractWindowedCursor.java b/core/java/android/database/AbstractWindowedCursor.java index 1ec4312f114dcbe1ef12868c9269d505f6e43be6..4ac0aef81ea3825c1af14389d3ef374bde8fcd9a 100644 --- a/core/java/android/database/AbstractWindowedCursor.java +++ b/core/java/android/database/AbstractWindowedCursor.java @@ -172,7 +172,7 @@ public abstract class AbstractWindowedCursor extends AbstractCursor super.checkPosition(); if (mWindow == null) { - throw new StaleDataException("This cursor has changed, you must call requery()"); + throw new StaleDataException("Access closed cursor"); } } diff --git a/core/java/android/database/CursorWindow.java b/core/java/android/database/CursorWindow.java index 72dc3a99f4535453fd15383c72c63ed58d61fd38..8e2673036e063197cc7eeff621679826b3c8b1d0 100644 --- a/core/java/android/database/CursorWindow.java +++ b/core/java/android/database/CursorWindow.java @@ -409,8 +409,13 @@ public class CursorWindow extends SQLiteClosable implements Parcelable { * change across a call to clear(). */ public void clear() { - mStartPos = 0; - native_clear(); + acquireReference(); + try { + mStartPos = 0; + native_clear(); + } finally { + releaseReference(); + } } /** Clears out the native side of things */ diff --git a/core/java/android/database/DatabaseUtils.java b/core/java/android/database/DatabaseUtils.java index ab0dc3f7d3a9580d6d6294c3961b5e7420624a55..2ff72947879f8af9c6d2fcfbda5393095958f26f 100644 --- a/core/java/android/database/DatabaseUtils.java +++ b/core/java/android/database/DatabaseUtils.java @@ -240,6 +240,21 @@ public class DatabaseUtils { } } + /** + * Concatenates two SQL WHERE clauses, handling empty or null values. + * @hide + */ + public static String concatenateWhere(String a, String b) { + if (TextUtils.isEmpty(a)) { + return b; + } + if (TextUtils.isEmpty(b)) { + return a; + } + + return "(" + a + ") AND (" + b + ")"; + } + /** * return the collation key * @param name diff --git a/core/java/android/database/sqlite/SQLiteCursor.java b/core/java/android/database/sqlite/SQLiteCursor.java index ae2fc956e751e0042fb46b01ced53a392404e596..70b9b835b5bb134c09a82a94113ae3e020acd6af 100644 --- a/core/java/android/database/sqlite/SQLiteCursor.java +++ b/core/java/android/database/sqlite/SQLiteCursor.java @@ -18,7 +18,12 @@ package android.database.sqlite; import android.database.AbstractWindowedCursor; import android.database.CursorWindow; +import android.database.DataSetObserver; import android.database.SQLException; + +import android.os.Handler; +import android.os.Message; +import android.os.Process; import android.text.TextUtils; import android.util.Config; import android.util.Log; @@ -26,6 +31,7 @@ import android.util.Log; import java.util.HashMap; import java.util.Iterator; import java.util.Map; +import java.util.concurrent.locks.ReentrantLock; /** * A Cursor implementation that exposes results from a query on a @@ -59,7 +65,131 @@ public class SQLiteCursor extends AbstractWindowedCursor { /** Used to find out where a cursor was allocated in case it never got * released. */ private StackTraceElement[] mStackTraceElements; - + + /** + * mMaxRead is the max items that each cursor window reads + * default to a very high value + */ + private int mMaxRead = Integer.MAX_VALUE; + private int mInitialRead = Integer.MAX_VALUE; + private int mCursorState = 0; + private ReentrantLock mLock = null; + private boolean mPendingData = false; + + /** + * support for a cursor variant that doesn't always read all results + * initialRead is the initial number of items that cursor window reads + * if query contains more than this number of items, a thread will be + * created and handle the left over items so that caller can show + * results as soon as possible + * @param initialRead initial number of items that cursor read + * @param maxRead leftover items read at maxRead items per time + * @hide + */ + public void setLoadStyle(int initialRead, int maxRead) { + mMaxRead = maxRead; + mInitialRead = initialRead; + mLock = new ReentrantLock(true); + } + + private void queryThreadLock() { + if (mLock != null) { + mLock.lock(); + } + } + + private void queryThreadUnlock() { + if (mLock != null) { + mLock.unlock(); + } + } + + + /** + * @hide + */ + final private class QueryThread implements Runnable { + private final int mThreadState; + QueryThread(int version) { + mThreadState = version; + } + private void sendMessage() { + if (mNotificationHandler != null) { + mNotificationHandler.sendEmptyMessage(1); + mPendingData = false; + } else { + mPendingData = true; + } + + } + public void run() { + // use cached mWindow, to avoid get null mWindow + CursorWindow cw = mWindow; + Process.setThreadPriority(Process.myTid(), Process.THREAD_PRIORITY_BACKGROUND); + // the cursor's state doesn't change + while (true) { + mLock.lock(); + if (mCursorState != mThreadState) { + mLock.unlock(); + break; + } + try { + int count = mQuery.fillWindow(cw, mMaxRead, mCount); + // return -1 means not finished + if (count != 0) { + if (count == NO_COUNT){ + mCount += mMaxRead; + sendMessage(); + } else { + mCount = count; + sendMessage(); + break; + } + } else { + break; + } + } catch (Exception e) { + // end the tread when the cursor is close + break; + } finally { + mLock.unlock(); + } + } + } + } + + /** + * @hide + */ + protected class MainThreadNotificationHandler extends Handler { + public void handleMessage(Message msg) { + notifyDataSetChange(); + } + } + + /** + * @hide + */ + protected MainThreadNotificationHandler mNotificationHandler; + + public void registerDataSetObserver(DataSetObserver observer) { + super.registerDataSetObserver(observer); + if ((Integer.MAX_VALUE != mMaxRead || Integer.MAX_VALUE != mInitialRead) && + mNotificationHandler == null) { + queryThreadLock(); + try { + mNotificationHandler = new MainThreadNotificationHandler(); + if (mPendingData) { + notifyDataSetChange(); + mPendingData = false; + } + } finally { + queryThreadUnlock(); + } + } + + } + /** * Execute a query and provide access to its result set through a Cursor * interface. For a query such as: {@code SELECT name, birth, phone FROM @@ -146,11 +276,22 @@ public class SQLiteCursor extends AbstractWindowedCursor { // If there isn't a window set already it will only be accessed locally mWindow = new CursorWindow(true /* the window is local only */); } else { - mWindow.clear(); + mCursorState++; + queryThreadLock(); + try { + mWindow.clear(); + } finally { + queryThreadUnlock(); + } } - - // mWindow must be cleared - mCount = mQuery.fillWindow(mWindow, startPos); + mWindow.setStartPosition(startPos); + mCount = mQuery.fillWindow(mWindow, mInitialRead, 0); + // return -1 means not finished + if (mCount == NO_COUNT){ + mCount = startPos + mInitialRead; + Thread t = new Thread(new QueryThread(mCursorState), "query thread"); + t.start(); + } } @Override @@ -344,6 +485,7 @@ public class SQLiteCursor extends AbstractWindowedCursor { private void deactivateCommon() { if (Config.LOGV) Log.v(TAG, "<<< Releasing cursor " + this); + mCursorState = 0; if (mWindow != null) { mWindow.close(); mWindow = null; @@ -368,6 +510,9 @@ public class SQLiteCursor extends AbstractWindowedCursor { @Override public boolean requery() { + if (isClosed()) { + return false; + } long timeStart = 0; if (Config.LOGV) { timeStart = System.currentTimeMillis(); @@ -385,8 +530,13 @@ public class SQLiteCursor extends AbstractWindowedCursor { // This one will recreate the temp table, and get its count mDriver.cursorRequeried(this); mCount = NO_COUNT; - // Requery the program that runs over the temp table - mQuery.requery(); + mCursorState++; + queryThreadLock(); + try { + mQuery.requery(); + } finally { + queryThreadUnlock(); + } } finally { mDatabase.unlock(); } @@ -405,9 +555,15 @@ public class SQLiteCursor extends AbstractWindowedCursor { } @Override - public void setWindow(CursorWindow window) { + public void setWindow(CursorWindow window) { if (mWindow != null) { - mWindow.close(); + mCursorState++; + queryThreadLock(); + try { + mWindow.close(); + } finally { + queryThreadUnlock(); + } mCount = NO_COUNT; } mWindow = window; diff --git a/core/java/android/database/sqlite/SQLiteDatabase.java b/core/java/android/database/sqlite/SQLiteDatabase.java index e49719098ffb9f2faad09f630f939dcc7d364d21..fa062c86e00e319bbce70a5a71047cbdd9901623 100644 --- a/core/java/android/database/sqlite/SQLiteDatabase.java +++ b/core/java/android/database/sqlite/SQLiteDatabase.java @@ -53,6 +53,69 @@ import java.util.concurrent.locks.ReentrantLock; public class SQLiteDatabase extends SQLiteClosable { private final static String TAG = "Database"; + /** + * Algorithms used in ON CONFLICT clause + * http://www.sqlite.org/lang_conflict.html + * @hide + */ + public enum ConflictAlgorithm { + /** + * When a constraint violation occurs, an immediate ROLLBACK occurs, + * thus ending the current transaction, and the command aborts with a + * return code of SQLITE_CONSTRAINT. If no transaction is active + * (other than the implied transaction that is created on every command) + * then this algorithm works the same as ABORT. + */ + ROLLBACK("ROLLBACK"), + + /** + * When a constraint violation occurs,no ROLLBACK is executed + * so changes from prior commands within the same transaction + * are preserved. This is the default behavior. + */ + ABORT("ABORT"), + + /** + * When a constraint violation occurs, the command aborts with a return + * code SQLITE_CONSTRAINT. But any changes to the database that + * the command made prior to encountering the constraint violation + * are preserved and are not backed out. + */ + FAIL("FAIL"), + + /** + * When a constraint violation occurs, the one row that contains + * the constraint violation is not inserted or changed. + * But the command continues executing normally. Other rows before and + * after the row that contained the constraint violation continue to be + * inserted or updated normally. No error is returned. + */ + IGNORE("IGNORE"), + + /** + * When a UNIQUE constraint violation occurs, the pre-existing rows that + * are causing the constraint violation are removed prior to inserting + * or updating the current row. Thus the insert or update always occurs. + * The command continues executing normally. No error is returned. + * If a NOT NULL constraint violation occurs, the NULL value is replaced + * by the default value for that column. If the column has no default + * value, then the ABORT algorithm is used. If a CHECK constraint + * violation occurs then the IGNORE algorithm is used. When this conflict + * resolution strategy deletes rows in order to satisfy a constraint, + * it does not invoke delete triggers on those rows. + * This behavior might change in a future release. + */ + REPLACE("REPLACE"); + + private final String mValue; + ConflictAlgorithm(String value) { + mValue = value; + } + public String value() { + return mValue; + } + } + /** * Maximum Length Of A LIKE Or GLOB Pattern * The pattern matching algorithm used in the default LIKE and GLOB implementation @@ -437,8 +500,26 @@ public class SQLiteDatabase extends SQLiteClosable { * successful so far. Do not call setTransactionSuccessful before calling this. When this * returns a new transaction will have been created but not marked as successful. * @return true if the transaction was yielded + * @deprecated if the db is locked more than once (becuase of nested transactions) then the lock + * will not be yielded. Use yieldIfContendedSafely instead. */ public boolean yieldIfContended() { + return yieldIfContendedHelper(false /* do not check yielding */); + } + + /** + * Temporarily end the transaction to let other threads run. The transaction is assumed to be + * successful so far. Do not call setTransactionSuccessful before calling this. When this + * returns a new transaction will have been created but not marked as successful. This assumes + * that there are no nested transactions (beginTransaction has only been called once) and will + * through an exception if that is not the case. + * @return true if the transaction was yielded + */ + public boolean yieldIfContendedSafely() { + return yieldIfContendedHelper(true /* check yielding */); + } + + private boolean yieldIfContendedHelper(boolean checkFullyYielded) { if (mLock.getQueueLength() == 0) { // Reset the lock acquire time since we know that the thread was willing to yield // the lock at this time. @@ -448,6 +529,12 @@ public class SQLiteDatabase extends SQLiteClosable { } setTransactionSuccessful(); endTransaction(); + if (checkFullyYielded) { + if (this.isDbLockedByCurrentThread()) { + throw new IllegalStateException( + "Db locked more than once. yielfIfContended cannot yield"); + } + } beginTransaction(); return true; } @@ -1030,6 +1117,28 @@ public class SQLiteDatabase extends SQLiteClosable { } } + /** + * Runs the provided SQL and returns a cursor over the result set. + * The cursor will read an initial set of rows and the return to the caller. + * It will continue to read in batches and send data changed notifications + * when the later batches are ready. + * @param sql the SQL query. The SQL string must not be ; terminated + * @param selectionArgs You may include ?s in where clause in the query, + * which will be replaced by the values from selectionArgs. The + * values will be bound as Strings. + * @param initialRead set the initial count of items to read from the cursor + * @param maxRead set the count of items to read on each iteration after the first + * @return A {@link Cursor} object, which is positioned before the first entry + * @hide pending API council approval + */ + public Cursor rawQuery(String sql, String[] selectionArgs, + int initialRead, int maxRead) { + SQLiteCursor c = (SQLiteCursor)rawQueryWithFactory( + null, sql, selectionArgs, null); + c.setLoadStyle(initialRead, maxRead); + return c; + } + /** * Convenience method for inserting a row into the database. * @@ -1044,7 +1153,7 @@ public class SQLiteDatabase extends SQLiteClosable { */ public long insert(String table, String nullColumnHack, ContentValues values) { try { - return insertOrReplace(table, nullColumnHack, values, false); + return insertWithOnConflict(table, nullColumnHack, values, null); } catch (SQLException e) { Log.e(TAG, "Error inserting " + values, e); return -1; @@ -1066,7 +1175,7 @@ public class SQLiteDatabase extends SQLiteClosable { */ public long insertOrThrow(String table, String nullColumnHack, ContentValues values) throws SQLException { - return insertOrReplace(table, nullColumnHack, values, false) ; + return insertWithOnConflict(table, nullColumnHack, values, null); } /** @@ -1082,7 +1191,8 @@ public class SQLiteDatabase extends SQLiteClosable { */ public long replace(String table, String nullColumnHack, ContentValues initialValues) { try { - return insertOrReplace(table, nullColumnHack, initialValues, true); + return insertWithOnConflict(table, nullColumnHack, initialValues, + ConflictAlgorithm.REPLACE); } catch (SQLException e) { Log.e(TAG, "Error inserting " + initialValues, e); return -1; @@ -1103,22 +1213,38 @@ public class SQLiteDatabase extends SQLiteClosable { */ public long replaceOrThrow(String table, String nullColumnHack, ContentValues initialValues) throws SQLException { - return insertOrReplace(table, nullColumnHack, initialValues, true); + return insertWithOnConflict(table, nullColumnHack, initialValues, + ConflictAlgorithm.REPLACE); } - private long insertOrReplace(String table, String nullColumnHack, - ContentValues initialValues, boolean allowReplace) { + /** + * General method for inserting a row into the database. + * + * @param table the table to insert the row into + * @param nullColumnHack SQL doesn't allow inserting a completely empty row, + * so if initialValues is empty this column will explicitly be + * assigned a NULL value + * @param initialValues this map contains the initial column values for the + * row. The keys should be the column names and the values the + * column values + * @param algorithm {@link ConflictAlgorithm} for insert conflict resolver + * @return the row ID of the newly inserted row, or -1 if an error occurred + * @hide + */ + public long insertWithOnConflict(String table, String nullColumnHack, + ContentValues initialValues, ConflictAlgorithm algorithm) { if (!isOpen()) { throw new IllegalStateException("database not open"); } // Measurements show most sql lengths <= 152 StringBuilder sql = new StringBuilder(152); - sql.append("INSERT "); - if (allowReplace) { - sql.append("OR REPLACE "); + sql.append("INSERT"); + if (algorithm != null) { + sql.append(" OR "); + sql.append(algorithm.value()); } - sql.append("INTO "); + sql.append(" INTO "); sql.append(table); // Measurements show most values lengths < 40 StringBuilder values = new StringBuilder(40); @@ -1241,6 +1367,23 @@ public class SQLiteDatabase extends SQLiteClosable { * @return the number of rows affected */ public int update(String table, ContentValues values, String whereClause, String[] whereArgs) { + return updateWithOnConflict(table, values, whereClause, whereArgs, null); + } + + /** + * Convenience method for updating rows in the database. + * + * @param table the table to update in + * @param values a map from column names to new column values. null is a + * valid value that will be translated to NULL. + * @param whereClause the optional WHERE clause to apply when updating. + * Passing null will update all rows. + * @param algorithm {@link ConflictAlgorithm} for update conflict resolver + * @return the number of rows affected + * @hide + */ + public int updateWithOnConflict(String table, ContentValues values, + String whereClause, String[] whereArgs, ConflictAlgorithm algorithm) { if (!isOpen()) { throw new IllegalStateException("database not open"); } @@ -1251,6 +1394,11 @@ public class SQLiteDatabase extends SQLiteClosable { StringBuilder sql = new StringBuilder(120); sql.append("UPDATE "); + if (algorithm != null) { + sql.append(" OR "); + sql.append(algorithm.value()); + } + sql.append(table); sql.append(" SET "); diff --git a/core/java/android/database/sqlite/SQLiteOpenHelper.java b/core/java/android/database/sqlite/SQLiteOpenHelper.java index f6872acb4fe893d8c97a28004de47bf79c6d5946..35bf6456ed97ccb06161a0e346d8382ca1fa3083 100644 --- a/core/java/android/database/sqlite/SQLiteOpenHelper.java +++ b/core/java/android/database/sqlite/SQLiteOpenHelper.java @@ -26,8 +26,6 @@ import android.util.Log; * optionally {@link #onOpen}, and this class takes care of opening the database * if it exists, creating it if it does not, and upgrading it as necessary. * Transactions are used to make sure the database is always in a sensible state. - * - * @see com.google.provider.NotePad.NotePadProvider */ public abstract class SQLiteOpenHelper { private static final String TAG = SQLiteOpenHelper.class.getSimpleName(); diff --git a/core/java/android/database/sqlite/SQLiteProgram.java b/core/java/android/database/sqlite/SQLiteProgram.java index e0341a2142edfd28606378e9d3851a92ae5a189d..f89c87d9baa1c3c787279cead9d3876d495dc0d4 100644 --- a/core/java/android/database/sqlite/SQLiteProgram.java +++ b/core/java/android/database/sqlite/SQLiteProgram.java @@ -239,7 +239,9 @@ public abstract class SQLiteProgram extends SQLiteClosable { Log.d(TAG, " " + ste); } } - onAllReferencesReleased(); + // when in finalize() it is already removed from weakhashmap + // so it is safe to not removed itself from db + onAllReferencesReleasedFromContainer(); } } diff --git a/core/java/android/database/sqlite/SQLiteQuery.java b/core/java/android/database/sqlite/SQLiteQuery.java index 40855b661f257372692c7e84a52ff47fc26ef425..22c53abca37e23eb20552f6ffd8afaf533832bd2 100644 --- a/core/java/android/database/sqlite/SQLiteQuery.java +++ b/core/java/android/database/sqlite/SQLiteQuery.java @@ -40,9 +40,8 @@ public class SQLiteQuery extends SQLiteProgram { * Create a persistent query object. * * @param db The database that this query object is associated with - * @param query The SQL string for this query. It must include "INDEX -1 - * OFFSET ?" at the end - * @param offsetIndex The 1-based index to the OFFSET parameter + * @param query The SQL string for this query. + * @param offsetIndex The 1-based index to the OFFSET parameter, */ /* package */ SQLiteQuery(SQLiteDatabase db, String query, int offsetIndex, String[] bindArgs) { super(db, query); @@ -59,24 +58,28 @@ public class SQLiteQuery extends SQLiteProgram { * @param startPos The position to start reading rows from * @return number of total rows in the query */ - /* package */ int fillWindow(CursorWindow window, int startPos) { - if (startPos < 0) { - throw new IllegalArgumentException("startPos should > 0"); - } - window.setStartPosition(startPos); + /* package */ int fillWindow(CursorWindow window, + int maxRead, int lastPos) { mDatabase.lock(); try { acquireReference(); - window.acquireReference(); - return native_fill_window(window, startPos, mOffsetIndex); - } catch (IllegalStateException e){ - // simply ignore it - return 0; - } catch (SQLiteDatabaseCorruptException e) { - mDatabase.onCorruption(); - throw e; + try { + window.acquireReference(); + // if the start pos is not equal to 0, then most likely window is + // too small for the data set, loading by another thread + // is not safe in this situation. the native code will ignore maxRead + return native_fill_window(window, window.getStartPosition(), mOffsetIndex, + maxRead, lastPos); + } catch (IllegalStateException e){ + // simply ignore it + return 0; + } catch (SQLiteDatabaseCorruptException e) { + mDatabase.onCorruption(); + throw e; + } finally { + window.releaseReference(); + } } finally { - window.releaseReference(); releaseReference(); mDatabase.unlock(); } @@ -113,7 +116,13 @@ public class SQLiteQuery extends SQLiteProgram { releaseReference(); } } - + + /** {@hide pending API Council approval} */ + @Override + public String toString() { + return "SQLiteQuery: " + mQuery; + } + @Override public void close() { super.close(); @@ -124,11 +133,6 @@ public class SQLiteQuery extends SQLiteProgram { * Called by SQLiteCursor when it is requeried. */ /* package */ void requery() { - boolean oldMClosed = mClosed; - if (mClosed) { - mClosed = false; - compile(mQuery, false); - } if (mBindArgs != null) { int len = mBindArgs.length; try { @@ -136,8 +140,7 @@ public class SQLiteQuery extends SQLiteProgram { super.bindString(i + 1, mBindArgs[i]); } } catch (SQLiteMisuseException e) { - StringBuilder errMsg = new StringBuilder - ("old mClosed " + oldMClosed + " mQuery " + mQuery); + StringBuilder errMsg = new StringBuilder("mQuery " + mQuery); for (int i = 0; i < len; i++) { errMsg.append(" "); errMsg.append(mBindArgs[i]); @@ -174,7 +177,8 @@ public class SQLiteQuery extends SQLiteProgram { if (!mClosed) super.bindString(index, value); } - private final native int native_fill_window(CursorWindow window, int startPos, int offsetParam); + private final native int native_fill_window(CursorWindow window, + int startPos, int offsetParam, int maxRead, int lastPos); private final native int native_column_count(); diff --git a/core/java/android/hardware/Camera.java b/core/java/android/hardware/Camera.java index 833075078a19ceec8944641ee68ac6e3f43c988a..dc757480d9a835087cddff1cd9ebbec351fd999d 100644 --- a/core/java/android/hardware/Camera.java +++ b/core/java/android/hardware/Camera.java @@ -18,6 +18,7 @@ package android.hardware; import java.lang.ref.WeakReference; import java.util.HashMap; +import java.io.IOException; import android.util.Log; import android.view.Surface; @@ -97,14 +98,29 @@ public class Camera { native_release(); } + /** + * Reconnect to the camera after passing it to MediaRecorder. To save + * setup/teardown time, a client of Camara can pass an initialized Camera + * object to a MediaRecorder to use for video recording. Once the + * MediaRecorder is done with the Camera, this method can be used to + * re-establish a connection with the camera hardware. + * + * @throws IOException if the method fails. + * + * FIXME: Unhide after approval + * @hide + */ + public native final void reconnect() throws IOException; + /** * Sets the SurfaceHolder to be used for a picture preview. If the surface * changed since the last call, the screen will blank. Nothing happens * if the same surface is re-set. * * @param holder the SurfaceHolder upon which to place the picture preview + * @throws IOException if the method fails. */ - public final void setPreviewDisplay(SurfaceHolder holder) { + public final void setPreviewDisplay(SurfaceHolder holder) throws IOException { setPreviewDisplay(holder.getSurface()); } @@ -263,10 +279,19 @@ public class Camera { }; /** - * Registers a callback to be invoked when a picture is taken. + * Triggers an asynchronous image capture. The camera service + * will initiate a series of callbacks to the application as the + * image capture progresses. The shutter callback occurs after + * the image is captured. This can be used to trigger a sound + * to let the user know that image has been captured. The raw + * callback occurs when the raw image data is available. The jpeg + * callback occurs when the compressed image is available. If the + * application does not need a particular callback, a null can be + * passed instead of a callback method. * - * @param raw the callback to run for raw images, may be null - * @param jpeg the callback to run for jpeg images, may be null + * @param shutter callback after the image is captured, may be null + * @param raw callback with raw image data, may be null + * @param jpeg callback with jpeg image data, may be null */ public final void takePicture(ShutterCallback shutter, PictureCallback raw, PictureCallback jpeg) { diff --git a/core/java/android/hardware/ISensorService.aidl b/core/java/android/hardware/ISensorService.aidl index b6ac3aba683f0633a60292a945ad56fa74e8e280..8aad9b465bda06c5c0278d02d5b72aa3995f4de8 100644 --- a/core/java/android/hardware/ISensorService.aidl +++ b/core/java/android/hardware/ISensorService.aidl @@ -26,5 +26,4 @@ interface ISensorService { ParcelFileDescriptor getDataChanel(); boolean enableSensor(IBinder listener, int sensor, int enable); - oneway void reportAccuracy(int sensor, int value); } diff --git a/core/java/android/hardware/Sensor.java b/core/java/android/hardware/Sensor.java new file mode 100644 index 0000000000000000000000000000000000000000..0ce2f7bc84784139c02cc541e712cf181eac36fa --- /dev/null +++ b/core/java/android/hardware/Sensor.java @@ -0,0 +1,146 @@ +/* + * 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 android.hardware; + +/** + * Class representing a sensor. Use {@link SensorManager#getSensorList} + * to get the list of available Sensors. + */ +public class Sensor { + + /** + * A constant describing an accelerometer sensor type. + * See {@link android.hardware.SensorEvent SensorEvent} + * for more details. + */ + public static final int TYPE_ACCELEROMETER = 1; + + /** + * A constant describing a magnetic field sensor type. + * See {@link android.hardware.SensorEvent SensorEvent} + * for more details. + */ + public static final int TYPE_MAGNETIC_FIELD = 2; + + /** + * A constant describing an orientation sensor type. + * See {@link android.hardware.SensorEvent SensorEvent} + * for more details. + */ + public static final int TYPE_ORIENTATION = 3; + + /** A constant describing a gyroscope sensor type */ + public static final int TYPE_GYROSCOPE = 4; + /** A constant describing a light sensor type */ + public static final int TYPE_LIGHT = 5; + /** A constant describing a pressure sensor type */ + public static final int TYPE_PRESSURE = 6; + /** A constant describing a temperature sensor type */ + public static final int TYPE_TEMPERATURE = 7; + /** A constant describing a proximity sensor type */ + public static final int TYPE_PROXIMITY = 8; + + + /** + * A constant describing all sensor types. + */ + public static final int TYPE_ALL = -1; + + /* Some of these fields are set only by the native bindings in + * SensorManager. + */ + private String mName; + private String mVendor; + private int mVersion; + private int mHandle; + private int mType; + private float mMaxRange; + private float mResolution; + private float mPower; + private int mLegacyType; + + + Sensor() { + } + + /** + * @return name string of the sensor. + */ + public String getName() { + return mName; + } + + /** + * @return vendor string of this sensor. + */ + public String getVendor() { + return mVendor; + } + + /** + * @return generic type of this sensor. + */ + public int getType() { + return mType; + } + + /** + * @return version of the sensor's module. + */ + public int getVersion() { + return mVersion; + } + + /** + * @return maximum range of the sensor in the sensor's unit. + */ + public float getMaximumRange() { + return mMaxRange; + } + + /** + * @return resolution of the sensor in the sensor's unit. + */ + public float getResolution() { + return mResolution; + } + + /** + * @return the power in mA used by this sensor while in use + */ + public float getPower() { + return mPower; + } + + int getHandle() { + return mHandle; + } + + void setRange(float max, float res) { + mMaxRange = max; + mResolution = res; + } + + void setLegacyType(int legacyType) { + mLegacyType = legacyType; + } + + int getLegacyType() { + return mLegacyType; + } +} diff --git a/core/java/android/hardware/SensorEvent.java b/core/java/android/hardware/SensorEvent.java new file mode 100644 index 0000000000000000000000000000000000000000..cf939c52a5e3ec7ab3602456447e2af1f8ce40c6 --- /dev/null +++ b/core/java/android/hardware/SensorEvent.java @@ -0,0 +1,146 @@ +/* + * 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 android.hardware; + +/** + * This class represents a sensor event and holds informations such as the + * sensor type (eg: accelerometer, orientation, etc...), the time-stamp, + * accuracy and of course the sensor's {@link SensorEvent#values data}. + * + *

    Definition of the coordinate system used by the SensorEvent API.

    + * + *

    + * The coordinate space is defined relative to the screen of the phone 
    + * in its default orientation. The axes are not swapped when the device's
    + * screen orientation changes.
    + * 
    + * The OpenGL ES coordinate system is used. The origin is in the
    + * lower-left corner  with respect to the screen, with the X axis horizontal
    + * and pointing  right, the Y axis vertical and pointing up and the Z axis
    + * pointing outside the front face of the screen. In this system, coordinates
    + * behind the screen have negative Z values.
    + * 
    + * Note: This coordinate system is different from the one used in the
    + * Android 2D APIs where the origin is in the top-left corner. 
    + *
    + *   x<0         x>0
    + *                ^
    + *                |
    + *    +-----------+-->  y>0
    + *    |           |
    + *    |           |
    + *    |           |
    + *    |           |   / z<0
    + *    |           |  /
    + *    |           | /
    + *    O-----------+/
    + *    |[]  [ ]  []/
    + *    +----------/+     y<0
    + *              /
    + *             /
    + *           |/ z>0 (toward the sky)
    + *
    + *    O: Origin (x=0,y=0,z=0)
    + * 
    + */ + +public class SensorEvent { + /** + * The length and contents of the values array vary depending on which + * sensor type is being monitored (see also {@link SensorEvent} for a + * definition of the coordinate system used): + * + *

    {@link android.hardware.Sensor#TYPE_ORIENTATION Sensor.TYPE_ORIENTATION}:

    + * All values are angles in degrees. + * + *

    values[0]: Azimuth, angle between the magnetic north direction and + * the Y axis, around the Z axis (0 to 359). + * 0=North, 90=East, 180=South, 270=West + * + *

    values[1]: Pitch, rotation around X axis (-180 to 180), + * with positive values when the z-axis moves toward the y-axis. + * + *

    values[2]: Roll, rotation around Y axis (-90 to 90), with + * positive values when the x-axis moves away from the z-axis. + * + *

    Note: This definition is different from yaw, pitch and + * roll used in aviation where the X axis is along the long side of + * the plane (tail to nose). + * + *

    Note: It is preferable to use + * {@link android.hardware.SensorManager#getRotationMatrix + * getRotationMatrix()} in conjunction with + * {@link android.hardware.SensorManager#remapCoordinateSystem + * remapCoordinateSystem()} and + * {@link android.hardware.SensorManager#getOrientation getOrientation()} + * to compute these values; while it may be more expensive, it is usually + * more accurate. + * + *

    {@link android.hardware.Sensor#TYPE_ACCELEROMETER Sensor.TYPE_ACCELEROMETER}:

    + * All values are in SI units (m/s^2) and measure the acceleration applied + * to the phone minus the force of gravity. + * + *

    values[0]: Acceleration minus Gx on the x-axis + *

    values[1]: Acceleration minus Gy on the y-axis + *

    values[2]: Acceleration minus Gz on the z-axis + * + *

    Examples: + *

  • When the device lies flat on a table and is pushed on its left + * side toward the right, the x acceleration value is positive.
  • + * + *
  • When the device lies flat on a table, the acceleration value is + * +9.81, which correspond to the acceleration of the device (0 m/s^2) + * minus the force of gravity (-9.81 m/s^2).
  • + * + *
  • When the device lies flat on a table and is pushed toward the sky + * with an acceleration of A m/s^2, the acceleration value is equal to + * A+9.81 which correspond to the acceleration of the + * device (+A m/s^2) minus the force of gravity (-9.81 m/s^2).
  • + * + * + *

    {@link android.hardware.Sensor#TYPE_MAGNETIC_FIELD Sensor.TYPE_MAGNETIC_FIELD}:

    + * All values are in micro-Tesla (uT) and measure the ambient magnetic + * field in the X, Y and Z axis. + * + */ + public final float[] values; + + /** + * The sensor that generated this event. + * See {@link android.hardware.SensorManager SensorManager} + * for details. + */ + public Sensor sensor; + + /** + * The accuracy of this event. + * See {@link android.hardware.SensorManager SensorManager} + * for details. + */ + public int accuracy; + + + /** + * The time in nanosecond at which the event happened + */ + public long timestamp; + + + SensorEvent(int size) { + values = new float[size]; + } +} diff --git a/core/java/android/hardware/SensorEventListener.java b/core/java/android/hardware/SensorEventListener.java new file mode 100644 index 0000000000000000000000000000000000000000..716d0d4734742f4fe72b7e576517d47dafff76b4 --- /dev/null +++ b/core/java/android/hardware/SensorEventListener.java @@ -0,0 +1,49 @@ +/* + * 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 android.hardware; + +/** + * Used for receiving notifications from the SensorManager when + * sensor values have changed. + */ +public interface SensorEventListener { + + /** + * Called when sensor values have changed. + *

    See {@link android.hardware.SensorManager SensorManager} + * for details on possible sensor types. + *

    See also {@link android.hardware.SensorEvent SensorEvent}. + * + *

    NOTE: The application doesn't own the + * {@link android.hardware.SensorEvent event} + * object passed as a parameter and therefore cannot hold on o it. + * The object may be part of an internal pool and may be reused by + * the framework. + * + * @param event the {@link android.hardware.SensorEvent SensorEvent}. + */ + public void onSensorChanged(SensorEvent event); + + /** + * Called when the accuracy of a sensor has changed. + *

    See {@link android.hardware.SensorManager SensorManager} + * for details. + * + * @param accuracy The new accuracy of this sensor + */ + public void onAccuracyChanged(Sensor sensor, int accuracy); +} diff --git a/core/java/android/hardware/SensorListener.java b/core/java/android/hardware/SensorListener.java index d676a5e093ee3a062aea9216f814ebc8ff7326ea..cfa184bf1784ded2c7bd035ae2f487a868283791 100644 --- a/core/java/android/hardware/SensorListener.java +++ b/core/java/android/hardware/SensorListener.java @@ -19,18 +19,74 @@ package android.hardware; /** * Used for receiving notifications from the SensorManager when * sensor values have changed. + * + * This interface is deprecated, use + * {@link android.hardware.SensorEventListener SensorEventListener} instead. + * */ +@Deprecated public interface SensorListener { /** - * Called when sensor values have changed. + *

    Called when sensor values have changed. * The length and contents of the values array vary * depending on which sensor is being monitored. * See {@link android.hardware.SensorManager SensorManager} - * for details on possible sensor types and values. + * for details on possible sensor types. * + *

    Definition of the coordinate system used below.

    + *

    The X axis refers to the screen's horizontal axis + * (the small edge in portrait mode, the long edge in landscape mode) and + * points to the right. + *

    The Y axis refers to the screen's vertical axis and points towards + * the top of the screen (the origin is in the lower-left corner). + *

    The Z axis points toward the sky when the device is lying on its back + * on a table. + *

    IMPORTANT NOTE: The axis are swapped when the + * device's screen orientation changes. To access the unswapped values, + * use indices 3, 4 and 5 in values[]. + * + *

    {@link android.hardware.SensorManager#SENSOR_ORIENTATION SENSOR_ORIENTATION}, + * {@link android.hardware.SensorManager#SENSOR_ORIENTATION_RAW SENSOR_ORIENTATION_RAW}:

    + * All values are angles in degrees. + * + *

    values[0]: Azimuth, rotation around the Z axis (0<=azimuth<360). + * 0 = North, 90 = East, 180 = South, 270 = West + * + *

    values[1]: Pitch, rotation around X axis (-180<=pitch<=180), with positive + * values when the z-axis moves toward the y-axis. + * + *

    values[2]: Roll, rotation around Y axis (-90<=roll<=90), with positive values + * when the z-axis moves toward the x-axis. + * + *

    Note that this definition of yaw, pitch and roll is different from the + * traditional definition used in aviation where the X axis is along the long + * side of the plane (tail to nose). + * + *

    {@link android.hardware.SensorManager#SENSOR_ACCELEROMETER SENSOR_ACCELEROMETER}:

    + * All values are in SI units (m/s^2) and measure contact forces. + * + *

    values[0]: force applied by the device on the x-axis + *

    values[1]: force applied by the device on the y-axis + *

    values[2]: force applied by the device on the z-axis + * + *

    Examples: + *

  • When the device is pushed on its left side toward the right, the + * x acceleration value is negative (the device applies a reaction force + * to the push toward the left)
  • + * + *
  • When the device lies flat on a table, the acceleration value is + * {@link android.hardware.SensorManager#STANDARD_GRAVITY -STANDARD_GRAVITY}, + * which correspond to the force the device applies on the table in reaction + * to gravity.
  • + * + *

    {@link android.hardware.SensorManager#SENSOR_MAGNETIC_FIELD SENSOR_MAGNETIC_FIELD}:

    + * All values are in micro-Tesla (uT) and measure the ambient magnetic + * field in the X, Y and -Z axis. + *

    Note: the magnetic field's Z axis is inverted. + * * @param sensor The ID of the sensor being monitored - * @param values The new values for the sensor + * @param values The new values for the sensor. */ public void onSensorChanged(int sensor, float[] values); @@ -40,7 +96,7 @@ public interface SensorListener { * for details. * * @param sensor The ID of the sensor being monitored - * @param accuracy The new accuracy of this sensor + * @param accuracy The new accuracy of this sensor. */ public void onAccuracyChanged(int sensor, int accuracy); } diff --git a/core/java/android/hardware/SensorManager.java b/core/java/android/hardware/SensorManager.java index 9b88fff0976f9087b0ce3c50b5a01123f7d284b8..f02094eed63d11f8b98b5c4f477ac464fee952e0 100644 --- a/core/java/android/hardware/SensorManager.java +++ b/core/java/android/hardware/SensorManager.java @@ -26,6 +26,7 @@ import android.os.Handler; import android.os.Message; import android.os.ServiceManager; import android.util.Log; +import android.util.SparseArray; import android.view.IRotationWatcher; import android.view.IWindowManager; import android.view.Surface; @@ -33,7 +34,9 @@ import android.view.Surface; import java.io.FileDescriptor; import java.io.IOException; import java.util.ArrayList; -import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; /** * Class that lets you access the device's sensors. Get an instance of this @@ -43,126 +46,119 @@ import java.util.Arrays; public class SensorManager extends IRotationWatcher.Stub { private static final String TAG = "SensorManager"; + private static final float[] mTempMatrix = new float[16]; - /** NOTE: sensor IDs must be a power of 2 */ + /* NOTE: sensor IDs must be a power of 2 */ - /** A constant describing an orientation sensor. - * Sensor values are yaw, pitch and roll - * - * Yaw is the compass heading in degrees, range [0, 360[ - * 0 = North, 90 = East, 180 = South, 270 = West - * - * Pitch indicates the tilt of the top of the device, - * with range -90 to 90. - * Positive values indicate that the bottom of the device is tilted up - * and negative values indicate the top of the device is tilted up. - * - * Roll indicates the side to side tilt of the device, - * with range -90 to 90. - * Positive values indicate that the left side of the device is tilted up - * and negative values indicate the right side of the device is tilted up. + /** + * A constant describing an orientation sensor. + * See {@link android.hardware.SensorListener SensorListener} for more details. + * @deprecated use {@link android.hardware.Sensor Sensor} instead. */ + @Deprecated public static final int SENSOR_ORIENTATION = 1 << 0; - /** A constant describing an accelerometer. - * Sensor values are acceleration in the X, Y and Z axis, - * where the X axis has positive direction toward the right side of the device, - * the Y axis has positive direction toward the top of the device - * and the Z axis has positive direction toward the front of the device. - * - * The direction of the force of gravity is indicated by acceleration values in the - * X, Y and Z axes. The typical case where the device is flat relative to the surface - * of the Earth appears as -STANDARD_GRAVITY in the Z axis - * and X and Z values close to zero. - * - * Acceleration values are given in SI units (m/s^2) - * + /** + * A constant describing an accelerometer. + * See {@link android.hardware.SensorListener SensorListener} for more details. + * @deprecated use {@link android.hardware.Sensor Sensor} instead. */ + @Deprecated public static final int SENSOR_ACCELEROMETER = 1 << 1; - /** A constant describing a temperature sensor - * Only the first value is defined for this sensor and it - * contains the ambient temperature in degree C. + /** + * A constant describing a temperature sensor + * See {@link android.hardware.SensorListener SensorListener} for more details. + * @deprecated use {@link android.hardware.Sensor Sensor} instead. */ + @Deprecated public static final int SENSOR_TEMPERATURE = 1 << 2; - /** A constant describing a magnetic sensor - * Sensor values are the magnetic vector in the X, Y and Z axis, - * where the X axis has positive direction toward the right side of the device, - * the Y axis has positive direction toward the top of the device - * and the Z axis has positive direction toward the front of the device. - * - * Magnetic values are given in micro-Tesla (uT) - * + /** + * A constant describing a magnetic sensor + * See {@link android.hardware.SensorListener SensorListener} for more details. + * @deprecated use {@link android.hardware.Sensor Sensor} instead. */ + @Deprecated public static final int SENSOR_MAGNETIC_FIELD = 1 << 3; - /** A constant describing an ambient light sensor - * Only the first value is defined for this sensor and it contains - * the ambient light measure in lux. - * + /** + * A constant describing an ambient light sensor + * See {@link android.hardware.SensorListener SensorListener} for more details. + * @deprecated use {@link android.hardware.Sensor Sensor} instead. */ + @Deprecated public static final int SENSOR_LIGHT = 1 << 4; - /** A constant describing a proximity sensor - * Only the first value is defined for this sensor and it contains - * the distance between the sensor and the object in meters (m) + /** + * A constant describing a proximity sensor + * See {@link android.hardware.SensorListener SensorListener} for more details. + * @deprecated use {@link android.hardware.Sensor Sensor} instead. */ + @Deprecated public static final int SENSOR_PROXIMITY = 1 << 5; - /** A constant describing a Tricorder - * When this sensor is available and enabled, the device can be - * used as a fully functional Tricorder. All values are returned in - * SI units. + /** + * A constant describing a Tricorder + * See {@link android.hardware.SensorListener SensorListener} for more details. + * @deprecated use {@link android.hardware.Sensor Sensor} instead. */ + @Deprecated public static final int SENSOR_TRICORDER = 1 << 6; - /** A constant describing an orientation sensor. - * Sensor values are yaw, pitch and roll - * - * Yaw is the compass heading in degrees, 0 <= range < 360 - * 0 = North, 90 = East, 180 = South, 270 = West - * - * This is similar to SENSOR_ORIENTATION except the data is not - * smoothed or filtered in any way. + /** + * A constant describing an orientation sensor. + * See {@link android.hardware.SensorListener SensorListener} for more details. + * @deprecated use {@link android.hardware.Sensor Sensor} instead. */ + @Deprecated public static final int SENSOR_ORIENTATION_RAW = 1 << 7; /** A constant that includes all sensors */ + @Deprecated public static final int SENSOR_ALL = 0x7F; /** Smallest sensor ID */ + @Deprecated public static final int SENSOR_MIN = SENSOR_ORIENTATION; /** Largest sensor ID */ + @Deprecated public static final int SENSOR_MAX = ((SENSOR_ALL + 1)>>1); - /** Index of the X value in the array returned by + /** Index of the X value in the array returned by * {@link android.hardware.SensorListener#onSensorChanged} */ + @Deprecated public static final int DATA_X = 0; - /** Index of the Y value in the array returned by + /** Index of the Y value in the array returned by * {@link android.hardware.SensorListener#onSensorChanged} */ + @Deprecated public static final int DATA_Y = 1; - /** Index of the Z value in the array returned by + /** Index of the Z value in the array returned by * {@link android.hardware.SensorListener#onSensorChanged} */ + @Deprecated public static final int DATA_Z = 2; - - /** Offset to the raw values in the array returned by + + /** Offset to the untransformed values in the array returned by * {@link android.hardware.SensorListener#onSensorChanged} */ + @Deprecated public static final int RAW_DATA_INDEX = 3; - /** Index of the raw X value in the array returned by + /** Index of the untransformed X value in the array returned by * {@link android.hardware.SensorListener#onSensorChanged} */ + @Deprecated public static final int RAW_DATA_X = 3; - /** Index of the raw X value in the array returned by + /** Index of the untransformed Y value in the array returned by * {@link android.hardware.SensorListener#onSensorChanged} */ + @Deprecated public static final int RAW_DATA_Y = 4; - /** Index of the raw X value in the array returned by + /** Index of the untransformed Z value in the array returned by * {@link android.hardware.SensorListener#onSensorChanged} */ + @Deprecated public static final int RAW_DATA_Z = 5; - - + + /** Standard gravity (g) on Earth. This value is equivalent to 1G */ public static final float STANDARD_GRAVITY = 9.80665f; @@ -177,7 +173,7 @@ public class SensorManager extends IRotationWatcher.Stub public static final float GRAVITY_JUPITER = 23.12f; public static final float GRAVITY_SATURN = 8.96f; public static final float GRAVITY_URANUS = 8.69f; - public static final float GRAVITY_NEPTUN = 11.0f; + public static final float GRAVITY_NEPTUNE = 11.0f; public static final float GRAVITY_PLUTO = 0.6f; public static final float GRAVITY_DEATH_STAR_I = 0.000000353036145f; public static final float GRAVITY_THE_ISLAND = 4.815162342f; @@ -208,52 +204,84 @@ public class SensorManager extends IRotationWatcher.Stub /** rate suitable for the user interface */ public static final int SENSOR_DELAY_UI = 2; /** rate (default) suitable for screen orientation changes */ - public static final int SENSOR_DELAY_NORMAL = 3; + public static final int SENSOR_DELAY_NORMAL = 3; + - /** The values returned by this sensor cannot be trusted, calibration * is needed or the environment doesn't allow readings */ public static final int SENSOR_STATUS_UNRELIABLE = 0; - + /** This sensor is reporting data with low accuracy, calibration with the * environment is needed */ public static final int SENSOR_STATUS_ACCURACY_LOW = 1; - /** This sensor is reporting data with an average level of accuracy, + /** This sensor is reporting data with an average level of accuracy, * calibration with the environment may improve the readings */ public static final int SENSOR_STATUS_ACCURACY_MEDIUM = 2; - + /** This sensor is reporting data with maximum accuracy */ public static final int SENSOR_STATUS_ACCURACY_HIGH = 3; - + /** see {@link #remapCoordinateSystem} */ + public static final int AXIS_X = 1; + /** see {@link #remapCoordinateSystem} */ + public static final int AXIS_Y = 2; + /** see {@link #remapCoordinateSystem} */ + public static final int AXIS_Z = 3; + /** see {@link #remapCoordinateSystem} */ + public static final int AXIS_MINUS_X = AXIS_X | 0x80; + /** see {@link #remapCoordinateSystem} */ + public static final int AXIS_MINUS_Y = AXIS_Y | 0x80; + /** see {@link #remapCoordinateSystem} */ + public static final int AXIS_MINUS_Z = AXIS_Z | 0x80; + + /*-----------------------------------------------------------------------*/ - private static final int SENSOR_DISABLE = -1; - private static final int SENSOR_ORDER_MASK = 0x1F; - private static final int SENSOR_STATUS_SHIFT = 28; private ISensorService mSensorService; - private Looper mLooper; + Looper mMainLooper; + @SuppressWarnings("deprecation") + private HashMap mLegacyListenersMap = + new HashMap(); - private static IWindowManager sWindowManager; - private static int sRotation = 0; + /*-----------------------------------------------------------------------*/ - /* The thread and the sensor list are global to the process + private static final int SENSOR_DISABLE = -1; + private static boolean sSensorModuleInitialized = false; + private static ArrayList sFullSensorsList = new ArrayList(); + private static SparseArray> sSensorListByType = new SparseArray>(); + private static IWindowManager sWindowManager; + private static int sRotation = Surface.ROTATION_0; + /* The thread and the sensor list are global to the process * but the actual thread is spawned on demand */ - static final private SensorThread sSensorThread = new SensorThread(); - static final private ArrayList sListeners = + private static SensorThread sSensorThread; + + // Used within this module from outside SensorManager, don't make private + static SparseArray sHandleToSensor = new SparseArray(); + static final ArrayList sListeners = new ArrayList(); + /*-----------------------------------------------------------------------*/ static private class SensorThread { - private Thread mThread; + Thread mThread; + + SensorThread() { + // this gets to the sensor module. We can have only one per process. + sensors_data_init(); + } + + @Override + protected void finalize() { + sensors_data_uninit(); + } // must be called with sListeners lock void startLocked(ISensorService service) { try { if (mThread == null) { ParcelFileDescriptor fd = service.getDataChanel(); - mThread = new Thread(new SensorThreadRunnable(fd, service), + mThread = new Thread(new SensorThreadRunnable(fd), SensorThread.class.getName()); mThread.start(); } @@ -263,162 +291,165 @@ public class SensorManager extends IRotationWatcher.Stub } private class SensorThreadRunnable implements Runnable { - private ISensorService mSensorService; private ParcelFileDescriptor mSensorDataFd; - private final byte mAccuracies[] = new byte[32]; - SensorThreadRunnable(ParcelFileDescriptor fd, ISensorService service) { + SensorThreadRunnable(ParcelFileDescriptor fd) { mSensorDataFd = fd; - mSensorService = service; - Arrays.fill(mAccuracies, (byte)-1); } public void run() { - int sensors_of_interest; - float[] values = new float[6]; + //Log.d(TAG, "entering main sensor thread"); + final float[] values = new float[3]; + final int[] status = new int[1]; + final long timestamp[] = new long[1]; Process.setThreadPriority(Process.THREAD_PRIORITY_DISPLAY); - synchronized (sListeners) { - _sensors_data_open(mSensorDataFd.getFileDescriptor()); - try { - mSensorDataFd.close(); - } catch (IOException e) { - // *shrug* - Log.e(TAG, "IOException: ", e); - } - mSensorDataFd = null; - //mSensorDataFd. - // the first time, compute the sensors we need. this is not - // a big deal if it changes by the time we call - // _sensors_data_poll, it'll get recomputed for the next - // round. - sensors_of_interest = 0; - final int size = sListeners.size(); - for (int i=0 ; i>>SENSOR_STATUS_SHIFT; - - if ((sensors_of_interest & sensor)!=0) { - // show the notification only if someone is listening for - // this sensor - if (accuracy != mAccuracies[sensor_order]) { - try { - mSensorService.reportAccuracy(sensor, accuracy); - mAccuracies[sensor_order] = (byte)accuracy; - } catch (RemoteException e) { - Log.e(TAG, "RemoteException in reportAccuracy: ", e); - } - } else { - accuracy = -1; - } + final int sensor = sensors_data_poll(values, status, timestamp); + + if (sensor == -1) { + // we lost the connection to the event stream. this happens + // when the last listener is removed. + Log.d(TAG, "_sensors_data_poll() failed, we bail out."); + break; } - + + int accuracy = status[0]; synchronized (sListeners) { if (sListeners.isEmpty()) { // we have no more listeners, terminate the thread - _sensors_data_close(); + sensors_data_close(); mThread = null; break; } - // convert for the current screen orientation - mapSensorDataToWindow(sensor, values, SensorManager.getRotation()); - // report the sensor event to all listeners that - // care about it. - sensors_of_interest = 0; - final int size = sListeners.size(); - for (int i=0 ; i mSensorList = new ArrayList(); + private final Handler mHandler; + private SensorEvent mValuesPool; + public int mSensors; + + ListenerDelegate(SensorEventListener listener, Sensor sensor, Handler handler) { + mSensorEventListener = listener; + Looper looper = (handler != null) ? handler.getLooper() : mMainLooper; + // currently we create one Handler instance per listener, but we could + // have one per looper (we'd need to pass the ListenerDelegate + // instance to handleMessage and keep track of them separately). + mHandler = new Handler(looper) { + @Override + public void handleMessage(Message msg) { + SensorEvent t = (SensorEvent)msg.obj; + if (t.accuracy >= 0) { + mSensorEventListener.onAccuracyChanged(t.sensor, t.accuracy); + } + mSensorEventListener.onSensorChanged(t); + returnToPool(t); + } + }; + addSensor(sensor); } - int addSensors(int sensors) { - mSensors |= sensors; - return mSensors; - } - int removeSensors(int sensors) { - mSensors &= ~sensors; - return mSensors; - } - boolean hasSensor(int sensor) { - return ((mSensors & sensor) != 0); + protected SensorEvent createSensorEvent() { + // maximal size for all legacy events is 3 + return new SensorEvent(3); } - void onSensorChanged(int sensor, float[] values, int accuracy) { - float[] v; + protected SensorEvent getFromPool() { + SensorEvent t = null; synchronized (this) { // remove the array from the pool - v = mValuesPool; + t = mValuesPool; mValuesPool = null; } + if (t == null) { + // the pool was empty, we need a new one + t = createSensorEvent(); + } + return t; + } - if (v != null) { - v[0] = values[0]; - v[1] = values[1]; - v[2] = values[2]; - v[3] = values[3]; - v[4] = values[4]; - v[5] = values[5]; - } else { - // the pool was empty, we need to dup the array - v = values.clone(); + protected void returnToPool(SensorEvent t) { + synchronized (this) { + // put back the array into the pool + if (mValuesPool == null) { + mValuesPool = t; + } } + } + + Object getListener() { + return mSensorEventListener; + } + + int addSensor(Sensor sensor) { + mSensors |= 1< getSensors() { + return mSensorList; + } + void onSensorChangedLocked(Sensor sensor, float[] values, long[] timestamp, int accuracy) { + SensorEvent t = getFromPool(); + final float[] v = t.values; + v[0] = values[0]; + v[1] = values[1]; + v[2] = values[2]; + t.timestamp = timestamp[0]; + t.accuracy = accuracy; + t.sensor = sensor; Message msg = Message.obtain(); - msg.what = sensor; - msg.obj = v; - msg.arg1 = accuracy; + msg.what = 0; + msg.obj = t; mHandler.sendMessage(msg); } - - private final Handler mHandler = new Handler(mLooper) { - @Override public void handleMessage(Message msg) { - if (msg.arg1 >= 0) { - try { - mListener.onAccuracyChanged(msg.what, msg.arg1); - } catch (AbstractMethodError e) { - // old app that doesn't implement this method - // just ignore it. - } - } - mListener.onSensorChanged(msg.what, (float[])msg.obj); - synchronized (this) { - // put back the array into the pool - if (mValuesPool == null) { - mValuesPool = (float[])msg.obj; - } - } - } - }; } /** @@ -427,41 +458,157 @@ public class SensorManager extends IRotationWatcher.Stub public SensorManager(Looper mainLooper) { mSensorService = ISensorService.Stub.asInterface( ServiceManager.getService(Context.SENSOR_SERVICE)); - - sWindowManager = IWindowManager.Stub.asInterface( - ServiceManager.getService("window")); + mMainLooper = mainLooper; - if (sWindowManager != null) { - // if it's null we're running in the system process - // which won't get the rotated values - try { - sWindowManager.watchRotation(this); - } catch (RemoteException e) { + + synchronized(sListeners) { + if (!sSensorModuleInitialized) { + sSensorModuleInitialized = true; + + nativeClassInit(); + + sWindowManager = IWindowManager.Stub.asInterface( + ServiceManager.getService("window")); + if (sWindowManager != null) { + // if it's null we're running in the system process + // which won't get the rotated values + try { + sRotation = sWindowManager.watchRotation(this); + } catch (RemoteException e) { + } + } + + // initialize the sensor list + sensors_module_init(); + final ArrayList fullList = sFullSensorsList; + int i = 0; + do { + Sensor sensor = new Sensor(); + i = sensors_module_get_next_sensor(sensor, i); + + if (i>=0) { + Log.d(TAG, "found sensor: " + sensor.getName() + + ", handle=" + sensor.getHandle()); + sensor.setLegacyType(getLegacySensorType(sensor.getType())); + fullList.add(sensor); + sHandleToSensor.append(sensor.getHandle(), sensor); + } + } while (i>0); + + sSensorThread = new SensorThread(); } } + } - mLooper = mainLooper; + private int getLegacySensorType(int type) { + switch (type) { + case Sensor.TYPE_ACCELEROMETER: + return SENSOR_ACCELEROMETER; + case Sensor.TYPE_MAGNETIC_FIELD: + return SENSOR_MAGNETIC_FIELD; + case Sensor.TYPE_ORIENTATION: + return SENSOR_ORIENTATION_RAW; + case Sensor.TYPE_TEMPERATURE: + return SENSOR_TEMPERATURE; + } + return 0; } - /** @return available sensors */ + /** @return available sensors. + * @deprecated This method is deprecated, use + * {@link SensorManager#getSensorList(int)} instead + */ + @Deprecated public int getSensors() { - return _sensors_data_get_sensors(); + int result = 0; + final ArrayList fullList = sFullSensorsList; + for (Sensor i : fullList) { + switch (i.getType()) { + case Sensor.TYPE_ACCELEROMETER: + result |= SensorManager.SENSOR_ACCELEROMETER; + break; + case Sensor.TYPE_MAGNETIC_FIELD: + result |= SensorManager.SENSOR_MAGNETIC_FIELD; + break; + case Sensor.TYPE_ORIENTATION: + result |= SensorManager.SENSOR_ORIENTATION | + SensorManager.SENSOR_ORIENTATION_RAW; + break; + } + } + return result; } + /** + * Use this method to get the list of available sensors of a certain + * type. Make multiple calls to get sensors of different types or use + * {@link android.hardware.Sensor#TYPE_ALL Sensor.TYPE_ALL} to get all + * the sensors. + * + * @param type of sensors requested + * @return a list of sensors matching the asked type. + */ + public List getSensorList(int type) { + // cache the returned lists the first time + List list; + final ArrayList fullList = sFullSensorsList; + synchronized(fullList) { + list = sSensorListByType.get(type); + if (list == null) { + if (type == Sensor.TYPE_ALL) { + list = fullList; + } else { + list = new ArrayList(); + for (Sensor i : fullList) { + if (i.getType() == type) + list.add(i); + } + } + list = Collections.unmodifiableList(list); + sSensorListByType.append(type, list); + } + } + return list; + } + + /** + * Use this method to get the default sensor for a given type. Note that + * the returned sensor could be a composite sensor, and its data could be + * averaged or filtered. If you need to access the raw sensors use + * {@link SensorManager#getSensorList(int) getSensorList}. + * + * + * @param type of sensors requested + * @return the default sensors matching the asked type. + */ + public Sensor getDefaultSensor(int type) { + // TODO: need to be smarter, for now, just return the 1st sensor + List l = getSensorList(type); + return l.isEmpty() ? null : l.get(0); + } + + /** * Registers a listener for given sensors. + * @deprecated This method is deprecated, use + * {@link SensorManager#registerListener(SensorEventListener, Sensor, int)} + * instead. * * @param listener sensor listener object * @param sensors a bit masks of the sensors to register to * * @return true if the sensor is supported and successfully enabled */ + @Deprecated public boolean registerListener(SensorListener listener, int sensors) { return registerListener(listener, sensors, SENSOR_DELAY_NORMAL); } /** - * Registers a listener for given sensors. + * Registers a SensorListener for given sensors. + * @deprecated This method is deprecated, use + * {@link SensorManager#registerListener(SensorEventListener, Sensor, int)} + * instead. * * @param listener sensor listener object * @param sensors a bit masks of the sensors to register to @@ -471,9 +618,189 @@ public class SensorManager extends IRotationWatcher.Stub * * @return true if the sensor is supported and successfully enabled */ + @Deprecated public boolean registerListener(SensorListener listener, int sensors, int rate) { - boolean result; + boolean result = false; + result = registerLegacyListener(SENSOR_ACCELEROMETER, Sensor.TYPE_ACCELEROMETER, + listener, sensors, rate) || result; + result = registerLegacyListener(SENSOR_MAGNETIC_FIELD, Sensor.TYPE_MAGNETIC_FIELD, + listener, sensors, rate) || result; + result = registerLegacyListener(SENSOR_ORIENTATION_RAW, Sensor.TYPE_ORIENTATION, + listener, sensors, rate) || result; + result = registerLegacyListener(SENSOR_ORIENTATION, Sensor.TYPE_ORIENTATION, + listener, sensors, rate) || result; + result = registerLegacyListener(SENSOR_TEMPERATURE, Sensor.TYPE_TEMPERATURE, + listener, sensors, rate) || result; + return result; + } + @SuppressWarnings("deprecation") + private boolean registerLegacyListener(int legacyType, int type, + SensorListener listener, int sensors, int rate) + { + boolean result = false; + // Are we activating this legacy sensor? + if ((sensors & legacyType) != 0) { + // if so, find a suitable Sensor + Sensor sensor = getDefaultSensor(type); + if (sensor != null) { + // If we don't already have one, create a LegacyListener + // to wrap this listener and process the events as + // they are expected by legacy apps. + LegacyListener legacyListener = null; + synchronized (mLegacyListenersMap) { + legacyListener = mLegacyListenersMap.get(listener); + if (legacyListener == null) { + // we didn't find a LegacyListener for this client, + // create one, and put it in our list. + legacyListener = new LegacyListener(listener); + mLegacyListenersMap.put(listener, legacyListener); + } + } + // register this legacy sensor with this legacy listener + legacyListener.registerSensor(legacyType); + // and finally, register the legacy listener with the new apis + result = registerListener(legacyListener, sensor, rate); + } + } + return result; + } + + /** + * Unregisters a listener for the sensors with which it is registered. + * @deprecated This method is deprecated, use + * {@link SensorManager#unregisterListener(SensorEventListener, Sensor)} + * instead. + * + * @param listener a SensorListener object + * @param sensors a bit masks of the sensors to unregister from + */ + @Deprecated + public void unregisterListener(SensorListener listener, int sensors) { + unregisterLegacyListener(SENSOR_ACCELEROMETER, Sensor.TYPE_ACCELEROMETER, + listener, sensors); + unregisterLegacyListener(SENSOR_MAGNETIC_FIELD, Sensor.TYPE_MAGNETIC_FIELD, + listener, sensors); + unregisterLegacyListener(SENSOR_ORIENTATION_RAW, Sensor.TYPE_ORIENTATION, + listener, sensors); + unregisterLegacyListener(SENSOR_ORIENTATION, Sensor.TYPE_ORIENTATION, + listener, sensors); + unregisterLegacyListener(SENSOR_TEMPERATURE, Sensor.TYPE_TEMPERATURE, + listener, sensors); + } + + @SuppressWarnings("deprecation") + private void unregisterLegacyListener(int legacyType, int type, + SensorListener listener, int sensors) + { + // do we know about this listener? + LegacyListener legacyListener = null; + synchronized (mLegacyListenersMap) { + legacyListener = mLegacyListenersMap.get(listener); + } + if (legacyListener != null) { + // Are we deactivating this legacy sensor? + if ((sensors & legacyType) != 0) { + // if so, find the corresponding Sensor + Sensor sensor = getDefaultSensor(type); + if (sensor != null) { + // unregister this legacy sensor and if we don't + // need the corresponding Sensor, unregister it too + if (legacyListener.unregisterSensor(legacyType)) { + // corresponding sensor not needed, unregister + unregisterListener(legacyListener, sensor); + // finally check if we still need the legacyListener + // in our mapping, if not, get rid of it too. + synchronized(sListeners) { + boolean found = false; + for (ListenerDelegate i : sListeners) { + if (i.getListener() == legacyListener) { + found = true; + break; + } + } + if (!found) { + synchronized (mLegacyListenersMap) { + mLegacyListenersMap.remove(listener); + } + } + } + } + } + } + } + } + + /** + * Unregisters a listener for all sensors. + * @deprecated This method is deprecated, use + * {@link SensorManager#unregisterListener(SensorEventListener)} + * instead. + * + * @param listener a SensorListener object + */ + @Deprecated + public void unregisterListener(SensorListener listener) { + unregisterListener(listener, SENSOR_ALL); + } + + /** + * Unregisters a listener for the sensors with which it is registered. + * + * @param listener a SensorEventListener object + * @param sensor the sensor to unregister from + * + */ + public void unregisterListener(SensorEventListener listener, Sensor sensor) { + unregisterListener((Object)listener, sensor); + } + + /** + * Unregisters a listener for all sensors. + * + * @param listener a SensorListener object + * + */ + public void unregisterListener(SensorEventListener listener) { + unregisterListener((Object)listener); + } + + + /** + * Registers a {@link android.hardware.SensorEventListener SensorEventListener} + * for the given sensor. + * + * @param listener A {@link android.hardware.SensorEventListener SensorEventListener} object. + * @param sensor The {@link android.hardware.Sensor Sensor} to register to. + * @param rate The rate {@link android.hardware.SensorEvent sensor events} are delivered at. + * This is only a hint to the system. Events may be received faster or + * slower than the specified rate. Usually events are received faster. + * + * @return true if the sensor is supported and successfully enabled. + * + */ + public boolean registerListener(SensorEventListener listener, Sensor sensor, int rate) { + return registerListener(listener, sensor, rate, null); + } + + /** + * Registers a {@link android.hardware.SensorEventListener SensorEventListener} + * for the given sensor. + * + * @param listener A {@link android.hardware.SensorEventListener SensorEventListener} object. + * @param sensor The {@link android.hardware.Sensor Sensor} to register to. + * @param rate The rate {@link android.hardware.SensorEvent sensor events} are delivered at. + * This is only a hint to the system. Events may be received faster or + * slower than the specified rate. Usually events are received faster. + * @param handler The {@link android.os.Handler Handler} the + * {@link android.hardware.SensorEvent sensor events} will be delivered to. + * + * @return true if the sensor is supported and successfully enabled. + * + */ + public boolean registerListener(SensorEventListener listener, Sensor sensor, int rate, + Handler handler) { + boolean result; int delay = -1; switch (rate) { case SENSOR_DELAY_FASTEST: @@ -496,15 +823,15 @@ public class SensorManager extends IRotationWatcher.Stub synchronized (sListeners) { ListenerDelegate l = null; for (ListenerDelegate i : sListeners) { - if (i.mListener == listener) { + if (i.getListener() == listener) { l = i; break; } } if (l == null) { - l = new ListenerDelegate(listener, sensors); - result = mSensorService.enableSensor(l, sensors, delay); + l = new ListenerDelegate(listener, sensor, handler); + result = mSensorService.enableSensor(l, sensor.getHandle(), delay); if (result) { sListeners.add(l); sListeners.notify(); @@ -513,9 +840,9 @@ public class SensorManager extends IRotationWatcher.Stub sSensorThread.startLocked(mSensorService); } } else { - result = mSensorService.enableSensor(l, sensors, delay); + result = mSensorService.enableSensor(l, sensor.getHandle(), delay); if (result) { - l.addSensors(sensors); + l.addSensor(sensor); } } } @@ -526,25 +853,42 @@ public class SensorManager extends IRotationWatcher.Stub return result; } - /** - * Unregisters a listener for the sensors with which it is registered. - * - * @param listener a SensorListener object - * @param sensors a bit masks of the sensors to unregister from - */ - public void unregisterListener(SensorListener listener, int sensors) { + private void unregisterListener(Object listener, Sensor sensor) { try { synchronized (sListeners) { final int size = sListeners.size(); for (int i=0 ; iI as well as the rotation + * matrix R transforming a vector from the + * device coordinate system to the world's coordinate system which is + * defined as a direct orthonormal basis, where: + * + *

  • X is defined as the vector product Y.Z (It is tangential to + * the ground at the device's current location and roughly points East).
  • + *
  • Y is tangential to the ground at the device's current location and + * points towards the magnetic North Pole.
  • + *
  • Z points towards the sky and is perpendicular to the ground.
  • + *

    + *


    + *

    By definition: + *

    [0 0 g] = R * gravity (g = magnitude of gravity) + *

    [0 m 0] = I * R * geomagnetic + * (m = magnitude of geomagnetic field) + *

    R is the identity matrix when the device is aligned with the + * world's coordinate system, that is, when the device's X axis points + * toward East, the Y axis points to the North Pole and the device is facing + * the sky. * - * @param listener a SensorListener object + *

    I is a rotation matrix transforming the geomagnetic + * vector into the same coordinate space as gravity (the world's coordinate + * space). I is a simple rotation around the X axis. + * The inclination angle in radians can be computed with + * {@link #getInclination}. + *


    + * + *

    Each matrix is returned either as a 3x3 or 4x4 row-major matrix + * depending on the length of the passed array: + *

    If the array length is 16: + *

    +     *   /  M[ 0]   M[ 1]   M[ 2]   M[ 3]  \
    +     *   |  M[ 4]   M[ 5]   M[ 6]   M[ 7]  |
    +     *   |  M[ 8]   M[ 9]   M[10]   M[11]  |
    +     *   \  M[12]   M[13]   M[14]   M[15]  /
    +     *
    + * This matrix is ready to be used by OpenGL ES's + * {@link javax.microedition.khronos.opengles.GL10#glLoadMatrixf(float[], int) + * glLoadMatrixf(float[], int)}. + *

    Note that because OpenGL matrices are column-major matrices you must + * transpose the matrix before using it. However, since the matrix is a + * rotation matrix, its transpose is also its inverse, conveniently, it is + * often the inverse of the rotation that is needed for rendering; it can + * therefore be used with OpenGL ES directly. + *

    + * Also note that the returned matrices always have this form: + *

    +     *   /  M[ 0]   M[ 1]   M[ 2]   0  \
    +     *   |  M[ 4]   M[ 5]   M[ 6]   0  |
    +     *   |  M[ 8]   M[ 9]   M[10]   0  |
    +     *   \      0       0       0   1  /
    +     *
    + *

    If the array length is 9: + *

    +     *   /  M[ 0]   M[ 1]   M[ 2]  \
    +     *   |  M[ 3]   M[ 4]   M[ 5]  |
    +     *   \  M[ 6]   M[ 7]   M[ 8]  /
    +     *
    + * + *
    + *

    The inverse of each matrix can be computed easily by taking its + * transpose. + * + *

    The matrices returned by this function are meaningful only when the + * device is not free-falling and it is not close to the magnetic north. + * If the device is accelerating, or placed into a strong magnetic field, + * the returned matrices may be inaccurate. + * + * @param R is an array of 9 floats holding the rotation matrix R + * when this function returns. R can be null.

    + * @param I is an array of 9 floats holding the rotation matrix I + * when this function returns. I can be null.

    + * @param gravity is an array of 3 floats containing the gravity vector + * expressed in the device's coordinate. You can simply use the + * {@link android.hardware.SensorEvent#values values} + * returned by a {@link android.hardware.SensorEvent SensorEvent} of a + * {@link android.hardware.Sensor Sensor} of type + * {@link android.hardware.Sensor#TYPE_ACCELEROMETER TYPE_ACCELEROMETER}.

    + * @param geomagnetic is an array of 3 floats containing the geomagnetic + * vector expressed in the device's coordinate. You can simply use the + * {@link android.hardware.SensorEvent#values values} + * returned by a {@link android.hardware.SensorEvent SensorEvent} of a + * {@link android.hardware.Sensor Sensor} of type + * {@link android.hardware.Sensor#TYPE_MAGNETIC_FIELD TYPE_MAGNETIC_FIELD}. + * @return + * true on success

    + * false on failure (for instance, if the device is in free fall). + * On failure the output matrices are not modified. */ - public void unregisterListener(SensorListener listener) { - unregisterListener(listener, SENSOR_ALL); + + public static boolean getRotationMatrix(float[] R, float[] I, + float[] gravity, float[] geomagnetic) { + // TODO: move this to native code for efficiency + float Ax = gravity[0]; + float Ay = gravity[1]; + float Az = gravity[2]; + final float Ex = geomagnetic[0]; + final float Ey = geomagnetic[1]; + final float Ez = geomagnetic[2]; + float Hx = Ey*Az - Ez*Ay; + float Hy = Ez*Ax - Ex*Az; + float Hz = Ex*Ay - Ey*Ax; + final float normH = (float)Math.sqrt(Hx*Hx + Hy*Hy + Hz*Hz); + if (normH < 0.1f) { + // device is close to free fall (or in space?), or close to + // magnetic north pole. Typical values are > 100. + return false; + } + final float invH = 1.0f / normH; + Hx *= invH; + Hy *= invH; + Hz *= invH; + final float invA = 1.0f / (float)Math.sqrt(Ax*Ax + Ay*Ay + Az*Az); + Ax *= invA; + Ay *= invA; + Az *= invA; + final float Mx = Ay*Hz - Az*Hy; + final float My = Az*Hx - Ax*Hz; + final float Mz = Ax*Hy - Ay*Hx; + if (R != null) { + if (R.length == 9) { + R[0] = Hx; R[1] = Hy; R[2] = Hz; + R[3] = Mx; R[4] = My; R[5] = Mz; + R[6] = Ax; R[7] = Ay; R[8] = Az; + } else if (R.length == 16) { + R[0] = Hx; R[1] = Hy; R[2] = Hz; R[3] = 0; + R[4] = Mx; R[5] = My; R[6] = Mz; R[7] = 0; + R[8] = Ax; R[9] = Ay; R[10] = Az; R[11] = 0; + R[12] = 0; R[13] = 0; R[14] = 0; R[15] = 1; + } + } + if (I != null) { + // compute the inclination matrix by projecting the geomagnetic + // vector onto the Z (gravity) and X (horizontal component + // of geomagnetic vector) axes. + final float invE = 1.0f / (float)Math.sqrt(Ex*Ex + Ey*Ey + Ez*Ez); + final float c = (Ex*Mx + Ey*My + Ez*Mz) * invE; + final float s = (Ex*Ax + Ey*Ay + Ez*Az) * invE; + if (I.length == 9) { + I[0] = 1; I[1] = 0; I[2] = 0; + I[3] = 0; I[4] = c; I[5] = s; + I[6] = 0; I[7] =-s; I[8] = c; + } else if (I.length == 16) { + I[0] = 1; I[1] = 0; I[2] = 0; + I[4] = 0; I[5] = c; I[6] = s; + I[8] = 0; I[9] =-s; I[10]= c; + I[3] = I[7] = I[11] = I[12] = I[13] = I[14] = 0; + I[15] = 1; + } + } + return true; } + /** + * Computes the geomagnetic inclination angle in radians from the + * inclination matrix I returned by {@link #getRotationMatrix}. + * @param I inclination matrix see {@link #getRotationMatrix}. + * @return The geomagnetic inclination angle in radians. + */ + public static float getInclination(float[] I) { + if (I.length == 9) { + return (float)Math.atan2(I[5], I[4]); + } else { + return (float)Math.atan2(I[6], I[5]); + } + } /** - * Helper function to convert the specified sensor's data to the windows's - * coordinate space from the device's coordinate space. - */ - - private static void mapSensorDataToWindow(int sensor, float[] values, int orientation) { - final float x = values[DATA_X]; - final float y = values[DATA_Y]; - final float z = values[DATA_Z]; - // copy the raw raw values... - values[RAW_DATA_X] = x; - values[RAW_DATA_Y] = y; - values[RAW_DATA_Z] = z; - // TODO: add support for 180 and 270 orientations - if (orientation == Surface.ROTATION_90) { - switch (sensor) { - case SENSOR_ACCELEROMETER: - case SENSOR_MAGNETIC_FIELD: - values[DATA_X] =-y; - values[DATA_Y] = x; - values[DATA_Z] = z; - break; - case SENSOR_ORIENTATION: - case SENSOR_ORIENTATION_RAW: - values[DATA_X] = x + ((x < 270) ? 90 : -270); - values[DATA_Y] = z; - values[DATA_Z] = y; - break; + * Rotates the supplied rotation matrix so it is expressed in a + * different coordinate system. This is typically used when an application + * needs to compute the three orientation angles of the device (see + * {@link #getOrientation}) in a different coordinate system. + * + *

    When the rotation matrix is used for drawing (for instance with + * OpenGL ES), it usually doesn't need to be transformed by this + * function, unless the screen is physically rotated, such as when used + * in landscape mode. + * + *

    Examples:

    + * + *

  • Using the camera (Y axis along the camera's axis) for an augmented + * reality application where the rotation angles are needed :
  • + * + * remapCoordinateSystem(inR, AXIS_X, AXIS_Z, outR);

    + * + *

  • Using the device as a mechanical compass in landscape mode:
  • + * + * remapCoordinateSystem(inR, AXIS_Y, AXIS_MINUS_X, outR);

    + * + * Beware of the above example. This call is needed only if the device is + * physically used in landscape mode to calculate the rotation angles (see + * {@link #getOrientation}). + * If the rotation matrix is also used for rendering, it may not need to + * be transformed, for instance if your {@link android.app.Activity + * Activity} is running in landscape mode. + * + *

    Since the resulting coordinate system is orthonormal, only two axes + * need to be specified. + * + * @param inR the rotation matrix to be transformed. Usually it is the + * matrix returned by {@link #getRotationMatrix}. + * @param X defines on which world axis and direction the X axis of the + * device is mapped. + * @param Y defines on which world axis and direction the Y axis of the + * device is mapped. + * @param outR the transformed rotation matrix. inR and outR can be the same + * array, but it is not recommended for performance reason. + * @return true on success. false if the input parameters are incorrect, for + * instance if X and Y define the same axis. Or if inR and outR don't have + * the same length. + */ + + public static boolean remapCoordinateSystem(float[] inR, int X, int Y, + float[] outR) + { + if (inR == outR) { + final float[] temp = mTempMatrix; + synchronized(temp) { + // we don't expect to have a lot of contention + if (remapCoordinateSystemImpl(inR, X, Y, temp)) { + final int size = outR.length; + for (int i=0 ; i=0x80); + final boolean sy = (Y>=0x80); + final boolean sz = (Z>=0x80); + + // Perform R * r, in avoiding actual muls and adds. + final int rowLength = ((length==16)?4:3); + for (int j=0 ; j<3 ; j++) { + final int offset = j*rowLength; + for (int i=0 ; i<3 ; i++) { + if (x==i) outR[offset+i] = sx ? -inR[offset+0] : inR[offset+0]; + if (y==i) outR[offset+i] = sy ? -inR[offset+1] : inR[offset+1]; + if (z==i) outR[offset+i] = sz ? -inR[offset+2] : inR[offset+2]; + } + } + if (length == 16) { + outR[3] = outR[7] = outR[11] = outR[12] = outR[13] = outR[14] = 0; + outR[15] = 1; + } + return true; + } - private static native int _sensors_data_open(FileDescriptor fd); - private static native int _sensors_data_close(); - // returns the sensor's status in the top 4 bits of "res". - private static native int _sensors_data_poll(float[] values, int sensors); - private static native int _sensors_data_get_sensors(); + /** + * Computes the device's orientation based on the rotation matrix. + *

    When it returns, the array values is filled with the result: + *

  • values[0]: azimuth, rotation around the Z axis.
  • + *
  • values[1]: pitch, rotation around the X axis.
  • + *
  • values[2]: roll, rotation around the Y axis.
  • + *

    + * + * @param R rotation matrix see {@link #getRotationMatrix}. + * @param values an array of 3 floats to hold the result. + * @return The array values passed as argument. + */ + public static float[] getOrientation(float[] R, float values[]) { + /* + * 4x4 (length=16) case: + * / R[ 0] R[ 1] R[ 2] 0 \ + * | R[ 4] R[ 5] R[ 6] 0 | + * | R[ 8] R[ 9] R[10] 0 | + * \ 0 0 0 1 / + * + * 3x3 (length=9) case: + * / R[ 0] R[ 1] R[ 2] \ + * | R[ 3] R[ 4] R[ 5] | + * \ R[ 6] R[ 7] R[ 8] / + * + */ + if (R.length == 9) { + values[0] = (float)Math.atan2(R[1], R[4]); + values[1] = (float)Math.asin(-R[7]); + values[2] = (float)Math.atan2(-R[6], R[8]); + } else { + values[0] = (float)Math.atan2(R[1], R[5]); + values[1] = (float)Math.asin(-R[9]); + values[2] = (float)Math.atan2(-R[8], R[10]); + } + return values; + } - /** {@hide} */ + + /** + * {@hide} + */ public void onRotationChanged(int rotation) { synchronized(sListeners) { sRotation = rotation; } } - - private static int getRotation() { + + static int getRotation() { synchronized(sListeners) { return sRotation; } } -} + private class LegacyListener implements SensorEventListener { + private float mValues[] = new float[6]; + @SuppressWarnings("deprecation") + private SensorListener mTarget; + private int mSensors; + private final LmsFilter mYawfilter = new LmsFilter(); + + @SuppressWarnings("deprecation") + LegacyListener(SensorListener target) { + mTarget = target; + mSensors = 0; + } + + void registerSensor(int legacyType) { + mSensors |= legacyType; + } + + boolean unregisterSensor(int legacyType) { + mSensors &= ~legacyType; + int mask = SENSOR_ORIENTATION|SENSOR_ORIENTATION_RAW; + if (((legacyType&mask)!=0) && ((mSensors&mask)!=0)) { + return false; + } + return true; + } + + @SuppressWarnings("deprecation") + public void onAccuracyChanged(Sensor sensor, int accuracy) { + try { + mTarget.onAccuracyChanged(sensor.getLegacyType(), accuracy); + } catch (AbstractMethodError e) { + // old app that doesn't implement this method + // just ignore it. + } + } + + @SuppressWarnings("deprecation") + public void onSensorChanged(SensorEvent event) { + final float v[] = mValues; + v[0] = event.values[0]; + v[1] = event.values[1]; + v[2] = event.values[2]; + int legacyType = event.sensor.getLegacyType(); + mapSensorDataToWindow(legacyType, v, SensorManager.getRotation()); + if (event.sensor.getType() == Sensor.TYPE_ORIENTATION) { + if ((mSensors & SENSOR_ORIENTATION_RAW)!=0) { + mTarget.onSensorChanged(SENSOR_ORIENTATION_RAW, v); + } + if ((mSensors & SENSOR_ORIENTATION)!=0) { + v[0] = mYawfilter.filter(event.timestamp, v[0]); + mTarget.onSensorChanged(SENSOR_ORIENTATION, v); + } + } else { + mTarget.onSensorChanged(legacyType, v); + } + } + + /* + * Helper function to convert the specified sensor's data to the windows's + * coordinate space from the device's coordinate space. + * + * output: 3,4,5: values in the old API format + * 0,1,2: transformed values in the old API format + * + */ + private void mapSensorDataToWindow(int sensor, + float[] values, int orientation) { + float x = values[0]; + float y = values[1]; + float z = values[2]; + + switch (sensor) { + case SensorManager.SENSOR_ORIENTATION: + case SensorManager.SENSOR_ORIENTATION_RAW: + z = -z; + break; + case SensorManager.SENSOR_ACCELEROMETER: + x = -x; + y = -y; + z = -z; + break; + case SensorManager.SENSOR_MAGNETIC_FIELD: + x = -x; + y = -y; + break; + } + values[0] = x; + values[1] = y; + values[2] = z; + values[3] = x; + values[4] = y; + values[5] = z; + // TODO: add support for 180 and 270 orientations + if (orientation == Surface.ROTATION_90) { + switch (sensor) { + case SENSOR_ACCELEROMETER: + case SENSOR_MAGNETIC_FIELD: + values[0] =-y; + values[1] = x; + values[2] = z; + break; + case SENSOR_ORIENTATION: + case SENSOR_ORIENTATION_RAW: + values[0] = x + ((x < 270) ? 90 : -270); + values[1] = z; + values[2] = y; + break; + } + } + } + } + + class LmsFilter { + private static final int SENSORS_RATE_MS = 20; + private static final int COUNT = 12; + private static final float PREDICTION_RATIO = 1.0f/3.0f; + private static final float PREDICTION_TIME = (SENSORS_RATE_MS*COUNT/1000.0f)*PREDICTION_RATIO; + private float mV[] = new float[COUNT*2]; + private float mT[] = new float[COUNT*2]; + private int mIndex; + + public LmsFilter() { + mIndex = COUNT; + } + + public float filter(long time, float in) { + float v = in; + final float ns = 1.0f / 1000000000.0f; + final float t = time*ns; + float v1 = mV[mIndex]; + if ((v-v1) > 180) { + v -= 360; + } else if ((v1-v) > 180) { + v += 360; + } + /* Manage the circular buffer, we write the data twice spaced + * by COUNT values, so that we don't have to copy the array + * when it's full + */ + mIndex++; + if (mIndex >= COUNT*2) + mIndex = COUNT; + mV[mIndex] = v; + mT[mIndex] = t; + mV[mIndex-COUNT] = v; + mT[mIndex-COUNT] = t; + + float A, B, C, D, E; + float a, b; + int i; + + A = B = C = D = E = 0; + for (i=0 ; i=0)?f:-f) >= 0.5f) + f = f - (float)Math.ceil(f + 0.5f) + 1.0f; + if (f < 0) + f += 1.0f; + f *= 360.0f; + return f; + } + } + + + private static native void nativeClassInit(); + + private static native int sensors_module_init(); + private static native int sensors_module_get_next_sensor(Sensor sensor, int next); + + // Used within this module from outside SensorManager, don't make private + static native int sensors_data_init(); + static native int sensors_data_uninit(); + static native int sensors_data_open(FileDescriptor fd); + static native int sensors_data_close(); + static native int sensors_data_poll(float[] values, int[] status, long[] timestamp); +} diff --git a/core/java/android/inputmethodservice/AbstractInputMethodService.java b/core/java/android/inputmethodservice/AbstractInputMethodService.java new file mode 100644 index 0000000000000000000000000000000000000000..7d02f6588db4cdf9e0351315bc4e3edea0eaefc7 --- /dev/null +++ b/core/java/android/inputmethodservice/AbstractInputMethodService.java @@ -0,0 +1,170 @@ +/* + * Copyright (C) 2007-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 android.inputmethodservice; + +import android.app.Service; +import android.content.Intent; +import android.os.IBinder; +import android.view.KeyEvent; +import android.view.MotionEvent; +import android.view.inputmethod.InputMethod; +import android.view.inputmethod.InputMethodSession; + +/** + * AbstractInputMethodService provides a abstract base class for input methods. + * Normal input method implementations will not derive from this directly, + * instead building on top of {@link InputMethodService} or another more + * complete base class. Be sure to read {@link InputMethod} for more + * information on the basics of writing input methods. + * + *

    This class combines a Service (representing the input method component + * to the system with the InputMethod interface that input methods must + * implement. This base class takes care of reporting your InputMethod from + * the service when clients bind to it, but provides no standard implementation + * of the InputMethod interface itself. Derived classes must implement that + * interface. + */ +public abstract class AbstractInputMethodService extends Service + implements KeyEvent.Callback { + private InputMethod mInputMethod; + + /** + * Base class for derived classes to implement their {@link InputMethod} + * interface. This takes care of basic maintenance of the input method, + * but most behavior must be implemented in a derived class. + */ + public abstract class AbstractInputMethodImpl implements InputMethod { + /** + * Instantiate a new client session for the input method, by calling + * back to {@link AbstractInputMethodService#onCreateInputMethodSessionInterface() + * AbstractInputMethodService.onCreateInputMethodSessionInterface()}. + */ + public void createSession(SessionCallback callback) { + callback.sessionCreated(onCreateInputMethodSessionInterface()); + } + + /** + * Take care of enabling or disabling an existing session by calling its + * {@link AbstractInputMethodSessionImpl#revokeSelf() + * AbstractInputMethodSessionImpl.setEnabled()} method. + */ + public void setSessionEnabled(InputMethodSession session, boolean enabled) { + ((AbstractInputMethodSessionImpl)session).setEnabled(enabled); + } + + /** + * Take care of killing an existing session by calling its + * {@link AbstractInputMethodSessionImpl#revokeSelf() + * AbstractInputMethodSessionImpl.revokeSelf()} method. + */ + public void revokeSession(InputMethodSession session) { + ((AbstractInputMethodSessionImpl)session).revokeSelf(); + } + } + + /** + * Base class for derived classes to implement their {@link InputMethodSession} + * interface. This takes care of basic maintenance of the session, + * but most behavior must be implemented in a derived class. + */ + public abstract class AbstractInputMethodSessionImpl implements InputMethodSession { + boolean mEnabled = true; + boolean mRevoked; + + /** + * Check whether this session has been enabled by the system. If not + * enabled, you should not execute any calls on to it. + */ + public boolean isEnabled() { + return mEnabled; + } + + /** + * Check whether this session has been revoked by the system. Revoked + * session is also always disabled, so there is generally no need to + * explicitly check for this. + */ + public boolean isRevoked() { + return mRevoked; + } + + /** + * Change the enabled state of the session. This only works if the + * session has not been revoked. + */ + public void setEnabled(boolean enabled) { + if (!mRevoked) { + mEnabled = enabled; + } + } + + /** + * Revoke the session from the client. This disabled the session, and + * prevents it from ever being enabled again. + */ + public void revokeSelf() { + mRevoked = true; + mEnabled = false; + } + + /** + * Take care of dispatching incoming key events to the appropriate + * callbacks on the service, and tell the client when this is done. + */ + public void dispatchKeyEvent(int seq, KeyEvent event, EventCallback callback) { + boolean handled = event.dispatch(AbstractInputMethodService.this); + if (callback != null) { + callback.finishedEvent(seq, handled); + } + } + + /** + * Take care of dispatching incoming trackball events to the appropriate + * callbacks on the service, and tell the client when this is done. + */ + public void dispatchTrackballEvent(int seq, MotionEvent event, EventCallback callback) { + boolean handled = onTrackballEvent(event); + if (callback != null) { + callback.finishedEvent(seq, handled); + } + } + } + + /** + * Called by the framework during initialization, when the InputMethod + * interface for this service needs to be created. + */ + public abstract AbstractInputMethodImpl onCreateInputMethodInterface(); + + /** + * Called by the framework when a new InputMethodSession interface is + * needed for a new client of the input method. + */ + public abstract AbstractInputMethodSessionImpl onCreateInputMethodSessionInterface(); + + @Override + final public IBinder onBind(Intent intent) { + if (mInputMethod == null) { + mInputMethod = onCreateInputMethodInterface(); + } + return new IInputMethodWrapper(this, mInputMethod); + } + + public boolean onTrackballEvent(MotionEvent event) { + return false; + } +} diff --git a/core/java/android/inputmethodservice/ExtractEditText.java b/core/java/android/inputmethodservice/ExtractEditText.java new file mode 100644 index 0000000000000000000000000000000000000000..e59f38b368db04843ea52868959886b6fb206fa3 --- /dev/null +++ b/core/java/android/inputmethodservice/ExtractEditText.java @@ -0,0 +1,23 @@ +package android.inputmethodservice; + +import android.content.Context; +import android.util.AttributeSet; +import android.widget.EditText; + +/*** + * Specialization of {@link EditText} for showing and interacting with the + * extracted text in a full-screen input method. + */ +public class ExtractEditText extends EditText { + public ExtractEditText(Context context) { + super(context, null); + } + + public ExtractEditText(Context context, AttributeSet attrs) { + super(context, attrs, com.android.internal.R.attr.editTextStyle); + } + + public ExtractEditText(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + } +} diff --git a/core/java/android/inputmethodservice/IInputMethodSessionWrapper.java b/core/java/android/inputmethodservice/IInputMethodSessionWrapper.java new file mode 100644 index 0000000000000000000000000000000000000000..40c03cd898f065f6f9a684e615254b3bb1013748 --- /dev/null +++ b/core/java/android/inputmethodservice/IInputMethodSessionWrapper.java @@ -0,0 +1,151 @@ +package android.inputmethodservice; + +import com.android.internal.os.HandlerCaller; +import com.android.internal.view.IInputMethodCallback; +import com.android.internal.view.IInputMethodSession; + +import android.content.Context; +import android.graphics.Rect; +import android.os.Bundle; +import android.os.Message; +import android.os.RemoteException; +import android.util.Log; +import android.view.KeyEvent; +import android.view.MotionEvent; +import android.view.inputmethod.CompletionInfo; +import android.view.inputmethod.ExtractedText; +import android.view.inputmethod.InputMethodSession; +import android.view.inputmethod.EditorInfo; + +class IInputMethodSessionWrapper extends IInputMethodSession.Stub + implements HandlerCaller.Callback { + private static final String TAG = "InputMethodWrapper"; + private static final boolean DEBUG = false; + + private static final int DO_FINISH_INPUT = 60; + private static final int DO_DISPLAY_COMPLETIONS = 65; + private static final int DO_UPDATE_EXTRACTED_TEXT = 67; + private static final int DO_DISPATCH_KEY_EVENT = 70; + private static final int DO_DISPATCH_TRACKBALL_EVENT = 80; + private static final int DO_UPDATE_SELECTION = 90; + private static final int DO_UPDATE_CURSOR = 95; + private static final int DO_APP_PRIVATE_COMMAND = 100; + + final HandlerCaller mCaller; + final InputMethodSession mInputMethodSession; + + // NOTE: we should have a cache of these. + static class InputMethodEventCallbackWrapper implements InputMethodSession.EventCallback { + final IInputMethodCallback mCb; + InputMethodEventCallbackWrapper(IInputMethodCallback cb) { + mCb = cb; + } + public void finishedEvent(int seq, boolean handled) { + try { + mCb.finishedEvent(seq, handled); + } catch (RemoteException e) { + } + } + } + + public IInputMethodSessionWrapper(Context context, + InputMethodSession inputMethodSession) { + mCaller = new HandlerCaller(context, this); + mInputMethodSession = inputMethodSession; + } + + public InputMethodSession getInternalInputMethodSession() { + return mInputMethodSession; + } + + public void executeMessage(Message msg) { + switch (msg.what) { + case DO_FINISH_INPUT: + mInputMethodSession.finishInput(); + return; + case DO_DISPLAY_COMPLETIONS: + mInputMethodSession.displayCompletions((CompletionInfo[])msg.obj); + return; + case DO_UPDATE_EXTRACTED_TEXT: + mInputMethodSession.updateExtractedText(msg.arg1, + (ExtractedText)msg.obj); + return; + case DO_DISPATCH_KEY_EVENT: { + HandlerCaller.SomeArgs args = (HandlerCaller.SomeArgs)msg.obj; + mInputMethodSession.dispatchKeyEvent(msg.arg1, + (KeyEvent)args.arg1, + new InputMethodEventCallbackWrapper( + (IInputMethodCallback)args.arg2)); + mCaller.recycleArgs(args); + return; + } + case DO_DISPATCH_TRACKBALL_EVENT: { + HandlerCaller.SomeArgs args = (HandlerCaller.SomeArgs)msg.obj; + mInputMethodSession.dispatchTrackballEvent(msg.arg1, + (MotionEvent)args.arg1, + new InputMethodEventCallbackWrapper( + (IInputMethodCallback)args.arg2)); + mCaller.recycleArgs(args); + return; + } + case DO_UPDATE_SELECTION: { + HandlerCaller.SomeArgs args = (HandlerCaller.SomeArgs)msg.obj; + mInputMethodSession.updateSelection(args.argi1, args.argi2, + args.argi3, args.argi4); + mCaller.recycleArgs(args); + return; + } + case DO_UPDATE_CURSOR: { + mInputMethodSession.updateCursor((Rect)msg.obj); + return; + } + case DO_APP_PRIVATE_COMMAND: { + HandlerCaller.SomeArgs args = (HandlerCaller.SomeArgs)msg.obj; + mInputMethodSession.appPrivateCommand((String)args.arg1, + (Bundle)args.arg2); + mCaller.recycleArgs(args); + return; + } + } + Log.w(TAG, "Unhandled message code: " + msg.what); + } + + public void finishInput() { + mCaller.executeOrSendMessage(mCaller.obtainMessage(DO_FINISH_INPUT)); + } + + public void displayCompletions(CompletionInfo[] completions) { + mCaller.executeOrSendMessage(mCaller.obtainMessageO( + DO_DISPLAY_COMPLETIONS, completions)); + } + + public void updateExtractedText(int token, ExtractedText text) { + mCaller.executeOrSendMessage(mCaller.obtainMessageIO( + DO_UPDATE_EXTRACTED_TEXT, token, text)); + } + + public void dispatchKeyEvent(int seq, KeyEvent event, IInputMethodCallback callback) { + mCaller.executeOrSendMessage(mCaller.obtainMessageIOO(DO_DISPATCH_KEY_EVENT, seq, + event, callback)); + } + + public void dispatchTrackballEvent(int seq, MotionEvent event, IInputMethodCallback callback) { + mCaller.executeOrSendMessage(mCaller.obtainMessageIOO(DO_DISPATCH_TRACKBALL_EVENT, seq, + event, callback)); + } + + public void updateSelection(int oldSelStart, int oldSelEnd, + int newSelStart, int newSelEnd) { + mCaller.executeOrSendMessage(mCaller.obtainMessageIIII(DO_UPDATE_SELECTION, + oldSelStart, oldSelEnd, newSelStart, newSelEnd)); + } + + public void updateCursor(Rect newCursor) { + mCaller.executeOrSendMessage(mCaller.obtainMessageO(DO_UPDATE_CURSOR, + newCursor)); + } + + public void appPrivateCommand(String action, Bundle data) { + mCaller.executeOrSendMessage(mCaller.obtainMessageOO(DO_APP_PRIVATE_COMMAND, action, data)); + } +} diff --git a/core/java/android/inputmethodservice/IInputMethodWrapper.java b/core/java/android/inputmethodservice/IInputMethodWrapper.java new file mode 100644 index 0000000000000000000000000000000000000000..4108bdd654d21d48eafe1382d188e7a9ef8a9aec --- /dev/null +++ b/core/java/android/inputmethodservice/IInputMethodWrapper.java @@ -0,0 +1,172 @@ +package android.inputmethodservice; + +import com.android.internal.os.HandlerCaller; +import com.android.internal.view.IInputContext; +import com.android.internal.view.IInputMethod; +import com.android.internal.view.IInputMethodCallback; +import com.android.internal.view.IInputMethodSession; +import com.android.internal.view.InputConnectionWrapper; + +import android.content.Context; +import android.os.IBinder; +import android.os.Message; +import android.os.RemoteException; +import android.util.Log; +import android.view.inputmethod.EditorInfo; +import android.view.inputmethod.InputBinding; +import android.view.inputmethod.InputConnection; +import android.view.inputmethod.InputMethod; +import android.view.inputmethod.InputMethodSession; + +/** + * Implements the internal IInputMethod interface to convert incoming calls + * on to it back to calls on the public InputMethod interface, scheduling + * them on the main thread of the process. + */ +class IInputMethodWrapper extends IInputMethod.Stub + implements HandlerCaller.Callback { + private static final String TAG = "InputMethodWrapper"; + private static final boolean DEBUG = false; + + private static final int DO_ATTACH_TOKEN = 10; + private static final int DO_SET_INPUT_CONTEXT = 20; + private static final int DO_UNSET_INPUT_CONTEXT = 30; + private static final int DO_START_INPUT = 32; + private static final int DO_RESTART_INPUT = 34; + private static final int DO_CREATE_SESSION = 40; + private static final int DO_SET_SESSION_ENABLED = 45; + private static final int DO_REVOKE_SESSION = 50; + private static final int DO_SHOW_SOFT_INPUT = 60; + private static final int DO_HIDE_SOFT_INPUT = 70; + + final HandlerCaller mCaller; + final InputMethod mInputMethod; + + // NOTE: we should have a cache of these. + static class InputMethodSessionCallbackWrapper implements InputMethod.SessionCallback { + final Context mContext; + final IInputMethodCallback mCb; + InputMethodSessionCallbackWrapper(Context context, IInputMethodCallback cb) { + mContext = context; + mCb = cb; + } + public void sessionCreated(InputMethodSession session) { + try { + if (session != null) { + IInputMethodSessionWrapper wrap = + new IInputMethodSessionWrapper(mContext, session); + mCb.sessionCreated(wrap); + } else { + mCb.sessionCreated(null); + } + } catch (RemoteException e) { + } + } + } + + public IInputMethodWrapper(Context context, InputMethod inputMethod) { + mCaller = new HandlerCaller(context, this); + mInputMethod = inputMethod; + } + + public InputMethod getInternalInputMethod() { + return mInputMethod; + } + + public void executeMessage(Message msg) { + switch (msg.what) { + case DO_ATTACH_TOKEN: { + mInputMethod.attachToken((IBinder)msg.obj); + return; + } + case DO_SET_INPUT_CONTEXT: { + mInputMethod.bindInput((InputBinding)msg.obj); + return; + } + case DO_UNSET_INPUT_CONTEXT: + mInputMethod.unbindInput(); + return; + case DO_START_INPUT: + mInputMethod.startInput((EditorInfo)msg.obj); + return; + case DO_RESTART_INPUT: + mInputMethod.restartInput((EditorInfo)msg.obj); + return; + case DO_CREATE_SESSION: { + mInputMethod.createSession(new InputMethodSessionCallbackWrapper( + mCaller.mContext, (IInputMethodCallback)msg.obj)); + return; + } + case DO_SET_SESSION_ENABLED: + mInputMethod.setSessionEnabled((InputMethodSession)msg.obj, + msg.arg1 != 0); + return; + case DO_REVOKE_SESSION: + mInputMethod.revokeSession((InputMethodSession)msg.obj); + return; + case DO_SHOW_SOFT_INPUT: + mInputMethod.showSoftInput(); + return; + case DO_HIDE_SOFT_INPUT: + mInputMethod.hideSoftInput(); + return; + } + Log.w(TAG, "Unhandled message code: " + msg.what); + } + + public void attachToken(IBinder token) { + mCaller.executeOrSendMessage(mCaller.obtainMessageO(DO_ATTACH_TOKEN, token)); + } + + public void bindInput(InputBinding binding) { + InputConnection ic = new InputConnectionWrapper( + IInputContext.Stub.asInterface(binding.getConnectionToken())); + InputBinding nu = new InputBinding(ic, binding); + mCaller.executeOrSendMessage(mCaller.obtainMessageO(DO_SET_INPUT_CONTEXT, nu)); + } + + public void unbindInput() { + mCaller.executeOrSendMessage(mCaller.obtainMessage(DO_UNSET_INPUT_CONTEXT)); + } + + public void startInput(EditorInfo attribute) { + mCaller.executeOrSendMessage(mCaller.obtainMessageO(DO_START_INPUT, attribute)); + } + + public void restartInput(EditorInfo attribute) { + mCaller.executeOrSendMessage(mCaller.obtainMessageO(DO_RESTART_INPUT, attribute)); + } + + public void createSession(IInputMethodCallback callback) { + mCaller.executeOrSendMessage(mCaller.obtainMessageO(DO_CREATE_SESSION, callback)); + } + + public void setSessionEnabled(IInputMethodSession session, boolean enabled) { + try { + InputMethodSession ls = ((IInputMethodSessionWrapper) + session).getInternalInputMethodSession(); + mCaller.executeOrSendMessage(mCaller.obtainMessageIO( + DO_SET_SESSION_ENABLED, enabled ? 1 : 0, ls)); + } catch (ClassCastException e) { + Log.w(TAG, "Incoming session not of correct type: " + session, e); + } + } + + public void revokeSession(IInputMethodSession session) { + try { + InputMethodSession ls = ((IInputMethodSessionWrapper) + session).getInternalInputMethodSession(); + mCaller.executeOrSendMessage(mCaller.obtainMessageO(DO_REVOKE_SESSION, ls)); + } catch (ClassCastException e) { + Log.w(TAG, "Incoming session not of correct type: " + session, e); + } + } + + public void showSoftInput() { + mCaller.executeOrSendMessage(mCaller.obtainMessage(DO_SHOW_SOFT_INPUT)); + } + + public void hideSoftInput() { + mCaller.executeOrSendMessage(mCaller.obtainMessage(DO_HIDE_SOFT_INPUT)); + } +} diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java new file mode 100644 index 0000000000000000000000000000000000000000..9ebf1271ee67f3af20811047dcb808aeb0d3da90 --- /dev/null +++ b/core/java/android/inputmethodservice/InputMethodService.java @@ -0,0 +1,864 @@ +/* + * Copyright (C) 2007-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 android.inputmethodservice; + +import static android.view.ViewGroup.LayoutParams.FILL_PARENT; +import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT; + +import android.app.Dialog; +import android.content.Context; +import android.content.res.Configuration; +import android.graphics.Rect; +import android.graphics.drawable.Drawable; +import android.os.Bundle; +import android.os.IBinder; +import android.util.Log; +import android.view.KeyEvent; +import android.view.LayoutInflater; +import android.view.MotionEvent; +import android.view.View; +import android.view.ViewGroup; +import android.view.ViewTreeObserver; +import android.view.inputmethod.CompletionInfo; +import android.view.inputmethod.ExtractedText; +import android.view.inputmethod.ExtractedTextRequest; +import android.view.inputmethod.InputBinding; +import android.view.inputmethod.InputConnection; +import android.view.inputmethod.InputMethod; +import android.view.inputmethod.InputMethodManager; +import android.view.inputmethod.EditorInfo; +import android.widget.FrameLayout; + +/** + * InputMethodService provides a standard implementation of an InputMethod, + * which final implementations can derive from and customize. See the + * base class {@link AbstractInputMethodService} and the {@link InputMethod} + * interface for more information on the basics of writing input methods. + */ +public class InputMethodService extends AbstractInputMethodService { + static final String TAG = "InputMethodService"; + static final boolean DEBUG = false; + + LayoutInflater mInflater; + View mRootView; + SoftInputWindow mWindow; + boolean mWindowCreated; + boolean mWindowAdded; + boolean mWindowVisible; + FrameLayout mExtractFrame; + FrameLayout mCandidatesFrame; + FrameLayout mInputFrame; + + IBinder mToken; + + InputBinding mInputBinding; + InputConnection mInputConnection; + boolean mInputStarted; + EditorInfo mInputInfo; + + boolean mShowInputRequested; + boolean mShowCandidatesRequested; + + boolean mFullscreenApplied; + boolean mIsFullscreen; + View mExtractView; + ExtractEditText mExtractEditText; + ExtractedText mExtractedText; + int mExtractedToken; + + View mInputView; + boolean mIsInputViewShown; + + int mStatusIcon; + + final Insets mTmpInsets = new Insets(); + final int[] mTmpLocation = new int[2]; + + final ViewTreeObserver.OnComputeInternalInsetsListener mInsetsComputer = + new ViewTreeObserver.OnComputeInternalInsetsListener() { + public void onComputeInternalInsets(ViewTreeObserver.InternalInsetsInfo info) { + if (isFullscreenMode()) { + // In fullscreen mode, we just say the window isn't covering + // any content so we don't impact whatever is behind. + View decor = getWindow().getWindow().getDecorView(); + info.contentInsets.top = info.visibleInsets.top + = decor.getHeight(); + info.setTouchableInsets(ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_FRAME); + } else { + onComputeInsets(mTmpInsets); + info.contentInsets.top = mTmpInsets.contentTopInsets; + info.visibleInsets.top = mTmpInsets.visibleTopInsets; + info.setTouchableInsets(mTmpInsets.touchableInsets); + } + } + }; + + /** + * Concrete implementation of + * {@link AbstractInputMethodService.AbstractInputMethodImpl} that provides + * all of the standard behavior for an input method. + */ + public class InputMethodImpl extends AbstractInputMethodImpl { + /** + * Take care of attaching the given window token provided by the system. + */ + public void attachToken(IBinder token) { + if (mToken == null) { + mToken = token; + mWindow.setToken(token); + } + } + + /** + * Handle a new input binding, calling + * {@link InputMethodService#onBindInput InputMethodService.onBindInput()} + * when done. + */ + public void bindInput(InputBinding binding) { + mInputBinding = binding; + mInputConnection = binding.getConnection(); + onBindInput(); + } + + /** + * Clear the current input binding. + */ + public void unbindInput() { + mInputStarted = false; + mInputBinding = null; + mInputConnection = null; + } + + public void startInput(EditorInfo attribute) { + doStartInput(attribute, false); + } + + public void restartInput(EditorInfo attribute) { + doStartInput(attribute, false); + } + + /** + * Handle a request by the system to hide the soft input area. + */ + public void hideSoftInput() { + if (DEBUG) Log.v(TAG, "hideSoftInput()"); + mShowInputRequested = false; + hideWindow(); + } + + /** + * Handle a request by the system to show the soft input area. + */ + public void showSoftInput() { + if (DEBUG) Log.v(TAG, "showSoftInput()"); + showWindow(true); + } + } + + /** + * Concrete implementation of + * {@link AbstractInputMethodService.AbstractInputMethodSessionImpl} that provides + * all of the standard behavior for an input method session. + */ + public class InputMethodSessionImpl extends AbstractInputMethodSessionImpl { + public void finishInput() { + if (!isEnabled()) { + return; + } + onFinishInput(); + mInputStarted = false; + } + + /** + * Call {@link InputMethodService#onDisplayCompletions + * InputMethodService.onDisplayCompletions()}. + */ + public void displayCompletions(CompletionInfo[] completions) { + if (!isEnabled()) { + return; + } + onDisplayCompletions(completions); + } + + /** + * Call {@link InputMethodService#onUpdateExtractedText + * InputMethodService.onUpdateExtractedText()}. + */ + public void updateExtractedText(int token, ExtractedText text) { + if (!isEnabled()) { + return; + } + onUpdateExtractedText(token, text); + } + + /** + * Call {@link InputMethodService#onUpdateSelection + * InputMethodService.onUpdateSelection()}. + */ + public void updateSelection(int oldSelStart, int oldSelEnd, + int newSelStart, int newSelEnd) { + if (!isEnabled()) { + return; + } + InputMethodService.this.onUpdateSelection(oldSelStart, oldSelEnd, + newSelStart, newSelEnd); + } + + /** + * Call {@link InputMethodService#onUpdateCursor + * InputMethodService.onUpdateCursor()}. + */ + public void updateCursor(Rect newCursor) { + if (!isEnabled()) { + return; + } + InputMethodService.this.onUpdateCursor(newCursor); + } + + /** + * Call {@link InputMethodService#onAppPrivateCommand + * InputMethodService.onAppPrivateCommand()}. + */ + public void appPrivateCommand(String action, Bundle data) { + if (!isEnabled()) { + return; + } + InputMethodService.this.onAppPrivateCommand(action, data); + } + } + + /** + * Information about where interesting parts of the input method UI appear. + */ + public static final class Insets { + /** + * This is the top part of the UI that is the main content. It is + * used to determine the basic space needed, to resize/pan the + * application behind. It is assumed that this inset does not + * change very much, since any change will cause a full resize/pan + * of the application behind. This value is relative to the top edge + * of the input method window. + */ + int contentTopInsets; + + /** + * This is the top part of the UI that is visibly covering the + * application behind it. This provides finer-grained control over + * visibility, allowing you to change it relatively frequently (such + * as hiding or showing candidates) without disrupting the underlying + * UI too much. For example, this will never resize the application + * UI, will only pan if needed to make the current focus visible, and + * will not aggressively move the pan position when this changes unless + * needed to make the focus visible. This value is relative to the top edge + * of the input method window. + */ + int visibleTopInsets; + + /** + * Option for {@link #touchableInsets}: the entire window frame + * can be touched. + */ + public static final int TOUCHABLE_INSETS_FRAME + = ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_FRAME; + + /** + * Option for {@link #touchableInsets}: the area inside of + * the content insets can be touched. + */ + public static final int TOUCHABLE_INSETS_CONTENT + = ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_CONTENT; + + /** + * Option for {@link #touchableInsets}: the area inside of + * the visible insets can be touched. + */ + public static final int TOUCHABLE_INSETS_VISIBLE + = ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_VISIBLE; + + /** + * Determine which area of the window is touchable by the user. May + * be one of: {@link #TOUCHABLE_INSETS_FRAME}, + * {@link #TOUCHABLE_INSETS_CONTENT}, or {@link #TOUCHABLE_INSETS_VISIBLE}. + */ + public int touchableInsets; + } + + @Override public void onCreate() { + super.onCreate(); + mInflater = (LayoutInflater)getSystemService( + Context.LAYOUT_INFLATER_SERVICE); + mWindow = new SoftInputWindow(this); + initViews(); + } + + void initViews() { + mWindowVisible = false; + mWindowCreated = false; + mShowInputRequested = false; + mShowCandidatesRequested = false; + + mRootView = mInflater.inflate( + com.android.internal.R.layout.input_method, null); + mWindow.setContentView(mRootView); + mRootView.getViewTreeObserver().addOnComputeInternalInsetsListener(mInsetsComputer); + + mExtractFrame = (FrameLayout)mRootView.findViewById(android.R.id.extractArea); + mExtractView = null; + mExtractEditText = null; + mFullscreenApplied = false; + + mCandidatesFrame = (FrameLayout)mRootView.findViewById(android.R.id.candidatesArea); + mInputFrame = (FrameLayout)mRootView.findViewById(android.R.id.inputArea); + mInputView = null; + mIsInputViewShown = false; + + mExtractFrame.setVisibility(View.GONE); + mCandidatesFrame.setVisibility(View.GONE); + mInputFrame.setVisibility(View.GONE); + } + + @Override public void onDestroy() { + super.onDestroy(); + mRootView.getViewTreeObserver().removeOnComputeInternalInsetsListener( + mInsetsComputer); + if (mWindowAdded) { + mWindow.dismiss(); + } + } + + /** + * Implement to return our standard {@link InputMethodImpl}. Subclasses + * can override to provide their own customized version. + */ + public AbstractInputMethodImpl onCreateInputMethodInterface() { + return new InputMethodImpl(); + } + + /** + * Implement to return our standard {@link InputMethodSessionImpl}. Subclasses + * can override to provide their own customized version. + */ + public AbstractInputMethodSessionImpl onCreateInputMethodSessionInterface() { + return new InputMethodSessionImpl(); + } + + public LayoutInflater getLayoutInflater() { + return mInflater; + } + + public Dialog getWindow() { + return mWindow; + } + + /** + * Return the currently active InputBinding for the input method, or + * null if there is none. + */ + public InputBinding getCurrentInputBinding() { + return mInputBinding; + } + + /** + * Retrieve the currently active InputConnection that is bound to + * the input method, or null if there is none. + */ + public InputConnection getCurrentInputConnection() { + return mInputConnection; + } + + public boolean getCurrentInputStarted() { + return mInputStarted; + } + + public EditorInfo getCurrentInputInfo() { + return mInputInfo; + } + + /** + * Re-evaluate whether the input method should be running in fullscreen + * mode, and update its UI if this has changed since the last time it + * was evaluated. This will call {@link #onEvaluateFullscreenMode()} to + * determine whether it should currently run in fullscreen mode. You + * can use {@link #isFullscreenMode()} to determine if the input method + * is currently running in fullscreen mode. + */ + public void updateFullscreenMode() { + boolean isFullscreen = onEvaluateFullscreenMode(); + if (mIsFullscreen != isFullscreen || !mFullscreenApplied) { + mIsFullscreen = isFullscreen; + mFullscreenApplied = true; + mWindow.getWindow().setBackgroundDrawable( + onCreateBackgroundDrawable()); + mExtractFrame.setVisibility(isFullscreen ? View.VISIBLE : View.GONE); + if (isFullscreen) { + if (mExtractView == null) { + View v = onCreateExtractTextView(); + if (v != null) { + setExtractView(v); + } + } + startExtractingText(); + mWindow.getWindow().setLayout(FILL_PARENT, FILL_PARENT); + } else { + mWindow.getWindow().setLayout(WRAP_CONTENT, WRAP_CONTENT); + } + } + } + + /** + * Return whether the input method is currently running in + * fullscreen mode. This is the mode that was last determined and + * applied by {@link #updateFullscreenMode()}. + */ + public boolean isFullscreenMode() { + return mIsFullscreen; + } + + /** + * Override this to control when the input method should run in + * fullscreen mode. The default implementation runs in fullsceen only + * when the screen is in landscape mode and the input view is being + * shown ({@link #onEvaluateInputViewShown} returns true). If you change what + * this returns, you will need to call {@link #updateFullscreenMode()} + * yourself whenever the returned value may have changed to have it + * re-evaluated and applied. + */ + public boolean onEvaluateFullscreenMode() { + Configuration config = getResources().getConfiguration(); + return config.orientation == Configuration.ORIENTATION_LANDSCAPE + && onEvaluateInputViewShown(); + } + + /** + * Compute the interesting insets into your UI. The default implementation + * uses the top of the candidates frame for the visible insets, and the + * top of the input frame for the content insets. The default touchable + * insets are {@link Insets#TOUCHABLE_INSETS_VISIBLE}. + * + *

    Note that this method is not called when in fullscreen mode, since + * in that case the application is left as-is behind the input method and + * not impacted by anything in its UI. + * + * @param outInsets Fill in with the current UI insets. + */ + public void onComputeInsets(Insets outInsets) { + int[] loc = mTmpLocation; + if (mInputFrame.getVisibility() == View.VISIBLE) { + mInputFrame.getLocationInWindow(loc); + outInsets.contentTopInsets = loc[1]; + } + if (mCandidatesFrame.getVisibility() == View.VISIBLE) { + mCandidatesFrame.getLocationInWindow(loc); + outInsets.visibleTopInsets = loc[1]; + } else { + outInsets.visibleTopInsets = loc[1]; + } + outInsets.touchableInsets = Insets.TOUCHABLE_INSETS_VISIBLE; + } + + /** + * Re-evaluate whether the soft input area should currently be shown, and + * update its UI if this has changed since the last time it + * was evaluated. This will call {@link #onEvaluateInputViewShown()} to + * determine whether the input view should currently be shown. You + * can use {@link #isInputViewShown()} to determine if the input view + * is currently shown. + */ + public void updateInputViewShown() { + boolean isShown = onEvaluateInputViewShown(); + if (mIsInputViewShown != isShown && mWindowVisible) { + mIsInputViewShown = isShown; + mInputFrame.setVisibility(isShown ? View.VISIBLE : View.GONE); + if (mInputView == null) { + View v = onCreateInputView(); + if (v != null) { + setInputView(v); + } + } + } + } + + /** + * Return whether the soft input view is currently shown to the + * user. This is the state that was last determined and + * applied by {@link #updateInputViewShown()}. + */ + public boolean isInputViewShown() { + return mIsInputViewShown; + } + + /** + * Override this to control when the soft input area should be shown to + * the user. The default implementation only shows the input view when + * there is no hard keyboard or the keyboard is hidden. If you change what + * this returns, you will need to call {@link #updateInputViewShown()} + * yourself whenever the returned value may have changed to have it + * re-evalauted and applied. + */ + public boolean onEvaluateInputViewShown() { + Configuration config = getResources().getConfiguration(); + return config.keyboard == Configuration.KEYBOARD_NOKEYS + || config.hardKeyboardHidden == Configuration.KEYBOARDHIDDEN_YES; + } + + /** + * Controls the visibility of the candidates display area. By default + * it is hidden. + */ + public void setCandidatesViewShown(boolean shown) { + if (mShowCandidatesRequested != shown) { + mCandidatesFrame.setVisibility(shown ? View.VISIBLE : View.INVISIBLE); + if (!mShowInputRequested) { + // If we are being asked to show the candidates view while the app + // has not asked for the input view to be shown, then we need + // to update whether the window is shown. + if (shown) { + showWindow(false); + } else { + hideWindow(); + } + } + mShowCandidatesRequested = shown; + } + } + + public void setStatusIcon(int iconResId) { + mStatusIcon = iconResId; + if (mInputConnection != null && mWindowVisible) { + mInputConnection.showStatusIcon(getPackageName(), iconResId); + } + } + + /** + * Force switch to a new input method, as identified by id. This + * input method will be destroyed, and the requested one started on the + * current input field. + * + * @param id Unique identifier of the new input method ot start. + */ + public void switchInputMethod(String id) { + ((InputMethodManager)getSystemService(INPUT_METHOD_SERVICE)) + .setInputMethod(mToken, id); + } + + public void setExtractView(View view) { + mExtractFrame.removeAllViews(); + mExtractFrame.addView(view, new FrameLayout.LayoutParams( + ViewGroup.LayoutParams.FILL_PARENT, + ViewGroup.LayoutParams.WRAP_CONTENT)); + mExtractView = view; + if (view != null) { + mExtractEditText = (ExtractEditText)view.findViewById( + com.android.internal.R.id.inputExtractEditText); + startExtractingText(); + } else { + mExtractEditText = null; + } + } + + /** + * Replaces the current candidates view with a new one. You only need to + * call this when dynamically changing the view; normally, you should + * implement {@link #onCreateCandidatesView()} and create your view when + * first needed by the input method. + */ + public void setCandidatesView(View view) { + mCandidatesFrame.removeAllViews(); + mCandidatesFrame.addView(view, new FrameLayout.LayoutParams( + ViewGroup.LayoutParams.FILL_PARENT, + ViewGroup.LayoutParams.WRAP_CONTENT)); + } + + /** + * Replaces the current input view with a new one. You only need to + * call this when dynamically changing the view; normally, you should + * implement {@link #onCreateInputView()} and create your view when + * first needed by the input method. + */ + public void setInputView(View view) { + mInputFrame.removeAllViews(); + mInputFrame.addView(view, new FrameLayout.LayoutParams( + ViewGroup.LayoutParams.FILL_PARENT, + ViewGroup.LayoutParams.WRAP_CONTENT)); + mInputView = view; + } + + /** + * Called by the framework to create a Drawable for the background of + * the input method window. May return null for no background. The default + * implementation returns a non-null standard background only when in + * fullscreen mode. + */ + public Drawable onCreateBackgroundDrawable() { + if (isFullscreenMode()) { + return getResources().getDrawable( + com.android.internal.R.drawable.input_method_fullscreen_background); + } + return null; + } + + /** + * Called by the framework to create the layout for showing extacted text. + * Only called when in fullscreen mode. The returned view hierarchy must + * have an {@link ExtractEditText} whose ID is + * {@link android.R.id#inputExtractEditText}. + */ + public View onCreateExtractTextView() { + return mInflater.inflate( + com.android.internal.R.layout.input_method_extract_view, null); + } + + /** + * Create and return the view hierarchy used to show candidates. This will + * be called once, when the candidates are first displayed. You can return + * null to have no candidates view; the default implementation returns null. + * + *

    To control when the candidates view is displayed, use + * {@link #setCandidatesViewShown(boolean)}. + * To change the candidates view after the first one is created by this + * function, use {@link #setCandidatesView(View)}. + */ + public View onCreateCandidatesView() { + return null; + } + + /** + * Create and return the view hierarchy used for the input area (such as + * a soft keyboard). This will be called once, when the input area is + * first displayed. You can return null to have no input area; the default + * implementation returns null. + * + *

    To control when the input view is displayed, implement + * {@link #onEvaluateInputViewShown()}. + * To change the input view after the first one is created by this + * function, use {@link #setInputView(View)}. + */ + public View onCreateInputView() { + return null; + } + + /** + * Called when an input session is starting or restarting. + * + * @param info Description of the type of text being edited. + * @param restarting Set to true if we are restarting input on the + * same text field as before. + */ + public void onStartInputView(EditorInfo info, boolean restarting) { + } + + @Override + public void onConfigurationChanged(Configuration newConfig) { + super.onConfigurationChanged(newConfig); + + boolean visible = mWindowVisible; + boolean showingInput = mShowInputRequested; + boolean showingCandidates = mShowCandidatesRequested; + initViews(); + if (visible) { + if (showingCandidates) { + setCandidatesViewShown(true); + } + showWindow(showingInput); + } + } + + public void showWindow(boolean showInput) { + if (DEBUG) Log.v(TAG, "Showing window: showInput=" + showInput + + " mShowInputRequested=" + mShowInputRequested + + " mWindowAdded=" + mWindowAdded + + " mWindowCreated=" + mWindowCreated + + " mWindowVisible=" + mWindowVisible + + " mInputStarted=" + mInputStarted); + boolean doShowInput = false; + boolean wasVisible = mWindowVisible; + mWindowVisible = true; + if (!mShowInputRequested) { + doShowInput = true; + mShowInputRequested = true; + } else { + showInput = true; + } + + if (doShowInput) { + if (DEBUG) Log.v(TAG, "showWindow: updating UI"); + updateFullscreenMode(); + updateInputViewShown(); + } + + if (!mWindowAdded || !mWindowCreated) { + mWindowAdded = true; + mWindowCreated = true; + View v = onCreateCandidatesView(); + if (DEBUG) Log.v(TAG, "showWindow: candidates=" + v); + if (v != null) { + setCandidatesView(v); + } + } + if (doShowInput) { + if (mInputStarted) { + if (DEBUG) Log.v(TAG, "showWindow: starting input view"); + onStartInputView(mInputInfo, false); + } + startExtractingText(); + } + + if (!wasVisible) { + if (DEBUG) Log.v(TAG, "showWindow: showing!"); + mWindow.show(); + if (mInputConnection != null) { + mInputConnection.showStatusIcon(getPackageName(), mStatusIcon); + } + } + } + + public void hideWindow() { + if (mWindowVisible) { + mWindow.hide(); + mWindowVisible = false; + if (mInputConnection != null) { + mInputConnection.hideStatusIcon(); + } + } + } + + public void onBindInput() { + } + + public void onStartInput(EditorInfo attribute, boolean restarting) { + } + + void doStartInput(EditorInfo attribute, boolean restarting) { + mInputStarted = true; + mInputInfo = attribute; + onStartInput(attribute, restarting); + if (mWindowVisible) { + if (mWindowCreated) { + onStartInputView(mInputInfo, restarting); + } + startExtractingText(); + } + } + + public void onFinishInput() { + } + + /** + * Called when the application has reported auto-completion candidates that + * it would like to have the input method displayed. Typically these are + * only used when an input method is running in full-screen mode, since + * otherwise the user can see and interact with the pop-up window of + * completions shown by the application. + * + *

    The default implementation here does nothing. + */ + public void onDisplayCompletions(CompletionInfo[] completions) { + } + + /** + * Called when the application has reported new extracted text to be shown + * due to changes in its current text state. The default implementation + * here places the new text in the extract edit text, when the input + * method is running in fullscreen mode. + */ + public void onUpdateExtractedText(int token, ExtractedText text) { + if (mExtractedToken != token) { + return; + } + if (mExtractEditText != null && text != null) { + mExtractedText = text; + mExtractEditText.setExtractedText(text); + } + } + + /** + * Called when the application has reported a new selection region of + * the text. This is called whether or not the input method has requested + * extracted text updates, although if so it will not receive this call + * if the extracted text has changed as well. + * + *

    The default implementation takes care of updating the cursor in + * the extract text, if it is being shown. + */ + public void onUpdateSelection(int oldSelStart, int oldSelEnd, + int newSelStart, int newSelEnd) { + if (mExtractEditText != null && mExtractedText != null) { + final int off = mExtractedText.startOffset; + mExtractEditText.setSelection(newSelStart-off, newSelEnd-off); + } + } + + /** + * Called when the application has reported a new location of its text + * cursor. This is only called if explicitly requested by the input method. + * The default implementation does nothing. + */ + public void onUpdateCursor(Rect newCursor) { + } + + /** + * Close this input method's soft input area, removing it from the display. + * The input method will continue running, but the user can no longer use + * it to generate input by touching the screen. + */ + public void dismissSoftInput() { + ((InputMethodManager)getSystemService(INPUT_METHOD_SERVICE)) + .hideSoftInputFromInputMethod(mToken); + } + + public boolean onKeyDown(int keyCode, KeyEvent event) { + if (mWindowVisible && event.getKeyCode() == KeyEvent.KEYCODE_BACK + && event.getRepeatCount() == 0) { + dismissSoftInput(); + return true; + } + return false; + } + + public boolean onKeyMultiple(int keyCode, int count, KeyEvent event) { + return false; + } + + public boolean onKeyUp(int keyCode, KeyEvent event) { + return false; + } + + public boolean onTrackballEvent(MotionEvent event) { + return false; + } + + public void onAppPrivateCommand(String action, Bundle data) { + } + + void startExtractingText() { + if (mExtractEditText != null && getCurrentInputStarted() + && isFullscreenMode()) { + mExtractedToken++; + ExtractedTextRequest req = new ExtractedTextRequest(); + req.token = mExtractedToken; + req.hintMaxLines = 10; + req.hintMaxChars = 10000; + mExtractedText = mInputConnection.getExtractedText(req, + InputConnection.EXTRACTED_TEXT_MONITOR); + if (mExtractedText != null) { + mExtractEditText.setExtractedText(mExtractedText); + } + mExtractEditText.setInputType(getCurrentInputInfo().inputType); + mExtractEditText.setHint(mInputInfo.hintText); + } + } +} diff --git a/core/java/android/inputmethodservice/Keyboard.java b/core/java/android/inputmethodservice/Keyboard.java new file mode 100755 index 0000000000000000000000000000000000000000..75a2911bcaea6a946c3c3aaf13da0461839740ec --- /dev/null +++ b/core/java/android/inputmethodservice/Keyboard.java @@ -0,0 +1,756 @@ +/* + * Copyright (C) 2008-2009 Google Inc. + * + * 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 android.inputmethodservice; + +import org.xmlpull.v1.XmlPullParserException; + +import android.content.Context; +import android.content.res.Resources; +import android.content.res.TypedArray; +import android.content.res.XmlResourceParser; +import android.graphics.drawable.Drawable; +import android.text.TextUtils; +import android.util.Log; +import android.util.TypedValue; +import android.util.Xml; +import android.view.Display; +import android.view.WindowManager; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.StringTokenizer; + + +/** + * Loads an XML description of a keyboard and stores the attributes of the keys. A keyboard + * consists of rows of keys. + *

    The layout file for a keyboard contains XML that looks like the following snippet:

    + *
    + * <Keyboard
    + *         android:keyWidth="%10p"
    + *         android:keyHeight="50px"
    + *         android:horizontalGap="2px"
    + *         android:verticalGap="2px" >
    + *     <Row android:keyWidth="32px" >
    + *         <Key android:keyLabel="A" />
    + *         ...
    + *     </Row>
    + *     ...
    + * </Keyboard>
    + * 
    + * @attr ref android.R.styleable#Keyboard_keyWidth + * @attr ref android.R.styleable#Keyboard_keyHeight + * @attr ref android.R.styleable#Keyboard_horizontalGap + * @attr ref android.R.styleable#Keyboard_verticalGap + */ +public class Keyboard { + + static final String TAG = "Keyboard"; + + // Keyboard XML Tags + private static final String TAG_KEYBOARD = "Keyboard"; + private static final String TAG_ROW = "Row"; + private static final String TAG_KEY = "Key"; + + public static final int EDGE_LEFT = 0x01; + public static final int EDGE_RIGHT = 0x02; + public static final int EDGE_TOP = 0x04; + public static final int EDGE_BOTTOM = 0x08; + + public static final int KEYCODE_SHIFT = -1; + public static final int KEYCODE_MODE_CHANGE = -2; + public static final int KEYCODE_CANCEL = -3; + public static final int KEYCODE_DONE = -4; + public static final int KEYCODE_DELETE = -5; + public static final int KEYCODE_ALT = -6; + + /** Keyboard label **/ + private CharSequence mLabel; + + /** Horizontal gap default for all rows */ + private int mDefaultHorizontalGap; + + /** Default key width */ + private int mDefaultWidth; + + /** Default key height */ + private int mDefaultHeight; + + /** Default gap between rows */ + private int mDefaultVerticalGap; + + /** Is the keyboard in the shifted state */ + private boolean mShifted; + + /** Key instance for the shift key, if present */ + private Key mShiftKey; + + /** Key index for the shift key, if present */ + private int mShiftKeyIndex = -1; + + /** Current key width, while loading the keyboard */ + private int mKeyWidth; + + /** Current key height, while loading the keyboard */ + private int mKeyHeight; + + /** Total height of the keyboard, including the padding and keys */ + private int mTotalHeight; + + /** + * Total width of the keyboard, including left side gaps and keys, but not any gaps on the + * right side. + */ + private int mTotalWidth; + + /** List of keys in this keyboard */ + private List mKeys; + + /** List of modifier keys such as Shift & Alt, if any */ + private List mModifierKeys; + + /** Width of the screen available to fit the keyboard */ + private int mDisplayWidth; + + /** Height of the screen */ + private int mDisplayHeight; + + /** Keyboard mode, or zero, if none. */ + private int mKeyboardMode; + + /** + * Container for keys in the keyboard. All keys in a row are at the same Y-coordinate. + * Some of the key size defaults can be overridden per row from what the {@link Keyboard} + * defines. + * @attr ref android.R.styleable#Keyboard_keyWidth + * @attr ref android.R.styleable#Keyboard_keyHeight + * @attr ref android.R.styleable#Keyboard_horizontalGap + * @attr ref android.R.styleable#Keyboard_verticalGap + * @attr ref android.R.styleable#Keyboard_Row_rowEdgeFlags + * @attr ref android.R.styleable#Keyboard_Row_keyboardMode + */ + public static class Row { + /** Default width of a key in this row. */ + public int defaultWidth; + /** Default height of a key in this row. */ + public int defaultHeight; + /** Default horizontal gap between keys in this row. */ + public int defaultHorizontalGap; + /** Vertical gap following this row. */ + public int verticalGap; + /** + * Edge flags for this row of keys. Possible values that can be assigned are + * {@link Keyboard#EDGE_TOP EDGE_TOP} and {@link Keyboard#EDGE_BOTTOM EDGE_BOTTOM} + */ + public int rowEdgeFlags; + + /** The keyboard mode for this row */ + public int mode; + + private Keyboard parent; + + public Row(Keyboard parent) { + this.parent = parent; + } + + public Row(Resources res, Keyboard parent, XmlResourceParser parser) { + this.parent = parent; + TypedArray a = res.obtainAttributes(Xml.asAttributeSet(parser), + com.android.internal.R.styleable.Keyboard); + defaultWidth = getDimensionOrFraction(a, + com.android.internal.R.styleable.Keyboard_keyWidth, + parent.mDisplayWidth, parent.mDefaultWidth); + defaultHeight = getDimensionOrFraction(a, + com.android.internal.R.styleable.Keyboard_keyHeight, + parent.mDisplayWidth, parent.mDefaultHeight); + defaultHorizontalGap = getDimensionOrFraction(a, + com.android.internal.R.styleable.Keyboard_horizontalGap, + parent.mDisplayWidth, parent.mDefaultHorizontalGap); + verticalGap = getDimensionOrFraction(a, + com.android.internal.R.styleable.Keyboard_verticalGap, + parent.mDisplayWidth, parent.mDefaultVerticalGap); + a.recycle(); + a = res.obtainAttributes(Xml.asAttributeSet(parser), + com.android.internal.R.styleable.Keyboard_Row); + rowEdgeFlags = a.getInt(com.android.internal.R.styleable.Keyboard_Row_rowEdgeFlags, 0); + mode = a.getResourceId(com.android.internal.R.styleable.Keyboard_Row_keyboardMode, + 0); + } + } + + /** + * Class for describing the position and characteristics of a single key in the keyboard. + * + * @attr ref android.R.styleable#Keyboard_keyWidth + * @attr ref android.R.styleable#Keyboard_keyHeight + * @attr ref android.R.styleable#Keyboard_horizontalGap + * @attr ref android.R.styleable#Keyboard_Key_codes + * @attr ref android.R.styleable#Keyboard_Key_keyIcon + * @attr ref android.R.styleable#Keyboard_Key_keyLabel + * @attr ref android.R.styleable#Keyboard_Key_iconPreview + * @attr ref android.R.styleable#Keyboard_Key_isSticky + * @attr ref android.R.styleable#Keyboard_Key_isRepeatable + * @attr ref android.R.styleable#Keyboard_Key_isModifier + * @attr ref android.R.styleable#Keyboard_Key_popupKeyboard + * @attr ref android.R.styleable#Keyboard_Key_popupCharacters + * @attr ref android.R.styleable#Keyboard_Key_keyOutputText + * @attr ref android.R.styleable#Keyboard_Key_keyEdgeFlags + */ + public static class Key { + /** + * All the key codes (unicode or custom code) that this key could generate, zero'th + * being the most important. + */ + public int[] codes; + + /** Label to display */ + public CharSequence label; + + /** Icon to display instead of a label. Icon takes precedence over a label */ + public Drawable icon; + /** Preview version of the icon, for the preview popup */ + public Drawable iconPreview; + /** Width of the key, not including the gap */ + public int width; + /** Height of the key, not including the gap */ + public int height; + /** The horizontal gap before this key */ + public int gap; + /** Whether this key is sticky, i.e., a toggle key */ + public boolean sticky; + /** X coordinate of the key in the keyboard layout */ + public int x; + /** Y coordinate of the key in the keyboard layout */ + public int y; + /** The current pressed state of this key */ + public boolean pressed; + /** If this is a sticky key, is it on? */ + public boolean on; + /** Text to output when pressed. This can be multiple characters, like ".com" */ + public CharSequence text; + /** Popup characters */ + public CharSequence popupCharacters; + + /** + * Flags that specify the anchoring to edges of the keyboard for detecting touch events + * that are just out of the boundary of the key. This is a bit mask of + * {@link Keyboard#EDGE_LEFT}, {@link Keyboard#EDGE_RIGHT}, {@link Keyboard#EDGE_TOP} and + * {@link Keyboard#EDGE_BOTTOM}. + */ + public int edgeFlags; + /** Whether this is a modifier key, such as Shift or Alt */ + public boolean modifier; + /** The keyboard that this key belongs to */ + private Keyboard keyboard; + /** + * If this key pops up a mini keyboard, this is the resource id for the XML layout for that + * keyboard. + */ + public int popupResId; + /** Whether this key repeats itself when held down */ + public boolean repeatable; + + + private final static int[] KEY_STATE_NORMAL_ON = { + android.R.attr.state_checkable, + android.R.attr.state_checked + }; + + private final static int[] KEY_STATE_PRESSED_ON = { + android.R.attr.state_pressed, + android.R.attr.state_checkable, + android.R.attr.state_checked + }; + + private final static int[] KEY_STATE_NORMAL_OFF = { + android.R.attr.state_checkable + }; + + private final static int[] KEY_STATE_PRESSED_OFF = { + android.R.attr.state_pressed, + android.R.attr.state_checkable + }; + + private final static int[] KEY_STATE_NORMAL = { + }; + + private final static int[] KEY_STATE_PRESSED = { + android.R.attr.state_pressed + }; + + /** Create an empty key with no attributes. */ + public Key(Row parent) { + keyboard = parent.parent; + } + + /** Create a key with the given top-left coordinate and extract its attributes from + * the XML parser. + * @param res resources associated with the caller's context + * @param parent the row that this key belongs to. The row must already be attached to + * a {@link Keyboard}. + * @param x the x coordinate of the top-left + * @param y the y coordinate of the top-left + * @param parser the XML parser containing the attributes for this key + */ + public Key(Resources res, Row parent, int x, int y, XmlResourceParser parser) { + this(parent); + + this.x = x; + this.y = y; + + TypedArray a = res.obtainAttributes(Xml.asAttributeSet(parser), + com.android.internal.R.styleable.Keyboard); + + width = getDimensionOrFraction(a, + com.android.internal.R.styleable.Keyboard_keyWidth, + keyboard.mDisplayWidth, parent.defaultWidth); + height = getDimensionOrFraction(a, + com.android.internal.R.styleable.Keyboard_keyHeight, + keyboard.mDisplayHeight, parent.defaultHeight); + gap = getDimensionOrFraction(a, + com.android.internal.R.styleable.Keyboard_horizontalGap, + keyboard.mDisplayWidth, parent.defaultHorizontalGap); + a.recycle(); + a = res.obtainAttributes(Xml.asAttributeSet(parser), + com.android.internal.R.styleable.Keyboard_Key); + this.x += gap; + TypedValue codesValue = new TypedValue(); + a.getValue(com.android.internal.R.styleable.Keyboard_Key_codes, + codesValue); + if (codesValue.type == TypedValue.TYPE_INT_DEC + || codesValue.type == TypedValue.TYPE_INT_HEX) { + codes = new int[] { codesValue.data }; + } else if (codesValue.type == TypedValue.TYPE_STRING) { + codes = parseCSV(codesValue.string.toString()); + } + + iconPreview = a.getDrawable(com.android.internal.R.styleable.Keyboard_Key_iconPreview); + if (iconPreview != null) { + iconPreview.setBounds(0, 0, iconPreview.getIntrinsicWidth(), + iconPreview.getIntrinsicHeight()); + } + popupCharacters = a.getText( + com.android.internal.R.styleable.Keyboard_Key_popupCharacters); + popupResId = a.getResourceId( + com.android.internal.R.styleable.Keyboard_Key_popupKeyboard, 0); + repeatable = a.getBoolean( + com.android.internal.R.styleable.Keyboard_Key_isRepeatable, false); + modifier = a.getBoolean( + com.android.internal.R.styleable.Keyboard_Key_isModifier, false); + sticky = a.getBoolean( + com.android.internal.R.styleable.Keyboard_Key_isSticky, false); + edgeFlags = a.getInt(com.android.internal.R.styleable.Keyboard_Key_keyEdgeFlags, 0); + edgeFlags |= parent.rowEdgeFlags; + + icon = a.getDrawable( + com.android.internal.R.styleable.Keyboard_Key_keyIcon); + if (icon != null) { + icon.setBounds(0, 0, icon.getIntrinsicWidth(), icon.getIntrinsicHeight()); + } + label = a.getText(com.android.internal.R.styleable.Keyboard_Key_keyLabel); + text = a.getText(com.android.internal.R.styleable.Keyboard_Key_keyOutputText); + + if (codes == null && !TextUtils.isEmpty(label)) { + codes = new int[] { label.charAt(0) }; + } + a.recycle(); + } + + /** + * Informs the key that it has been pressed, in case it needs to change its appearance or + * state. + * @see #onReleased(boolean) + */ + public void onPressed() { + pressed = !pressed; + } + + /** + * Changes the pressed state of the key. If it is a sticky key, it will also change the + * toggled state of the key if the finger was release inside. + * @param inside whether the finger was released inside the key + * @see #onPressed() + */ + public void onReleased(boolean inside) { + pressed = !pressed; + if (sticky) { + on = !on; + } + } + + int[] parseCSV(String value) { + int count = 0; + int lastIndex = 0; + if (value.length() > 0) { + count++; + while ((lastIndex = value.indexOf(",", lastIndex + 1)) > 0) { + count++; + } + } + int[] values = new int[count]; + count = 0; + StringTokenizer st = new StringTokenizer(value, ","); + while (st.hasMoreTokens()) { + try { + values[count++] = Integer.parseInt(st.nextToken()); + } catch (NumberFormatException nfe) { + Log.e(TAG, "Error parsing keycodes " + value); + } + } + return values; + } + + /** + * Detects if a point falls inside this key. + * @param x the x-coordinate of the point + * @param y the y-coordinate of the point + * @return whether or not the point falls inside the key. If the key is attached to an edge, + * it will assume that all points between the key and the edge are considered to be inside + * the key. + */ + public boolean isInside(int x, int y) { + boolean leftEdge = (edgeFlags & EDGE_LEFT) > 0; + boolean rightEdge = (edgeFlags & EDGE_RIGHT) > 0; + boolean topEdge = (edgeFlags & EDGE_TOP) > 0; + boolean bottomEdge = (edgeFlags & EDGE_BOTTOM) > 0; + if ((x >= this.x || (leftEdge && x <= this.x + this.width)) + && (x < this.x + this.width || (rightEdge && x >= this.x)) + && (y >= this.y || (topEdge && y <= this.y + this.height)) + && (y < this.y + this.height || (bottomEdge && y >= this.y))) { + return true; + } else { + return false; + } + } + + + /** + * Returns the square of the distance between the center of the key and the given point. + * @param x the x-coordinate of the point + * @param y the y-coordinate of the point + * @return the square of the distance of the point from the center of the key + */ + public int squaredDistanceFrom(int x, int y) { + float xDist = Math.abs((this.x + this.x + width) / 2f - x); + float yDist = Math.abs((this.y + this.y + height) / 2f - y); + return (int) (xDist * xDist + yDist * yDist); + } + + /** + * Returns the drawable state for the key, based on the current state and type of the key. + * @return the drawable state of the key. + * @see android.graphics.drawable.StateListDrawable#setState(int[]) + */ + public int[] getCurrentDrawableState() { + int[] states = KEY_STATE_NORMAL; + + if (on) { + if (pressed) { + states = KEY_STATE_PRESSED_ON; + } else { + states = KEY_STATE_NORMAL_ON; + } + } else { + if (sticky) { + if (pressed) { + states = KEY_STATE_PRESSED_OFF; + } else { + states = KEY_STATE_NORMAL_OFF; + } + } else { + if (pressed) { + states = KEY_STATE_PRESSED; + } + } + } + return states; + } + } + + /** + * Creates a keyboard from the given xml key layout file. + * @param context the application or service context + * @param xmlLayoutResId the resource file that contains the keyboard layout and keys. + */ + public Keyboard(Context context, int xmlLayoutResId) { + this(context, xmlLayoutResId, 0); + } + + /** + * Creates a keyboard from the given xml key layout file. Weeds out rows + * that have a keyboard mode defined but don't match the specified mode. + * @param context the application or service context + * @param xmlLayoutResId the resource file that contains the keyboard layout and keys. + * @param modeId keyboard mode identifier + */ + public Keyboard(Context context, int xmlLayoutResId, int modeId) { + WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); + final Display display = wm.getDefaultDisplay(); + mDisplayWidth = display.getWidth(); + mDisplayHeight = display.getHeight(); + mDefaultHorizontalGap = 0; + mDefaultWidth = mDisplayWidth / 10; + mDefaultVerticalGap = 0; + mDefaultHeight = mDefaultWidth; + mKeys = new ArrayList(); + mModifierKeys = new ArrayList(); + mKeyboardMode = modeId; + loadKeyboard(context, context.getResources().getXml(xmlLayoutResId)); + } + + /** + *

    Creates a blank keyboard from the given resource file and populates it with the specified + * characters in left-to-right, top-to-bottom fashion, using the specified number of columns. + *

    + *

    If the specified number of columns is -1, then the keyboard will fit as many keys as + * possible in each row.

    + * @param context the application or service context + * @param layoutTemplateResId the layout template file, containing no keys. + * @param characters the list of characters to display on the keyboard. One key will be created + * for each character. + * @param columns the number of columns of keys to display. If this number is greater than the + * number of keys that can fit in a row, it will be ignored. If this number is -1, the + * keyboard will fit as many keys as possible in each row. + */ + public Keyboard(Context context, int layoutTemplateResId, + CharSequence characters, int columns, int horizontalPadding) { + this(context, layoutTemplateResId); + int x = 0; + int y = 0; + int column = 0; + mTotalWidth = 0; + + Row row = new Row(this); + row.defaultHeight = mDefaultHeight; + row.defaultWidth = mDefaultWidth; + row.defaultHorizontalGap = mDefaultHorizontalGap; + row.verticalGap = mDefaultVerticalGap; + row.rowEdgeFlags = EDGE_TOP | EDGE_BOTTOM; + + final int maxColumns = columns == -1 ? Integer.MAX_VALUE : columns; + for (int i = 0; i < characters.length(); i++) { + char c = characters.charAt(i); + if (column >= maxColumns + || x + mDefaultWidth + horizontalPadding > mDisplayWidth) { + x = 0; + y += mDefaultVerticalGap + mDefaultHeight; + column = 0; + } + final Key key = new Key(row); + key.x = x; + key.y = y; + key.width = mDefaultWidth; + key.height = mDefaultHeight; + key.gap = mDefaultHorizontalGap; + key.label = String.valueOf(c); + key.codes = new int[] { c }; + column++; + x += key.width + key.gap; + mKeys.add(key); + if (x > mTotalWidth) { + mTotalWidth = x; + } + } + mTotalHeight = y + mDefaultHeight; + } + + public List getKeys() { + return mKeys; + } + + public List getModifierKeys() { + return mModifierKeys; + } + + protected int getHorizontalGap() { + return mDefaultHorizontalGap; + } + + protected void setHorizontalGap(int gap) { + mDefaultHorizontalGap = gap; + } + + protected int getVerticalGap() { + return mDefaultVerticalGap; + } + + protected void setVerticalGap(int gap) { + mDefaultVerticalGap = gap; + } + + protected int getKeyHeight() { + return mDefaultHeight; + } + + protected void setKeyHeight(int height) { + mDefaultHeight = height; + } + + protected int getKeyWidth() { + return mDefaultWidth; + } + + protected void setKeyWidth(int width) { + mDefaultWidth = width; + } + + /** + * Returns the total height of the keyboard + * @return the total height of the keyboard + */ + public int getHeight() { + return mTotalHeight; + } + + public int getMinWidth() { + return mTotalWidth; + } + + public boolean setShifted(boolean shiftState) { + if (mShiftKey != null) { + mShiftKey.on = shiftState; + } + if (mShifted != shiftState) { + mShifted = shiftState; + return true; + } + return false; + } + + public boolean isShifted() { + return mShifted; + } + + public int getShiftKeyIndex() { + return mShiftKeyIndex; + } + + protected Row createRowFromXml(Resources res, XmlResourceParser parser) { + return new Row(res, this, parser); + } + + protected Key createKeyFromXml(Resources res, Row parent, int x, int y, + XmlResourceParser parser) { + return new Key(res, parent, x, y, parser); + } + + private void loadKeyboard(Context context, XmlResourceParser parser) { + boolean inKey = false; + boolean inRow = false; + boolean leftMostKey = false; + int row = 0; + int x = 0; + int y = 0; + Key key = null; + Row currentRow = null; + Resources res = context.getResources(); + boolean skipRow = false; + + try { + int event; + while ((event = parser.next()) != XmlResourceParser.END_DOCUMENT) { + if (event == XmlResourceParser.START_TAG) { + String tag = parser.getName(); + if (TAG_ROW.equals(tag)) { + inRow = true; + x = 0; + currentRow = createRowFromXml(res, parser); + skipRow = currentRow.mode != 0 && currentRow.mode != mKeyboardMode; + if (skipRow) { + skipToEndOfRow(parser); + inRow = false; + } + } else if (TAG_KEY.equals(tag)) { + inKey = true; + key = createKeyFromXml(res, currentRow, x, y, parser); + mKeys.add(key); + if (key.codes[0] == KEYCODE_SHIFT) { + mShiftKey = key; + mShiftKeyIndex = mKeys.size()-1; + mModifierKeys.add(key); + } else if (key.codes[0] == KEYCODE_ALT) { + mModifierKeys.add(key); + } + } else if (TAG_KEYBOARD.equals(tag)) { + parseKeyboardAttributes(res, parser); + } + } else if (event == XmlResourceParser.END_TAG) { + if (inKey) { + inKey = false; + x += key.gap + key.width; + if (x > mTotalWidth) { + mTotalWidth = x; + } + } else if (inRow) { + inRow = false; + y += currentRow.verticalGap; + y += currentRow.defaultHeight; + row++; + } else { + // TODO: error or extend? + } + } + } + } catch (Exception e) { + Log.e(TAG, "Parse error:" + e); + e.printStackTrace(); + } + mTotalHeight = y - mDefaultVerticalGap; + } + + private void skipToEndOfRow(XmlResourceParser parser) + throws XmlPullParserException, IOException { + int event; + while ((event = parser.next()) != XmlResourceParser.END_DOCUMENT) { + if (event == XmlResourceParser.END_TAG + && parser.getName().equals(TAG_ROW)) { + break; + } + } + } + + private void parseKeyboardAttributes(Resources res, XmlResourceParser parser) { + TypedArray a = res.obtainAttributes(Xml.asAttributeSet(parser), + com.android.internal.R.styleable.Keyboard); + + mDefaultWidth = getDimensionOrFraction(a, + com.android.internal.R.styleable.Keyboard_keyWidth, + mDisplayWidth, mDisplayWidth / 10); + mDefaultHeight = getDimensionOrFraction(a, + com.android.internal.R.styleable.Keyboard_keyHeight, + mDisplayHeight, 50); + mDefaultHorizontalGap = getDimensionOrFraction(a, + com.android.internal.R.styleable.Keyboard_horizontalGap, + mDisplayWidth, 0); + mDefaultVerticalGap = getDimensionOrFraction(a, + com.android.internal.R.styleable.Keyboard_verticalGap, + mDisplayHeight, 0); + a.recycle(); + } + + static int getDimensionOrFraction(TypedArray a, int index, int base, int defValue) { + TypedValue value = a.peekValue(index); + if (value == null) return defValue; + if (value.type == TypedValue.TYPE_DIMENSION) { + return a.getDimensionPixelOffset(index, defValue); + } else if (value.type == TypedValue.TYPE_FRACTION) { + return (int) a.getFraction(index, base, base, defValue); + } + return defValue; + } +} diff --git a/core/java/android/inputmethodservice/KeyboardView.java b/core/java/android/inputmethodservice/KeyboardView.java new file mode 100755 index 0000000000000000000000000000000000000000..56473da3589959bf49f97e2c50a0d2fcecb1dbd1 --- /dev/null +++ b/core/java/android/inputmethodservice/KeyboardView.java @@ -0,0 +1,1049 @@ +/* + * Copyright (C) 2008-2009 Google Inc. + * + * 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 android.inputmethodservice; + +import com.android.internal.R; + +import android.content.Context; +import android.content.SharedPreferences; +import android.content.res.TypedArray; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.Rect; +import android.graphics.Paint.Align; +import android.graphics.drawable.Drawable; +import android.inputmethodservice.Keyboard.Key; +import android.os.Handler; +import android.os.Message; +import android.os.Vibrator; +import android.preference.PreferenceManager; +import android.util.AttributeSet; +import android.view.GestureDetector; +import android.view.Gravity; +import android.view.LayoutInflater; +import android.view.MotionEvent; +import android.view.View; +import android.view.ViewGroup.LayoutParams; +import android.widget.Button; +import android.widget.PopupWindow; +import android.widget.TextView; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * A view that renders a virtual {@link Keyboard}. It handles rendering of keys and + * detecting key presses and touch movements. + * + * @attr ref android.R.styleable#KeyboardView_keyBackground + * @attr ref android.R.styleable#KeyboardView_keyPreviewLayout + * @attr ref android.R.styleable#KeyboardView_keyPreviewOffset + * @attr ref android.R.styleable#KeyboardView_labelTextSize + * @attr ref android.R.styleable#KeyboardView_keyTextSize + * @attr ref android.R.styleable#KeyboardView_keyTextColor + * @attr ref android.R.styleable#KeyboardView_verticalCorrection + * @attr ref android.R.styleable#KeyboardView_popupLayout + */ +public class KeyboardView extends View implements View.OnClickListener { + + /** + * Listener for virtual keyboard events. + */ + public interface OnKeyboardActionListener { + /** + * Send a key press to the listener. + * @param primaryCode this is the key that was pressed + * @param keyCodes the codes for all the possible alternative keys + * with the primary code being the first. If the primary key code is + * a single character such as an alphabet or number or symbol, the alternatives + * will include other characters that may be on the same key or adjacent keys. + * These codes are useful to correct for accidental presses of a key adjacent to + * the intended key. + */ + void onKey(int primaryCode, int[] keyCodes); + + /** + * Called when the user quickly moves the finger from right to left. + */ + void swipeLeft(); + + /** + * Called when the user quickly moves the finger from left to right. + */ + void swipeRight(); + + /** + * Called when the user quickly moves the finger from up to down. + */ + void swipeDown(); + + /** + * Called when the user quickly moves the finger from down to up. + */ + void swipeUp(); + } + + private static final boolean DEBUG = false; + private static final int NOT_A_KEY = -1; + private static final int[] KEY_DELETE = { Keyboard.KEYCODE_DELETE }; + private static final int[] LONG_PRESSABLE_STATE_SET = { R.attr.state_long_pressable }; + + private Keyboard mKeyboard; + private int mCurrentKeyIndex = NOT_A_KEY; + private int mLabelTextSize; + private int mKeyTextSize; + private int mKeyTextColor; + + private TextView mPreviewText; + private PopupWindow mPreviewPopup; + private int mPreviewTextSizeLarge; + private int mPreviewOffset; + private int mPreviewHeight; + private int[] mOffsetInWindow; + + private PopupWindow mPopupKeyboard; + private View mMiniKeyboardContainer; + private KeyboardView mMiniKeyboard; + private boolean mMiniKeyboardOnScreen; + private View mPopupParent; + private int mMiniKeyboardOffsetX; + private int mMiniKeyboardOffsetY; + private Map mMiniKeyboardCache; + private int[] mWindowOffset; + + /** Listener for {@link OnKeyboardActionListener}. */ + private OnKeyboardActionListener mKeyboardActionListener; + + private static final int MSG_REMOVE_PREVIEW = 1; + private static final int MSG_REPEAT = 2; + + private int mVerticalCorrection; + private int mProximityThreshold; + + private boolean mPreviewCentered = false; + private boolean mShowPreview = true; + private boolean mShowTouchPoints = false; + private int mPopupPreviewX; + private int mPopupPreviewY; + + private int mLastX; + private int mLastY; + private int mStartX; + private int mStartY; + + private boolean mVibrateOn; + private boolean mSoundOn; + private boolean mProximityCorrectOn; + + private Paint mPaint; + private Rect mPadding; + + private long mDownTime; + private long mLastMoveTime; + private int mLastKey; + private int mLastCodeX; + private int mLastCodeY; + private int mCurrentKey = NOT_A_KEY; + private long mLastKeyTime; + private long mCurrentKeyTime; + private int[] mKeyIndices = new int[12]; + private GestureDetector mGestureDetector; + private int mPopupX; + private int mPopupY; + private int mRepeatKeyIndex = NOT_A_KEY; + private int mPopupLayout; + private boolean mAbortKey; + + private Drawable mKeyBackground; + + private static final String PREF_VIBRATE_ON = "vibrate_on"; + private static final String PREF_SOUND_ON = "sound_on"; + private static final String PREF_PROXIMITY_CORRECTION = "hit_correction"; + + private static final int REPEAT_INTERVAL = 50; // ~20 keys per second + private static final int REPEAT_START_DELAY = 400; + + private Vibrator mVibrator; + private long[] mVibratePattern = new long[] {1, 20}; + + private static int MAX_NEARBY_KEYS = 12; + private int[] mDistances = new int[MAX_NEARBY_KEYS]; + + // For multi-tap + private int mLastSentIndex; + private int mTapCount; + private long mLastTapTime; + private boolean mInMultiTap; + private static final int MULTITAP_INTERVAL = 800; // milliseconds + private StringBuilder mPreviewLabel = new StringBuilder(1); + + Handler mHandler = new Handler() { + @Override + public void handleMessage(Message msg) { + switch (msg.what) { + case MSG_REMOVE_PREVIEW: + mPreviewText.setVisibility(INVISIBLE); + break; + case MSG_REPEAT: + if (repeatKey()) { + Message repeat = Message.obtain(this, MSG_REPEAT); + sendMessageDelayed(repeat, REPEAT_INTERVAL); + } + break; + } + + } + }; + + public KeyboardView(Context context, AttributeSet attrs) { + this(context, attrs, com.android.internal.R.attr.keyboardViewStyle); + } + + public KeyboardView(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + + TypedArray a = + context.obtainStyledAttributes( + attrs, android.R.styleable.KeyboardView, defStyle, 0); + + LayoutInflater inflate = + (LayoutInflater) context + .getSystemService(Context.LAYOUT_INFLATER_SERVICE); + + int previewLayout = 0; + int keyTextSize = 0; + + int n = a.getIndexCount(); + + for (int i = 0; i < n; i++) { + int attr = a.getIndex(i); + + switch (attr) { + case com.android.internal.R.styleable.KeyboardView_keyBackground: + mKeyBackground = a.getDrawable(attr); + break; + case com.android.internal.R.styleable.KeyboardView_verticalCorrection: + mVerticalCorrection = a.getDimensionPixelOffset(attr, 0); + break; + case com.android.internal.R.styleable.KeyboardView_keyPreviewLayout: + previewLayout = a.getResourceId(attr, 0); + break; + case com.android.internal.R.styleable.KeyboardView_keyPreviewOffset: + mPreviewOffset = a.getDimensionPixelOffset(attr, 0); + break; + case com.android.internal.R.styleable.KeyboardView_keyPreviewHeight: + mPreviewHeight = a.getDimensionPixelSize(attr, 80); + break; + case com.android.internal.R.styleable.KeyboardView_keyTextSize: + mKeyTextSize = a.getDimensionPixelSize(attr, 18); + break; + case com.android.internal.R.styleable.KeyboardView_keyTextColor: + mKeyTextColor = a.getColor(attr, 0xFF000000); + break; + case com.android.internal.R.styleable.KeyboardView_labelTextSize: + mLabelTextSize = a.getDimensionPixelSize(attr, 14); + break; + case com.android.internal.R.styleable.KeyboardView_popupLayout: + mPopupLayout = a.getResourceId(attr, 0); + break; + } + } + + // Get the settings preferences + SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context); + mVibrateOn = sp.getBoolean(PREF_VIBRATE_ON, mVibrateOn); + mSoundOn = sp.getBoolean(PREF_SOUND_ON, mSoundOn); + mProximityCorrectOn = sp.getBoolean(PREF_PROXIMITY_CORRECTION, true); + + mPreviewPopup = new PopupWindow(context); + if (previewLayout != 0) { + mPreviewText = (TextView) inflate.inflate(previewLayout, null); + mPreviewTextSizeLarge = (int) mPreviewText.getTextSize(); + mPreviewPopup.setContentView(mPreviewText); + mPreviewPopup.setBackgroundDrawable(null); + } else { + mShowPreview = false; + } + + mPreviewPopup.setTouchable(false); + + mPopupKeyboard = new PopupWindow(context); + mPopupKeyboard.setBackgroundDrawable(null); + //mPopupKeyboard.setClippingEnabled(false); + + mPopupParent = this; + //mPredicting = true; + + mPaint = new Paint(); + mPaint.setAntiAlias(true); + mPaint.setTextSize(keyTextSize); + mPaint.setTextAlign(Align.CENTER); + + mPadding = new Rect(0, 0, 0, 0); + mMiniKeyboardCache = new HashMap(); + mKeyBackground.getPadding(mPadding); + + resetMultiTap(); + initGestureDetector(); + } + + private void initGestureDetector() { + mGestureDetector = new GestureDetector(new GestureDetector.SimpleOnGestureListener() { + @Override + public boolean onFling(MotionEvent me1, MotionEvent me2, + float velocityX, float velocityY) { + if (velocityX > 400 && Math.abs(velocityY) < 400) { + swipeRight(); + return true; + } else if (velocityX < -400 && Math.abs(velocityY) < 400) { + swipeLeft(); + return true; + } else if (velocityY < -400 && Math.abs(velocityX) < 400) { + swipeUp(); + return true; + } else if (velocityY > 400 && Math.abs(velocityX) < 400) { + swipeDown(); + return true; + } + return false; + } + + @Override + public void onLongPress(MotionEvent me) { + openPopupIfRequired(me); + } + }); + } + + public void setOnKeyboardActionListener(OnKeyboardActionListener listener) { + mKeyboardActionListener = listener; + } + + /** + * Returns the {@link OnKeyboardActionListener} object. + * @return the listener attached to this keyboard + */ + protected OnKeyboardActionListener getOnKeyboardActionListener() { + return mKeyboardActionListener; + } + + /** + * Attaches a keyboard to this view. The keyboard can be switched at any time and the + * view will re-layout itself to accommodate the keyboard. + * @see Keyboard + * @see #getKeyboard() + * @param keyboard the keyboard to display in this view + */ + public void setKeyboard(Keyboard keyboard) { + mKeyboard = keyboard; + requestLayout(); + invalidate(); + computeProximityThreshold(keyboard); + } + + /** + * Returns the current keyboard being displayed by this view. + * @return the currently attached keyboard + * @see #setKeyboard(Keyboard) + */ + public Keyboard getKeyboard() { + return mKeyboard; + } + + /** + * Sets the state of the shift key of the keyboard, if any. + * @param shifted whether or not to enable the state of the shift key + * @return true if the shift key state changed, false if there was no change + * @see KeyboardView#isShifted() + */ + public boolean setShifted(boolean shifted) { + if (mKeyboard != null) { + if (mKeyboard.setShifted(shifted)) { + // The whole keyboard probably needs to be redrawn + invalidate(); + return true; + } + } + return false; + } + + /** + * Returns the state of the shift key of the keyboard, if any. + * @return true if the shift is in a pressed state, false otherwise. If there is + * no shift key on the keyboard or there is no keyboard attached, it returns false. + * @see KeyboardView#setShifted(boolean) + */ + public boolean isShifted() { + if (mKeyboard != null) { + return mKeyboard.isShifted(); + } + return false; + } + + /** + * Enables or disables the key feedback popup. This is a popup that shows a magnified + * version of the depressed key. By default the preview is enabled. + * @param previewEnabled whether or not to enable the key feedback popup + * @see #isPreviewEnabled() + */ + public void setPreviewEnabled(boolean previewEnabled) { + mShowPreview = previewEnabled; + } + + /** + * Returns the enabled state of the key feedback popup. + * @return whether or not the key feedback popup is enabled + * @see #setPreviewEnabled(boolean) + */ + public boolean isPreviewEnabled() { + return mShowPreview; + } + + public void setVerticalCorrection(int verticalOffset) { + + } + public void setPopupParent(View v) { + mPopupParent = v; + } + + public void setPopupOffset(int x, int y) { + mMiniKeyboardOffsetX = x; + mMiniKeyboardOffsetY = y; + if (mPreviewPopup.isShowing()) { + mPreviewPopup.dismiss(); + } + } + + /** + * Popup keyboard close button clicked. + * @hide + */ + public void onClick(View v) { + dismissPopupKeyboard(); + } + + private CharSequence adjustCase(CharSequence label) { + if (mKeyboard.isShifted() && label != null && label.length() == 1 + && Character.isLowerCase(label.charAt(0))) { + label = label.toString().toUpperCase(); + } + return label; + } + + @Override + public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + // Round up a little + if (mKeyboard == null) { + setMeasuredDimension(mPaddingLeft + mPaddingRight, mPaddingTop + mPaddingBottom); + } else { + int width = mKeyboard.getMinWidth() + mPaddingLeft + mPaddingRight; + if (MeasureSpec.getSize(widthMeasureSpec) < width + 10) { + width = MeasureSpec.getSize(widthMeasureSpec); + } + setMeasuredDimension(width, mKeyboard.getHeight() + mPaddingTop + mPaddingBottom); + } + } + + /** + * Compute the average distance between adjacent keys (horizontally and vertically) + * and square it to get the proximity threshold. We use a square here and in computing + * the touch distance from a key's center to avoid taking a square root. + * @param keyboard + */ + private void computeProximityThreshold(Keyboard keyboard) { + if (keyboard == null) return; + List keys = keyboard.getKeys(); + if (keys == null) return; + int length = keys.size(); + int dimensionSum = 0; + for (int i = 0; i < length; i++) { + Key key = keys.get(i); + dimensionSum += key.width + key.gap + key.height; + } + if (dimensionSum < 0 || length == 0) return; + mProximityThreshold = dimensionSum / (length * 2); + mProximityThreshold *= mProximityThreshold; // Square it + } + + @Override + public void onDraw(Canvas canvas) { + super.onDraw(canvas); + if (mKeyboard == null) return; + + final Paint paint = mPaint; + //final int descent = (int) paint.descent(); + final Drawable keyBackground = mKeyBackground; + final Rect padding = mPadding; + final int kbdPaddingLeft = mPaddingLeft; + final int kbdPaddingTop = mPaddingTop; + List keys = mKeyboard.getKeys(); + //canvas.translate(0, mKeyboardPaddingTop); + paint.setAlpha(255); + paint.setColor(mKeyTextColor); + + final int keyCount = keys.size(); + for (int i = 0; i < keyCount; i++) { + final Key key = keys.get(i); + int[] drawableState = key.getCurrentDrawableState(); + keyBackground.setState(drawableState); + + // Switch the character to uppercase if shift is pressed + String label = key.label == null? null : adjustCase(key.label).toString(); + + final Rect bounds = keyBackground.getBounds(); + if (key.width != bounds.right || + key.height != bounds.bottom) { + keyBackground.setBounds(0, 0, key.width, key.height); + } + canvas.translate(key.x + kbdPaddingLeft, key.y + kbdPaddingTop); + keyBackground.draw(canvas); + + if (label != null) { + // For characters, use large font. For labels like "Done", use small font. + if (label.length() > 1 && key.codes.length < 2) { + paint.setTextSize(mLabelTextSize); + paint.setFakeBoldText(true); + } else { + paint.setTextSize(mKeyTextSize); + paint.setFakeBoldText(false); + } + // Draw a drop shadow for the text + paint.setShadowLayer(3f, 0, 0, 0xCC000000); + // Draw the text + canvas.drawText(label, + (key.width - padding.left - padding.right) / 2 + + padding.left, + (key.height - padding.top - padding.bottom) / 2 + + (paint.getTextSize() - paint.descent()) / 2 + padding.top, + paint); + // Turn off drop shadow + paint.setShadowLayer(0, 0, 0, 0); + } else if (key.icon != null) { + final int drawableX = (key.width - padding.left - padding.right + - key.icon.getIntrinsicWidth()) / 2 + padding.left; + final int drawableY = (key.height - padding.top - padding.bottom + - key.icon.getIntrinsicHeight()) / 2 + padding.top; + canvas.translate(drawableX, drawableY); + key.icon.setBounds(0, 0, + key.icon.getIntrinsicWidth(), key.icon.getIntrinsicHeight()); + key.icon.draw(canvas); + canvas.translate(-drawableX, -drawableY); + } + canvas.translate(-key.x - kbdPaddingLeft, -key.y - kbdPaddingTop); + } + + // Overlay a dark rectangle to dim the keyboard + if (mMiniKeyboardOnScreen) { + paint.setColor(0xA0000000); + canvas.drawRect(0, 0, getWidth(), getHeight(), paint); + } + + if (DEBUG && mShowTouchPoints) { + paint.setAlpha(128); + paint.setColor(0xFFFF0000); + canvas.drawCircle(mStartX, mStartY, 3, paint); + canvas.drawLine(mStartX, mStartY, mLastX, mLastY, paint); + paint.setColor(0xFF0000FF); + canvas.drawCircle(mLastX, mLastY, 3, paint); + paint.setColor(0xFF00FF00); + canvas.drawCircle((mStartX + mLastX) / 2, (mStartY + mLastY) / 2, 2, paint); + } + } + + private void playKeyClick() { + if (mSoundOn) { + playSoundEffect(0); + } + } + + private void vibrate() { + if (!mVibrateOn) { + return; + } + if (mVibrator == null) { + mVibrator = new Vibrator(); + } + mVibrator.vibrate(mVibratePattern, -1); + } + + private int getKeyIndices(int x, int y, int[] allKeys) { + final List keys = mKeyboard.getKeys(); + final boolean shifted = mKeyboard.isShifted(); + int primaryIndex = NOT_A_KEY; + int closestKey = NOT_A_KEY; + int closestKeyDist = mProximityThreshold + 1; + java.util.Arrays.fill(mDistances, Integer.MAX_VALUE); + final int keyCount = keys.size(); + for (int i = 0; i < keyCount; i++) { + final Key key = keys.get(i); + int dist = 0; + boolean isInside = key.isInside(x,y); + if (((mProximityCorrectOn + && (dist = key.squaredDistanceFrom(x, y)) < mProximityThreshold) + || isInside) + && key.codes[0] > 32) { + // Find insertion point + final int nCodes = key.codes.length; + if (dist < closestKeyDist) { + closestKeyDist = dist; + closestKey = i; + } + + if (allKeys == null) continue; + + for (int j = 0; j < mDistances.length; j++) { + if (mDistances[j] > dist) { + // Make space for nCodes codes + System.arraycopy(mDistances, j, mDistances, j + nCodes, + mDistances.length - j - nCodes); + System.arraycopy(allKeys, j, allKeys, j + nCodes, + allKeys.length - j - nCodes); + for (int c = 0; c < nCodes; c++) { + allKeys[j + c] = key.codes[c]; + if (shifted) { + //allKeys[j + c] = Character.toUpperCase(key.codes[c]); + } + mDistances[j + c] = dist; + } + break; + } + } + } + + if (isInside) { + primaryIndex = i; + } + } + if (primaryIndex == NOT_A_KEY) { + primaryIndex = closestKey; + } + return primaryIndex; + } + + private void detectAndSendKey(int x, int y, long eventTime) { + int index = mCurrentKey; + if (index != NOT_A_KEY) { + vibrate(); + final Key key = mKeyboard.getKeys().get(index); + if (key.text != null) { + for (int i = 0; i < key.text.length(); i++) { + mKeyboardActionListener.onKey(key.text.charAt(i), key.codes); + } + } else { + int code = key.codes[0]; + //TextEntryState.keyPressedAt(key, x, y); + int[] codes = new int[MAX_NEARBY_KEYS]; + Arrays.fill(codes, NOT_A_KEY); + getKeyIndices(x, y, codes); + // Multi-tap + if (mInMultiTap) { + if (mTapCount != -1) { + mKeyboardActionListener.onKey(Keyboard.KEYCODE_DELETE, KEY_DELETE); + } else { + mTapCount = 0; + } + code = key.codes[mTapCount]; + } + mKeyboardActionListener.onKey(code, codes); + } + mLastSentIndex = index; + mLastTapTime = eventTime; + } + } + + /** + * Handle multi-tap keys by producing the key label for the current multi-tap state. + */ + private CharSequence getPreviewText(Key key) { + if (mInMultiTap) { + // Multi-tap + mPreviewLabel.setLength(0); + mPreviewLabel.append((char) key.codes[mTapCount < 0 ? 0 : mTapCount]); + return adjustCase(mPreviewLabel); + } else { + return adjustCase(key.label); + } + } + + private void showPreview(int keyIndex) { + int oldKeyIndex = mCurrentKeyIndex; + final PopupWindow previewPopup = mPreviewPopup; + + mCurrentKeyIndex = keyIndex; + // Release the old key and press the new key + final List keys = mKeyboard.getKeys(); + if (oldKeyIndex != mCurrentKeyIndex) { + if (oldKeyIndex != NOT_A_KEY && keys.size() > oldKeyIndex) { + keys.get(oldKeyIndex).onReleased(mCurrentKeyIndex == NOT_A_KEY); + invalidateKey(oldKeyIndex); + } + if (mCurrentKeyIndex != NOT_A_KEY && keys.size() > mCurrentKeyIndex) { + keys.get(mCurrentKeyIndex).onPressed(); + invalidateKey(mCurrentKeyIndex); + } + } + // If key changed and preview is on ... + if (oldKeyIndex != mCurrentKeyIndex && mShowPreview) { + if (previewPopup.isShowing()) { + if (keyIndex == NOT_A_KEY) { + mHandler.sendMessageDelayed(mHandler + .obtainMessage(MSG_REMOVE_PREVIEW), 60); + } + } + if (keyIndex != NOT_A_KEY) { + Key key = keys.get(keyIndex); + if (key.icon != null) { + mPreviewText.setCompoundDrawables(null, null, null, + key.iconPreview != null ? key.iconPreview : key.icon); + mPreviewText.setText(null); + } else { + mPreviewText.setCompoundDrawables(null, null, null, null); + mPreviewText.setText(getPreviewText(key)); + if (key.label.length() > 1 && key.codes.length < 2) { + mPreviewText.setTextSize(mLabelTextSize); + } else { + mPreviewText.setTextSize(mPreviewTextSizeLarge); + } + } + mPreviewText.measure(MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED), + MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED)); + int popupWidth = Math.max(mPreviewText.getMeasuredWidth(), key.width + + mPreviewText.getPaddingLeft() + mPreviewText.getPaddingRight()); + final int popupHeight = mPreviewHeight; + LayoutParams lp = mPreviewText.getLayoutParams(); + if (lp != null) { + lp.width = popupWidth; + lp.height = popupHeight; + } + previewPopup.setWidth(popupWidth); + previewPopup.setHeight(popupHeight); + if (!mPreviewCentered) { + mPopupPreviewX = key.x - mPreviewText.getPaddingLeft() + mPaddingLeft; + mPopupPreviewY = key.y - popupHeight + mPreviewOffset; + } else { + // TODO: Fix this if centering is brought back + mPopupPreviewX = 160 - mPreviewText.getMeasuredWidth() / 2; + mPopupPreviewY = - mPreviewText.getMeasuredHeight(); + } + mHandler.removeMessages(MSG_REMOVE_PREVIEW); + if (mOffsetInWindow == null) { + mOffsetInWindow = new int[2]; + getLocationInWindow(mOffsetInWindow); + mOffsetInWindow[0] += mMiniKeyboardOffsetX; // Offset may be zero + mOffsetInWindow[1] += mMiniKeyboardOffsetY; // Offset may be zero + } + // Set the preview background state + mPreviewText.getBackground().setState( + key.popupResId != 0 ? LONG_PRESSABLE_STATE_SET : EMPTY_STATE_SET); + if (previewPopup.isShowing()) { + previewPopup.update(mPopupPreviewX + mOffsetInWindow[0], + mPopupPreviewY + mOffsetInWindow[1], + popupWidth, popupHeight); + } else { + previewPopup.showAtLocation(mPopupParent, Gravity.NO_GRAVITY, + mPopupPreviewX + mOffsetInWindow[0], + mPopupPreviewY + mOffsetInWindow[1]); + } + mPreviewText.setVisibility(VISIBLE); + } + } + } + + private void invalidateKey(int keyIndex) { + if (keyIndex < 0 || keyIndex >= mKeyboard.getKeys().size()) { + return; + } + final Key key = mKeyboard.getKeys().get(keyIndex); + invalidate(key.x + mPaddingLeft, key.y + mPaddingTop, + key.x + key.width + mPaddingLeft, key.y + key.height + mPaddingTop); + } + + private boolean openPopupIfRequired(MotionEvent me) { + // Check if we have a popup layout specified first. + if (mPopupLayout == 0) { + return false; + } + if (mCurrentKey < 0 || mCurrentKey >= mKeyboard.getKeys().size()) { + return false; + } + + Key popupKey = mKeyboard.getKeys().get(mCurrentKey); + boolean result = onLongPress(popupKey); + if (result) { + mAbortKey = true; + showPreview(NOT_A_KEY); + } + return result; + } + + /** + * Called when a key is long pressed. By default this will open any popup keyboard associated + * with this key through the attributes popupLayout and popupCharacters. + * @param popupKey the key that was long pressed + * @return true if the long press is handled, false otherwise. Subclasses should call the + * method on the base class if the subclass doesn't wish to handle the call. + */ + protected boolean onLongPress(Key popupKey) { + int popupKeyboardId = popupKey.popupResId; + + if (popupKeyboardId != 0) { + mMiniKeyboardContainer = mMiniKeyboardCache.get(popupKey); + if (mMiniKeyboardContainer == null) { + LayoutInflater inflater = (LayoutInflater) getContext().getSystemService( + Context.LAYOUT_INFLATER_SERVICE); + mMiniKeyboardContainer = inflater.inflate(mPopupLayout, null); + mMiniKeyboard = (KeyboardView) mMiniKeyboardContainer.findViewById( + com.android.internal.R.id.keyboardView); + View closeButton = mMiniKeyboardContainer.findViewById( + com.android.internal.R.id.button_close); + if (closeButton != null) closeButton.setOnClickListener(this); + mMiniKeyboard.setOnKeyboardActionListener(new OnKeyboardActionListener() { + public void onKey(int primaryCode, int[] keyCodes) { + mKeyboardActionListener.onKey(primaryCode, keyCodes); + dismissPopupKeyboard(); + } + + public void swipeLeft() { } + public void swipeRight() { } + public void swipeUp() { } + public void swipeDown() { } + }); + //mInputView.setSuggest(mSuggest); + Keyboard keyboard; + if (popupKey.popupCharacters != null) { + keyboard = new Keyboard(getContext(), popupKeyboardId, + popupKey.popupCharacters, -1, getPaddingLeft() + getPaddingRight()); + } else { + keyboard = new Keyboard(getContext(), popupKeyboardId); + } + mMiniKeyboard.setKeyboard(keyboard); + mMiniKeyboard.setPopupParent(this); + mMiniKeyboardContainer.measure( + MeasureSpec.makeMeasureSpec(getWidth(), MeasureSpec.AT_MOST), + MeasureSpec.makeMeasureSpec(getHeight(), MeasureSpec.AT_MOST)); + + mMiniKeyboardCache.put(popupKey, mMiniKeyboardContainer); + } else { + mMiniKeyboard = (KeyboardView) mMiniKeyboardContainer.findViewById( + com.android.internal.R.id.keyboardView); + } + if (mWindowOffset == null) { + mWindowOffset = new int[2]; + getLocationInWindow(mWindowOffset); + } + mPopupX = popupKey.x + mPaddingLeft; + mPopupY = popupKey.y + mPaddingTop; + mPopupX = mPopupX + popupKey.width - mMiniKeyboardContainer.getMeasuredWidth(); + mPopupY = mPopupY - mMiniKeyboardContainer.getMeasuredHeight(); + final int x = mPopupX + mMiniKeyboardContainer.getPaddingRight() + mWindowOffset[0]; + final int y = mPopupY + mMiniKeyboardContainer.getPaddingBottom() + mWindowOffset[1]; + mMiniKeyboard.setPopupOffset(x < 0 ? 0 : x, y); + mMiniKeyboard.setShifted(isShifted()); + mPopupKeyboard.setContentView(mMiniKeyboardContainer); + mPopupKeyboard.setWidth(mMiniKeyboardContainer.getMeasuredWidth()); + mPopupKeyboard.setHeight(mMiniKeyboardContainer.getMeasuredHeight()); + mPopupKeyboard.showAtLocation(this, Gravity.NO_GRAVITY, x, y); + mMiniKeyboardOnScreen = true; + //mMiniKeyboard.onTouchEvent(getTranslatedEvent(me)); + invalidate(); + return true; + } + return false; + } + + @Override + public boolean onTouchEvent(MotionEvent me) { + int touchX = (int) me.getX() - mPaddingLeft; + int touchY = (int) me.getY() + mVerticalCorrection - mPaddingTop; + int action = me.getAction(); + long eventTime = me.getEventTime(); + int keyIndex = getKeyIndices(touchX, touchY, null); + + if (mGestureDetector.onTouchEvent(me)) { + showPreview(NOT_A_KEY); + mHandler.removeMessages(MSG_REPEAT); + return true; + } + + // Needs to be called after the gesture detector gets a turn, as it may have + // displayed the mini keyboard + if (mMiniKeyboardOnScreen) { + return true; + } + + switch (action) { + case MotionEvent.ACTION_DOWN: + mAbortKey = false; + mStartX = touchX; + mStartY = touchY; + mLastCodeX = touchX; + mLastCodeY = touchY; + mLastKeyTime = 0; + mCurrentKeyTime = 0; + mLastKey = NOT_A_KEY; + mCurrentKey = keyIndex; + mDownTime = me.getEventTime(); + mLastMoveTime = mDownTime; + checkMultiTap(eventTime, keyIndex); + if (mCurrentKey >= 0 && mKeyboard.getKeys().get(mCurrentKey).repeatable) { + mRepeatKeyIndex = mCurrentKey; + repeatKey(); + Message msg = mHandler.obtainMessage(MSG_REPEAT); + mHandler.sendMessageDelayed(msg, REPEAT_START_DELAY); + } + showPreview(keyIndex); + playKeyClick(); + vibrate(); + break; + + case MotionEvent.ACTION_MOVE: + if (keyIndex != NOT_A_KEY) { + if (mCurrentKey == NOT_A_KEY) { + mCurrentKey = keyIndex; + mCurrentKeyTime = eventTime - mDownTime; + } else { + if (keyIndex == mCurrentKey) { + mCurrentKeyTime += eventTime - mLastMoveTime; + } else { + resetMultiTap(); + mLastKey = mCurrentKey; + mLastCodeX = mLastX; + mLastCodeY = mLastY; + mLastKeyTime = + mCurrentKeyTime + eventTime - mLastMoveTime; + mCurrentKey = keyIndex; + mCurrentKeyTime = 0; + } + } + if (keyIndex != mRepeatKeyIndex) { + mHandler.removeMessages(MSG_REPEAT); + mRepeatKeyIndex = NOT_A_KEY; + } + } + showPreview(keyIndex); + break; + + case MotionEvent.ACTION_UP: + mHandler.removeMessages(MSG_REPEAT); + if (keyIndex == mCurrentKey) { + mCurrentKeyTime += eventTime - mLastMoveTime; + } else { + resetMultiTap(); + mLastKey = mCurrentKey; + mLastKeyTime = mCurrentKeyTime + eventTime - mLastMoveTime; + mCurrentKey = keyIndex; + mCurrentKeyTime = 0; + } + if (mCurrentKeyTime < mLastKeyTime && mLastKey != NOT_A_KEY) { + mCurrentKey = mLastKey; + touchX = mLastCodeX; + touchY = mLastCodeY; + } + showPreview(NOT_A_KEY); + Arrays.fill(mKeyIndices, NOT_A_KEY); + invalidateKey(keyIndex); + // If we're not on a repeating key (which sends on a DOWN event) + if (mRepeatKeyIndex == NOT_A_KEY && !mMiniKeyboardOnScreen && !mAbortKey) { + detectAndSendKey(touchX, touchY, eventTime); + } + mRepeatKeyIndex = NOT_A_KEY; + break; + } + mLastX = touchX; + mLastY = touchY; + return true; + } + + private boolean repeatKey() { + Key key = mKeyboard.getKeys().get(mRepeatKeyIndex); + detectAndSendKey(key.x, key.y, mLastTapTime); + return true; + } + + protected void swipeRight() { + mKeyboardActionListener.swipeRight(); + } + + protected void swipeLeft() { + mKeyboardActionListener.swipeLeft(); + } + + protected void swipeUp() { + mKeyboardActionListener.swipeUp(); + } + + protected void swipeDown() { + mKeyboardActionListener.swipeDown(); + } + + public void closing() { + if (mPreviewPopup.isShowing()) { + mPreviewPopup.dismiss(); + } + dismissPopupKeyboard(); + } + + @Override + public void onDetachedFromWindow() { + super.onDetachedFromWindow(); + closing(); + } + + private void dismissPopupKeyboard() { + if (mPopupKeyboard.isShowing()) { + mPopupKeyboard.dismiss(); + mMiniKeyboardOnScreen = false; + invalidate(); + } + } + + public boolean handleBack() { + if (mPopupKeyboard.isShowing()) { + dismissPopupKeyboard(); + return true; + } + return false; + } + + private void resetMultiTap() { + mLastSentIndex = NOT_A_KEY; + mTapCount = 0; + mLastTapTime = -1; + mInMultiTap = false; + } + + private void checkMultiTap(long eventTime, int keyIndex) { + if (keyIndex == NOT_A_KEY) return; + Key key = mKeyboard.getKeys().get(keyIndex); + if (key.codes.length > 1) { + mInMultiTap = true; + if (eventTime < mLastTapTime + MULTITAP_INTERVAL + && keyIndex == mLastSentIndex) { + mTapCount = (mTapCount + 1) % key.codes.length; + return; + } else { + mTapCount = -1; + return; + } + } + if (eventTime > mLastTapTime + MULTITAP_INTERVAL || keyIndex != mLastSentIndex) { + resetMultiTap(); + } + } +} diff --git a/core/java/android/inputmethodservice/SoftInputWindow.java b/core/java/android/inputmethodservice/SoftInputWindow.java new file mode 100644 index 0000000000000000000000000000000000000000..9ff1665988dad640c6a78e7a15d3de0b00fa38d4 --- /dev/null +++ b/core/java/android/inputmethodservice/SoftInputWindow.java @@ -0,0 +1,151 @@ +/* + * Copyright (C) 2007-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 android.inputmethodservice; + +import android.app.Dialog; +import android.content.Context; +import android.os.IBinder; +import android.view.Gravity; +import android.view.WindowManager; + +/** + * A SoftInputWindow is a Dialog that is intended to be used for a top-level input + * method window. It will be displayed along the edge of the screen, moving + * the application user interface away from it so that the focused item is + * always visible. + */ +class SoftInputWindow extends Dialog { + + /** + * Create a DockWindow that uses the default style. + * + * @param context The Context the DockWindow is to run it. In particular, it + * uses the window manager and theme in this context to present its + * UI. + */ + public SoftInputWindow(Context context) { + super(context, com.android.internal.R.style.Theme_InputMethod); + initDockWindow(); + } + + public void setToken(IBinder token) { + WindowManager.LayoutParams lp = getWindow().getAttributes(); + lp.token = token; + getWindow().setAttributes(lp); + } + + /** + * Create a DockWindow that uses a custom style. + * + * @param context The Context in which the DockWindow should run. In + * particular, it uses the window manager and theme from this context + * to present its UI. + * @param theme A style resource describing the theme to use for the window. + * See Style + * and Theme Resources for more information about defining and + * using styles. This theme is applied on top of the current theme in + * context. If 0, the default dialog theme will be used. + */ + public SoftInputWindow(Context context, int theme) { + super(context, theme); + initDockWindow(); + } + + /** + * Get the size of the DockWindow. + * + * @return If the DockWindow sticks to the top or bottom of the screen, the + * return value is the height of the DockWindow, and its width is + * equal to the width of the screen; If the DockWindow sticks to the + * left or right of the screen, the return value is the width of the + * DockWindow, and its height is equal to the height of the screen. + */ + public int getSize() { + WindowManager.LayoutParams lp = getWindow().getAttributes(); + + if (lp.gravity == Gravity.TOP || lp.gravity == Gravity.BOTTOM) { + return lp.height; + } else { + return lp.width; + } + } + + /** + * Set the size of the DockWindow. + * + * @param size If the DockWindow sticks to the top or bottom of the screen, + * size is the height of the DockWindow, and its width is + * equal to the width of the screen; If the DockWindow sticks to the + * left or right of the screen, size is the width of the + * DockWindow, and its height is equal to the height of the screen. + */ + public void setSize(int size) { + WindowManager.LayoutParams lp = getWindow().getAttributes(); + + if (lp.gravity == Gravity.TOP || lp.gravity == Gravity.BOTTOM) { + lp.width = -1; + lp.height = size; + } else { + lp.width = size; + lp.height = -1; + } + getWindow().setAttributes(lp); + } + + /** + * Set which boundary of the screen the DockWindow sticks to. + * + * @param gravity The boundary of the screen to stick. See {#link + * android.view.Gravity.LEFT}, {#link android.view.Gravity.TOP}, + * {#link android.view.Gravity.BOTTOM}, {#link + * android.view.Gravity.RIGHT}. + */ + public void setGravity(int gravity) { + WindowManager.LayoutParams lp = getWindow().getAttributes(); + + boolean oldIsVertical = (lp.gravity == Gravity.TOP || lp.gravity == Gravity.BOTTOM); + + lp.gravity = gravity; + + boolean newIsVertical = (lp.gravity == Gravity.TOP || lp.gravity == Gravity.BOTTOM); + + if (oldIsVertical != newIsVertical) { + int tmp = lp.width; + lp.width = lp.height; + lp.height = tmp; + getWindow().setAttributes(lp); + } + } + + private void initDockWindow() { + WindowManager.LayoutParams lp = getWindow().getAttributes(); + + lp.type = WindowManager.LayoutParams.TYPE_INPUT_METHOD; + lp.setTitle("InputMethod"); + + lp.gravity = Gravity.BOTTOM; + lp.width = -1; + + getWindow().setAttributes(lp); + getWindow().setFlags( + WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN | + WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE, + WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN | + WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | + WindowManager.LayoutParams.FLAG_DIM_BEHIND); + } +} diff --git a/core/java/android/inputmethodservice/package.html b/core/java/android/inputmethodservice/package.html new file mode 100644 index 0000000000000000000000000000000000000000..164349ba9a3fa846f023fd3424a7ed028b19b430 --- /dev/null +++ b/core/java/android/inputmethodservice/package.html @@ -0,0 +1,8 @@ + + +Base classes for writing input methods. These APIs are not for use by +normal applications, they are a framework specifically for writing input +method components. Implementations will typically derive from +{@link android.inputmethodservice.InputMethodService}. + + diff --git a/core/java/android/net/MobileDataStateTracker.java b/core/java/android/net/MobileDataStateTracker.java index ae74e6f24ca112b48f78142e42e5ccb1e49624e9..1d939e10068c3fb597c1eae8b8c94bb81ec2f778 100644 --- a/core/java/android/net/MobileDataStateTracker.java +++ b/core/java/android/net/MobileDataStateTracker.java @@ -30,7 +30,6 @@ import com.android.internal.telephony.TelephonyIntents; import android.net.NetworkInfo.DetailedState; import android.telephony.TelephonyManager; import android.util.Log; -import android.util.Config; import android.text.TextUtils; import java.util.List; @@ -71,7 +70,9 @@ public class MobileDataStateTracker extends NetworkStateTracker { * @param target a message handler for getting callbacks about state changes */ public MobileDataStateTracker(Context context, Handler target) { - super(context, target, ConnectivityManager.TYPE_MOBILE); + super(context, target, ConnectivityManager.TYPE_MOBILE, + TelephonyManager.getDefault().getNetworkType(), "MOBILE", + TelephonyManager.getDefault().getNetworkTypeName()); mPhoneService = null; mDnsServers = new ArrayList(); } @@ -80,9 +81,10 @@ public class MobileDataStateTracker extends NetworkStateTracker { * Begin monitoring mobile data connectivity. */ public void startMonitoring() { - - IntentFilter filter = new IntentFilter(TelephonyIntents.ACTION_ANY_DATA_CONNECTION_STATE_CHANGED); + IntentFilter filter = + new IntentFilter(TelephonyIntents.ACTION_ANY_DATA_CONNECTION_STATE_CHANGED); filter.addAction(TelephonyIntents.ACTION_DATA_CONNECTION_FAILED); + filter.addAction(TelephonyIntents.ACTION_SERVICE_STATE_CHANGED); Intent intent = mContext.registerReceiver(new MobileDataStateReceiver(), filter); if (intent != null) @@ -146,6 +148,9 @@ public class MobileDataStateTracker extends NetworkStateTracker { reason == null ? "" : "(" + reason + ")"); setDetailedState(DetailedState.FAILED, reason, apnName); } + TelephonyManager tm = TelephonyManager.getDefault(); + setRoamingStatus(tm.isNetworkRoaming()); + setSubtype(tm.getNetworkType(), tm.getNetworkTypeName()); } } @@ -222,6 +227,15 @@ public class MobileDataStateTracker extends NetworkStateTracker { return getNameServerList(sDnsPropNames); } + /** + * {@inheritDoc} + * The mobile data network subtype indicates what generation network technology is in effect, + * e.g., GPRS, EDGE, UMTS, etc. + */ + public int getNetworkSubtype() { + return TelephonyManager.getDefault().getNetworkType(); + } + /** * Return the system properties name associated with the tcp buffer sizes * for this network. @@ -358,8 +372,8 @@ public class MobileDataStateTracker extends NetworkStateTracker { } /** - * Tells the phone sub-system that the caller is finished is - * finished using the named feature. The only supported feature at + * Tells the phone sub-system that the caller is finished + * using the named feature. The only supported feature at * this time is {@code Phone.FEATURE_ENABLE_MMS}, which allows an application * to specify that it wants to send and/or receive MMS data. * @param feature the name of the feature that is no longer needed diff --git a/core/java/android/net/NetworkInfo.java b/core/java/android/net/NetworkInfo.java index f776abfb05bcb64fdc782b273c32bf78d0ab216b..8c82212f0d867eba0e5ca5aa251fef46a8ac4c9d 100644 --- a/core/java/android/net/NetworkInfo.java +++ b/core/java/android/net/NetworkInfo.java @@ -99,24 +99,38 @@ public class NetworkInfo implements Parcelable { } private int mNetworkType; + private int mSubtype; + private String mTypeName; + private String mSubtypeName; private State mState; private DetailedState mDetailedState; private String mReason; private String mExtraInfo; private boolean mIsFailover; + private boolean mIsRoaming; /** * Indicates whether network connectivity is possible: */ private boolean mIsAvailable; - public NetworkInfo(int type) { + /** + * TODO This is going away as soon as API council review happens. + * @param type network type + */ + public NetworkInfo(int type) {} + + NetworkInfo(int type, int subtype, String typeName, String subtypeName) { if (!ConnectivityManager.isNetworkTypeValid(type)) { throw new IllegalArgumentException("Invalid network type: " + type); } - this.mNetworkType = type; + mNetworkType = type; + mSubtype = subtype; + mTypeName = typeName; + mSubtypeName = subtypeName; setDetailedState(DetailedState.IDLE, null, null); mState = State.UNKNOWN; mIsAvailable = true; + mIsRoaming = false; } /** @@ -128,6 +142,41 @@ public class NetworkInfo implements Parcelable { return mNetworkType; } + /** + * Return a network-type-specific integer describing the subtype + * of the network. + * @return the network subtype + * + * @hide pending API council review + */ + public int getSubtype() { + return mSubtype; + } + + void setSubtype(int subtype, String subtypeName) { + mSubtype = subtype; + mSubtypeName = subtypeName; + } + + /** + * Return a human-readable name describe the type of the network, + * for example "WIFI" or "MOBILE". + * @return the name of the network type + */ + public String getTypeName() { + return mTypeName; + } + + /** + * Return a human-readable name describing the subtype of the network. + * @return the name of the network subtype + * + * @hide pending API council review + */ + public String getSubtypeName() { + return mSubtypeName; + } + /** * Indicates whether network connectivity exists or is in the process * of being established. This is good for applications that need to @@ -170,7 +219,7 @@ public class NetworkInfo implements Parcelable { * Sets if the network is available, ie, if the connectivity is possible. * @param isAvailable the new availability value. * - * {@hide} + * @hide */ public void setIsAvailable(boolean isAvailable) { mIsAvailable = isAvailable; @@ -187,11 +236,32 @@ public class NetworkInfo implements Parcelable { return mIsFailover; } - /** {@hide} */ + /** + * Set the failover boolean. + * @param isFailover {@code true} to mark the current connection attempt + * as a failover. + * @hide + */ public void setFailover(boolean isFailover) { mIsFailover = isFailover; } + /** + * Indicates whether the device is currently roaming on this network. + * When {@code true}, it suggests that use of data on this network + * may incur extra costs. + * @return {@code true} if roaming is in effect, {@code false} otherwise. + * + * @hide pending API council + */ + public boolean isRoaming() { + return mIsRoaming; + } + + void setRoaming(boolean isRoaming) { + mIsRoaming = isRoaming; + } + /** * Reports the current coarse-grained state of the network. * @return the coarse-grained state @@ -215,8 +285,6 @@ public class NetworkInfo implements Parcelable { * if one was supplied. May be {@code null}. * @param extraInfo an optional {@code String} providing addditional network state * information passed up from the lower networking layers. - * - * {@hide} */ void setDetailedState(DetailedState detailedState, String reason, String extraInfo) { this.mDetailedState = detailedState; @@ -247,52 +315,59 @@ public class NetworkInfo implements Parcelable { @Override public String toString() { StringBuilder builder = new StringBuilder("NetworkInfo: "); - builder.append("type: ").append(getTypeName()).append(", state: ").append(mState). - append("/").append(mDetailedState). + builder.append("type: ").append(getTypeName()).append("[").append(getSubtypeName()). + append("], state: ").append(mState).append("/").append(mDetailedState). append(", reason: ").append(mReason == null ? "(unspecified)" : mReason). append(", extra: ").append(mExtraInfo == null ? "(none)" : mExtraInfo). + append(", roaming: ").append(mIsRoaming). append(", failover: ").append(mIsFailover). append(", isAvailable: ").append(mIsAvailable); return builder.toString(); } - public String getTypeName() { - switch (mNetworkType) { - case ConnectivityManager.TYPE_WIFI: - return "WIFI"; - case ConnectivityManager.TYPE_MOBILE: - return "MOBILE"; - default: - return ""; - } - } - - /** Implement the Parcelable interface {@hide} */ + /** + * Implement the Parcelable interface + * @hide + */ public int describeContents() { return 0; } - /** Implement the Parcelable interface {@hide} */ + /** + * Implement the Parcelable interface. + * @hide + */ public void writeToParcel(Parcel dest, int flags) { dest.writeInt(mNetworkType); + dest.writeInt(mSubtype); + dest.writeString(mTypeName); + dest.writeString(mSubtypeName); dest.writeString(mState.name()); dest.writeString(mDetailedState.name()); dest.writeInt(mIsFailover ? 1 : 0); dest.writeInt(mIsAvailable ? 1 : 0); + dest.writeInt(mIsRoaming ? 1 : 0); dest.writeString(mReason); dest.writeString(mExtraInfo); } - /** Implement the Parcelable interface {@hide} */ + /** + * Implement the Parcelable interface. + * @hide + */ public static final Creator CREATOR = new Creator() { public NetworkInfo createFromParcel(Parcel in) { int netType = in.readInt(); - NetworkInfo netInfo = new NetworkInfo(netType); + int subtype = in.readInt(); + String typeName = in.readString(); + String subtypeName = in.readString(); + NetworkInfo netInfo = new NetworkInfo(netType, subtype, typeName, subtypeName); netInfo.mState = State.valueOf(in.readString()); netInfo.mDetailedState = DetailedState.valueOf(in.readString()); netInfo.mIsFailover = in.readInt() != 0; netInfo.mIsAvailable = in.readInt() != 0; + netInfo.mIsRoaming = in.readInt() != 0; netInfo.mReason = in.readString(); netInfo.mExtraInfo = in.readString(); return netInfo; diff --git a/core/java/android/net/NetworkStateTracker.java b/core/java/android/net/NetworkStateTracker.java index 4e1efa6d42933ec49d21d400a9556152fffc370e..37087aca23a91d0e8d45cea2561987ce7314df7d 100644 --- a/core/java/android/net/NetworkStateTracker.java +++ b/core/java/android/net/NetworkStateTracker.java @@ -22,7 +22,6 @@ import java.io.IOException; import android.os.Handler; import android.os.Message; import android.os.SystemProperties; -import android.os.PowerManager; import android.content.Context; import android.text.TextUtils; import android.util.Config; @@ -41,6 +40,7 @@ public abstract class NetworkStateTracker extends Handler { protected NetworkInfo mNetworkInfo; protected Context mContext; protected Handler mTarget; + private boolean mTeardownRequested; private static boolean DBG = Config.LOGV; private static final String TAG = "NetworkStateTracker"; @@ -54,12 +54,20 @@ public abstract class NetworkStateTracker extends Handler { */ public static final int EVENT_NOTIFICATION_CHANGED = 3; public static final int EVENT_CONFIGURATION_CHANGED = 4; - - public NetworkStateTracker(Context context, Handler target, int networkType) { + public static final int EVENT_ROAMING_CHANGED = 5; + public static final int EVENT_NETWORK_SUBTYPE_CHANGED = 6; + + public NetworkStateTracker(Context context, + Handler target, + int networkType, + int subType, + String typeName, + String subtypeName) { super(); mContext = context; mTarget = target; - this.mNetworkInfo = new NetworkInfo(networkType); + mTeardownRequested = false; + this.mNetworkInfo = new NetworkInfo(networkType, subType, typeName, subtypeName); } public NetworkInfo getNetworkInfo() { @@ -222,6 +230,14 @@ public abstract class NetworkStateTracker extends Handler { mNetworkInfo.setDetailedState(state, null, null); } + public void setTeardownRequested(boolean isRequested) { + mTeardownRequested = isRequested; + } + + public boolean isTeardownRequested() { + return mTeardownRequested; + } + /** * Send a notification that the results of a scan for network access * points has completed, and results are available. @@ -231,6 +247,32 @@ public abstract class NetworkStateTracker extends Handler { msg.sendToTarget(); } + /** + * Record the roaming status of the device, and if it is a change from the previous + * status, send a notification to any listeners. + * @param isRoaming {@code true} if the device is now roaming, {@code false} + * if it is no longer roaming. + */ + protected void setRoamingStatus(boolean isRoaming) { + if (isRoaming != mNetworkInfo.isRoaming()) { + mNetworkInfo.setRoaming(isRoaming); + Message msg = mTarget.obtainMessage(EVENT_ROAMING_CHANGED, mNetworkInfo); + msg.sendToTarget(); + } + } + + protected void setSubtype(int subtype, String subtypeName) { + if (mNetworkInfo.isConnected()) { + int oldSubtype = mNetworkInfo.getSubtype(); + if (subtype != oldSubtype) { + mNetworkInfo.setSubtype(subtype, subtypeName); + Message msg = mTarget.obtainMessage( + EVENT_NETWORK_SUBTYPE_CHANGED, oldSubtype, 0, mNetworkInfo); + msg.sendToTarget(); + } + } + } + public abstract void startMonitoring(); /** diff --git a/core/java/android/net/NetworkUtils.java b/core/java/android/net/NetworkUtils.java index 129248aebf10df0061d9310625069931ee049c1f..115364872955d47e10064d816ce78233ed598a29 100644 --- a/core/java/android/net/NetworkUtils.java +++ b/core/java/android/net/NetworkUtils.java @@ -66,6 +66,14 @@ public class NetworkUtils { */ public native static boolean stopDhcp(String interfaceName); + /** + * Release the current DHCP lease. + * @param interfaceName the name of the interface for which the lease should + * be released + * @return {@code true} for success, {@code false} for failure + */ + public native static boolean releaseDhcpLease(String interfaceName); + /** * Return the last DHCP-related error message that was recorded. *

    NOTE: This string is not localized, but currently it is only diff --git a/core/java/android/net/Proxy.java b/core/java/android/net/Proxy.java index 86e1d5b64c6ff9a19b190b4f3100afe9c78e184c..9f07c0a2c5b04d425aadd4bd598e9e68768b48de 100644 --- a/core/java/android/net/Proxy.java +++ b/core/java/android/net/Proxy.java @@ -43,9 +43,9 @@ final public class Proxy { static final public String getHost(Context ctx) { ContentResolver contentResolver = ctx.getContentResolver(); Assert.assertNotNull(contentResolver); - String host = Settings.System.getString( + String host = Settings.Secure.getString( contentResolver, - Settings.System.HTTP_PROXY); + Settings.Secure.HTTP_PROXY); if (host != null) { int i = host.indexOf(':'); if (i == -1) { @@ -67,9 +67,9 @@ final public class Proxy { static final public int getPort(Context ctx) { ContentResolver contentResolver = ctx.getContentResolver(); Assert.assertNotNull(contentResolver); - String host = Settings.System.getString( + String host = Settings.Secure.getString( contentResolver, - Settings.System.HTTP_PROXY); + Settings.Secure.HTTP_PROXY); if (host != null) { int i = host.indexOf(':'); if (i == -1) { diff --git a/core/java/android/net/http/Connection.java b/core/java/android/net/http/Connection.java index 2c82582c204251ff3e4d7be22c91c985868a9315..563634fd4690a0e107b3300f0264ae38a105fcb3 100644 --- a/core/java/android/net/http/Connection.java +++ b/core/java/android/net/http/Connection.java @@ -375,6 +375,11 @@ abstract class Connection { if (HttpLog.LOGV) HttpLog.v("Failed to open connection"); error = EventHandler.ERROR_LOOKUP; exception = e; + } catch (IllegalArgumentException e) { + if (HttpLog.LOGV) HttpLog.v("Illegal argument exception"); + error = EventHandler.ERROR_CONNECT; + req.mFailCount = RETRY_REQUEST_LIMIT; + exception = e; } catch (SSLConnectionClosedByUserException e) { // hack: if we have an SSL connection failure, // we don't want to reconnect diff --git a/core/java/android/net/http/Headers.java b/core/java/android/net/http/Headers.java index 5d85ba40662328bbe29be0c1389240af6f9021e5..b0923d1ce27efbfe28b5b4eb44e7db044c9ab96d 100644 --- a/core/java/android/net/http/Headers.java +++ b/core/java/android/net/http/Headers.java @@ -30,7 +30,7 @@ import org.apache.http.util.CharArrayBuffer; /** * Manages received headers - * + * * {@hide} */ public final class Headers { @@ -42,16 +42,16 @@ public final class Headers { */ public final static int CONN_CLOSE = 1; /** - * indicate HTTP 1.1 connection keep alive + * indicate HTTP 1.1 connection keep alive */ public final static int CONN_KEEP_ALIVE = 2; - + // initial values. public final static int NO_CONN_TYPE = 0; public final static long NO_TRANSFER_ENCODING = 0; public final static long NO_CONTENT_LENGTH = -1; - // header string + // header strings public final static String TRANSFER_ENCODING = "transfer-encoding"; public final static String CONTENT_LEN = "content-length"; public final static String CONTENT_TYPE = "content-type"; @@ -93,25 +93,61 @@ public final class Headers { private final static int HASH_PRAGMA = -980228804; private final static int HASH_REFRESH = 1085444827; + // keep any headers that require direct access in a presized + // string array + private final static int IDX_TRANSFER_ENCODING = 0; + private final static int IDX_CONTENT_LEN = 1; + private final static int IDX_CONTENT_TYPE = 2; + private final static int IDX_CONTENT_ENCODING = 3; + private final static int IDX_CONN_DIRECTIVE = 4; + private final static int IDX_LOCATION = 5; + private final static int IDX_PROXY_CONNECTION = 6; + private final static int IDX_WWW_AUTHENTICATE = 7; + private final static int IDX_PROXY_AUTHENTICATE = 8; + private final static int IDX_CONTENT_DISPOSITION = 9; + private final static int IDX_ACCEPT_RANGES = 10; + private final static int IDX_EXPIRES = 11; + private final static int IDX_CACHE_CONTROL = 12; + private final static int IDX_LAST_MODIFIED = 13; + private final static int IDX_ETAG = 14; + private final static int IDX_SET_COOKIE = 15; + private final static int IDX_PRAGMA = 16; + private final static int IDX_REFRESH = 17; + + private final static int HEADER_COUNT = 18; + + /* parsed values */ private long transferEncoding; private long contentLength; // Content length of the incoming data private int connectionType; - - private String contentType; - private String contentEncoding; - private String location; - private String wwwAuthenticate; - private String proxyAuthenticate; - private String contentDisposition; - private String acceptRanges; - private String expires; - private String cacheControl; - private String lastModified; - private String etag; - private String pragma; - private String refresh; private ArrayList cookies = new ArrayList(2); + private String[] mHeaders = new String[HEADER_COUNT]; + private final static String[] sHeaderNames = { + TRANSFER_ENCODING, + CONTENT_LEN, + CONTENT_TYPE, + CONTENT_ENCODING, + CONN_DIRECTIVE, + LOCATION, + PROXY_CONNECTION, + WWW_AUTHENTICATE, + PROXY_AUTHENTICATE, + CONTENT_DISPOSITION, + ACCEPT_RANGES, + EXPIRES, + CACHE_CONTROL, + LAST_MODIFIED, + ETAG, + SET_COOKIE, + PRAGMA, + REFRESH + }; + + // Catch-all for headers not explicitly handled + private ArrayList mExtraHeaderNames = new ArrayList(4); + private ArrayList mExtraHeaderValues = new ArrayList(4); + public Headers() { transferEncoding = NO_TRANSFER_ENCODING; contentLength = NO_CONTENT_LENGTH; @@ -129,23 +165,22 @@ public final class Headers { } pos++; + String val = buffer.substringTrimmed(pos, buffer.length()); if (HttpLog.LOGV) { - String val = buffer.substringTrimmed(pos, buffer.length()); HttpLog.v("hdr " + buffer.length() + " " + buffer); } switch (name.hashCode()) { case HASH_TRANSFER_ENCODING: if (name.equals(TRANSFER_ENCODING)) { - // headers.transferEncoding = + mHeaders[IDX_TRANSFER_ENCODING] = val; HeaderElement[] encodings = BasicHeaderValueParser.DEFAULT - .parseElements(buffer, new ParserCursor(pos, + .parseElements(buffer, new ParserCursor(pos, buffer.length())); // The chunked encoding must be the last one applied RFC2616, // 14.41 int len = encodings.length; - if (HTTP.IDENTITY_CODING.equalsIgnoreCase(buffer - .substringTrimmed(pos, buffer.length()))) { + if (HTTP.IDENTITY_CODING.equalsIgnoreCase(val)) { transferEncoding = ContentLengthStrategy.IDENTITY; } else if ((len > 0) && (HTTP.CHUNK_CODING @@ -158,9 +193,9 @@ public final class Headers { break; case HASH_CONTENT_LEN: if (name.equals(CONTENT_LEN)) { + mHeaders[IDX_CONTENT_LEN] = val; try { - contentLength = Long.parseLong(buffer.substringTrimmed(pos, - buffer.length())); + contentLength = Long.parseLong(val); } catch (NumberFormatException e) { if (Config.LOGV) { Log.v(LOGTAG, "Headers.headers(): error parsing" @@ -171,88 +206,90 @@ public final class Headers { break; case HASH_CONTENT_TYPE: if (name.equals(CONTENT_TYPE)) { - contentType = buffer.substringTrimmed(pos, buffer.length()); + mHeaders[IDX_CONTENT_TYPE] = val; } break; case HASH_CONTENT_ENCODING: if (name.equals(CONTENT_ENCODING)) { - contentEncoding = buffer.substringTrimmed(pos, buffer.length()); + mHeaders[IDX_CONTENT_ENCODING] = val; } break; case HASH_CONN_DIRECTIVE: if (name.equals(CONN_DIRECTIVE)) { + mHeaders[IDX_CONN_DIRECTIVE] = val; setConnectionType(buffer, pos); } break; case HASH_LOCATION: if (name.equals(LOCATION)) { - location = buffer.substringTrimmed(pos, buffer.length()); + mHeaders[IDX_LOCATION] = val; } break; case HASH_PROXY_CONNECTION: if (name.equals(PROXY_CONNECTION)) { + mHeaders[IDX_PROXY_CONNECTION] = val; setConnectionType(buffer, pos); } break; case HASH_WWW_AUTHENTICATE: if (name.equals(WWW_AUTHENTICATE)) { - wwwAuthenticate = buffer.substringTrimmed(pos, buffer.length()); + mHeaders[IDX_WWW_AUTHENTICATE] = val; } break; case HASH_PROXY_AUTHENTICATE: if (name.equals(PROXY_AUTHENTICATE)) { - proxyAuthenticate = buffer.substringTrimmed(pos, buffer - .length()); + mHeaders[IDX_PROXY_AUTHENTICATE] = val; } break; case HASH_CONTENT_DISPOSITION: if (name.equals(CONTENT_DISPOSITION)) { - contentDisposition = buffer.substringTrimmed(pos, buffer - .length()); + mHeaders[IDX_CONTENT_DISPOSITION] = val; } break; case HASH_ACCEPT_RANGES: if (name.equals(ACCEPT_RANGES)) { - acceptRanges = buffer.substringTrimmed(pos, buffer.length()); + mHeaders[IDX_ACCEPT_RANGES] = val; } break; case HASH_EXPIRES: if (name.equals(EXPIRES)) { - expires = buffer.substringTrimmed(pos, buffer.length()); + mHeaders[IDX_EXPIRES] = val; } break; case HASH_CACHE_CONTROL: if (name.equals(CACHE_CONTROL)) { - cacheControl = buffer.substringTrimmed(pos, buffer.length()); + mHeaders[IDX_CACHE_CONTROL] = val; } break; case HASH_LAST_MODIFIED: if (name.equals(LAST_MODIFIED)) { - lastModified = buffer.substringTrimmed(pos, buffer.length()); + mHeaders[IDX_LAST_MODIFIED] = val; } break; case HASH_ETAG: if (name.equals(ETAG)) { - etag = buffer.substringTrimmed(pos, buffer.length()); + mHeaders[IDX_ETAG] = val; } break; case HASH_SET_COOKIE: if (name.equals(SET_COOKIE)) { - cookies.add(buffer.substringTrimmed(pos, buffer.length())); + mHeaders[IDX_SET_COOKIE] = val; + cookies.add(val); } break; case HASH_PRAGMA: if (name.equals(PRAGMA)) { - pragma = buffer.substringTrimmed(pos, buffer.length()); + mHeaders[IDX_PRAGMA] = val; } break; case HASH_REFRESH: if (name.equals(REFRESH)) { - refresh = buffer.substringTrimmed(pos, buffer.length()); + mHeaders[IDX_REFRESH] = val; } break; default: - // ignore + mExtraHeaderNames.add(name); + mExtraHeaderValues.add(val); } } @@ -268,70 +305,60 @@ public final class Headers { return connectionType; } - private void setConnectionType(CharArrayBuffer buffer, int pos) { - if (CharArrayBuffers.containsIgnoreCaseTrimmed( - buffer, pos, HTTP.CONN_CLOSE)) { - connectionType = CONN_CLOSE; - } else if (CharArrayBuffers.containsIgnoreCaseTrimmed( - buffer, pos, HTTP.CONN_KEEP_ALIVE)) { - connectionType = CONN_KEEP_ALIVE; - } - } - public String getContentType() { - return this.contentType; + return mHeaders[IDX_CONTENT_TYPE]; } public String getContentEncoding() { - return this.contentEncoding; + return mHeaders[IDX_CONTENT_ENCODING]; } public String getLocation() { - return this.location; + return mHeaders[IDX_LOCATION]; } public String getWwwAuthenticate() { - return this.wwwAuthenticate; + return mHeaders[IDX_WWW_AUTHENTICATE]; } public String getProxyAuthenticate() { - return this.proxyAuthenticate; + return mHeaders[IDX_PROXY_AUTHENTICATE]; } public String getContentDisposition() { - return this.contentDisposition; + return mHeaders[IDX_CONTENT_DISPOSITION]; } public String getAcceptRanges() { - return this.acceptRanges; + return mHeaders[IDX_ACCEPT_RANGES]; } public String getExpires() { - return this.expires; + return mHeaders[IDX_EXPIRES]; } public String getCacheControl() { - return this.cacheControl; + return mHeaders[IDX_CACHE_CONTROL]; } public String getLastModified() { - return this.lastModified; + return mHeaders[IDX_LAST_MODIFIED]; } public String getEtag() { - return this.etag; + return mHeaders[IDX_ETAG]; } public ArrayList getSetCookie() { return this.cookies; } - + public String getPragma() { - return this.pragma; + return mHeaders[IDX_PRAGMA]; } - + public String getRefresh() { - return this.refresh; + return mHeaders[IDX_REFRESH]; } public void setContentLength(long value) { @@ -339,46 +366,82 @@ public final class Headers { } public void setContentType(String value) { - this.contentType = value; + mHeaders[IDX_CONTENT_TYPE] = value; } public void setContentEncoding(String value) { - this.contentEncoding = value; + mHeaders[IDX_CONTENT_ENCODING] = value; } public void setLocation(String value) { - this.location = value; + mHeaders[IDX_LOCATION] = value; } public void setWwwAuthenticate(String value) { - this.wwwAuthenticate = value; + mHeaders[IDX_WWW_AUTHENTICATE] = value; } public void setProxyAuthenticate(String value) { - this.proxyAuthenticate = value; + mHeaders[IDX_PROXY_AUTHENTICATE] = value; } public void setContentDisposition(String value) { - this.contentDisposition = value; + mHeaders[IDX_CONTENT_DISPOSITION] = value; } public void setAcceptRanges(String value) { - this.acceptRanges = value; + mHeaders[IDX_ACCEPT_RANGES] = value; } public void setExpires(String value) { - this.expires = value; + mHeaders[IDX_EXPIRES] = value; } public void setCacheControl(String value) { - this.cacheControl = value; + mHeaders[IDX_CACHE_CONTROL] = value; } public void setLastModified(String value) { - this.lastModified = value; + mHeaders[IDX_LAST_MODIFIED] = value; } public void setEtag(String value) { - this.etag = value; + mHeaders[IDX_ETAG] = value; + } + + public interface HeaderCallback { + public void header(String name, String value); + } + + /** + * Reports all non-null headers to the callback + */ + public void getHeaders(HeaderCallback hcb) { + for (int i = 0; i < HEADER_COUNT; i++) { + String h = mHeaders[i]; + if (h != null) { + hcb.header(sHeaderNames[i], h); + } + } + int extraLen = mExtraHeaderNames.size(); + for (int i = 0; i < extraLen; i++) { + if (Config.LOGV) { + HttpLog.v("Headers.getHeaders() extra: " + i + " " + + mExtraHeaderNames.get(i) + " " + mExtraHeaderValues.get(i)); + } + hcb.header(mExtraHeaderNames.get(i), + mExtraHeaderValues.get(i)); + } + + } + + private void setConnectionType(CharArrayBuffer buffer, int pos) { + if (CharArrayBuffers.containsIgnoreCaseTrimmed( + buffer, pos, HTTP.CONN_CLOSE)) { + connectionType = CONN_CLOSE; + } else if (CharArrayBuffers.containsIgnoreCaseTrimmed( + buffer, pos, HTTP.CONN_KEEP_ALIVE)) { + connectionType = CONN_KEEP_ALIVE; + } } } diff --git a/core/java/android/net/http/Request.java b/core/java/android/net/http/Request.java index bcbecf0a47d2421d3bf900c5e431525d54c4fa5c..df4fff015dc0cad04ec012b5ce88190b967d8530 100644 --- a/core/java/android/net/http/Request.java +++ b/core/java/android/net/http/Request.java @@ -16,6 +16,7 @@ package android.net.http; +import java.io.EOFException; import java.io.InputStream; import java.io.IOException; import java.util.Iterator; @@ -279,6 +280,11 @@ class Request { count = 0; } } + } catch (EOFException e) { + /* InflaterInputStream throws an EOFException when the + server truncates gzipped content. Handle this case + as we do truncated non-gzipped content: no error */ + if (HttpLog.LOGV) HttpLog.v( "readResponse() handling " + e); } catch(IOException e) { // don't throw if we have a non-OK status code if (statusCode == HttpStatus.SC_OK) { diff --git a/core/java/android/net/http/RequestHandle.java b/core/java/android/net/http/RequestHandle.java index 5d8125092bddc6ecb6c64f0ff2bf7fa3ea52b390..65e6117d2de0e638a53873e5880eb8af3d4ae9c4 100644 --- a/core/java/android/net/http/RequestHandle.java +++ b/core/java/android/net/http/RequestHandle.java @@ -113,7 +113,7 @@ public class RequestHandle { * @param statusCode HTTP status code returned from original request * @param cacheHeaders Cache header for redirect URL * @return true if setup succeeds, false otherwise (redirect loop - * count exceeded) + * count exceeded, body provider unable to rewind on 307 redirect) */ public boolean setupRedirect(String redirectTo, int statusCode, Map cacheHeaders) { @@ -164,8 +164,22 @@ public class RequestHandle { } mMethod = "GET"; } - mHeaders.remove("Content-Type"); - mBodyProvider = null; + /* Only repost content on a 307. If 307, reset the body + provider so we can replay the body */ + if (statusCode == 307) { + try { + if (mBodyProvider != null) mBodyProvider.reset(); + } catch (java.io.IOException ex) { + if (HttpLog.LOGV) { + HttpLog.v("setupAuthResponse() failed to reset body provider"); + } + return false; + } + + } else { + mHeaders.remove("Content-Type"); + mBodyProvider = null; + } // Update the cache headers for this URL mHeaders.putAll(cacheHeaders); diff --git a/core/java/android/net/http/RequestQueue.java b/core/java/android/net/http/RequestQueue.java index d59299560f0afd96bb09f8704ee9f595ede5af77..66d572288f1cd3dc14f8363e917cbcdadf81da06 100644 --- a/core/java/android/net/http/RequestQueue.java +++ b/core/java/android/net/http/RequestQueue.java @@ -596,7 +596,7 @@ public class RequestQueue implements RequestFeeder { } protected synchronized void queueRequest(Request request, boolean head) { - HttpHost host = request.mHost; + HttpHost host = request.mProxyHost == null ? request.mHost : request.mProxyHost; LinkedList reqList; if (mPending.containsKey(host)) { reqList = mPending.get(host); diff --git a/core/java/android/os/AsyncTask.java b/core/java/android/os/AsyncTask.java new file mode 100644 index 0000000000000000000000000000000000000000..ee4e8974b5c7c50ff97d20d3af6f27f25a725bb2 --- /dev/null +++ b/core/java/android/os/AsyncTask.java @@ -0,0 +1,454 @@ +/* + * 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 android.os; + +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.ThreadFactory; +import java.util.concurrent.Callable; +import java.util.concurrent.FutureTask; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeoutException; +import java.util.concurrent.CancellationException; +import java.util.concurrent.atomic.AtomicInteger; + +/** + *

    AsyncTask enables proper and easy use of the UI thread. This class allows to + * perform background operations and publish results on the UI thread without + * having to manipulate threads and/or handlers.

    + * + *

    An asynchronous task is defined by a computation that runs on a background thread and + * whose result is published on the UI thread. An asynchronous task is defined by 3 generic + * types, called Params, Progress and Result, + * and 4 steps, called begin, doInBackground, + * processProgress and end.

    + * + *

    Usage

    + *

    AsyncTask must be subclassed to be used. The subclass will override at least + * one method ({@link #doInBackground}), and most often will override a + * second one ({@link #onPostExecute}.)

    + * + *

    Here is an example of subclassing:

    + *
    + * private class DownloadFilesTask extends AsyncTask<URL, Integer, Long> {
    + *     protected Long doInBackground(URL... urls) {
    + *         int count = urls.length;
    + *         long totalSize = 0;
    + *         for (int i = 0; i < count; i++) {
    + *             totalSize += Downloader.downloadFile(urls[i]);
    + *             publishProgress((int) ((i / (float) count) * 100));
    + *         }
    + *         return totalSize;
    + *     }
    + *
    + *     protected void onProgressUpdate(Integer... progress) {
    + *         setProgressPercent(progress[0]);
    + *     }
    + *
    + *     protected void onPostExecute(Long result) {
    + *         showDialog("Downloaded " + result + " bytes");
    + *     }
    + * }
    + * 
    + * + *

    Once created, a task is executed very simply:

    + *
    + * new DownloadFilesTask().execute(url1, url2, url3);
    + * 
    + * + *

    AsyncTask's generic types

    + *

    The three types used by an asynchronous task are the following:

    + *
      + *
    1. Params, the type of the parameters sent to the task upon + * execution.
    2. + *
    3. Progress, the type of the progress units published during + * the background computation.
    4. + *
    5. Result, the type of the result of the background + * computation.
    6. + *
    + *

    Not all types are always used by am asynchronous task. To mark a type as unused, + * simply use the type {@link Void}:

    + *
    + * private class MyTask extends AsyncTask
    + *
    + * 

    The 4 steps

    + *

    When an asynchronous task is executed, the task goes through 4 steps:

    + *
      + *
    1. {@link #onPreExecute()}, invoked on the UI thread immediately after the task + * is executed. This step is normally used to setup the task, for instance by + * showing a progress bar in the user interface.
    2. + *
    3. {@link #doInBackground}, invoked on the background thread + * immediately after {@link #onPreExecute()} finishes executing. This step is used + * to perform background computation that can take a long time. The parameters + * of the asynchronous task are passed to this step. The result of the computation must + * be returned by this step and will be passed back to the last step. This step + * can also use {@link #publishProgress} to publish one or more units + * of progress. These values are published on the UI thread, in the + * {@link #onProgressUpdate} step.
    4. + *
    5. {@link #onProgressUpdate}, invoked on the UI thread after a + * call to {@link #publishProgress}. The timing of the execution is + * undefined. This method is used to display any form of progress in the user + * interface while the background computation is still executing. For instance, + * it can be used to animate a progress bar or show logs in a text field.
    6. + *
    7. {@link #onPostExecute}, invoked on the UI thread after the background + * computation finishes. The result of the background computation is passed to + * this step as a parameter.
    8. + *
    + * + *

    Threading rules

    + *

    There are a few threading rules that must be followed for this class to + * work properly:

    + *
      + *
    • The task instance must be created on the UI thread.
    • + *
    • {@link #execute} must be invoked on the UI thread.
    • + *
    • Do not call {@link #onPreExecute()}, {@link #onPostExecute}, + * {@link #doInBackground}, {@link #onProgressUpdate} manually.
    • + *
    • The task can be executed only once (an exception will be thrown if + * a second execution is attempted.)
    • + *
    + */ +public abstract class AsyncTask { + private static final String LOG_TAG = "AsyncTask"; + + private static final int CORE_POOL_SIZE = 1; + private static final int MAXIMUM_POOL_SIZE = 10; + private static final int KEEP_ALIVE = 10; + + private static final BlockingQueue sWorkQueue = + new LinkedBlockingQueue(MAXIMUM_POOL_SIZE); + + private static final ThreadFactory sThreadFactory = new ThreadFactory() { + private final AtomicInteger mCount = new AtomicInteger(1); + + public Thread newThread(Runnable r) { + return new Thread(r, "AsyncTask #" + mCount.getAndIncrement()); + } + }; + + private static final ThreadPoolExecutor sExecutor = new ThreadPoolExecutor(CORE_POOL_SIZE, + MAXIMUM_POOL_SIZE, KEEP_ALIVE, TimeUnit.SECONDS, sWorkQueue, sThreadFactory); + + private static final int MESSAGE_POST_RESULT = 0x1; + private static final int MESSAGE_POST_PROGRESS = 0x2; + private static final int MESSAGE_POST_CANCEL = 0x3; + + private static final InternalHandler sHandler = new InternalHandler(); + + private final WorkerRunnable mWorker; + private final FutureTask mFuture; + + private volatile Status mStatus = Status.PENDING; + + /** + * Indicates the current status of the task. Each status will be set only once + * during the lifetime of a task. + */ + public enum Status { + /** + * Indicates that the task has not been executed yet. + */ + PENDING, + /** + * Indicates that the task is running. + */ + RUNNING, + /** + * Indicates that {@link AsyncTask#onPostExecute} has finished. + */ + FINISHED, + } + + /** + * Creates a new asynchronous task. This constructor must be invoked on the UI thread. + */ + public AsyncTask() { + mWorker = new WorkerRunnable() { + public Result call() throws Exception { + Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); + return doInBackground(mParams); + } + }; + + mFuture = new FutureTask(mWorker) { + @Override + protected void done() { + Message message; + Result result = null; + + try { + result = get(); + } catch (InterruptedException e) { + android.util.Log.w(LOG_TAG, e); + } catch (ExecutionException e) { + throw new RuntimeException("An error occured while executing doInBackground()", + e.getCause()); + } catch (CancellationException e) { + message = sHandler.obtainMessage(MESSAGE_POST_CANCEL, + new AsyncTaskResult(AsyncTask.this, (Result[]) null)); + message.sendToTarget(); + return; + } catch (Throwable t) { + throw new RuntimeException("An error occured while executing " + + "doInBackground()", t); + } + + message = sHandler.obtainMessage(MESSAGE_POST_RESULT, + new AsyncTaskResult(AsyncTask.this, result)); + message.sendToTarget(); + } + }; + } + + /** + * Returns the current status of this task. + * + * @return The current status. + */ + public final Status getStatus() { + return mStatus; + } + + /** + * Override this method to perform a computation on a background thread. The + * specified parameters are the parameters passed to {@link #execute} + * by the caller of this task. + * + * This method can call {@link #publishProgress} to publish updates + * on the UI thread. + * + * @param params The parameters of the task. + * + * @return A result, defined by the subclass of this task. + * + * @see #onPreExecute() + * @see #onPostExecute + * @see #publishProgress + */ + protected abstract Result doInBackground(Params... params); + + /** + * Runs on the UI thread before {@link #doInBackground}. + * + * @see #onPostExecute + * @see #doInBackground + */ + protected void onPreExecute() { + } + + /** + * Runs on the UI thread after {@link #doInBackground}. The + * specified result is the value returned by {@link #doInBackground} + * or null if the task was cancelled or an exception occured. + * + * @param result The result of the operation computed by {@link #doInBackground}. + * + * @see #onPreExecute + * @see #doInBackground + */ + @SuppressWarnings({"UnusedDeclaration"}) + protected void onPostExecute(Result result) { + } + + /** + * Runs on the UI thread after {@link #publishProgress} is invoked. + * The specified values are the values passed to {@link #publishProgress}. + * + * @param values The values indicating progress. + * + * @see #publishProgress + * @see #doInBackground + */ + @SuppressWarnings({"UnusedDeclaration"}) + protected void onProgressUpdate(Progress... values) { + } + + /** + * Runs on the UI thread after {@link #cancel(boolean)} is invoked. + * + * @see #cancel(boolean) + * @see #isCancelled() + */ + protected void onCancelled() { + } + + /** + * Returns true if this task was cancelled before it completed + * normally. + * + * @return true if task was cancelled before it completed + * + * @see #cancel(boolean) + */ + public final boolean isCancelled() { + return mFuture.isCancelled(); + } + + /** + * Attempts to cancel execution of this task. This attempt will + * fail if the task has already completed, already been cancelled, + * or could not be cancelled for some other reason. If successful, + * and this task has not started when cancel is called, + * this task should never run. If the task has already started, + * then the mayInterruptIfRunning parameter determines + * whether the thread executing this task should be interrupted in + * an attempt to stop the task. + * + * @param mayInterruptIfRunning true if the thread executing this + * task should be interrupted; otherwise, in-progress tasks are allowed + * to complete. + * + * @return false if the task could not be cancelled, + * typically because it has already completed normally; + * true otherwise + * + * @see #isCancelled() + * @see #onCancelled() + */ + public final boolean cancel(boolean mayInterruptIfRunning) { + return mFuture.cancel(mayInterruptIfRunning); + } + + /** + * Waits if necessary for the computation to complete, and then + * retrieves its result. + * + * @return The computed result. + * + * @throws CancellationException If the computation was cancelled. + * @throws ExecutionException If the computation threw an exception. + * @throws InterruptedException If the current thread was interrupted + * while waiting. + */ + public final Result get() throws InterruptedException, ExecutionException { + return mFuture.get(); + } + + /** + * Waits if necessary for at most the given time for the computation + * to complete, and then retrieves its result. + * + * @param timeout Time to wait before cancelling the operation. + * @param unit The time unit for the timeout. + * + * @return The computed result. + * + * @throws CancellationException If the computation was cancelled. + * @throws ExecutionException If the computation threw an exception. + * @throws InterruptedException If the current thread was interrupted + * while waiting. + * @throws TimeoutException If the wait timed out. + */ + public final Result get(long timeout, TimeUnit unit) throws InterruptedException, + ExecutionException, TimeoutException { + return mFuture.get(timeout, unit); + } + + /** + * Executes the task with the specified parameters. The task returns + * itself (this) so that the caller can keep a reference to it. + * + * This method must be invoked on the UI thread. + * + * @param params The parameters of the task. + * + * @return This instance of AsyncTask. + * + * @throws IllegalStateException If {@link #getStatus()} returns either + * {@link AsyncTask.Status#RUNNING} or {@link AsyncTask.Status#FINISHED}. + */ + public final AsyncTask execute(Params... params) { + if (mStatus != Status.PENDING) { + switch (mStatus) { + case RUNNING: + throw new IllegalStateException("Cannot execute task:" + + " the task is already running."); + case FINISHED: + throw new IllegalStateException("Cannot execute task:" + + " the task has already been executed " + + "(a task can be executed only once)"); + } + } + + mStatus = Status.RUNNING; + + onPreExecute(); + + mWorker.mParams = params; + sExecutor.execute(mFuture); + + return this; + } + + /** + * This method can be invoked from {@link #doInBackground} to + * publish updates on the UI thread while the background computation is + * still running. Each call to this method will trigger the execution of + * {@link #onProgressUpdate} on the UI thread. + * + * @param values The progress values to update the UI with. + * + * @see #onProgressUpdate + * @see #doInBackground + */ + protected final void publishProgress(Progress... values) { + sHandler.obtainMessage(MESSAGE_POST_PROGRESS, + new AsyncTaskResult(this, values)).sendToTarget(); + } + + private void finish(Result result) { + onPostExecute(result); + mStatus = Status.FINISHED; + } + + private static class InternalHandler extends Handler { + @SuppressWarnings({"unchecked", "RawUseOfParameterizedType"}) + @Override + public void handleMessage(Message msg) { + AsyncTaskResult result = (AsyncTaskResult) msg.obj; + switch (msg.what) { + case MESSAGE_POST_RESULT: + // There is only one result + result.mTask.finish(result.mData[0]); + break; + case MESSAGE_POST_PROGRESS: + result.mTask.onProgressUpdate(result.mData); + break; + case MESSAGE_POST_CANCEL: + result.mTask.onCancelled(); + break; + } + } + } + + private static abstract class WorkerRunnable implements Callable { + Params[] mParams; + } + + @SuppressWarnings({"RawUseOfParameterizedType"}) + private static class AsyncTaskResult { + final AsyncTask mTask; + final Data[] mData; + + AsyncTaskResult(AsyncTask task, Data... data) { + mTask = task; + mData = data; + } + } +} diff --git a/core/java/android/os/BatteryManager.java b/core/java/android/os/BatteryManager.java index bf4755553d2927f72924d017f3cb407c2d704f22..8f1a756b295ce617c87148409b586afcc386df08 100644 --- a/core/java/android/os/BatteryManager.java +++ b/core/java/android/os/BatteryManager.java @@ -37,8 +37,10 @@ public class BatteryManager { public static final int BATTERY_HEALTH_OVER_VOLTAGE = 5; public static final int BATTERY_HEALTH_UNSPECIFIED_FAILURE = 6; - // values of the "plugged" field in the ACTION_BATTERY_CHANGED intent + // values of the "plugged" field in the ACTION_BATTERY_CHANGED intent. + // These must be powers of 2. + /** Power source is an AC charger. */ public static final int BATTERY_PLUGGED_AC = 1; + /** Power source is a USB port. */ public static final int BATTERY_PLUGGED_USB = 2; - } diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java new file mode 100644 index 0000000000000000000000000000000000000000..e065063c21b008cdfe0a2e151211c5a84d06bd87 --- /dev/null +++ b/core/java/android/os/BatteryStats.java @@ -0,0 +1,518 @@ +package android.os; + +import java.io.FileDescriptor; +import java.io.PrintWriter; +import java.util.Formatter; +import java.util.Map; + +import android.util.SparseArray; + +/** + * A class providing access to battery usage statistics, including information on + * wakelocks, processes, packages, and services. All times are represented in microseconds + * except where indicated otherwise. + */ +public abstract class BatteryStats { + + /** + * A constant indicating a partial wake lock. + */ + public static final int WAKE_TYPE_PARTIAL = 0; + + /** + * A constant indicating a full wake lock. + */ + public static final int WAKE_TYPE_FULL = 1; + + /** + * A constant indicating a window wake lock. + */ + public static final int WAKE_TYPE_WINDOW = 2; + + /** + * Include all of the data in the stats, including previously saved data. + */ + public static final int STATS_TOTAL = 0; + + /** + * Include only the last run in the stats. + */ + public static final int STATS_LAST = 1; + + /** + * Include only the current run in the stats. + */ + public static final int STATS_CURRENT = 2; + + /** + * Include only the run since the last time the device was unplugged in the stats. + */ + public static final int STATS_UNPLUGGED = 3; + + private final StringBuilder mFormatBuilder = new StringBuilder(8); + private final Formatter mFormatter = new Formatter(mFormatBuilder); + + /** + * State for keeping track of timing information. + */ + public static abstract class Timer { + + /** + * Returns the count associated with this Timer for the + * selected type of statistics. + * + * @param which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT + */ + public abstract int getCount(int which); + + /** + * Returns the total time in microseconds associated with this Timer for the + * selected type of statistics. + * + * @param now system uptime time in microseconds + * @param which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT + * @return a time in microseconds + */ + public abstract long getTotalTime(long now, int which); + } + + /** + * The statistics associated with a particular uid. + */ + public static abstract class Uid { + + /** + * Returns a mapping containing wakelock statistics. + * + * @return a Map from Strings to Uid.Wakelock objects. + */ + public abstract Map getWakelockStats(); + + /** + * The statistics associated with a particular wake lock. + */ + public static abstract class Wakelock { + public abstract Timer getWakeTime(int type); + } + + /** + * Returns a mapping containing sensor statistics. + * + * @return a Map from Integer sensor ids to Uid.Sensor objects. + */ + public abstract Map getSensorStats(); + + /** + * Returns a mapping containing process statistics. + * + * @return a Map from Strings to Uid.Proc objects. + */ + public abstract Map getProcessStats(); + + /** + * Returns a mapping containing package statistics. + * + * @return a Map from Strings to Uid.Pkg objects. + */ + public abstract Map getPackageStats(); + + public static abstract class Sensor { + public abstract Timer getSensorTime(); + } + + /** + * The statistics associated with a particular process. + */ + public static abstract class Proc { + + /** + * Returns the total time (in 1/100 sec) spent executing in user code. + * + * @param which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT. + */ + public abstract long getUserTime(int which); + + /** + * Returns the total time (in 1/100 sec) spent executing in system code. + * + * @param which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT. + */ + public abstract long getSystemTime(int which); + + /** + * Returns the number of times the process has been started. + * + * @param which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT. + */ + public abstract int getStarts(int which); + } + + /** + * The statistics associated with a particular package. + */ + public static abstract class Pkg { + + /** + * Returns the number of times this package has done something that could wake up the + * device from sleep. + * + * @param which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT. + */ + public abstract int getWakeups(int which); + + /** + * Returns a mapping containing service statistics. + */ + public abstract Map getServiceStats(); + + /** + * The statistics associated with a particular service. + */ + public abstract class Serv { + + /** + * Returns the amount of time spent started. + * + * @param now elapsed realtime in microseconds. + * @param which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT. + * @return + */ + public abstract long getStartTime(long now, int which); + + /** + * Returns the total number of times startService() has been called. + * + * @param which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT. + */ + public abstract int getStarts(int which); + + /** + * Returns the total number times the service has been launched. + * + * @param which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT. + */ + public abstract int getLaunches(int which); + } + } + } + + /** + * Returns the number of times the device has been started. + */ + public abstract int getStartCount(); + + /** + * Returns a SparseArray containing the statistics for each uid. + */ + public abstract SparseArray getUidStats(); + + /** + * Returns the current battery uptime in microseconds. + * + * @param curTime the amount of elapsed realtime in microseconds. + */ + public abstract long getBatteryUptime(long curTime); + + /** + * Returns the current battery realtime in microseconds. + * + * @param curTime the amount of elapsed realtime in microseconds. + */ + public abstract long getBatteryRealtime(long curTime); + + /** + * Returns the total, last, or current battery uptime in microseconds. + * + * @param curTime the elapsed realtime in microseconds. + * @param which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT. + */ + public abstract long computeBatteryUptime(long curTime, int which); + + /** + * Returns the total, last, or current battery realtime in microseconds. + * + * @param curTime the current elapsed realtime in microseconds. + * @param which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT. + */ + public abstract long computeBatteryRealtime(long curTime, int which); + + /** + * Returns the total, last, or current uptime in micropeconds. + * + * @param curTime the current elapsed realtime in microseconds. + * @param which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT. + */ + public abstract long computeUptime(long curTime, int which); + + /** + * Returns the total, last, or current realtime in microseconds. + * * + * @param curTime the current elapsed realtime in microseconds. + * @param which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT. + */ + public abstract long computeRealtime(long curTime, int which); + + private final static void formatTime(StringBuilder out, long seconds) { + long days = seconds / (60 * 60 * 24); + if (days != 0) { + out.append(days); + out.append("d "); + } + long used = days * 60 * 60 * 24; + + long hours = (seconds - used) / (60 * 60); + if (hours != 0 || used != 0) { + out.append(hours); + out.append("h "); + } + used += hours * 60 * 60; + + long mins = (seconds-used) / 60; + if (mins != 0 || used != 0) { + out.append(mins); + out.append("m "); + } + used += mins * 60; + + if (seconds != 0 || used != 0) { + out.append(seconds-used); + out.append("s "); + } + } + + private final static String formatTime(long time) { + long sec = time / 100; + StringBuilder sb = new StringBuilder(); + formatTime(sb, sec); + sb.append((time - (sec * 100)) * 10); + sb.append("ms "); + return sb.toString(); + } + + private final static String formatTimeMs(long time) { + long sec = time / 1000; + StringBuilder sb = new StringBuilder(); + formatTime(sb, sec); + sb.append(time - (sec * 1000)); + sb.append("ms "); + return sb.toString(); + } + + private final String formatRatioLocked(long num, long den) { + float perc = ((float)num) / ((float)den) * 100; + mFormatBuilder.setLength(0); + mFormatter.format("%.1f%%", perc); + return mFormatBuilder.toString(); + } + + /** + * + * @param sb a StringBuilder object. + * @param timer a Timer object contining the wakelock times. + * @param now the current time in microseconds. + * @param name the name of the wakelock. + * @param which which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT. + * @param linePrefix a String to be prepended to each line of output. + * @return the line prefix + */ + private final String printWakeLock(StringBuilder sb, Timer timer, long now, + String name, int which, String linePrefix) { + if (timer != null) { + // Convert from microseconds to milliseconds with rounding + long totalTimeMillis = (timer.getTotalTime(now, which) + 500) / 1000; + int count = timer.getCount(which); + if (totalTimeMillis != 0) { + sb.append(linePrefix); + sb.append(formatTimeMs(totalTimeMillis)); + sb.append(name); + sb.append(' '); + sb.append('('); + sb.append(count); + sb.append(" times)"); + return ", "; + } + } + return linePrefix; + } + + @SuppressWarnings("unused") + private final void dumpLocked(FileDescriptor fd, PrintWriter pw, String prefix, int which) { + long uSecTime = SystemClock.elapsedRealtime() * 1000; + final long uSecNow = getBatteryUptime(uSecTime); + + StringBuilder sb = new StringBuilder(128); + if (which == STATS_TOTAL) { + pw.println(prefix + "Current and Historic Battery Usage Statistics:"); + pw.println(prefix + " System starts: " + getStartCount()); + } else if (which == STATS_LAST) { + pw.println(prefix + "Last Battery Usage Statistics:"); + } else { + pw.println(prefix + "Current Battery Usage Statistics:"); + } + long batteryUptime = computeBatteryUptime(uSecNow, which); + long batteryRealtime = computeBatteryRealtime(getBatteryRealtime(uSecTime), which); + long elapsedRealtime = computeRealtime(uSecTime, which); + pw.println(prefix + + " On battery: " + formatTimeMs(batteryUptime) + "(" + + formatRatioLocked(batteryUptime, batteryRealtime) + + ") uptime, " + + formatTimeMs(batteryRealtime) + "(" + + formatRatioLocked(batteryRealtime, elapsedRealtime) + + ") realtime"); + pw.println(prefix + + " Total: " + + formatTimeMs(computeUptime(SystemClock.uptimeMillis() * 1000, which)) + + "uptime, " + + formatTimeMs(elapsedRealtime) + + "realtime"); + + pw.println(" "); + + SparseArray uidStats = getUidStats(); + final int NU = uidStats.size(); + for (int iu=0; iu wakelocks = u.getWakelockStats(); + if (wakelocks.size() > 0) { + for (Map.Entry ent + : wakelocks.entrySet()) { + Uid.Wakelock wl = ent.getValue(); + String linePrefix = ": "; + sb.setLength(0); + sb.append(prefix); + sb.append(" Wake lock "); + sb.append(ent.getKey()); + linePrefix = printWakeLock(sb, wl.getWakeTime(WAKE_TYPE_FULL), uSecNow, + "full", which, linePrefix); + linePrefix = printWakeLock(sb, wl.getWakeTime(WAKE_TYPE_PARTIAL), uSecNow, + "partial", which, linePrefix); + linePrefix = printWakeLock(sb, wl.getWakeTime(WAKE_TYPE_WINDOW), uSecNow, + "window", which, linePrefix); + if (linePrefix.equals(": ")) { + sb.append(": (nothing executed)"); + } + pw.println(sb.toString()); + uidActivity = true; + } + } + + Map sensors = u.getSensorStats(); + if (sensors.size() > 0) { + for (Map.Entry ent + : sensors.entrySet()) { + Uid.Sensor se = ent.getValue(); + int sensorNumber = ent.getKey(); + sb.setLength(0); + sb.append(prefix); + sb.append(" Sensor "); + sb.append(sensorNumber); + + Timer timer = se.getSensorTime(); + if (timer != null) { + // Convert from microseconds to milliseconds with rounding + long totalTime = (timer.getTotalTime(uSecNow, which) + 500) / 1000; + int count = timer.getCount(which); + if (totalTime != 0) { + sb.append(": "); + sb.append(formatTimeMs(totalTime)); + sb.append(' '); + sb.append('('); + sb.append(count); + sb.append(" times)"); + } + } else { + sb.append(": (none used)"); + } + + pw.println(sb.toString()); + uidActivity = true; + } + } + + Map processStats = u.getProcessStats(); + if (processStats.size() > 0) { + for (Map.Entry ent + : processStats.entrySet()) { + Uid.Proc ps = ent.getValue(); + long userTime; + long systemTime; + int starts; + + userTime = ps.getUserTime(which); + systemTime = ps.getSystemTime(which); + starts = ps.getStarts(which); + + if (userTime != 0 || systemTime != 0 || starts != 0) { + pw.println(prefix + " Proc " + ent.getKey() + ":"); + pw.println(prefix + " CPU: " + formatTime(userTime) + "user + " + + formatTime(systemTime) + "kernel"); + pw.println(prefix + " " + starts + " process starts"); + uidActivity = true; + } + } + } + + Map packageStats = u.getPackageStats(); + if (packageStats.size() > 0) { + for (Map.Entry ent + : packageStats.entrySet()) { + pw.println(prefix + " Apk " + ent.getKey() + ":"); + boolean apkActivity = false; + Uid.Pkg ps = ent.getValue(); + int wakeups = ps.getWakeups(which); + if (wakeups != 0) { + pw.println(prefix + " " + wakeups + " wakeup alarms"); + apkActivity = true; + } + Map serviceStats = ps.getServiceStats(); + if (serviceStats.size() > 0) { + for (Map.Entry sent + : serviceStats.entrySet()) { + BatteryStats.Uid.Pkg.Serv ss = sent.getValue(); + long startTime = ss.getStartTime(uSecNow, which); + int starts = ss.getStarts(which); + int launches = ss.getLaunches(which); + if (startTime != 0 || starts != 0 || launches != 0) { + pw.println(prefix + " Service " + sent.getKey() + ":"); + pw.println(prefix + " Time spent started: " + + formatTimeMs(startTime)); + pw.println(prefix + " Starts: " + starts + + ", launches: " + launches); + apkActivity = true; + } + } + } + if (!apkActivity) { + pw.println(prefix + " (nothing executed)"); + } + uidActivity = true; + } + } + if (!uidActivity) { + pw.println(prefix + " (nothing executed)"); + } + } + } + + /** + * Dumps a human-readable summary of the battery statistics to the given PrintWriter. + * + * @param fd a FileDescriptor, currently unused. + * @param pw a PrintWriter to receive the dump output. + * @param args an array of Strings, currently unused. + */ + @SuppressWarnings("unused") + public void dumpLocked(FileDescriptor fd, PrintWriter pw, String[] args) { + synchronized (this) { + dumpLocked(fd, pw, "", STATS_TOTAL); + pw.println(""); + dumpLocked(fd, pw, "", STATS_LAST); + pw.println(""); + dumpLocked(fd, pw, "", STATS_CURRENT); + } + } +} diff --git a/core/java/android/os/Debug.java b/core/java/android/os/Debug.java index b9b277309e34be727c092c2d13dc2deeaad6ac8e..c3bb967635d5760bdef6f2567e5176a09036cdd2 100644 --- a/core/java/android/os/Debug.java +++ b/core/java/android/os/Debug.java @@ -117,6 +117,10 @@ public final class Debug * waitForDebugger() call if you want to start tracing immediately. */ public static void waitForDebugger() { + if (!VMDebug.isDebuggingEnabled()) { + //System.out.println("debugging not enabled, not waiting"); + return; + } if (isDebuggerConnected()) return; diff --git a/core/java/android/os/Handler.java b/core/java/android/os/Handler.java index b6f38d961786c08c9c16310070ab486687494d22..2a32e543f19f8facb58d78dbc85f7dec72d33c33 100644 --- a/core/java/android/os/Handler.java +++ b/core/java/android/os/Handler.java @@ -54,7 +54,7 @@ import java.lang.reflect.Modifier; *

    When a * process is created for your application, its main thread is dedicated to * running a message queue that takes care of managing the top-level - * application objects (activities, intent receivers, etc) and any windows + * application objects (activities, broadcast receivers, etc) and any windows * they create. You can create your own threads, and communicate back with * the main application thread through a Handler. This is done by calling * the same post or sendMessage methods as before, but from @@ -70,21 +70,32 @@ public class Handler { private static final boolean FIND_POTENTIAL_LEAKS = false; private static final String TAG = "Handler"; + /** + * Callback interface you can use when instantiating a Handler to avoid + * having to implement your own subclass of Handler. + */ + public interface Callback { + public boolean handleMessage(Message msg); + } + /** * Subclasses must implement this to receive messages. */ - public void handleMessage(Message msg) - { + public void handleMessage(Message msg) { } /** * Handle system messages here. */ - public void dispatchMessage(Message msg) - { + public void dispatchMessage(Message msg) { if (msg.callback != null) { handleCallback(msg); } else { + if (mCallback != null) { + if (mCallback.handleMessage(msg)) { + return; + } + } handleMessage(msg); } } @@ -95,8 +106,31 @@ public class Handler { * * If there isn't one, this handler won't be able to receive messages. */ - public Handler() - { + public Handler() { + if (FIND_POTENTIAL_LEAKS) { + final Class klass = getClass(); + if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) && + (klass.getModifiers() & Modifier.STATIC) == 0) { + Log.w(TAG, "The following Handler class should be static or leaks might occur: " + + klass.getCanonicalName()); + } + } + + mLooper = Looper.myLooper(); + if (mLooper == null) { + throw new RuntimeException( + "Can't create handler inside thread that has not called Looper.prepare()"); + } + mQueue = mLooper.mQueue; + mCallback = null; + } + + /** + * Constructor associates this handler with the queue for the + * current thread and takes a callback interface in which you can handle + * messages. + */ + public Handler(Callback callback) { if (FIND_POTENTIAL_LEAKS) { final Class klass = getClass(); if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) && @@ -112,15 +146,26 @@ public class Handler { "Can't create handler inside thread that has not called Looper.prepare()"); } mQueue = mLooper.mQueue; + mCallback = callback; } /** * Use the provided queue instead of the default one. */ - public Handler(Looper looper) - { + public Handler(Looper looper) { + mLooper = looper; + mQueue = looper.mQueue; + mCallback = null; + } + + /** + * Use the provided queue instead of the default one and take a callback + * interface in which to handle messages. + */ + public Handler(Looper looper, Callback callback) { mLooper = looper; mQueue = looper.mQueue; + mCallback = callback; } /** @@ -544,5 +589,6 @@ public class Handler { final MessageQueue mQueue; final Looper mLooper; + final Callback mCallback; IMessenger mMessenger; } diff --git a/core/java/android/os/ICheckinService.aidl b/core/java/android/os/ICheckinService.aidl index aa43852cdf4ca15c70de3bfa10df4a4618ebd708..70ad28e4e469888de8d96cc7548e8ac6d684cf8a 100644 --- a/core/java/android/os/ICheckinService.aidl +++ b/core/java/android/os/ICheckinService.aidl @@ -39,5 +39,6 @@ interface ICheckinService { * Determine if the device is under parental control. Return null if * we are unable to check the parental control status. */ - void getParentalControlState(IParentalControlCallback p); + void getParentalControlState(IParentalControlCallback p, + String requestingApp); } diff --git a/core/java/android/os/IPowerManager.aidl b/core/java/android/os/IPowerManager.aidl index 9d059172283dc8faaf2c9f3de0a52473df79f27e..abc1e2f3105fab279b7ef956cf8356e3dfc6e8bc 100644 --- a/core/java/android/os/IPowerManager.aidl +++ b/core/java/android/os/IPowerManager.aidl @@ -26,6 +26,6 @@ interface IPowerManager void userActivity(long when, boolean noChangeLights); void userActivityWithForce(long when, boolean noChangeLights, boolean force); void setPokeLock(int pokey, IBinder lock, String tag); - void setStayOnSetting(boolean val); + void setStayOnSetting(int val); long getScreenOnTime(); } diff --git a/core/java/android/os/Looper.java b/core/java/android/os/Looper.java index 80b68e252a604b485fdc40d049ed316cb5666ca0..95818938d5eabf1d43dd4cdc394794749429bcfa 100644 --- a/core/java/android/os/Looper.java +++ b/core/java/android/os/Looper.java @@ -130,7 +130,8 @@ public class Looper { } /** - * Return the Looper object associated with the current thread. + * Return the Looper object associated with the current thread. Returns + * null if the calling thread is not associated with a Looper. */ public static final Looper myLooper() { return (Looper)sThreadLocal.get(); @@ -151,7 +152,8 @@ public class Looper { /** * Return the {@link MessageQueue} object associated with the current - * thread. + * thread. This must be called from a thread running a Looper, or a + * NullPointerException will be thrown. */ public static final MessageQueue myQueue() { return myLooper().mQueue; @@ -171,6 +173,16 @@ public class Looper { mQueue.enqueueMessage(msg, 0); } + /** + * Return the Thread associated with this Looper. + * + * @since CURRENT + * {@hide pending API Council approval} + */ + public Thread getThread() { + return mThread; + } + public void dump(Printer pw, String prefix) { pw.println(prefix + this); pw.println(prefix + "mRun=" + mRun); diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java index 2be776842cb996c13e51d5fa77a9661c50f756cc..cd86fbe70dac1c9873356bf43c2fab25e037699e 100644 --- a/core/java/android/os/Process.java +++ b/core/java/android/os/Process.java @@ -19,6 +19,7 @@ package android.os; import android.net.LocalSocketAddress; import android.net.LocalSocket; import android.util.Log; +import dalvik.system.Zygote; import java.io.BufferedWriter; import java.io.DataInputStream; @@ -221,13 +222,13 @@ public class Process { public static final int start(final String processClass, final String niceName, int uid, int gid, int[] gids, - boolean enableDebugger, + int debugFlags, String[] zygoteArgs) { if (supportsProcesses()) { try { return startViaZygote(processClass, niceName, uid, gid, gids, - enableDebugger, zygoteArgs); + debugFlags, zygoteArgs); } catch (ZygoteStartFailedEx ex) { Log.e(LOG_TAG, "Starting VM process through Zygote failed"); @@ -259,9 +260,9 @@ public class Process { * {@hide} */ public static final int start(String processClass, int uid, int gid, - int[] gids, boolean enableDebugger, String[] zygoteArgs) { + int[] gids, int debugFlags, String[] zygoteArgs) { return start(processClass, "", uid, gid, gids, - enableDebugger, zygoteArgs); + debugFlags, zygoteArgs); } private static void invokeStaticMain(String className) { @@ -452,7 +453,7 @@ public class Process { final String niceName, final int uid, final int gid, final int[] gids, - boolean enableDebugger, + int debugFlags, String[] extraArgs) throws ZygoteStartFailedEx { int pid; @@ -465,9 +466,15 @@ public class Process { argsForZygote.add("--runtime-init"); argsForZygote.add("--setuid=" + uid); argsForZygote.add("--setgid=" + gid); - if (enableDebugger) { + if ((debugFlags & Zygote.DEBUG_ENABLE_DEBUGGER) != 0) { argsForZygote.add("--enable-debugger"); } + if ((debugFlags & Zygote.DEBUG_ENABLE_CHECKJNI) != 0) { + argsForZygote.add("--enable-checkjni"); + } + if ((debugFlags & Zygote.DEBUG_ENABLE_ASSERT) != 0) { + argsForZygote.add("--enable-assert"); + } //TODO optionally enable debuger //argsForZygote.add("--enable-debugger"); @@ -529,7 +536,12 @@ public class Process { public static final native int myTid(); /** - * Returns the UID assigned to a partlicular user name, or -1 if there is + * Returns the identifier of this process's user. + */ + public static final native int myUid(); + + /** + * Returns the UID assigned to a particular user name, or -1 if there is * none. If the given string consists of only numbers, it is converted * directly to a uid. */ diff --git a/core/java/android/pim/EventRecurrence.java b/core/java/android/pim/EventRecurrence.java index ad671f6856488ab2ad54c493c6da444665c7e0a8..edf69eea8a86d182ada45958d93dbe557a375c62 100644 --- a/core/java/android/pim/EventRecurrence.java +++ b/core/java/android/pim/EventRecurrence.java @@ -18,6 +18,7 @@ package android.pim; import android.content.res.Resources; import android.text.TextUtils; +import android.text.format.Time; import java.util.Calendar; diff --git a/core/java/android/pim/RecurrenceSet.java b/core/java/android/pim/RecurrenceSet.java index c02ff52e84f5be12718cc091196a8944e0868225..c6615da03eef8c600b84fd33bed7ac9e4870a643 100644 --- a/core/java/android/pim/RecurrenceSet.java +++ b/core/java/android/pim/RecurrenceSet.java @@ -21,6 +21,7 @@ import android.database.Cursor; import android.os.Bundle; import android.provider.Calendar; import android.text.TextUtils; +import android.text.format.Time; import android.util.Config; import android.util.Log; @@ -145,7 +146,7 @@ public class RecurrenceSet { long[] dates = new long[n]; for (int i = 0; i * This preference will store a boolean into the SharedPreferences. diff --git a/core/java/android/preference/DialogPreference.java b/core/java/android/preference/DialogPreference.java index 3eb65e2c033dcc1848bea9857cb7ff3a69b53ba0..666efaeaffd3713b9ec9455c399bfb10d3da1877 100644 --- a/core/java/android/preference/DialogPreference.java +++ b/core/java/android/preference/DialogPreference.java @@ -34,7 +34,7 @@ import android.view.View; import android.widget.TextView; /** - * The {@link DialogPreference} class is a base class for preferences that are + * A base class for {@link Preference} objects that are * dialog-based. These preferences will, when clicked, open a dialog showing the * actual preference controls. * @@ -356,7 +356,7 @@ public abstract class DialogPreference extends Preference implements getPreferenceManager().unregisterOnActivityDestroyListener(this); mDialog = null; - onDialogClosed(mWhichButtonClicked == DialogInterface.BUTTON1); + onDialogClosed(mWhichButtonClicked == DialogInterface.BUTTON_POSITIVE); } /** @@ -369,6 +369,15 @@ public abstract class DialogPreference extends Preference implements protected void onDialogClosed(boolean positiveResult) { } + /** + * Gets the dialog that is shown by this preference. + * + * @return The dialog, or null if a dialog is not being shown. + */ + public Dialog getDialog() { + return mDialog; + } + /** * {@inheritDoc} */ diff --git a/core/java/android/preference/EditTextPreference.java b/core/java/android/preference/EditTextPreference.java index be56003c94bce675041a98b3f87be861033fe58a..a12704f4820a3fcd45d25bcb9c0dd3983117006a 100644 --- a/core/java/android/preference/EditTextPreference.java +++ b/core/java/android/preference/EditTextPreference.java @@ -31,7 +31,7 @@ import android.widget.EditText; import android.widget.LinearLayout; /** - * The {@link EditTextPreference} class is a preference that allows for string + * A {@link Preference} that allows for string * input. *

    * It is a subclass of {@link DialogPreference} and shows the {@link EditText} diff --git a/core/java/android/preference/ListPreference.java b/core/java/android/preference/ListPreference.java index 6c98dedf91bb66fec45bde0e163c7a6fe11f5974..f842d754cbb6e6cb5b9744e9a59437da572b11a6 100644 --- a/core/java/android/preference/ListPreference.java +++ b/core/java/android/preference/ListPreference.java @@ -26,7 +26,7 @@ import android.os.Parcelable; import android.util.AttributeSet; /** - * The {@link ListPreference} is a preference that displays a list of entries as + * A {@link Preference} that displays a list of entries as * a dialog. *

    * This preference will store a string into the SharedPreferences. This string will be the value @@ -192,8 +192,22 @@ public class ListPreference extends DialogPreference { new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { mClickedDialogEntryIndex = which; + + /* + * Clicking on an item simulates the positive button + * click, and dismisses the dialog. + */ + ListPreference.this.onClick(dialog, DialogInterface.BUTTON_POSITIVE); + dialog.dismiss(); } }); + + /* + * The typical interaction for list-based dialogs is to have + * click-on-an-item dismiss the dialog instead of the user having to + * press 'Ok'. + */ + builder.setPositiveButton(null, null); } @Override diff --git a/core/java/android/preference/Preference.java b/core/java/android/preference/Preference.java index 1db7525da0e44348df363937a77354b5334a8482..3820f28563262fd6842ca8b3732400dd084bb703 100644 --- a/core/java/android/preference/Preference.java +++ b/core/java/android/preference/Preference.java @@ -37,13 +37,13 @@ import android.widget.ListView; import android.widget.TextView; /** - * The {@link Preference} class represents the basic preference UI building - * block that is displayed by a {@link PreferenceActivity} in the form of a + * Represents the basic Preference UI building + * block displayed by a {@link PreferenceActivity} in the form of a * {@link ListView}. This class provides the {@link View} to be displayed in * the activity and associates with a {@link SharedPreferences} to * store/retrieve the preference data. *

    - * When specifying a preference hierarchy in XML, each tag name can point to a + * When specifying a preference hierarchy in XML, each element can point to a * subclass of {@link Preference}, similar to the view hierarchy and layouts. *

    * This class contains a {@code key} that will be used as the key into the @@ -109,46 +109,46 @@ public class Preference implements Comparable, OnDependencyChangeLis private boolean mBaseMethodCalled; /** - * Interface definition for a callback to be invoked when this - * {@link Preference Preference's} value has been changed by the user and is + * Interface definition for a callback to be invoked when the value of this + * {@link Preference} has been changed by the user and is * about to be set and/or persisted. This gives the client a chance * to prevent setting and/or persisting the value. */ public interface OnPreferenceChangeListener { /** - * Called when this preference has been changed by the user. This is - * called before the preference's state is about to be updated and + * Called when a Preference has been changed by the user. This is + * called before the state of the Preference is about to be updated and * before the state is persisted. * - * @param preference This preference. - * @param newValue The new value of the preference. - * @return Whether or not to update this preference's state with the new value. + * @param preference The changed Preference. + * @param newValue The new value of the Preference. + * @return True to update the state of the Preference with the new value. */ boolean onPreferenceChange(Preference preference, Object newValue); } /** - * Interface definition for a callback to be invoked when a preference is + * Interface definition for a callback to be invoked when a {@link Preference} is * clicked. */ public interface OnPreferenceClickListener { /** - * Called when a preference has been clicked. + * Called when a Preference has been clicked. * - * @param preference The preference that was clicked. - * @return Whether the click was handled. + * @param preference The Preference that was clicked. + * @return True if the click was handled. */ boolean onPreferenceClick(Preference preference); } /** * Interface definition for a callback to be invoked when this - * {@link Preference} is changed or if this is a group, there is an + * {@link Preference} is changed or, if this is a group, there is an * addition/removal of {@link Preference}(s). This is used internally. */ interface OnPreferenceChangeInternalListener { /** - * Called when this preference has changed. + * Called when this Preference has changed. * * @param preference This preference. */ @@ -157,18 +157,18 @@ public class Preference implements Comparable, OnDependencyChangeLis /** * Called when this group has added/removed {@link Preference}(s). * - * @param preference This preference. + * @param preference This Preference. */ void onPreferenceHierarchyChange(Preference preference); } /** * Perform inflation from XML and apply a class-specific base style. This - * constructor of {@link Preference} allows subclasses to use their own base - * style when they are inflating. For example, a {@link CheckBoxPreference}'s - * constructor would call this version of the super class constructor and - * supply {@code android.R.attr.checkBoxPreferenceStyle} for defStyle; - * this allows the theme's checkbox preference style to modify all of the base + * constructor of Preference allows subclasses to use their own base + * style when they are inflating. For example, a {@link CheckBoxPreference} + * constructor calls this version of the super class constructor and + * supplies {@code android.R.attr.checkBoxPreferenceStyle} for defStyle. + * This allows the theme's checkbox preference style to modify all of the base * preference attributes as well as the {@link CheckBoxPreference} class's * attributes. * @@ -254,8 +254,8 @@ public class Preference implements Comparable, OnDependencyChangeLis } /** - * Constructor that is called when inflating a preference from XML. This is - * called when a preference is being constructed from an XML file, supplying + * Constructor that is called when inflating a Preference from XML. This is + * called when a Preference is being constructed from an XML file, supplying * attributes that were specified in the XML file. This version uses a * default style of 0, so the only attribute values applied are those in the * Context's Theme and the given AttributeSet. @@ -274,15 +274,15 @@ public class Preference implements Comparable, OnDependencyChangeLis /** * Constructor to create a Preference. * - * @param context The context to store preference values. + * @param context The Context in which to store Preference values. */ public Preference(Context context) { this(context, null); } /** - * Called when {@link Preference} is being inflated and the default value - * attribute needs to be read. Since different preference types have + * Called when a Preference is being inflated and the default value + * attribute needs to be read. Since different Preference types have * different value types, the subclass should get and return the default * value which will be its value type. *

    @@ -299,16 +299,16 @@ public class Preference implements Comparable, OnDependencyChangeLis /** * Sets an {@link Intent} to be used for - * {@link Context#startActivity(Intent)} when the preference is clicked. + * {@link Context#startActivity(Intent)} when this Preference is clicked. * - * @param intent The intent associated with the preference. + * @param intent The intent associated with this Preference. */ public void setIntent(Intent intent) { mIntent = intent; } /** - * Return the {@link Intent} associated with this preference. + * Return the {@link Intent} associated with this Preference. * * @return The {@link Intent} last set via {@link #setIntent(Intent)} or XML. */ @@ -318,12 +318,12 @@ public class Preference implements Comparable, OnDependencyChangeLis /** * Sets the layout resource that is inflated as the {@link View} to be shown - * for this preference. In most cases, the default layout is sufficient for - * custom preferences and only the widget layout needs to be changed. + * for this Preference. In most cases, the default layout is sufficient for + * custom Preference objects and only the widget layout needs to be changed. *

    * This layout should contain a {@link ViewGroup} with ID * {@link android.R.id#widget_frame} to be the parent of the specific widget - * for this preference. It should similarly contain + * for this Preference. It should similarly contain * {@link android.R.id#title} and {@link android.R.id#summary}. * * @param layoutResId The layout resource ID to be inflated and returned as @@ -340,7 +340,7 @@ public class Preference implements Comparable, OnDependencyChangeLis } /** - * Gets the layout resource that will be shown as the {@link View} for this preference. + * Gets the layout resource that will be shown as the {@link View} for this Preference. * * @return The layout resource ID. */ @@ -349,8 +349,8 @@ public class Preference implements Comparable, OnDependencyChangeLis } /** - * Sets The layout for the controllable widget portion of a preference. This - * is inflated into the main layout. For example, a checkbox preference + * Sets The layout for the controllable widget portion of this Preference. This + * is inflated into the main layout. For example, a {@link CheckBoxPreference} * would specify a custom layout (consisting of just the CheckBox) here, * instead of creating its own main layout. * @@ -363,7 +363,7 @@ public class Preference implements Comparable, OnDependencyChangeLis } /** - * Gets the layout resource for the controllable widget portion of a preference. + * Gets the layout resource for the controllable widget portion of this Preference. * * @return The layout resource ID. */ @@ -374,11 +374,11 @@ public class Preference implements Comparable, OnDependencyChangeLis /** * Gets the View that will be shown in the {@link PreferenceActivity}. * - * @param convertView The old view to reuse, if possible. Note: You should - * check that this view is non-null and of an appropriate type - * before using. If it is not possible to convert this view to - * display the correct data, this method can create a new view. - * @param parent The parent that this view will eventually be attached to. + * @param convertView The old View to reuse, if possible. Note: You should + * check that this View is non-null and of an appropriate type + * before using. If it is not possible to convert this View to + * display the correct data, this method can create a new View. + * @param parent The parent that this View will eventually be attached to. * @return Returns the same Preference object, for chaining multiple calls * into a single statement. * @see #onCreateView(ViewGroup) @@ -393,16 +393,16 @@ public class Preference implements Comparable, OnDependencyChangeLis } /** - * Creates the View to be shown for this preference in the + * Creates the View to be shown for this Preference in the * {@link PreferenceActivity}. The default behavior is to inflate the main - * layout of this preference (see {@link #setLayoutResource(int)}. If + * layout of this Preference (see {@link #setLayoutResource(int)}. If * changing this behavior, please specify a {@link ViewGroup} with ID * {@link android.R.id#widget_frame}. *

    * Make sure to call through to the superclass's implementation. * - * @param parent The parent that this view will eventually be attached to. - * @return The View that displays this preference. + * @param parent The parent that this View will eventually be attached to. + * @return The View that displays this Preference. * @see #onBindView(View) */ protected View onCreateView(ViewGroup parent) { @@ -420,14 +420,14 @@ public class Preference implements Comparable, OnDependencyChangeLis } /** - * Binds the created View to the data for the preference. + * Binds the created View to the data for this Preference. *

    * This is a good place to grab references to custom Views in the layout and * set properties on them. *

    * Make sure to call through to the superclass's implementation. * - * @param view The View that shows this preference. + * @param view The View that shows this Preference. * @see #onCreateView(ViewGroup) */ protected void onBindView(View view) { @@ -453,7 +453,7 @@ public class Preference implements Comparable, OnDependencyChangeLis } if (mShouldDisableView) { - setEnabledStateOnViews(view, mEnabled); + setEnabledStateOnViews(view, isEnabled()); } } @@ -472,13 +472,13 @@ public class Preference implements Comparable, OnDependencyChangeLis } /** - * Sets the order of this {@link Preference} with respect to other - * {@link Preference} on the same level. If this is not specified, the + * Sets the order of this Preference with respect to other + * Preference objects on the same level. If this is not specified, the * default behavior is to sort alphabetically. The * {@link PreferenceGroup#setOrderingAsAdded(boolean)} can be used to order - * preferences based on the order they appear in the XML. + * Preference objects based on the order they appear in the XML. * - * @param order The order for this preference. A lower value will be shown + * @param order The order for this Preference. A lower value will be shown * first. Use {@link #DEFAULT_ORDER} to sort alphabetically or * allow ordering from XML. * @see PreferenceGroup#setOrderingAsAdded(boolean) @@ -494,9 +494,10 @@ public class Preference implements Comparable, OnDependencyChangeLis } /** - * Gets the order of this {@link Preference}. + * Gets the order of this Preference with respect to other Preference objects + * on the same level. * - * @return The order of this {@link Preference}. + * @return The order of this Preference. * @see #setOrder(int) */ public int getOrder() { @@ -504,11 +505,12 @@ public class Preference implements Comparable, OnDependencyChangeLis } /** - * Sets the title for the preference. This title will be placed into the ID + * Sets the title for this Preference with a CharSequence. + * This title will be placed into the ID * {@link android.R.id#title} within the View created by * {@link #onCreateView(ViewGroup)}. * - * @param title The title of the preference. + * @param title The title for this Preference. */ public void setTitle(CharSequence title) { if (title == null && mTitle != null || title != null && !title.equals(mTitle)) { @@ -518,6 +520,8 @@ public class Preference implements Comparable, OnDependencyChangeLis } /** + * Sets the title for this Preference with a resource ID. + * * @see #setTitle(CharSequence) * @param titleResId The title as a resource ID. */ @@ -526,7 +530,7 @@ public class Preference implements Comparable, OnDependencyChangeLis } /** - * Returns the title of the preference. + * Returns the title of this Preference. * * @return The title. * @see #setTitle(CharSequence) @@ -536,7 +540,7 @@ public class Preference implements Comparable, OnDependencyChangeLis } /** - * Returns the summary of the preference. + * Returns the summary of this Preference. * * @return The summary. * @see #setSummary(CharSequence) @@ -546,11 +550,9 @@ public class Preference implements Comparable, OnDependencyChangeLis } /** - * Sets the summary for the preference. This summary will be placed into the - * ID {@link android.R.id#summary} within the View created by - * {@link #onCreateView(ViewGroup)}. + * Sets the summary for this Preference with a CharSequence. * - * @param summary The summary of the preference. + * @param summary The summary for the preference. */ public void setSummary(CharSequence summary) { if (summary == null && mSummary != null || summary != null && !summary.equals(mSummary)) { @@ -560,6 +562,8 @@ public class Preference implements Comparable, OnDependencyChangeLis } /** + * Sets the summary for this Preference with a resource ID. + * * @see #setSummary(CharSequence) * @param summaryResId The summary as a resource. */ @@ -568,10 +572,10 @@ public class Preference implements Comparable, OnDependencyChangeLis } /** - * Sets whether this preference is enabled. If disabled, the preference will + * Sets whether this Preference is enabled. If disabled, it will * not handle clicks. * - * @param enabled Whether the preference is enabled. + * @param enabled Set true to enable it. */ public void setEnabled(boolean enabled) { if (mEnabled != enabled) { @@ -585,18 +589,18 @@ public class Preference implements Comparable, OnDependencyChangeLis } /** - * Whether this {@link Preference} should be enabled in the list. + * Checks whether this Preference should be enabled in the list. * - * @return Whether this preference is enabled. + * @return True if this Preference is enabled, false otherwise. */ public boolean isEnabled() { return mEnabled; } /** - * Sets whether this preference is selectable. + * Sets whether this Preference is selectable. * - * @param selectable Whether the preference is selectable. + * @param selectable Set true to make it selectable. */ public void setSelectable(boolean selectable) { if (mSelectable != selectable) { @@ -606,23 +610,23 @@ public class Preference implements Comparable, OnDependencyChangeLis } /** - * Whether this {@link Preference} should be selectable in the list. + * Checks whether this Preference should be selectable in the list. * - * @return Whether this preference is selectable. + * @return True if it is selectable, false otherwise. */ public boolean isSelectable() { return mSelectable; } /** - * Sets whether this {@link Preference} should disable its view when it gets + * Sets whether this Preference should disable its view when it gets * disabled. *

    * For example, set this and {@link #setEnabled(boolean)} to false for * preferences that are only displaying information and 1) should not be * clickable 2) should not have the view set to the disabled state. * - * @param shouldDisableView Whether this preference should disable its view + * @param shouldDisableView Set true if this preference should disable its view * when the preference is disabled. */ public void setShouldDisableView(boolean shouldDisableView) { @@ -631,18 +635,19 @@ public class Preference implements Comparable, OnDependencyChangeLis } /** + * Checks whether this Preference should disable its view when it's action is disabled. * @see #setShouldDisableView(boolean) - * @return Whether this preference should disable its view when it is disabled. + * @return True if it should disable the view. */ public boolean getShouldDisableView() { return mShouldDisableView; } /** - * Returns a unique ID for this preference. This ID should be unique across all - * preferences in a hierarchy. + * Returns a unique ID for this Preference. This ID should be unique across all + * Preference objects in a hierarchy. * - * @return A unique ID for this preference. + * @return A unique ID for this Preference. */ long getId() { return mId; @@ -658,7 +663,7 @@ public class Preference implements Comparable, OnDependencyChangeLis } /** - * Sets the key for the preference which is used as a key to the + * Sets the key for this Preference, which is used as a key to the * {@link SharedPreferences}. This should be unique for the package. * * @param key The key for the preference. @@ -673,7 +678,7 @@ public class Preference implements Comparable, OnDependencyChangeLis } /** - * Gets the key for the preference, which is also the key used for storing + * Gets the key for this Preference, which is also the key used for storing * values into SharedPreferences. * * @return The key. @@ -686,6 +691,8 @@ public class Preference implements Comparable, OnDependencyChangeLis * Checks whether the key is present, and if it isn't throws an * exception. This should be called by subclasses that store preferences in * the {@link SharedPreferences}. + * + * @throws IllegalStateException If there is no key assigned. */ void requireKey() { if (mKey == null) { @@ -696,43 +703,43 @@ public class Preference implements Comparable, OnDependencyChangeLis } /** - * Returns whether this {@link Preference} has a valid key. + * Checks whether this Preference has a valid key. * - * @return Whether the key exists and is not a blank string. + * @return True if the key exists and is not a blank string, false otherwise. */ public boolean hasKey() { return !TextUtils.isEmpty(mKey); } /** - * Returns whether this {@link Preference} is persistent. If it is persistent, it stores its value(s) into + * Checks whether this Preference is persistent. If it is, it stores its value(s) into * the persistent {@link SharedPreferences} storage. * - * @return Whether this is persistent. + * @return True if it is persistent. */ public boolean isPersistent() { return mPersistent; } /** - * Convenience method of whether at the given time this method is called, - * the {@link Preference} should store/restore its value(s) into the - * {@link SharedPreferences}. This, at minimum, checks whether the - * {@link Preference} is persistent and it currently has a key. Before you + * Checks whether, at the given time this method is called, + * this Preference should store/restore its value(s) into the + * {@link SharedPreferences}. This, at minimum, checks whether this + * Preference is persistent and it currently has a key. Before you * save/restore from the {@link SharedPreferences}, check this first. * - * @return Whether to persist the value. + * @return True if it should persist the value. */ protected boolean shouldPersist() { return mPreferenceManager != null && isPersistent() && hasKey(); } /** - * Sets whether this {@link Preference} is persistent. If it is persistent, + * Sets whether this Preference is persistent. When persistent, * it stores its value(s) into the persistent {@link SharedPreferences} * storage. * - * @param persistent Whether it should store its value(s) into the {@link SharedPreferences}. + * @param persistent Set true if it should store its value(s) into the {@link SharedPreferences}. */ public void setPersistent(boolean persistent) { mPersistent = persistent; @@ -742,8 +749,8 @@ public class Preference implements Comparable, OnDependencyChangeLis * Call this method after the user changes the preference, but before the * internal state is set. This allows the client to ignore the user value. * - * @param newValue The new value of the preference. - * @return Whether or not the user value should be set as the preference + * @param newValue The new value of this Preference. + * @return True if the user value should be set as the preference * value (and persisted). */ protected boolean callChangeListener(Object newValue) { @@ -751,7 +758,7 @@ public class Preference implements Comparable, OnDependencyChangeLis } /** - * Sets the callback to be invoked when this preference is changed by the + * Sets the callback to be invoked when this Preference is changed by the * user (but before the internal state has been updated). * * @param onPreferenceChangeListener The callback to be invoked. @@ -761,7 +768,7 @@ public class Preference implements Comparable, OnDependencyChangeLis } /** - * Gets the callback to be invoked when this preference is changed by the + * Returns the callback to be invoked when this Preference is changed by the * user (but before the internal state has been updated). * * @return The callback to be invoked. @@ -771,7 +778,7 @@ public class Preference implements Comparable, OnDependencyChangeLis } /** - * Sets the callback to be invoked when this preference is clicked. + * Sets the callback to be invoked when this Preference is clicked. * * @param onPreferenceClickListener The callback to be invoked. */ @@ -780,7 +787,7 @@ public class Preference implements Comparable, OnDependencyChangeLis } /** - * Gets the callback to be invoked when this preference is clicked. + * Returns the callback to be invoked when this Preference is clicked. * * @return The callback to be invoked. */ @@ -791,9 +798,9 @@ public class Preference implements Comparable, OnDependencyChangeLis /** * Called when a click should be performed. * - * @param preferenceScreen Optional {@link PreferenceScreen} whose hierarchy click + * @param preferenceScreen A {@link PreferenceScreen} whose hierarchy click * listener should be called in the proper order (between other - * processing). + * processing). May be null. */ void performClick(PreferenceScreen preferenceScreen) { @@ -824,18 +831,19 @@ public class Preference implements Comparable, OnDependencyChangeLis } /** - * Returns the context of this preference. Each preference in a preference hierarchy can be - * from different context (for example, if multiple activities provide preferences into a single - * {@link PreferenceActivity}). This context will be used to save the preference valus. + * Returns the {@link android.content.Context} of this Preference. + * Each Preference in a Preference hierarchy can be + * from different Context (for example, if multiple activities provide preferences into a single + * {@link PreferenceActivity}). This Context will be used to save the Preference values. * - * @return The context of this preference. + * @return The Context of this Preference. */ public Context getContext() { return mContext; } /** - * Returns the {@link SharedPreferences} where this preference can read its + * Returns the {@link SharedPreferences} where this Preference can read its * value(s). Usually, it's easier to use one of the helper read methods: * {@link #getPersistedBoolean(boolean)}, {@link #getPersistedFloat(float)}, * {@link #getPersistedInt(int)}, {@link #getPersistedLong(long)}, @@ -847,8 +855,8 @@ public class Preference implements Comparable, OnDependencyChangeLis * {@link SharedPreferences}, this is intended behavior to improve * performance. * - * @return The {@link SharedPreferences} where this preference reads its - * value(s), or null if it isn't attached to a preference hierarchy. + * @return The {@link SharedPreferences} where this Preference reads its + * value(s), or null if it isn't attached to a Preference hierarchy. * @see #getEditor() */ public SharedPreferences getSharedPreferences() { @@ -860,7 +868,7 @@ public class Preference implements Comparable, OnDependencyChangeLis } /** - * Returns an {@link SharedPreferences.Editor} where this preference can + * Returns an {@link SharedPreferences.Editor} where this Preference can * save its value(s). Usually it's easier to use one of the helper save * methods: {@link #persistBoolean(boolean)}, {@link #persistFloat(float)}, * {@link #persistInt(int)}, {@link #persistLong(long)}, @@ -869,11 +877,11 @@ public class Preference implements Comparable, OnDependencyChangeLis * true, it is this Preference's responsibility to commit. *

    * In some cases, writes to this will not be committed right away and hence - * not show up in the shared preferences, this is intended behavior to + * not show up in the SharedPreferences, this is intended behavior to * improve performance. * * @return A {@link SharedPreferences.Editor} where this preference saves - * its value(s), or null if it isn't attached to a preference + * its value(s), or null if it isn't attached to a Preference * hierarchy. * @see #shouldCommit() * @see #getSharedPreferences() @@ -903,9 +911,11 @@ public class Preference implements Comparable, OnDependencyChangeLis } /** - * Compares preferences based on order (if set), otherwise alphabetically on title. - *

    - * {@inheritDoc} + * Compares Preference objects based on order (if set), otherwise alphabetically on the titles. + * + * @param another The Preference to compare to this one. + * @return 0 if the same; less than 0 if this Preference sorts ahead of another; + * greater than 0 if this Preference sorts after another. */ public int compareTo(Preference another) { if (mOrder != DEFAULT_ORDER @@ -942,7 +952,7 @@ public class Preference implements Comparable, OnDependencyChangeLis } /** - * Should be called this is a group a {@link Preference} has been + * Should be called when a Preference has been * added/removed from this group, or the ordering should be * re-evaluated. */ @@ -953,7 +963,7 @@ public class Preference implements Comparable, OnDependencyChangeLis } /** - * Gets the {@link PreferenceManager} that manages this preference's tree. + * Gets the {@link PreferenceManager} that manages this Preference object's tree. * * @return The {@link PreferenceManager}. */ @@ -962,10 +972,10 @@ public class Preference implements Comparable, OnDependencyChangeLis } /** - * Called when this preference has been attached to a preference hierarchy. + * Called when this Preference has been attached to a Preference hierarchy. * Make sure to call the super implementation. * - * @param preferenceManager The preference manager of the hierarchy. + * @param preferenceManager The PreferenceManager of the hierarchy. */ protected void onAttachedToHierarchy(PreferenceManager preferenceManager) { mPreferenceManager = preferenceManager; @@ -976,9 +986,9 @@ public class Preference implements Comparable, OnDependencyChangeLis } /** - * Called when the preference hierarchy has been attached to the + * Called when the Preference hierarchy has been attached to the * {@link PreferenceActivity}. This can also be called when this - * {@link Preference} has been attached to a group that was already attached + * Preference has been attached to a group that was already attached * to the {@link PreferenceActivity}. */ protected void onAttachedToActivity() { @@ -1010,15 +1020,14 @@ public class Preference implements Comparable, OnDependencyChangeLis } /** - * Find a Preference in this hierarchy (the whole thing, + * Finds a Preference in this hierarchy (the whole thing, * even above/below your {@link PreferenceScreen} screen break) with the given * key. *

    * This only functions after we have been attached to a hierarchy. * - * @param key The key of the {@link Preference} to find. - * @return The {@link Preference} object of a preference - * with the given key. + * @param key The key of the Preference to find. + * @return The Preference that uses the given key. */ protected Preference findPreferenceInHierarchy(String key) { if (TextUtils.isEmpty(key) || mPreferenceManager == null) { @@ -1029,13 +1038,13 @@ public class Preference implements Comparable, OnDependencyChangeLis } /** - * Adds a dependent Preference on this preference so we can notify it. - * Usually, the dependent preference registers itself (it's good for it to + * Adds a dependent Preference on this Preference so we can notify it. + * Usually, the dependent Preference registers itself (it's good for it to * know it depends on something), so please use - * {@link Preference#setDependency(String)} on the dependent preference. + * {@link Preference#setDependency(String)} on the dependent Preference. * * @param dependent The dependent Preference that will be enabled/disabled - * according to the state of this preference. + * according to the state of this Preference. */ private void registerDependent(Preference dependent) { if (mDependents == null) { @@ -1048,10 +1057,10 @@ public class Preference implements Comparable, OnDependencyChangeLis } /** - * Removes a dependent Preference on this preference. + * Removes a dependent Preference on this Preference. * * @param dependent The dependent Preference that will be enabled/disabled - * according to the state of this preference. + * according to the state of this Preference. * @return Returns the same Preference object, for chaining multiple calls * into a single statement. */ @@ -1065,7 +1074,7 @@ public class Preference implements Comparable, OnDependencyChangeLis * Notifies any listening dependents of a change that affects the * dependency. * - * @param disableDependents Whether this {@link Preference} should disable + * @param disableDependents Whether this Preference should disable * its dependents. */ public void notifyDependencyChange(boolean disableDependents) { @@ -1084,15 +1093,15 @@ public class Preference implements Comparable, OnDependencyChangeLis /** * Called when the dependency changes. * - * @param dependency The preference that this preference depends on. - * @param disableDependent Whether to disable this preference. + * @param dependency The Preference that this Preference depends on. + * @param disableDependent Set true to disable this Preference. */ public void onDependencyChanged(Preference dependency, boolean disableDependent) { setEnabled(!disableDependent); } /** - * Should return whether this preference's dependents should currently be + * Checks whether this preference's dependents should currently be * disabled. * * @return True if the dependents should be disabled, otherwise false. @@ -1117,7 +1126,7 @@ public class Preference implements Comparable, OnDependencyChangeLis } /** - * Returns the key of the dependency on this preference. + * Returns the key of the dependency on this Preference. * * @return The key of the dependency. * @see #setDependency(String) @@ -1136,7 +1145,7 @@ public class Preference implements Comparable, OnDependencyChangeLis } /** - * Sets the default value for the preference, which will be set either if + * Sets the default value for this Preference, which will be set either if * persistence is off or persistence is on and the preference is not found * in the persistent storage. * @@ -1159,17 +1168,21 @@ public class Preference implements Comparable, OnDependencyChangeLis } /** - * Implement this to set the initial value of the Preference. If the - * restoreValue flag is true, you should restore the value from the shared - * preferences. If false, you should set (and possibly store to shared - * preferences if {@link #shouldPersist()}) to defaultValue. + * Implement this to set the initial value of the Preference. + *

    + * If restorePersistedValue is true, you should restore the + * Preference value from the {@link android.content.SharedPreferences}. If + * restorePersistedValue is false, you should set the Preference + * value to defaultValue that is given (and possibly store to SharedPreferences + * if {@link #shouldPersist()} is true). *

    * This may not always be called. One example is if it should not persist * but there is no default value given. * - * @param restorePersistedValue Whether to restore the persisted value - * (true), or use the given default value (false). - * @param defaultValue The default value. Only use if restoreValue is false. + * @param restorePersistedValue True to restore the persisted value; + * false to use the given defaultValue. + * @param defaultValue The default value for this Preference. Only use this + * if restorePersistedValue is false. */ protected void onSetInitialValue(boolean restorePersistedValue, Object defaultValue) { } @@ -1181,14 +1194,14 @@ public class Preference implements Comparable, OnDependencyChangeLis } /** - * Attempts to persist a String to the SharedPreferences. + * Attempts to persist a String to the {@link android.content.SharedPreferences}. *

    - * This will check if the Preference is persistent, get an editor from - * the preference manager, put the string, check if we should commit (and + * This will check if this Preference is persistent, get an editor from + * the {@link PreferenceManager}, put in the string, and check if we should commit (and * commit if so). * * @param value The value to persist. - * @return Whether the Preference is persistent. (This is not whether the + * @return True if the Preference is persistent. (This is not whether the * value was persisted, since we may not necessarily commit if there * will be a batch commit later.) * @see #getPersistedString(String) @@ -1210,15 +1223,15 @@ public class Preference implements Comparable, OnDependencyChangeLis } /** - * Attempts to get a persisted String from the SharedPreferences. + * Attempts to get a persisted String from the {@link android.content.SharedPreferences}. *

    - * This will check if the Preference is persistent, get the shared - * preferences from the preference manager, get the value. + * This will check if this Preference is persistent, get the SharedPreferences + * from the {@link PreferenceManager}, and get the value. * * @param defaultReturnValue The default value to return if either the * Preference is not persistent or the Preference is not in the * shared preferences. - * @return The value from the shared preferences or the default return + * @return The value from the SharedPreferences or the default return * value. * @see #persistString(String) */ @@ -1231,10 +1244,10 @@ public class Preference implements Comparable, OnDependencyChangeLis } /** - * Attempts to persist an int to the SharedPreferences. + * Attempts to persist an int to the {@link android.content.SharedPreferences}. * * @param value The value to persist. - * @return Whether the Preference is persistent. (This is not whether the + * @return True if the Preference is persistent. (This is not whether the * value was persisted, since we may not necessarily commit if there * will be a batch commit later.) * @see #persistString(String) @@ -1256,12 +1269,12 @@ public class Preference implements Comparable, OnDependencyChangeLis } /** - * Attempts to get a persisted int from the SharedPreferences. + * Attempts to get a persisted int from the {@link android.content.SharedPreferences}. * - * @param defaultReturnValue The default value to return if either the - * Preference is not persistent or the Preference is not in the - * shared preferences. - * @return The value from the shared preferences or the default return + * @param defaultReturnValue The default value to return if either this + * Preference is not persistent or this Preference is not in the + * SharedPreferences. + * @return The value from the SharedPreferences or the default return * value. * @see #getPersistedString(String) * @see #persistInt(int) @@ -1275,10 +1288,10 @@ public class Preference implements Comparable, OnDependencyChangeLis } /** - * Attempts to persist a float to the SharedPreferences. + * Attempts to persist a float to the {@link android.content.SharedPreferences}. * * @param value The value to persist. - * @return Whether the Preference is persistent. (This is not whether the + * @return True if this Preference is persistent. (This is not whether the * value was persisted, since we may not necessarily commit if there * will be a batch commit later.) * @see #persistString(String) @@ -1300,12 +1313,12 @@ public class Preference implements Comparable, OnDependencyChangeLis } /** - * Attempts to get a persisted float from the SharedPreferences. + * Attempts to get a persisted float from the {@link android.content.SharedPreferences}. * - * @param defaultReturnValue The default value to return if either the - * Preference is not persistent or the Preference is not in the - * shared preferences. - * @return The value from the shared preferences or the default return + * @param defaultReturnValue The default value to return if either this + * Preference is not persistent or this Preference is not in the + * SharedPreferences. + * @return The value from the SharedPreferences or the default return * value. * @see #getPersistedString(String) * @see #persistFloat(float) @@ -1319,10 +1332,10 @@ public class Preference implements Comparable, OnDependencyChangeLis } /** - * Attempts to persist a long to the SharedPreferences. + * Attempts to persist a long to the {@link android.content.SharedPreferences}. * * @param value The value to persist. - * @return Whether the Preference is persistent. (This is not whether the + * @return True if this Preference is persistent. (This is not whether the * value was persisted, since we may not necessarily commit if there * will be a batch commit later.) * @see #persistString(String) @@ -1344,12 +1357,12 @@ public class Preference implements Comparable, OnDependencyChangeLis } /** - * Attempts to get a persisted long from the SharedPreferences. + * Attempts to get a persisted long from the {@link android.content.SharedPreferences}. * - * @param defaultReturnValue The default value to return if either the - * Preference is not persistent or the Preference is not in the - * shared preferences. - * @return The value from the shared preferences or the default return + * @param defaultReturnValue The default value to return if either this + * Preference is not persistent or this Preference is not in the + * SharedPreferences. + * @return The value from the SharedPreferences or the default return * value. * @see #getPersistedString(String) * @see #persistLong(long) @@ -1363,10 +1376,10 @@ public class Preference implements Comparable, OnDependencyChangeLis } /** - * Attempts to persist a boolean to the SharedPreferences. + * Attempts to persist a boolean to the {@link android.content.SharedPreferences}. * * @param value The value to persist. - * @return Whether the Preference is persistent. (This is not whether the + * @return True if this Preference is persistent. (This is not whether the * value was persisted, since we may not necessarily commit if there * will be a batch commit later.) * @see #persistString(String) @@ -1388,12 +1401,12 @@ public class Preference implements Comparable, OnDependencyChangeLis } /** - * Attempts to get a persisted boolean from the SharedPreferences. + * Attempts to get a persisted boolean from the {@link android.content.SharedPreferences}. * - * @param defaultReturnValue The default value to return if either the - * Preference is not persistent or the Preference is not in the - * shared preferences. - * @return The value from the shared preferences or the default return + * @param defaultReturnValue The default value to return if either this + * Preference is not persistent or this Preference is not in the + * SharedPreferences. + * @return The value from the SharedPreferences or the default return * value. * @see #getPersistedString(String) * @see #persistBoolean(boolean) @@ -1416,7 +1429,7 @@ public class Preference implements Comparable, OnDependencyChangeLis } /** - * Returns the text that will be used to filter this preference depending on + * Returns the text that will be used to filter this Preference depending on * user input. *

    * If overridding and calling through to the superclass, make sure to prepend @@ -1442,9 +1455,9 @@ public class Preference implements Comparable, OnDependencyChangeLis } /** - * Store this preference hierarchy's frozen state into the given container. + * Store this Preference hierarchy's frozen state into the given container. * - * @param container The Bundle in which to save the preference's icicles. + * @param container The Bundle in which to save the instance of this Preference. * * @see #restoreHierarchyState * @see #dispatchSaveInstanceState @@ -1455,11 +1468,11 @@ public class Preference implements Comparable, OnDependencyChangeLis } /** - * Called by {@link #saveHierarchyState} to store the icicles for this preference and its children. - * May be overridden to modify how freezing happens to a preference's children; for example, some - * preferences may want to not store icicles for their children. + * Called by {@link #saveHierarchyState} to store the instance for this Preference and its children. + * May be overridden to modify how the save happens for children. For example, some + * Preference objects may want to not store an instance for their children. * - * @param container The Bundle in which to save the preference's icicles. + * @param container The Bundle in which to save the instance of this Preference. * * @see #dispatchRestoreInstanceState * @see #saveHierarchyState @@ -1480,13 +1493,13 @@ public class Preference implements Comparable, OnDependencyChangeLis } /** - * Hook allowing a preference to generate a representation of its internal + * Hook allowing a Preference to generate a representation of its internal * state that can later be used to create a new instance with that same * state. This state should only contain information that is not persistent * or can be reconstructed later. * - * @return Returns a Parcelable object containing the preference's current - * dynamic state, or null if there is nothing interesting to save. + * @return A Parcelable object containing the current dynamic state of + * this Preference, or null if there is nothing interesting to save. * The default implementation returns null. * @see #onRestoreInstanceState * @see #saveHierarchyState @@ -1498,9 +1511,9 @@ public class Preference implements Comparable, OnDependencyChangeLis } /** - * Restore this preference hierarchy's frozen state from the given container. + * Restore this Preference hierarchy's previously saved state from the given container. * - * @param container The Bundle which holds previously frozen icicles. + * @param container The Bundle that holds the previously saved state. * * @see #saveHierarchyState * @see #dispatchRestoreInstanceState @@ -1511,12 +1524,12 @@ public class Preference implements Comparable, OnDependencyChangeLis } /** - * Called by {@link #restoreHierarchyState} to retrieve the icicles for this - * preference and its children. May be overridden to modify how restoreing - * happens to a preference's children; for example, some preferences may - * want to not store icicles for their children. + * Called by {@link #restoreHierarchyState} to retrieve the saved state for this + * Preference and its children. May be overridden to modify how restoring + * happens to the children of a Preference. For example, some Preference objects may + * not want to save state for their children. * - * @param container The Bundle which holds previously frozen icicles. + * @param container The Bundle that holds the previously saved state. * @see #dispatchSaveInstanceState * @see #restoreHierarchyState * @see #onRestoreInstanceState @@ -1536,11 +1549,11 @@ public class Preference implements Comparable, OnDependencyChangeLis } /** - * Hook allowing a preference to re-apply a representation of its internal + * Hook allowing a Preference to re-apply a representation of its internal * state that had previously been generated by {@link #onSaveInstanceState}. - * This function will never be called with a null icicle. + * This function will never be called with a null state. * - * @param state The frozen state that had previously been returned by + * @param state The saved state that had previously been returned by * {@link #onSaveInstanceState}. * @see #onSaveInstanceState * @see #restoreHierarchyState @@ -1553,6 +1566,9 @@ public class Preference implements Comparable, OnDependencyChangeLis } } + /** + * A base class for managing the instance state of a {@link Preference}. + */ public static class BaseSavedState extends AbsSavedState { public BaseSavedState(Parcel source) { super(source); diff --git a/core/java/android/preference/PreferenceActivity.java b/core/java/android/preference/PreferenceActivity.java index 98144ca3c3304192b19d58c9c90ec28593077564..95970eae0276fc184d10ef52b91833feb29ef8bb 100644 --- a/core/java/android/preference/PreferenceActivity.java +++ b/core/java/android/preference/PreferenceActivity.java @@ -27,7 +27,7 @@ import android.view.View; import android.view.Window; /** - * The {@link PreferenceActivity} activity shows a hierarchy of preferences as + * Shows a hierarchy of {@link Preference} objects as * lists, possibly spanning multiple screens. These preferences will * automatically save to {@link SharedPreferences} as the user interacts with * them. To retrieve an instance of {@link SharedPreferences} that the @@ -108,7 +108,7 @@ public abstract class PreferenceActivity extends ListActivity implements setContentView(com.android.internal.R.layout.preference_list_content); mPreferenceManager = onCreatePreferenceManager(); - getListView().setScrollBarStyle(View.SCROLLBARS_INSIDE_INSET); + getListView().setScrollBarStyle(View.SCROLLBARS_INSIDE_OVERLAY); } @Override diff --git a/core/java/android/preference/PreferenceCategory.java b/core/java/android/preference/PreferenceCategory.java index a1b6f09a836b74193fcd4a3ea369b7d382417d1c..237c5ce8c84ac79d38ba7dd14ec1c5f3bb4d2f84 100644 --- a/core/java/android/preference/PreferenceCategory.java +++ b/core/java/android/preference/PreferenceCategory.java @@ -22,7 +22,7 @@ import android.content.Context; import android.util.AttributeSet; /** - * The {@link PreferenceCategory} class is used to group {@link Preference}s + * Used to group {@link Preference} objects * and provide a disabled title above the group. */ public class PreferenceCategory extends PreferenceGroup { diff --git a/core/java/android/preference/PreferenceGroup.java b/core/java/android/preference/PreferenceGroup.java index 55b3753006df14948d7004ebd5ccd6074ca303a5..4258b4123f9c4cf57c4f483bea8e467b6047e1ed 100644 --- a/core/java/android/preference/PreferenceGroup.java +++ b/core/java/android/preference/PreferenceGroup.java @@ -28,8 +28,8 @@ import android.os.Parcelable; import android.util.AttributeSet; /** - * The {@link PreferenceGroup} class is a container for multiple - * {@link Preference}s. It is a base class for {@link Preference} that are + * A container for multiple + * {@link Preference} objects. It is a base class for Preference objects that are * parents, such as {@link PreferenceCategory} and {@link PreferenceScreen}. * * @attr ref android.R.styleable#PreferenceGroup_orderingFromXml diff --git a/core/java/android/preference/PreferenceManager.java b/core/java/android/preference/PreferenceManager.java index 996354453ab432c98c2aa0b679ada60ab41ed2e0..a7a3eef68b6f42f9bd8477b5d24b2d2e2d254261 100644 --- a/core/java/android/preference/PreferenceManager.java +++ b/core/java/android/preference/PreferenceManager.java @@ -35,7 +35,7 @@ import android.os.Bundle; import android.util.Log; /** - * The {@link PreferenceManager} is used to help create preference hierarchies + * Used to help create {@link Preference} hierarchies * from activities or XML. *

    * In most cases, clients should use @@ -643,17 +643,23 @@ public class PreferenceManager { * event. */ void dispatchActivityDestroy() { - List list; + List list = null; synchronized (this) { - if (mActivityDestroyListeners == null) return; - list = new ArrayList(mActivityDestroyListeners); + if (mActivityDestroyListeners != null) { + list = new ArrayList(mActivityDestroyListeners); + } } - final int N = list.size(); - for (int i = 0; i < N; i++) { - list.get(i).onActivityDestroy(); + if (list != null) { + final int N = list.size(); + for (int i = 0; i < N; i++) { + list.get(i).onActivityDestroy(); + } } + + // Dismiss any PreferenceScreens still showing + dismissAllScreens(); } /** @@ -697,10 +703,13 @@ public class PreferenceManager { * @param intent The new Intent. */ void dispatchNewIntent(Intent intent) { + dismissAllScreens(); + } + private void dismissAllScreens() { // Remove any of the previously shown preferences screens ArrayList screensToDismiss; - + synchronized (this) { if (mPreferencesScreens == null) { @@ -715,7 +724,7 @@ public class PreferenceManager { screensToDismiss.get(i).dismiss(); } } - + /** * Sets the callback to be invoked when a {@link Preference} in the * hierarchy rooted at this {@link PreferenceManager} is clicked. diff --git a/core/java/android/preference/PreferenceScreen.java b/core/java/android/preference/PreferenceScreen.java index e4ecb88824b2fa5d298b9a998f0d2b1eb4be6163..9929b963755e03609c37822b01fe101f3ce575a2 100644 --- a/core/java/android/preference/PreferenceScreen.java +++ b/core/java/android/preference/PreferenceScreen.java @@ -30,11 +30,11 @@ import android.widget.ListAdapter; import android.widget.ListView; /** - * The {@link PreferenceScreen} class represents a top-level {@link Preference} that - * is the root of a {@link Preference} hierarchy. A {@link PreferenceActivity} + * Represents a top-level {@link Preference} that + * is the root of a Preference hierarchy. A {@link PreferenceActivity} * points to an instance of this class to show the preferences. To instantiate * this class, use {@link PreferenceManager#createPreferenceScreen(Context)}. - *

    + *

      * This class can appear in two places: *
    • When a {@link PreferenceActivity} points to this, it is used as the root * and is not shown (only the contained preferences are shown). @@ -45,24 +45,25 @@ import android.widget.ListView; * {@link Preference#getIntent()}). The children of this {@link PreferenceScreen} * are NOT shown in the screen that this {@link PreferenceScreen} is shown in. * Instead, a separate screen will be shown when this preference is clicked. + *
    + *

    Here's an example XML layout of a PreferenceScreen:

    + *
    +<PreferenceScreen
    +        xmlns:android="http://schemas.android.com/apk/res/android"
    +        android:key="first_preferencescreen">
    +    <CheckBoxPreference
    +            android:key="wifi enabled"
    +            android:title="WiFi" />
    +    <PreferenceScreen
    +            android:key="second_preferencescreen"
    +            android:title="WiFi settings">
    +        <CheckBoxPreference
    +                android:key="prefer wifi"
    +                android:title="Prefer WiFi" />
    +        ... other preferences here ...
    +    </PreferenceScreen>
    +</PreferenceScreen> 
    *

    - * - <PreferenceScreen - xmlns:android="http://schemas.android.com/apk/res/android" - android:key="first_preferencescreen"> - <CheckBoxPreference - android:key="wifi enabled" - android:title="WiFi" /> - <PreferenceScreen - android:key="second_preferencescreen" - android:title="WiFi settings"> - <CheckBoxPreference - android:key="prefer wifi" - android:title="Prefer WiFi" /> - ... other preferences here ... - </PreferenceScreen> - </PreferenceScreen> - * * In this example, the "first_preferencescreen" will be used as the root of the * hierarchy and given to a {@link PreferenceActivity}. The first screen will * show preferences "WiFi" (which can be used to quickly enable/disable WiFi) diff --git a/core/java/android/preference/RingtonePreference.java b/core/java/android/preference/RingtonePreference.java index 97674cee48ccf624baf2969dc3f803e4b790a4c9..6beb06dc470e9100d38f09d1e99b0669cc1b6c9f 100644 --- a/core/java/android/preference/RingtonePreference.java +++ b/core/java/android/preference/RingtonePreference.java @@ -27,8 +27,8 @@ import android.util.AttributeSet; import android.util.Log; /** - * The {@link RingtonePreference} allows the user to choose one from all of the - * available ringtones. The chosen ringtone's URI will be persisted as a string. + * A {@link Preference} that allows the user to choose a ringtone from those on the device. + * The chosen ringtone's URI will be persisted as a string. *

    * If the user chooses the "Default" item, the saved string will be one of * {@link System#DEFAULT_RINGTONE_URI} or diff --git a/core/java/android/preference/VolumePreference.java b/core/java/android/preference/VolumePreference.java index 5a0a0893897eee6a1d72f4089cbb71fa0c3de568..6e215dcd74910e089b777e823be63d04bb336678 100644 --- a/core/java/android/preference/VolumePreference.java +++ b/core/java/android/preference/VolumePreference.java @@ -16,7 +16,6 @@ package android.preference; -import android.content.ContentResolver; import android.content.Context; import android.content.res.TypedArray; import android.database.ContentObserver; @@ -35,33 +34,15 @@ import android.widget.SeekBar.OnSeekBarChangeListener; /** * @hide */ -public class VolumePreference extends SeekBarPreference implements OnSeekBarChangeListener, - Runnable, PreferenceManager.OnActivityStopListener { +public class VolumePreference extends SeekBarPreference implements + PreferenceManager.OnActivityStopListener { private static final String TAG = "VolumePreference"; - private ContentResolver mContentResolver; - private Handler mHandler = new Handler(); - - private AudioManager mVolume; private int mStreamType; - private int mOriginalStreamVolume; - private Ringtone mRingtone; - - private int mLastProgress; - private SeekBar mSeekBar; - private ContentObserver mVolumeObserver = new ContentObserver(mHandler) { - @Override - public void onChange(boolean selfChange) { - super.onChange(selfChange); - - if (mSeekBar != null) { - mSeekBar.setProgress(System.getInt(mContentResolver, - System.VOLUME_SETTINGS[mStreamType], 0)); - } - } - }; + /** May be null if the dialog isn't visible. */ + private SeekBarVolumizer mSeekBarVolumizer; public VolumePreference(Context context, AttributeSet attrs) { super(context, attrs); @@ -70,39 +51,32 @@ public class VolumePreference extends SeekBarPreference implements OnSeekBarChan com.android.internal.R.styleable.VolumePreference, 0, 0); mStreamType = a.getInt(android.R.styleable.VolumePreference_streamType, 0); a.recycle(); - - mContentResolver = context.getContentResolver(); - - mVolume = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE); } + public void setStreamType(int streamType) { + mStreamType = streamType; + } + @Override protected void onBindDialogView(View view) { super.onBindDialogView(view); - final SeekBar seekBar = mSeekBar = (SeekBar) view.findViewById(com.android.internal.R.id.seekbar); - seekBar.setMax(mVolume.getStreamMaxVolume(mStreamType)); - mOriginalStreamVolume = mVolume.getStreamVolume(mStreamType); - seekBar.setProgress(mOriginalStreamVolume); - seekBar.setOnSeekBarChangeListener(this); + final SeekBar seekBar = (SeekBar) view.findViewById(com.android.internal.R.id.seekbar); + mSeekBarVolumizer = new SeekBarVolumizer(getContext(), seekBar, mStreamType); - mContentResolver.registerContentObserver(System.getUriFor(System.VOLUME_SETTINGS[mStreamType]), false, mVolumeObserver); - getPreferenceManager().registerOnActivityStopListener(this); - mRingtone = RingtoneManager.getRingtone(getContext(), Settings.System.DEFAULT_RINGTONE_URI); } @Override protected void onDialogClosed(boolean positiveResult) { super.onDialogClosed(positiveResult); - if (!positiveResult) { - mVolume.setStreamVolume(mStreamType, mOriginalStreamVolume, 0); + if (!positiveResult && mSeekBarVolumizer != null) { + mSeekBarVolumizer.revertVolume(); } cleanup(); } - public void onActivityStop() { cleanup(); @@ -112,50 +86,134 @@ public class VolumePreference extends SeekBarPreference implements OnSeekBarChan * Do clean up. This can be called multiple times! */ private void cleanup() { - stopSample(); - if (mVolumeObserver != null) { - mContentResolver.unregisterContentObserver(mVolumeObserver); + getPreferenceManager().unregisterOnActivityStopListener(this); + + if (mSeekBarVolumizer != null) { + mSeekBarVolumizer.stop(); + mSeekBarVolumizer = null; + } + } + + protected void onSampleStarting(SeekBarVolumizer volumizer) { + if (mSeekBarVolumizer != null && volumizer != mSeekBarVolumizer) { + mSeekBarVolumizer.stopSample(); } - getPreferenceManager().unregisterOnActivityStopListener(this); - mSeekBar = null; } + + /** + * Turns a {@link SeekBar} into a volume control. + */ + public class SeekBarVolumizer implements OnSeekBarChangeListener, Runnable { - public void onProgressChanged(SeekBar seekBar, int progress, boolean fromTouch) { - if (!fromTouch) { - return; + private Context mContext; + private Handler mHandler = new Handler(); + + private AudioManager mAudioManager; + private int mStreamType; + private int mOriginalStreamVolume; + private Ringtone mRingtone; + + private int mLastProgress; + private SeekBar mSeekBar; + + private ContentObserver mVolumeObserver = new ContentObserver(mHandler) { + @Override + public void onChange(boolean selfChange) { + super.onChange(selfChange); + + if (mSeekBar != null) { + mSeekBar.setProgress(System.getInt(mContext.getContentResolver(), + System.VOLUME_SETTINGS[mStreamType], 0)); + } + } + }; + + public SeekBarVolumizer(Context context, SeekBar seekBar, int streamType) { + mContext = context; + mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE); + mStreamType = streamType; + mSeekBar = seekBar; + + initSeekBar(seekBar); } - postSetVolume(progress); - } - - private void postSetVolume(int progress) { - // Do the volume changing separately to give responsive UI - mLastProgress = progress; - mHandler.removeCallbacks(this); - mHandler.post(this); - } + private void initSeekBar(SeekBar seekBar) { + seekBar.setMax(mAudioManager.getStreamMaxVolume(mStreamType)); + mOriginalStreamVolume = mAudioManager.getStreamVolume(mStreamType); + seekBar.setProgress(mOriginalStreamVolume); + seekBar.setOnSeekBarChangeListener(this); + + mContext.getContentResolver().registerContentObserver( + System.getUriFor(System.VOLUME_SETTINGS[mStreamType]), + false, mVolumeObserver); - public void onStartTrackingTouch(SeekBar seekBar) { - } + mRingtone = RingtoneManager.getRingtone(mContext, + mStreamType == AudioManager.STREAM_NOTIFICATION + ? Settings.System.DEFAULT_NOTIFICATION_URI + : Settings.System.DEFAULT_RINGTONE_URI); + mRingtone.setStreamType(mStreamType); + } + + public void stop() { + stopSample(); + mContext.getContentResolver().unregisterContentObserver(mVolumeObserver); + mSeekBar.setOnSeekBarChangeListener(null); + } + + public void revertVolume() { + mAudioManager.setStreamVolume(mStreamType, mOriginalStreamVolume, 0); + } + + public void onProgressChanged(SeekBar seekBar, int progress, + boolean fromTouch) { + if (!fromTouch) { + return; + } + + postSetVolume(progress); + } - public void onStopTrackingTouch(SeekBar seekBar) { - if (mRingtone != null && !mRingtone.isPlaying()) { - sample(); + private void postSetVolume(int progress) { + // Do the volume changing separately to give responsive UI + mLastProgress = progress; + mHandler.removeCallbacks(this); + mHandler.post(this); + } + + public void onStartTrackingTouch(SeekBar seekBar) { } - } - public void run() { - mVolume.setStreamVolume(mStreamType, mLastProgress, 0); - } + public void onStopTrackingTouch(SeekBar seekBar) { + if (mRingtone != null && !mRingtone.isPlaying()) { + sample(); + } + } + + public void run() { + mAudioManager.setStreamVolume(mStreamType, mLastProgress, 0); + } + + private void sample() { - private void sample() { - mRingtone.play(); - } + // Only play a preview sample when controlling the ringer stream + if (mStreamType != AudioManager.STREAM_RING + && mStreamType != AudioManager.STREAM_NOTIFICATION) { + return; + } + + onSampleStarting(this); + mRingtone.play(); + } + + public void stopSample() { + if (mRingtone != null) { + mRingtone.stop(); + } + } - private void stopSample() { - if (mRingtone != null) { - mRingtone.stop(); + public SeekBar getSeekBar() { + return mSeekBar; } + } - } diff --git a/core/java/android/provider/Calendar.java b/core/java/android/provider/Calendar.java index b07f1b823a28e0dc4f43f9fd7676d201150dd6f9..b137b34b33d1a3932884d139068c39a374970117 100644 --- a/core/java/android/provider/Calendar.java +++ b/core/java/android/provider/Calendar.java @@ -38,11 +38,11 @@ import android.content.Context; import android.content.Intent; import android.database.Cursor; import android.net.Uri; -import android.pim.DateUtils; import android.pim.ICalendar; import android.pim.RecurrenceSet; -import android.pim.Time; import android.text.TextUtils; +import android.text.format.DateUtils; +import android.text.format.Time; import android.util.Config; import android.util.Log; @@ -429,17 +429,26 @@ public final class Calendar { public static final String EXDATE = "exdate"; /** - * The original event this event is an exception for + * The _sync_id of the original recurring event for which this event is + * an exception. *

    Type: TEXT

    */ public static final String ORIGINAL_EVENT = "originalEvent"; /** - * The time of the original instance time this event is an exception for + * The original instance time of the recurring event for which this + * event is an exception. *

    Type: INTEGER (long; millis since epoch)

    */ public static final String ORIGINAL_INSTANCE_TIME = "originalInstanceTime"; + /** + * The allDay status (true or false) of the original recurring event + * for which this event is an exception. + *

    Type: INTEGER (boolean)

    + */ + public static final String ORIGINAL_ALL_DAY = "originalAllDay"; + /** * The last date this event repeats on, or NULL if it never ends *

    Type: INTEGER (long; millis since epoch)

    @@ -543,7 +552,7 @@ public final class Calendar { time.clear(tzidParam.value); } try { - time.parse2445(dtstart); + time.parse(dtstart); } catch (Exception e) { if (Config.LOGD) { Log.d(TAG, "Cannot parse dtstart " + dtstart, e); @@ -564,7 +573,7 @@ public final class Calendar { // TODO: make sure the timezones are the same for // start, end. try { - time.parse2445(dtend); + time.parse(dtend); } catch (Exception e) { if (Config.LOGD) { Log.d(TAG, "Cannot parse dtend " + dtend, e); diff --git a/core/java/android/provider/Checkin.java b/core/java/android/provider/Checkin.java index 5b7948216360f3f8bc718026fc54e51597753015..ef5ededc24b11b817e4ffbe4e155cd024d01a0f5 100644 --- a/core/java/android/provider/Checkin.java +++ b/core/java/android/provider/Checkin.java @@ -96,8 +96,6 @@ public final class Checkin { SYSTEM_SERVICE_LOOPING, SYSTEM_TOMBSTONE, TEST, - NETWORK_RX_MOBILE, - NETWORK_TX_MOBILE, } } diff --git a/core/java/android/provider/Contacts.java b/core/java/android/provider/Contacts.java index 91b1853471d452bc3f6dd507335c9e02bd385c75..6d24ba87aa5323f12c0e3bafbc2befa2e3048c40 100644 --- a/core/java/android/provider/Contacts.java +++ b/core/java/android/provider/Contacts.java @@ -16,6 +16,8 @@ package android.provider; +import com.android.internal.R; + import android.content.ContentResolver; import android.content.ContentUris; import android.content.ContentValues; @@ -29,8 +31,6 @@ import android.text.TextUtils; import android.util.Log; import android.widget.ImageView; -import com.android.internal.R; - import java.io.ByteArrayInputStream; import java.io.InputStream; @@ -1229,7 +1229,7 @@ public class Contacts { try { display = labels[type - 1]; } catch (ArrayIndexOutOfBoundsException e) { - display = labels[People.Phones.TYPE_HOME - 1]; + display = labels[Organizations.TYPE_WORK - 1]; } } else { if (!TextUtils.isEmpty(label)) { @@ -1545,6 +1545,32 @@ public class Contacts { */ public static final String PHONE_ISPRIMARY = "phone_isprimary"; + /** + * The extra field for an optional second contact phone number. + *

    Type: String

    + */ + public static final String SECONDARY_PHONE = "secondary_phone"; + + /** + * The extra field for an optional second contact phone number type. + *

    Type: Either an integer value from {@link android.provider.Contacts.PhonesColumns PhonesColumns}, + * or a string specifying a type and label.

    + */ + public static final String SECONDARY_PHONE_TYPE = "secondary_phone_type"; + + /** + * The extra field for an optional third contact phone number. + *

    Type: String

    + */ + public static final String TERTIARY_PHONE = "tertiary_phone"; + + /** + * The extra field for an optional third contact phone number type. + *

    Type: Either an integer value from {@link android.provider.Contacts.PhonesColumns PhonesColumns}, + * or a string specifying a type and label.

    + */ + public static final String TERTIARY_PHONE_TYPE = "tertiary_phone_type"; + /** * The extra field for the contact email address. *

    Type: String

    @@ -1564,6 +1590,32 @@ public class Contacts { */ public static final String EMAIL_ISPRIMARY = "email_isprimary"; + /** + * The extra field for an optional second contact email address. + *

    Type: String

    + */ + public static final String SECONDARY_EMAIL = "secondary_email"; + + /** + * The extra field for an optional second contact email type. + *

    Type: Either an integer value from {@link android.provider.Contacts.ContactMethodsColumns ContactMethodsColumns} + * or a string specifying a type and label.

    + */ + public static final String SECONDARY_EMAIL_TYPE = "secondary_email_type"; + + /** + * The extra field for an optional third contact email address. + *

    Type: String

    + */ + public static final String TERTIARY_EMAIL = "tertiary_email"; + + /** + * The extra field for an optional third contact email type. + *

    Type: Either an integer value from {@link android.provider.Contacts.ContactMethodsColumns ContactMethodsColumns} + * or a string specifying a type and label.

    + */ + public static final String TERTIARY_EMAIL_TYPE = "tertiary_email_type"; + /** * The extra field for the contact postal address. *

    Type: String

    diff --git a/core/java/android/provider/Downloads.java b/core/java/android/provider/Downloads.java index 42e9d95a2ad741cca20bea80bae34aa9520d7e2f..a5a30b92f553a0bc3659f1ed4cab634b1393858d 100644 --- a/core/java/android/provider/Downloads.java +++ b/core/java/android/provider/Downloads.java @@ -29,6 +29,29 @@ import android.net.Uri; // this API is hidden. public final class Downloads implements BaseColumns { private Downloads() {} + + /** + * The permission to access the download manager + */ + public static final String PERMISSION_ACCESS = "android.permission.ACCESS_DOWNLOAD_MANAGER"; + + /** + * The permission to access the download manager's advanced functions + */ + public static final String PERMISSION_ACCESS_ADVANCED = + "android.permission.ACCESS_DOWNLOAD_MANAGER_ADVANCED"; + + /** + * The permission to directly access the download manager's cache directory + */ + public static final String PERMISSION_CACHE = "android.permission.ACCESS_CACHE_FILESYSTEM"; + + /** + * The permission to send broadcasts on download completion + */ + public static final String PERMISSION_SEND_INTENTS = + "android.permission.SEND_DOWNLOAD_COMPLETED_INTENTS"; + /** * The content:// URI for the data table in the provider */ @@ -64,21 +87,11 @@ public final class Downloads implements BaseColumns { public static final String URI = "uri"; /** - * The name of the column containing the HTTP method to use for this - * download. See the METHOD_* constants for a list of legal values. - *

    Type: INTEGER

    - *

    Owner can Init/Read

    - */ - public static final String METHOD = "method"; - - /** - * The name of the column containing the entity to be sent with the - * request of this download. Only use for methods that support sending - * entities, i.e. POST. + * The name of the column containing application-specific data. *

    Type: TEXT

    - *

    Owner can Init

    + *

    Owner can Init/Read/Write

    */ - public static final String ENTITY = "entity"; + public static final String APP_DATA = "entity"; /** * The name of the column containing the flags that indicates whether @@ -89,7 +102,7 @@ public final class Downloads implements BaseColumns { * a byte-range request without an ETag, or when it can't determine * whether a download fully completed). *

    Type: BOOLEAN

    - *

    Owner can Init/Read

    + *

    Owner can Init

    */ public static final String NO_INTEGRITY = "no_integrity"; @@ -98,7 +111,7 @@ public final class Downloads implements BaseColumns { * application recommends. When possible, the download manager will attempt * to use this filename, or a variation, as the actual name for the file. *

    Type: TEXT

    - *

    Owner can Init/Read

    + *

    Owner can Init

    */ public static final String FILENAME_HINT = "hint"; @@ -107,15 +120,13 @@ public final class Downloads implements BaseColumns { * was actually stored. *

    Type: TEXT

    *

    Owner can Read

    - *

    UI can Read

    */ - public static final String FILENAME = "_data"; + public static final String _DATA = "_data"; /** * The name of the column containing the MIME type of the downloaded data. *

    Type: TEXT

    *

    Owner can Init/Read

    - *

    UI can Read

    */ public static final String MIMETYPE = "mimetype"; @@ -123,51 +134,25 @@ public final class Downloads implements BaseColumns { * The name of the column containing the flag that controls the destination * of the download. See the DESTINATION_* constants for a list of legal values. *

    Type: INTEGER

    - *

    Owner can Init/Read

    - *

    UI can Read

    + *

    Owner can Init

    */ public static final String DESTINATION = "destination"; - /** - * The name of the column containing the flags that controls whether - * the download must be saved with the filename used for OTA updates. - * Must be used with INTERNAL, and the initiating application must hold the - * android.permission.DOWNLOAD_OTA_UPDATE permission. - *

    Type: BOOLEAN

    - *

    Owner can Init/Read

    - *

    UI can Read

    - */ - public static final String OTA_UPDATE = "otaupdate"; - - /** - * The name of the columns containing the flag that controls whether - * files with private/inernal/system MIME types can be downloaded. - *

    Type: BOOLEAN

    - *

    Owner can Init/Read

    - */ - public static final String NO_SYSTEM_FILES = "no_system"; - /** * The name of the column containing the flags that controls whether the * download is displayed by the UI. See the VISIBILITY_* constants for * a list of legal values. *

    Type: INTEGER

    *

    Owner can Init/Read/Write

    - *

    UI can Read/Write (only for entries that are visible)

    */ public static final String VISIBILITY = "visibility"; /** - * The name of the column containing the command associated with the - * download. After a download is initiated, this is the only column that - * applications can modify. See the CONTROL_* constants for a list of legal - * values. Note: doesn't do anything in 1.0. The API will be hooked up - * in a future version, and is provided here as an indication of things - * to come. + * The name of the column containing the current control state of the download. + * Applications can write to this to control (pause/resume) the download. + * the CONTROL_* constants for a list of legal values. *

    Type: INTEGER

    - *

    Owner can Init/Read/Write

    - *

    UI can Init/Read/Write

    - * @hide + *

    Owner can Read

    */ public static final String CONTROL = "control"; @@ -177,7 +162,6 @@ public final class Downloads implements BaseColumns { * the STATUS_* constants for a list of legal values. *

    Type: INTEGER

    *

    Owner can Read

    - *

    UI can Read

    */ public static final String STATUS = "status"; @@ -187,24 +171,15 @@ public final class Downloads implements BaseColumns { * value. *

    Type: BIGINT

    *

    Owner can Read

    - *

    UI can Read

    */ public static final String LAST_MODIFICATION = "lastmod"; - /** - * The name of the column containing the number of consecutive connections - * that have failed. - *

    Type: INTEGER

    - */ - public static final String FAILED_CONNECTIONS = "numfailed"; - /** * The name of the column containing the package name of the application * that initiating the download. The download manager will send * notifications to a component in this package when the download completes. *

    Type: TEXT

    *

    Owner can Init/Read

    - *

    UI can Read

    */ public static final String NOTIFICATION_PACKAGE = "notificationpackage"; @@ -215,13 +190,14 @@ public final class Downloads implements BaseColumns { * Intent.setClassName(String,String). *

    Type: TEXT

    *

    Owner can Init/Read

    - *

    UI can Read

    */ public static final String NOTIFICATION_CLASS = "notificationclass"; /** * If extras are specified when requesting a download they will be provided in the intent that * is sent to the specified class and package when a download has finished. + *

    Type: TEXT

    + *

    Owner can Init

    */ public static final String NOTIFICATION_EXTRAS = "notificationextras"; @@ -255,7 +231,6 @@ public final class Downloads implements BaseColumns { * downloaded. *

    Type: INTEGER

    *

    Owner can Read

    - *

    UI can Read

    */ public static final String TOTAL_BYTES = "total_bytes"; @@ -264,33 +239,18 @@ public final class Downloads implements BaseColumns { * has been downloaded so far. *

    Type: INTEGER

    *

    Owner can Read

    - *

    UI can Read

    */ public static final String CURRENT_BYTES = "current_bytes"; - /** - * The name of the column containing the entity tag for the response. - *

    Type: TEXT

    - * @hide - */ - public static final String ETAG = "etag"; - - /** - * The name of the column containing the UID of the application that - * initiated the download. - *

    Type: INTEGER

    - * @hide - */ - public static final String UID = "uid"; - /** * The name of the column where the initiating application can provide the * UID of another application that is allowed to access this download. If * multiple applications share the same UID, all those applications will be * allowed to access this download. This column can be updated after the - * download is initiated. + * download is initiated. This requires the permission + * android.permission.ACCESS_DOWNLOAD_MANAGER_ADVANCED. *

    Type: INTEGER

    - *

    Owner can Init/Read/Write

    + *

    Owner can Init

    */ public static final String OTHER_UID = "otheruid"; @@ -300,7 +260,6 @@ public final class Downloads implements BaseColumns { * list of downloads. *

    Type: TEXT

    *

    Owner can Init/Read/Write

    - *

    UI can Read

    */ public static final String TITLE = "title"; @@ -310,18 +269,9 @@ public final class Downloads implements BaseColumns { * user in the list of downloads. *

    Type: TEXT

    *

    Owner can Init/Read/Write

    - *

    UI can Read

    */ public static final String DESCRIPTION = "description"; - /** - * The name of the column where the download manager indicates whether the - * media scanner was notified about this download. - *

    Type: BOOLEAN

    - * @hide - */ - public static final String MEDIA_SCANNED = "scanned"; - /* * Lists the destinations that an application can specify for a download. */ @@ -343,7 +293,8 @@ public final class Downloads implements BaseColumns { * download private files that are used and deleted soon after they * get downloaded. All file types are allowed, and only the initiating * application can access the file (indirectly through a content - * provider). + * provider). This requires the + * android.permission.ACCESS_DOWNLOAD_MANAGER_ADVANCED permission. */ public static final int DESTINATION_CACHE_PARTITION = 1; @@ -357,40 +308,21 @@ public final class Downloads implements BaseColumns { public static final int DESTINATION_CACHE_PARTITION_PURGEABLE = 2; /** - * This download will be saved to the download manager's cache - * on the shared data partition. Use CACHE_PARTITION_PURGEABLE instead. - */ - public static final int DESTINATION_DATA_CACHE = 3; - - /* (not javadoc) - * This download will be saved to a file specified by the initiating - * applications. - * @hide - */ - //public static final int DESTINATION_PROVIDER = 4; - - /* - * Lists the commands that an application can set to control an ongoing - * download. Note: those aren't working. + * This download will be saved to the download manager's private + * partition, as with DESTINATION_CACHE_PARTITION, but the download + * will not proceed if the user is on a roaming data connection. */ + public static final int DESTINATION_CACHE_PARTITION_NOROAMING = 3; /** - * This download can run - * @hide + * This download is allowed to run. */ public static final int CONTROL_RUN = 0; /** - * This download must pause (might be restarted) - * @hide - */ - public static final int CONTROL_PAUSE = 1; - - /** - * This download must abort (will never be restarted) - * @hide + * This download must pause at the first opportunity. */ - public static final int CONTROL_STOP = 2; + public static final int CONTROL_PAUSED = 1; /* * Lists the states that the download manager can set on a download @@ -489,11 +421,6 @@ public final class Downloads implements BaseColumns { */ public static final int STATUS_BAD_REQUEST = 400; - /** - * The server returned an auth error. - */ - public static final int STATUS_NOT_AUTHORIZED = 401; - /** * This download can't be performed because the content type cannot be * handled. @@ -522,11 +449,6 @@ public final class Downloads implements BaseColumns { * This download was canceled */ public static final int STATUS_CANCELED = 490; - /** - * @hide - * Alternate spelling - */ - public static final int STATUS_CANCELLED = 490; /** * This download has completed with an error. @@ -534,11 +456,6 @@ public final class Downloads implements BaseColumns { * the future. Use isStatusError() to capture the entire category. */ public static final int STATUS_UNKNOWN_ERROR = 491; - /** - * @hide - * Legacy name - use STATUS_UNKNOWN_ERROR - */ - public static final int STATUS_ERROR = 491; /** * This download couldn't be completed because of a storage issue. @@ -548,54 +465,40 @@ public final class Downloads implements BaseColumns { /** * This download couldn't be completed because of an HTTP - * redirect code. + * redirect response that the download manager couldn't + * handle. */ public static final int STATUS_UNHANDLED_REDIRECT = 493; /** - * This download couldn't be completed because of an - * unspecified unhandled HTTP code. + * This download couldn't be completed because there were + * too many redirects. */ - public static final int STATUS_UNHANDLED_HTTP_CODE = 494; + public static final int STATUS_TOO_MANY_REDIRECTS = 494; /** * This download couldn't be completed because of an - * error receiving or processing data at the HTTP level. + * unspecified unhandled HTTP code. */ - public static final int STATUS_HTTP_DATA_ERROR = 495; + public static final int STATUS_UNHANDLED_HTTP_CODE = 495; /** * This download couldn't be completed because of an - * HttpException while setting up the request. - */ - public static final int STATUS_HTTP_EXCEPTION = 496; - - /* - * Lists the HTTP methods that the download manager can use. - */ - - /** - * GET + * error receiving or processing data at the HTTP level. */ - public static final int METHOD_GET = 0; + public static final int STATUS_HTTP_DATA_ERROR = 496; /** - * POST + * This download is visible and shows in the notifications while + * in progress and after completion. */ - public static final int METHOD_POST = 1; + public static final int VISIBILITY_VISIBLE_NOTIFY_COMPLETED = 0; /** * This download is visible but only shows in the notifications - * while it's running (a separate download UI would still show it - * after completion). - */ - public static final int VISIBILITY_VISIBLE = 0; - - /** - * This download is visible and shows in the notifications after - * completion. + * while it's in progress. */ - public static final int VISIBILITY_VISIBLE_NOTIFY_COMPLETED = 1; + public static final int VISIBILITY_VISIBLE = 1; /** * This download doesn't show in the UI or in the notifications. diff --git a/core/java/android/provider/Gmail.java b/core/java/android/provider/Gmail.java index 038ba21074370407ebf4b424075292ef6d2043df..0b6a7588eaf144c749f2cbd46c9535d5817c7a99 100644 --- a/core/java/android/provider/Gmail.java +++ b/core/java/android/provider/Gmail.java @@ -72,6 +72,7 @@ public final class Gmail { public static final String LABEL_STARRED = "^t"; public static final String LABEL_CHAT = "^b"; // 'b' for 'buzz' public static final String LABEL_VOICEMAIL = "^vm"; + public static final String LABEL_IGNORED = "^g"; public static final String LABEL_ALL = "^all"; // These constants (starting with "^^") are only used locally and are not understood by the // server. @@ -142,6 +143,8 @@ public final class Gmail { public static final String RESPOND_INPUT_COMMAND = "command"; public static final String COMMAND_RETRY = "retry"; public static final String COMMAND_ACTIVATE = "activate"; + public static final String COMMAND_SET_VISIBLE = "setVisible"; + public static final String SET_VISIBLE_PARAM_VISIBLE = "visible"; public static final String RESPOND_OUTPUT_COMMAND_RESPONSE = "commandResponse"; public static final String COMMAND_RESPONSE_OK = "ok"; public static final String COMMAND_RESPONSE_UNKNOWN = "unknownCommand"; @@ -210,7 +213,8 @@ public final class Gmail { Gmail.LABEL_UNREAD, Gmail.LABEL_TRASH, Gmail.LABEL_SPAM, - Gmail.LABEL_STARRED); + Gmail.LABEL_STARRED, + Gmail.LABEL_IGNORED); /** * Returns whether the label is user-settable. For example, labels such as LABEL_DRAFT should @@ -337,6 +341,8 @@ public final class Gmail { public static final String LABEL_IDS = "labelIds"; public static final String JOINED_ATTACHMENT_INFOS = "joinedAttachmentInfos"; public static final String ERROR = "error"; + // TODO: add a method for accessing this + public static final String REF_MESSAGE_ID = "refMessageId"; // Fake columns used only for saving or sending messages. public static final String FAKE_SAVE = "save"; @@ -773,7 +779,8 @@ public final class Gmail { priorityToLength.clear(); int maxFoundPriority = Integer.MIN_VALUE; - String numMessagesFragment = ""; + int numMessages = 0; + int numDrafts = 0; CharSequence draftsFragment = ""; CharSequence sendingFragment = ""; CharSequence sendFailedFragment = ""; @@ -799,10 +806,10 @@ public final class Gmail { } else if (Gmail.SENDER_LIST_TOKEN_ELIDED.equals(fragment0)) { // ignore } else if (Gmail.SENDER_LIST_TOKEN_NUM_MESSAGES.equals(fragment0)) { - numMessagesFragment = " (" + fragments[i++] + ")"; + numMessages = Integer.valueOf(fragments[i++]); } else if (Gmail.SENDER_LIST_TOKEN_NUM_DRAFTS.equals(fragment0)) { String numDraftsString = fragments[i++]; - int numDrafts = Integer.parseInt(numDraftsString); + numDrafts = Integer.parseInt(numDraftsString); draftsFragment = numDrafts == 1 ? draftString : draftPluralString + " (" + numDraftsString + ")"; } else if (Gmail.SENDER_LIST_TOKEN_LITERAL.equals(fragment0)) { @@ -821,6 +828,8 @@ public final class Gmail { maxFoundPriority = Math.max(maxFoundPriority, priority); } } + String numMessagesFragment = + (numMessages != 0) ? " (" + Integer.toString(numMessages + numDrafts) + ")" : ""; // Don't allocate fixedFragment unless we need it SpannableStringBuilder fixedFragment = null; @@ -1242,6 +1251,7 @@ public final class Gmail { private long mLabelIdStarred; private long mLabelIdChat; private long mLabelIdVoicemail; + private long mLabelIdIgnored; private long mLabelIdVoicemailInbox; private long mLabelIdCached; private long mLabelIdOutbox; @@ -1313,6 +1323,8 @@ public final class Gmail { mLabelIdStarred = labelId; } else if (LABEL_CHAT.equals(canonicalName)) { mLabelIdChat = labelId; + } else if (LABEL_IGNORED.equals(canonicalName)) { + mLabelIdIgnored = labelId; } else if (LABEL_VOICEMAIL.equals(canonicalName)) { mLabelIdVoicemail = labelId; } else if (LABEL_VOICEMAIL_INBOX.equals(canonicalName)) { @@ -1330,6 +1342,7 @@ public final class Gmail { && mLabelIdSpam != 0 && mLabelIdStarred != 0 && mLabelIdChat != 0 + && mLabelIdIgnored != 0 && mLabelIdVoicemail != 0; } } @@ -1374,6 +1387,11 @@ public final class Gmail { return mLabelIdChat; } + public long getLabelIdIgnored() { + checkLabelsSynced(); + return mLabelIdIgnored; + } + public long getLabelIdVoicemail() { checkLabelsSynced(); return mLabelIdVoicemail; @@ -2237,9 +2255,28 @@ public final class Gmail { } /** - * Gets the conversation id. This must be immutable. (For example, with - * GMail this should be the original conversation id rather than the - * default notion of converation id.) + * Tells the cursor whether its contents are visible to the user. The cursor will + * automatically broadcast intents to remove any matching new-mail notifications when this + * cursor's results become visible and, if they are visible, when the cursor is requeried. + * + * Note that contents shown in an activity that is resumed but not focused + * (onWindowFocusChanged/hasWindowFocus) then results shown in that activity do not count + * as visible. (This happens when the activity is behind the lock screen or a dialog.) + * + * @param visible whether the contents of this cursor are visible to the user. + */ + public void setContentsVisibleToUser(boolean visible) { + Bundle input = new Bundle(); + input.putString(RESPOND_INPUT_COMMAND, COMMAND_SET_VISIBLE); + input.putBoolean(SET_VISIBLE_PARAM_VISIBLE, visible); + Bundle output = mCursor.respond(input); + String response = output.getString(RESPOND_OUTPUT_COMMAND_RESPONSE); + assert COMMAND_RESPONSE_OK.equals(response); + } + + /** + * Gets the conversation id. This is immutable. (The server calls it the original + * conversation id.) * * @return the conversation id */ diff --git a/core/java/android/provider/Im.java b/core/java/android/provider/Im.java index 8ca97e1f7306e8a3bf7ac633b150728920d5a03d..68b2acdfaf53f09663072d8009063cd46017d2a0 100644 --- a/core/java/android/provider/Im.java +++ b/core/java/android/provider/Im.java @@ -43,16 +43,25 @@ public class Im { public interface ProviderColumns { /** * The name of the IM provider + *

    Type: TEXT

    */ String NAME = "name"; /** * The full name of the provider + *

    Type: TEXT

    */ String FULLNAME = "fullname"; + /** + * The category for the provider, used to form intent. + *

    Type: TEXT

    + */ + String CATEGORY = "category"; + /** * The url users should visit to create a new account for this provider + *

    Type: TEXT

    */ String SIGNUP_URL = "signup_url"; } @@ -187,6 +196,9 @@ public class Im { public static final String ACTIVE_ACCOUNT_ID = "account_id"; public static final String ACTIVE_ACCOUNT_USERNAME = "account_username"; public static final String ACTIVE_ACCOUNT_PW = "account_pw"; + public static final String ACTIVE_ACCOUNT_LOCKED = "account_locked"; + public static final String ACCOUNT_PRESENCE_STATUS = "account_presenceStatus"; + public static final String ACCOUNT_CONNECTION_STATUS = "account_connStatus"; /** * The content:// style URL for this table @@ -204,6 +216,9 @@ public class Im { public static final String CONTENT_TYPE = "vnd.android.cursor.dir/im-providers"; + public static final String CONTENT_ITEM_TYPE = + "vnd.android.cursor.item/im-providers"; + /** * The default sort order for this table */ @@ -319,6 +334,76 @@ public class Im { } + /** + * Connection status + */ + public interface ConnectionStatus { + /** + * The connection is offline, not logged in. + */ + int OFFLINE = 0; + + /** + * The connection is attempting to connect. + */ + int CONNECTING = 1; + + /** + * The connection is suspended due to network not available. + */ + int SUSPENDED = 2; + + /** + * The connection is logged in and online. + */ + int ONLINE = 3; + } + + public interface AccountStatusColumns { + /** + * account id + *

    Type: INTEGER

    + */ + String ACCOUNT = "account"; + + /** + * User's presence status, see definitions in {#link CommonPresenceColumn} + *

    Type: INTEGER

    + */ + String PRESENCE_STATUS = "presenceStatus"; + + /** + * The connection status of this account, see {#link ConnectionStatus} + *

    Type: INTEGER

    + */ + String CONNECTION_STATUS = "connStatus"; + } + + public static final class AccountStatus implements BaseColumns, AccountStatusColumns { + /** + * The content:// style URL for this table + */ + public static final Uri CONTENT_URI = + Uri.parse("content://im/accountStatus"); + + /** + * The MIME type of {@link #CONTENT_URI} providing a directory of account status. + */ + public static final String CONTENT_TYPE = + "vnd.android.cursor.dir/im-account-status"; + + /** + * The MIME type of a {@link #CONTENT_URI} subdirectory of a single account status. + */ + public static final String CONTENT_ITEM_TYPE = + "vnd.android.cursor.item/im-account-status"; + + /** + * The default sort order for this table + */ + public static final String DEFAULT_SORT_ORDER = "name ASC"; + } + /** * Columns from the Contacts table. */ @@ -451,8 +536,36 @@ public class Im { *

    Type: INTEGER

    */ String REJECTED = "rejected"; + + /** + * Off The Record status: 0 for disabled, 1 for enabled + *

    Type: INTEGER

    + */ + String OTR = "otr"; } + /** + * This defines the different type of values of {@link ContactsColumns#OTR} + */ + public interface OffTheRecordType { + /* + * Off the record not turned on + */ + int DISABLED = 0; + /** + * Off the record turned on, but we don't know who turned it on + */ + int ENABLED = 1; + /** + * Off the record turned on by the user + */ + int ENABLED_BY_USER = 2; + /** + * Off the record turned on by the buddy + */ + int ENABLED_BY_BUDDY = 3; + }; + /** * This table contains contacts. */ @@ -755,15 +868,32 @@ public class Im { * Message type definition */ public interface MessageType { + /* sent message */ int OUTGOING = 0; + /* received message */ int INCOMING = 1; + /* presence became available */ int PRESENCE_AVAILABLE = 2; + /* presence became away */ int PRESENCE_AWAY = 3; + /* presence became DND (busy) */ int PRESENCE_DND = 4; + /* presence became unavailable */ int PRESENCE_UNAVAILABLE = 5; + /* the message is converted to a group chat */ int CONVERT_TO_GROUPCHAT = 6; + /* generic status */ int STATUS = 7; + /* the message cannot be sent now, but will be sent later */ int POSTPONED = 8; + /* off The Record status is turned off */ + int OTR_IS_TURNED_OFF = 9; + /* off the record status is turned on */ + int OTR_IS_TURNED_ON = 10; + /* off the record status turned on by user */ + int OTR_TURNED_ON_BY_USER = 11; + /* off the record status turned on by buddy */ + int OTR_TURNED_ON_BY_BUDDY = 12; } /** @@ -1244,26 +1374,25 @@ public class Im { public interface ChatsColumns { /** * The contact ID this chat belongs to. The value is a long. - *

    Type: TEXT

    + *

    Type: INT

    */ String CONTACT_ID = "contact_id"; /** * The GTalk JID resource. The value is a string. + *

    Type: TEXT

    */ String JID_RESOURCE = "jid_resource"; /** * Whether this is a groupchat or not. + *

    Type: INT

    */ - // TODO: remove this column since we already have a tag in contacts - // table to indicate it's a group chat. String GROUP_CHAT = "groupchat"; /** * The last unread message. This both indicates that there is an * unread message, and what the message is. - * *

    Type: TEXT

    */ String LAST_UNREAD_MESSAGE = "last_unread_message"; @@ -1278,10 +1407,17 @@ public class Im { * A message that is being composed. This indicates that there was a * message being composed when the chat screen was shutdown, and what the * message is. - * *

    Type: TEXT

    */ String UNSENT_COMPOSED_MESSAGE = "unsent_composed_message"; + + /** + * A value from 0-9 indicating which quick-switch chat screen slot this + * chat is occupying. If none (for instance, this is the 12th active chat) + * then the value is -1. + *

    Type: INT

    + */ + String SHORTCUT = "shortcut"; } /** diff --git a/core/java/android/provider/LiveFolders.java b/core/java/android/provider/LiveFolders.java new file mode 100644 index 0000000000000000000000000000000000000000..6e95fb7fc115fd2cf83d31ad68329a574b029be6 --- /dev/null +++ b/core/java/android/provider/LiveFolders.java @@ -0,0 +1,298 @@ +/* + * 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 android.provider; + +import android.annotation.SdkConstant; + +/** + *

    A LiveFolder is a special folder whose content is provided by a + * {@link android.content.ContentProvider}. To create a live folder, two components + * are required:

    + *
      + *
    • An activity that can respond to the intent action {@link #ACTION_CREATE_LIVE_FOLDER}. The + * activity is responsible for creating the live folder.
    • + *
    • A {@link android.content.ContentProvider} to provide the live folder items.
    • + *
    + * + *

    Lifecycle

    + *

    When a user wants to create a live folder, the system looks for all activities with the + * intent filter action {@link #ACTION_CREATE_LIVE_FOLDER} and presents the list to the user. + * When the user chooses one of the activities, the activity is invoked with the + * {@link #ACTION_CREATE_LIVE_FOLDER} action. The activity then creates the live folder and + * passes it back to the system by setting it as an + * {@link android.app.Activity#setResult(int, android.content.Intent) activity result}. The + * live folder is described by a content provider URI, a name, an icon and a display mode. + * Finally, when the user opens the live folder, the system queries the content provider + * to retrieve the folder's content.

    + * + *

    Setting up the live folder activity

    + *

    The following code sample shows how to write an activity that creates a live fodler:

    + *
    + * public static class MyLiveFolder extends Activity {
    + *     public static final Uri CONTENT_URI = Uri.parse("content://my.app/live");
    + *
    + *     @Override
    + *     protected void onCreate(Bundle savedInstanceState) {
    + *         super.onCreate(savedInstanceState);
    + *
    + *         final Intent intent = getIntent();
    + *         final String action = intent.getAction();
    + *
    + *         if (LiveFolders.ACTION_CREATE_LIVE_FOLDER.equals(action)) {
    + *             setResult(RESULT_OK, createLiveFolder(this, CONTENT_URI, "My LiveFolder",
    + *                     R.drawable.ic_launcher_contacts_phones));
    + *         } else {
    + *             setResult(RESULT_CANCELED);
    + *         }
    + *
    + *         finish();
    + *     }
    + *
    + *     private static Intent createLiveFolder(Context context, Uri uri, String name,
    + *             int icon) {
    + *
    + *         final Intent intent = new Intent();
    + *
    + *         intent.setData(uri);
    + *         intent.putExtra(LiveFolders.EXTRA_LIVE_FOLDER_NAME, name);
    + *         intent.putExtra(LiveFolders.EXTRA_LIVE_FOLDER_ICON,
    + *                 Intent.ShortcutIconResource.fromContext(context, icon));
    + *         intent.putExtra(LiveFolders.EXTRA_LIVE_FOLDER_DISPLAY_MODE, LiveFolders.DISPLAY_MODE_LIST);
    + *
    + *         return intent;
    + *     }
    + * }
    + * 
    + *

    The live folder is described by an {@link android.content.Intent} as follows:

    + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
    Component Type Description Required
    URIURIThe ContentProvider URIYes
    {@link #EXTRA_LIVE_FOLDER_NAME}Extra StringThe name of the live folderYes
    {@link #EXTRA_LIVE_FOLDER_ICON}Extra {@link android.content.Intent.ShortcutIconResource}The icon of the live folderYes
    {@link #EXTRA_LIVE_FOLDER_DISPLAY_MODE}Extra intThe display mode of the live folder. The value must be either + * {@link #DISPLAY_MODE_GRID} or {@link #DISPLAY_MODE_LIST}.Yes
    {@link #EXTRA_LIVE_FOLDER_BASE_INTENT}Extra IntentWhen the user clicks an item inside a live folder, the system will either fire + * the intent associated with that item or, if present, the live folder's base intent + * with the id of the item appended to the base intent's URI.No
    + * + *

    Setting up the content provider

    + *

    The live folder's content provider must, upon query, return a {@link android.database.Cursor} + * whose columns match the following names:

    + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
    Column Type Description Required
    {@link #NAME}StringThe name of the itemYes
    {@link #DESCRIPTION}StringThe description of the item. The description is ignored when the live folder's + * display mode is {@link #DISPLAY_MODE_GRID}.No
    {@link #INTENT}{@link android.content.Intent}The intent to fire when the item is clicked. Ignored when the live folder defines + * a base intent.No
    {@link #ICON_BITMAP}BitmapThe icon for the item. When this column value is not null, the values for the + * columns {@link #ICON_PACKAGE} and {@link #ICON_RESOURCE} must be null.No
    {@link #ICON_PACKAGE}StringThe package of the item's icon. When this value is not null, the value for the + * column {@link #ICON_RESOURCE} must be specified and the value for the column + * {@link #ICON_BITMAP} must be null.No
    {@link #ICON_RESOURCE}StringThe resource name of the item's icon. When this value is not null, the value for the + * column {@link #ICON_PACKAGE} must be specified and the value for the column + * {@link #ICON_BITMAP} must be null.No
    + */ +public final class LiveFolders implements BaseColumns { + /** + *

    Content provider column.

    + *

    Name of the live folder item.

    + *

    Required.

    + *

    Type: String.

    + */ + public static final String NAME = "name"; + + /** + *

    Content provider column.

    + *

    Description of the live folder item. This value is ignored if the + * live folder's display mode is {@link LiveFolders#DISPLAY_MODE_GRID}.

    + *

    Optional.

    + *

    Type: String.

    + * + * @see LiveFolders#EXTRA_LIVE_FOLDER_DISPLAY_MODE + */ + public static final String DESCRIPTION = "description"; + + /** + *

    Content provider column.

    + *

    Intent of the live folder item.

    + *

    Optional if the live folder has a base intent.

    + *

    Type: {@link android.content.Intent}.

    + * + * @see LiveFolders#EXTRA_LIVE_FOLDER_BASE_INTENT + */ + public static final String INTENT = "intent"; + + /** + *

    Content provider column.

    + *

    Icon of the live folder item, as a custom bitmap.

    + *

    Optional.

    + *

    Type: {@link android.graphics.Bitmap}.

    + */ + public static final String ICON_BITMAP = "icon_bitmap"; + + /** + *

    Content provider column.

    + *

    Package where to find the icon of the live folder item. This value can be + * obtained easily using + * {@link android.content.Intent.ShortcutIconResource#fromContext(android.content.Context, int)}.

    + *

    Optional.

    + *

    Type: String.

    + * + * @see #ICON_RESOURCE + * @see android.content.Intent.ShortcutIconResource + */ + public static final String ICON_PACKAGE = "icon_package"; + + /** + *

    Content provider column.

    + *

    Resource name of the live folder item. This value can be obtained easily using + * {@link android.content.Intent.ShortcutIconResource#fromContext(android.content.Context, int)}.

    + *

    Optional.

    + *

    Type: String.

    + * + * @see #ICON_PACKAGE + * @see android.content.Intent.ShortcutIconResource + */ + public static final String ICON_RESOURCE = "icon_resource"; + + /** + * Displays a live folder's content in a grid. + * + * @see LiveFolders#EXTRA_LIVE_FOLDER_DISPLAY_MODE + */ + public static final int DISPLAY_MODE_GRID = 0x1; + + /** + * Displays a live folder's content in a list. + * + * @see LiveFolders#EXTRA_LIVE_FOLDER_DISPLAY_MODE + */ + public static final int DISPLAY_MODE_LIST = 0x2; + + /** + * The name of the extra used to define the name of a live folder. + * + * @see #ACTION_CREATE_LIVE_FOLDER + */ + public static final String EXTRA_LIVE_FOLDER_NAME = "android.intent.extra.livefolder.NAME"; + + /** + * The name of the extra used to define the icon of a live folder. + * + * @see #ACTION_CREATE_LIVE_FOLDER + */ + public static final String EXTRA_LIVE_FOLDER_ICON = "android.intent.extra.livefolder.ICON"; + + /** + * The name of the extra used to define the display mode of a live folder. + * + * @see #ACTION_CREATE_LIVE_FOLDER + * @see #DISPLAY_MODE_GRID + * @see #DISPLAY_MODE_LIST + */ + public static final String EXTRA_LIVE_FOLDER_DISPLAY_MODE = + "android.intent.extra.livefolder.DISPLAY_MODE"; + + /** + * The name of the extra used to define the base Intent of a live folder. + * + * @see #ACTION_CREATE_LIVE_FOLDER + */ + public static final String EXTRA_LIVE_FOLDER_BASE_INTENT = + "android.intent.extra.livefolder.BASE_INTENT"; + + /** + * Activity Action: Creates a live folder. + *

    Input: Nothing.

    + *

    Output: An Intent representing the live folder. The intent must contain four + * extras: EXTRA_LIVE_FOLDER_NAME (value: String), + * EXTRA_LIVE_FOLDER_ICON (value: ShortcutIconResource), + * EXTRA_LIVE_FOLDER_URI (value: String) and + * EXTRA_LIVE_FOLDER_DISPLAY_MODE (value: int). The Intent can optionnally contain + * EXTRA_LIVE_FOLDER_BASE_INTENT (value: Intent).

    + * + * @see #EXTRA_LIVE_FOLDER_NAME + * @see #EXTRA_LIVE_FOLDER_ICON + * @see #EXTRA_LIVE_FOLDER_DISPLAY_MODE + * @see #EXTRA_LIVE_FOLDER_BASE_INTENT + * @see android.content.Intent.ShortcutIconResource + */ + @SdkConstant(SdkConstant.SdkConstantType.ACTIVITY_INTENT_ACTION) + public static final String ACTION_CREATE_LIVE_FOLDER = + "android.intent.action.CREATE_LIVE_FOLDER"; + + private LiveFolders() { + } +} diff --git a/core/java/android/provider/MediaStore.java b/core/java/android/provider/MediaStore.java index d99ad368d59871ba7f8f55157a4119ae7ceacc04..d4b728b437eaa983e947902d1691ae34ce1f9c68 100644 --- a/core/java/android/provider/MediaStore.java +++ b/core/java/android/provider/MediaStore.java @@ -45,11 +45,70 @@ import java.text.Collator; public final class MediaStore { private final static String TAG = "MediaStore"; - + public static final String AUTHORITY = "media"; - + private static final String CONTENT_AUTHORITY_SLASH = "content://" + AUTHORITY + "/"; - + + /** + * Activity Action: Perform a search for media. + * Contains at least the {@link android.app.SearchManager#QUERY} extra. + * May also contain any combination of the following extras: + * EXTRA_MEDIA_ARTIST, EXTRA_MEDIA_ALBUM, EXTRA_MEDIA_TITLE, EXTRA_MEDIA_FOCUS + * + * @see android.provider.MediaStore#EXTRA_MEDIA_ARTIST + * @see android.provider.MediaStore#EXTRA_MEDIA_ALBUM + * @see android.provider.MediaStore#EXTRA_MEDIA_TITLE + * @see android.provider.MediaStore#EXTRA_MEDIA_FOCUS + */ + @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) + public static final String INTENT_ACTION_MEDIA_SEARCH = "android.intent.action.MEDIA_SEARCH"; + + /** + * The name of the Intent-extra used to define the artist + */ + public static final String EXTRA_MEDIA_ARTIST = "android.intent.extra.artist"; + /** + * The name of the Intent-extra used to define the album + */ + public static final String EXTRA_MEDIA_ALBUM = "android.intent.extra.album"; + /** + * The name of the Intent-extra used to define the song title + */ + public static final String EXTRA_MEDIA_TITLE = "android.intent.extra.title"; + /** + * The name of the Intent-extra used to define the search focus. The search focus + * indicates whether the search should be for things related to the artist, album + * or song that is identified by the other extras. + */ + public static final String EXTRA_MEDIA_FOCUS = "android.intent.extra.focus"; + + /** + * The name of the Intent-extra used to control the orientation of a MovieView. + * This is an int property that overrides the MovieView activity's requestedOrientation. + * @see android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED + */ + public static final String EXTRA_SCREEN_ORIENTATION = "android.intent.extra.screenOrientation"; + + /** + * The name of the Intent-extra used to control the onCompletion behavior of a MovieView. + * This is a boolean property that specifies whether or not to finish the MovieView activity + * when the movie completes playing. The default value is true, which means to automatically + * exit the movie player activity when the movie completes playing. + */ + public static final String EXTRA_FINISH_ON_COMPLETION = "android.intent.extra.finishOnCompletion"; + + /** + * The name of the Intent action used to launch a camera in still image mode. + */ + public static final String INTENT_ACTION_STILL_IMAGE_CAMERA = "android.media.action.STILL_IMAGE_CAMERA"; + + + /** + * The name of the Intent action used to launch a camera in video mode. + */ + public static final String INTENT_ACTION_VIDEO_CAMERA = "android.media.action.VIDEO_CAMERA"; + /** * Standard Intent action that can be sent to have the media application * capture an image and return it. The image is returned as a Bitmap @@ -57,11 +116,11 @@ public final class MediaStore * @hide */ public final static String ACTION_IMAGE_CAPTURE = "android.media.action.IMAGE_CAPTURE"; - - /** + + /** * Common fields for most MediaProvider tables */ - + public interface MediaColumns extends BaseColumns { /** * The data stream for the file @@ -108,7 +167,7 @@ public final class MediaStore */ public static final String MIME_TYPE = "mime_type"; } - + /** * Contains meta data for all available images. */ @@ -120,19 +179,19 @@ public final class MediaStore *

    Type: TEXT

    */ public static final String DESCRIPTION = "description"; - + /** * The picasa id of the image *

    Type: TEXT

    */ public static final String PICASA_ID = "picasa_id"; - + /** * Whether the video should be published as public or private *

    Type: INTEGER

    */ public static final String IS_PRIVATE = "isprivate"; - + /** * The latitude where the image was captured. *

    Type: DOUBLE

    @@ -144,14 +203,14 @@ public final class MediaStore *

    Type: DOUBLE

    */ public static final String LONGITUDE = "longitude"; - + /** * The date & time that the image was taken in units * of milliseconds since jan 1, 1970. *

    Type: INTEGER

    */ public static final String DATE_TAKEN = "datetaken"; - + /** * The orientation for the image expressed as degrees. * Only degrees 0, 90, 180, 270 will work. @@ -164,15 +223,17 @@ public final class MediaStore *

    Type: INTEGER

    */ public static final String MINI_THUMB_MAGIC = "mini_thumb_magic"; - + /** - * The bucket id of the image + * The bucket id of the image. This is a read-only property that + * is automatically computed from the DATA column. *

    Type: TEXT

    */ public static final String BUCKET_ID = "bucket_id"; - + /** - * The bucket display name of the image + * The bucket display name of the image. This is a read-only property that + * is automatically computed from the DATA column. *

    Type: TEXT

    */ public static final String BUCKET_DISPLAY_NAME = "bucket_display_name"; @@ -183,14 +244,14 @@ public final class MediaStore { return cr.query(uri, projection, null, null, DEFAULT_SORT_ORDER); } - + public static final Cursor query(ContentResolver cr, Uri uri, String[] projection, String where, String orderBy) { return cr.query(uri, projection, where, null, orderBy == null ? DEFAULT_SORT_ORDER : orderBy); } - + public static final Cursor query(ContentResolver cr, Uri uri, String[] projection, String selection, String [] selectionArgs, String orderBy) { @@ -200,7 +261,7 @@ public final class MediaStore /** * Retrieves an image for the given url as a {@link Bitmap}. - * + * * @param cr The content resolver to use * @param url The url of the image * @throws FileNotFoundException @@ -214,10 +275,10 @@ public final class MediaStore input.close(); return bitmap; } - + /** * Insert an image and create a thumbnail for it. - * + * * @param cr The content resolver to use * @param imagePath The path to the image to insert * @param name The name of the image @@ -239,38 +300,38 @@ public final class MediaStore } } } - + private static final Bitmap StoreThumbnail( - ContentResolver cr, + ContentResolver cr, Bitmap source, long id, - float width, float height, + float width, float height, int kind) { // create the matrix to scale it Matrix matrix = new Matrix(); - + float scaleX = width / source.getWidth(); float scaleY = height / source.getHeight(); - + matrix.setScale(scaleX, scaleY); - - Bitmap thumb = Bitmap.createBitmap(source, 0, 0, + + Bitmap thumb = Bitmap.createBitmap(source, 0, 0, source.getWidth(), source.getHeight(), matrix, true); - + ContentValues values = new ContentValues(4); values.put(Images.Thumbnails.KIND, kind); values.put(Images.Thumbnails.IMAGE_ID, (int)id); values.put(Images.Thumbnails.HEIGHT, thumb.getHeight()); values.put(Images.Thumbnails.WIDTH, thumb.getWidth()); - + Uri url = cr.insert(Images.Thumbnails.EXTERNAL_CONTENT_URI, values); - + try { OutputStream thumbOut = cr.openOutputStream(url); - - thumb.compress(Bitmap.CompressFormat.JPEG, 100, thumbOut); + + thumb.compress(Bitmap.CompressFormat.JPEG, 100, thumbOut); thumbOut.close(); return thumb; } @@ -281,10 +342,10 @@ public final class MediaStore return null; } } - + /** * Insert an image and create a thumbnail for it. - * + * * @param cr The content resolver to use * @param source The stream to use for the image * @param title The name of the image @@ -306,7 +367,7 @@ public final class MediaStore try { url = cr.insert(EXTERNAL_CONTENT_URI, values); - + if (source != null) { OutputStream imageOut = cr.openOutputStream(url); try { @@ -337,11 +398,11 @@ public final class MediaStore return stringUrl; } - + /** - * Get the content:// style URI for the image media table on the + * Get the content:// style URI for the image media table on the * given volume. - * + * * @param volumeName the name of the volume to get the URI for * @return the URI to the image media table on the given volume */ @@ -355,7 +416,7 @@ public final class MediaStore */ public static final Uri INTERNAL_CONTENT_URI = getContentUri("internal"); - + /** * The content:// style URI for the "primary" external storage * volume. @@ -369,7 +430,7 @@ public final class MediaStore * image MIME type as appropriate -- for example, image/jpeg. */ public static final String CONTENT_TYPE = "vnd.android.cursor.dir/image"; - + /** * The default sort order for this table */ @@ -382,23 +443,23 @@ public final class MediaStore { return cr.query(uri, projection, null, null, DEFAULT_SORT_ORDER); } - + public static final Cursor queryMiniThumbnails(ContentResolver cr, Uri uri, int kind, String[] projection) { return cr.query(uri, projection, "kind = " + kind, null, DEFAULT_SORT_ORDER); } - + public static final Cursor queryMiniThumbnail(ContentResolver cr, long origId, int kind, String[] projection) { return cr.query(EXTERNAL_CONTENT_URI, projection, IMAGE_ID + " = " + origId + " AND " + KIND + " = " + kind, null, null); } - + /** - * Get the content:// style URI for the image media table on the + * Get the content:// style URI for the image media table on the * given volume. - * + * * @param volumeName the name of the volume to get the URI for * @return the URI to the image media table on the given volume */ @@ -406,13 +467,13 @@ public final class MediaStore return Uri.parse(CONTENT_AUTHORITY_SLASH + volumeName + "/images/thumbnails"); } - + /** * The content:// style URI for the internal storage. */ public static final Uri INTERNAL_CONTENT_URI = getContentUri("internal"); - + /** * The content:// style URI for the "primary" external storage * volume. @@ -424,35 +485,35 @@ public final class MediaStore * The default sort order for this table */ public static final String DEFAULT_SORT_ORDER = "image_id ASC"; - + /** * The data stream for the thumbnail *

    Type: DATA STREAM

    */ public static final String DATA = "_data"; - + /** * The original image for the thumbnal *

    Type: INTEGER (ID from Images table)

    */ public static final String IMAGE_ID = "image_id"; - + /** * The kind of the thumbnail *

    Type: INTEGER (One of the values below)

    */ public static final String KIND = "kind"; - + public static final int MINI_KIND = 1; public static final int FULL_SCREEN_KIND = 2; public static final int MICRO_KIND = 3; - + /** * The width of the thumbnal *

    Type: INTEGER (long)

    */ public static final String WIDTH = "width"; - + /** * The height of the thumbnail *

    Type: INTEGER (long)

    @@ -460,7 +521,7 @@ public final class MediaStore public static final String HEIGHT = "height"; } } - + /** * Container for all audio content. */ @@ -532,7 +593,7 @@ public final class MediaStore *

    Type: TEXT

    */ public static final String ALBUM_ART = "album_art"; - + /** * The track number of this song on the album, if any. * This number encodes both the track number and the @@ -632,9 +693,9 @@ public final class MediaStore public static final class Media implements AudioColumns { /** - * Get the content:// style URI for the audio media table on the + * Get the content:// style URI for the audio media table on the * given volume. - * + * * @param volumeName the name of the volume to get the URI for * @return the URI to the audio media table on the given volume */ @@ -642,46 +703,56 @@ public final class MediaStore return Uri.parse(CONTENT_AUTHORITY_SLASH + volumeName + "/audio/media"); } - + public static Uri getContentUriForPath(String path) { return (path.startsWith(Environment.getExternalStorageDirectory().getPath()) ? EXTERNAL_CONTENT_URI : INTERNAL_CONTENT_URI); } - + /** * The content:// style URI for the internal storage. */ public static final Uri INTERNAL_CONTENT_URI = getContentUri("internal"); - + /** * The content:// style URI for the "primary" external storage * volume. */ public static final Uri EXTERNAL_CONTENT_URI = getContentUri("external"); - + /** * The MIME type for this table. */ public static final String CONTENT_TYPE = "vnd.android.cursor.dir/audio"; - + /** * The default sort order for this table */ public static final String DEFAULT_SORT_ORDER = TITLE; - + /** * Activity Action: Start SoundRecorder application. *

    Input: nothing. *

    Output: An uri to the recorded sound stored in the Media Library * if the recording was successful. - * + * May also contain the extra EXTRA_MAX_BYTES. + * @see #EXTRA_MAX_BYTES */ - public static final String RECORD_SOUND_ACTION = + public static final String RECORD_SOUND_ACTION = "android.provider.MediaStore.RECORD_SOUND"; + + /** + * The name of the Intent-extra used to define a maximum file size for + * a recording made by the SoundRecorder application. + * + * @see #RECORD_SOUND_ACTION + */ + public static final String EXTRA_MAX_BYTES = + "android.provider.MediaStore.extra.MAX_BYTES"; } - + /** * Columns representing an audio genre */ @@ -698,9 +769,9 @@ public final class MediaStore */ public static final class Genres implements BaseColumns, GenresColumns { /** - * Get the content:// style URI for the audio genres table on the + * Get the content:// style URI for the audio genres table on the * given volume. - * + * * @param volumeName the name of the volume to get the URI for * @return the URI to the audio genres table on the given volume */ @@ -714,7 +785,7 @@ public final class MediaStore */ public static final Uri INTERNAL_CONTENT_URI = getContentUri("internal"); - + /** * The content:// style URI for the "primary" external storage * volume. @@ -726,7 +797,7 @@ public final class MediaStore * The MIME type for this table. */ public static final String CONTENT_TYPE = "vnd.android.cursor.dir/genre"; - + /** * The MIME type for entries in this table. */ @@ -794,7 +865,7 @@ public final class MediaStore *

    Type: INTEGER (long)

    */ public static final String DATE_ADDED = "date_added"; - + /** * The time the file was last modified * Units are seconds since 1970. @@ -803,16 +874,16 @@ public final class MediaStore */ public static final String DATE_MODIFIED = "date_modified"; } - + /** * Contains playlists for audio files */ public static final class Playlists implements BaseColumns, PlaylistsColumns { /** - * Get the content:// style URI for the audio playlists table on the + * Get the content:// style URI for the audio playlists table on the * given volume. - * + * * @param volumeName the name of the volume to get the URI for * @return the URI to the audio playlists table on the given volume */ @@ -826,7 +897,7 @@ public final class MediaStore */ public static final Uri INTERNAL_CONTENT_URI = getContentUri("internal"); - + /** * The content:// style URI for the "primary" external storage * volume. @@ -838,7 +909,7 @@ public final class MediaStore * The MIME type for this table. */ public static final String CONTENT_TYPE = "vnd.android.cursor.dir/playlist"; - + /** * The MIME type for entries in this table. */ @@ -863,7 +934,7 @@ public final class MediaStore * The ID within the playlist. */ public static final String _ID = "_id"; - + /** * A subdirectory of each playlist containing all member audio * files. @@ -881,7 +952,7 @@ public final class MediaStore *

    Type: INTEGER (long)

    */ public static final String PLAYLIST_ID = "playlist_id"; - + /** * The order of the songs in the playlist *

    Type: INTEGER (long)>

    @@ -922,15 +993,15 @@ public final class MediaStore */ public static final String NUMBER_OF_TRACKS = "number_of_tracks"; } - + /** * Contains artists for audio files */ public static final class Artists implements BaseColumns, ArtistColumns { /** - * Get the content:// style URI for the artists table on the + * Get the content:// style URI for the artists table on the * given volume. - * + * * @param volumeName the name of the volume to get the URI for * @return the URI to the audio artists table on the given volume */ @@ -944,7 +1015,7 @@ public final class MediaStore */ public static final Uri INTERNAL_CONTENT_URI = getContentUri("internal"); - + /** * The content:// style URI for the "primary" external storage * volume. @@ -956,7 +1027,7 @@ public final class MediaStore * The MIME type for this table. */ public static final String CONTENT_TYPE = "vnd.android.cursor.dir/artists"; - + /** * The MIME type for entries in this table. */ @@ -979,7 +1050,7 @@ public final class MediaStore } } } - + /** * Columns representing an album */ @@ -1009,6 +1080,16 @@ public final class MediaStore */ public static final String NUMBER_OF_SONGS = "numsongs"; + /** + * This column is available when getting album info via artist, + * and indicates the number of songs on the album by the given + * artist. + *

    Type: INTEGER

    + * + * @hide pending API Council approval + */ + public static final String NUMBER_OF_SONGS_FOR_ARTIST = "numsongs_by_artist"; + /** * The year in which the earliest and latest songs * on this album were released. These will often @@ -1025,22 +1106,22 @@ public final class MediaStore *

    Type: TEXT

    */ public static final String ALBUM_KEY = "album_key"; - + /** * Cached album art. *

    Type: TEXT

    */ public static final String ALBUM_ART = "album_art"; } - + /** * Contains artists for audio files */ public static final class Albums implements BaseColumns, AlbumColumns { /** - * Get the content:// style URI for the albums table on the + * Get the content:// style URI for the albums table on the * given volume. - * + * * @param volumeName the name of the volume to get the URI for * @return the URI to the audio albums table on the given volume */ @@ -1054,7 +1135,7 @@ public final class MediaStore */ public static final Uri INTERNAL_CONTENT_URI = getContentUri("internal"); - + /** * The content:// style URI for the "primary" external storage * volume. @@ -1066,7 +1147,7 @@ public final class MediaStore * The MIME type for this table. */ public static final String CONTENT_TYPE = "vnd.android.cursor.dir/albums"; - + /** * The MIME type for entries in this table. */ @@ -1145,7 +1226,7 @@ public final class MediaStore *

    Type: TEXT

    */ public static final String LANGUAGE = "language"; - + /** * The latitude where the image was captured. *

    Type: DOUBLE

    @@ -1157,7 +1238,7 @@ public final class MediaStore *

    Type: DOUBLE

    */ public static final String LONGITUDE = "longitude"; - + /** * The date & time that the image was taken in units * of milliseconds since jan 1, 1970. @@ -1170,13 +1251,27 @@ public final class MediaStore *

    Type: INTEGER

    */ public static final String MINI_THUMB_MAGIC = "mini_thumb_magic"; + + /** + * The bucket id of the video. This is a read-only property that + * is automatically computed from the DATA column. + *

    Type: TEXT

    + */ + public static final String BUCKET_ID = "bucket_id"; + + /** + * The bucket display name of the video. This is a read-only property that + * is automatically computed from the DATA column. + *

    Type: TEXT

    + */ + public static final String BUCKET_DISPLAY_NAME = "bucket_display_name"; } public static final class Media implements VideoColumns { /** - * Get the content:// style URI for the video media table on the + * Get the content:// style URI for the video media table on the * given volume. - * + * * @param volumeName the name of the volume to get the URI for * @return the URI to the video media table on the given volume */ @@ -1190,7 +1285,7 @@ public final class MediaStore */ public static final Uri INTERNAL_CONTENT_URI = getContentUri("internal"); - + /** * The content:// style URI for the "primary" external storage * volume. diff --git a/core/java/android/provider/SearchRecentSuggestions.java b/core/java/android/provider/SearchRecentSuggestions.java index 1439b2649e2dd5ee5f716ef81f674110fce7d73e..0632d9498b84d263d423d53650ca4c33681cdf97 100644 --- a/core/java/android/provider/SearchRecentSuggestions.java +++ b/core/java/android/provider/SearchRecentSuggestions.java @@ -190,6 +190,11 @@ public class SearchRecentSuggestions { /** * Completely delete the history. Use this call to implement a "clear history" UI. + * + * Any application that implements search suggestions based on previous actions (such as + * recent queries, page/items viewed, etc.) should provide a way for the user to clear the + * history. This gives the user a measure of privacy, if they do not wish for their recent + * searches to be replayed by other users of the device (via suggestions). */ public void clearHistory() { ContentResolver cr = mContext.getContentResolver(); diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index 6897bd564a8abe3ec2c8d412b23db74aec5ed2af..e93bbeb95cc0df6f0e936328f5ac8e5cae4c351c 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -40,6 +40,7 @@ import android.util.Log; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.HashMap; +import java.util.HashSet; /** @@ -99,6 +100,20 @@ public final class Settings { public static final String ACTION_WIRELESS_SETTINGS = "android.settings.WIRELESS_SETTINGS"; + /** + * Activity Action: Show settings to allow entering/exiting airplane mode. + *

    + * In some cases, a matching Activity may not exist, so ensure you + * safeguard against this. + *

    + * Input: Nothing. + *

    + * Output: Nothing. + */ + @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) + public static final String ACTION_AIRPLANE_MODE_SETTINGS = + "android.settings.AIRPLANE_MODE_SETTINGS"; + /** * Activity Action: Show settings to allow configuration of security and * location privacy. @@ -116,6 +131,7 @@ public final class Settings { /** * Activity Action: Show settings to allow configuration of Wi-Fi. + *

    * In some cases, a matching Activity may not exist, so ensure you * safeguard against this. @@ -123,10 +139,26 @@ public final class Settings { * Input: Nothing. *

    * Output: Nothing. + */ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) public static final String ACTION_WIFI_SETTINGS = "android.settings.WIFI_SETTINGS"; + + /** + * Activity Action: Show settings to allow configuration of a static IP + * address for Wi-Fi. + *

    + * In some cases, a matching Activity may not exist, so ensure you safeguard + * against this. + *

    + * Input: Nothing. + *

    + * Output: Nothing. + */ + @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) + public static final String ACTION_WIFI_IP_SETTINGS = + "android.settings.WIFI_IP_SETTINGS"; /** * Activity Action: Show settings to allow configuration of Bluetooth. @@ -213,7 +245,50 @@ public final class Settings { "android.settings.APPLICATION_SETTINGS"; /** - * Activity Action: Show settings to allow configuration of sync settings. + * Activity Action: Show settings to allow configuration of application + * development-related settings. + *

    + * In some cases, a matching Activity may not exist, so ensure you safeguard + * against this. + *

    + * Input: Nothing. + *

    + * Output: Nothing. + */ + @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) + public static final String ACTION_APPLICATION_DEVELOPMENT_SETTINGS = + "android.settings.APPLICATION_DEVELOPMENT_SETTINGS"; + + /** + * Activity Action: Show settings to allow configuration of quick launch shortcuts. + *

    + * In some cases, a matching Activity may not exist, so ensure you + * safeguard against this. + *

    + * Input: Nothing. + *

    + * Output: Nothing. + */ + @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) + public static final String ACTION_QUICK_LAUNCH_SETTINGS = + "android.settings.QUICK_LAUNCH_SETTINGS"; + + /** + * Activity Action: Show settings to manage installed applications. + *

    + * In some cases, a matching Activity may not exist, so ensure you + * safeguard against this. + *

    + * Input: Nothing. + *

    + * Output: Nothing. + */ + @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) + public static final String ACTION_MANAGE_APPLICATIONS_SETTINGS = + "android.settings.MANAGE_APPLICATIONS_SETTINGS"; + + /** + * Activity Action: Show settings for system update functionality. *

    * In some cases, a matching Activity may not exist, so ensure you * safeguard against this. @@ -225,9 +300,78 @@ public final class Settings { * @hide */ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) + public static final String ACTION_SYSTEM_UPDATE_SETTINGS = + "android.settings.SYSTEM_UPDATE_SETTINGS"; + + /** + * Activity Action: Show settings to allow configuration of sync settings. + *

    + * In some cases, a matching Activity may not exist, so ensure you + * safeguard against this. + *

    + * Input: Nothing. + *

    + * Output: Nothing. + */ + @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) public static final String ACTION_SYNC_SETTINGS = "android.settings.SYNC_SETTINGS"; + /** + * Activity Action: Show settings for selecting the network operator. + *

    + * In some cases, a matching Activity may not exist, so ensure you + * safeguard against this. + *

    + * Input: Nothing. + *

    + * Output: Nothing. + */ + @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) + public static final String ACTION_NETWORK_OPERATOR_SETTINGS = + "android.settings.NETWORK_OPERATOR_SETTINGS"; + + /** + * Activity Action: Show settings for selection of 2G/3G. + *

    + * In some cases, a matching Activity may not exist, so ensure you + * safeguard against this. + *

    + * Input: Nothing. + *

    + * Output: Nothing. + */ + @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) + public static final String ACTION_DATA_ROAMING_SETTINGS = + "android.settings.DATA_ROAMING_SETTINGS"; + + /** + * Activity Action: Show settings for internal storage. + *

    + * In some cases, a matching Activity may not exist, so ensure you + * safeguard against this. + *

    + * Input: Nothing. + *

    + * Output: Nothing. + */ + @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) + public static final String ACTION_INTERNAL_STORAGE_SETTINGS = + "android.settings.INTERNAL_STORAGE_SETTINGS"; + /** + * Activity Action: Show settings for memory card storage. + *

    + * In some cases, a matching Activity may not exist, so ensure you + * safeguard against this. + *

    + * Input: Nothing. + *

    + * Output: Nothing. + */ + @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) + public static final String ACTION_MEMORY_CARD_SETTINGS = + "android.settings.MEMORY_CARD_SETTINGS"; + // End of Intent actions for Settings private static final String JID_RESOURCE_PREFIX = "android"; @@ -246,8 +390,6 @@ public final class Settings { /** * Common base for tables of name/value settings. - * - * */ public static class NameValueTable implements BaseColumns { public static final String NAME = "name"; @@ -296,7 +438,7 @@ public final class Settings { try { c = cr.query(mUri, new String[] { Settings.NameValueTable.VALUE }, Settings.NameValueTable.NAME + "=?", new String[]{name}, null); - if (c.moveToNext()) value = c.getString(0); + if (c != null && c.moveToNext()) value = c.getString(0); mValues.put(name, value); } catch (SQLException e) { // SQL error: return null, but don't cache it. @@ -320,6 +462,41 @@ public final class Settings { public static final String SYS_PROP_SETTING_VERSION = "sys.settings_system_version"; private static volatile NameValueCache mNameValueCache = null; + + private static final HashSet MOVED_TO_SECURE; + static { + MOVED_TO_SECURE = new HashSet(30); + MOVED_TO_SECURE.add(Secure.ADB_ENABLED); + MOVED_TO_SECURE.add(Secure.ANDROID_ID); + MOVED_TO_SECURE.add(Secure.BLUETOOTH_ON); + MOVED_TO_SECURE.add(Secure.DATA_ROAMING); + MOVED_TO_SECURE.add(Secure.DEVICE_PROVISIONED); + MOVED_TO_SECURE.add(Secure.HTTP_PROXY); + MOVED_TO_SECURE.add(Secure.INSTALL_NON_MARKET_APPS); + MOVED_TO_SECURE.add(Secure.LOCATION_PROVIDERS_ALLOWED); + MOVED_TO_SECURE.add(Secure.LOGGING_ID); + MOVED_TO_SECURE.add(Secure.PARENTAL_CONTROL_ENABLED); + MOVED_TO_SECURE.add(Secure.PARENTAL_CONTROL_LAST_UPDATE); + MOVED_TO_SECURE.add(Secure.PARENTAL_CONTROL_REDIRECT_URL); + MOVED_TO_SECURE.add(Secure.SETTINGS_CLASSNAME); + MOVED_TO_SECURE.add(Secure.USB_MASS_STORAGE_ENABLED); + MOVED_TO_SECURE.add(Secure.USE_GOOGLE_MAIL); + MOVED_TO_SECURE.add(Secure.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON); + MOVED_TO_SECURE.add(Secure.WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY); + MOVED_TO_SECURE.add(Secure.WIFI_NUM_OPEN_NETWORKS_KEPT); + MOVED_TO_SECURE.add(Secure.WIFI_ON); + MOVED_TO_SECURE.add(Secure.WIFI_WATCHDOG_ACCEPTABLE_PACKET_LOSS_PERCENTAGE); + MOVED_TO_SECURE.add(Secure.WIFI_WATCHDOG_AP_COUNT); + MOVED_TO_SECURE.add(Secure.WIFI_WATCHDOG_BACKGROUND_CHECK_DELAY_MS); + MOVED_TO_SECURE.add(Secure.WIFI_WATCHDOG_BACKGROUND_CHECK_ENABLED); + MOVED_TO_SECURE.add(Secure.WIFI_WATCHDOG_BACKGROUND_CHECK_TIMEOUT_MS); + MOVED_TO_SECURE.add(Secure.WIFI_WATCHDOG_INITIAL_IGNORED_PING_COUNT); + MOVED_TO_SECURE.add(Secure.WIFI_WATCHDOG_MAX_AP_CHECKS); + MOVED_TO_SECURE.add(Secure.WIFI_WATCHDOG_ON); + MOVED_TO_SECURE.add(Secure.WIFI_WATCHDOG_PING_COUNT); + MOVED_TO_SECURE.add(Secure.WIFI_WATCHDOG_PING_DELAY_MS); + MOVED_TO_SECURE.add(Secure.WIFI_WATCHDOG_PING_TIMEOUT_MS); + } /** * Look up a name in the database. @@ -328,6 +505,11 @@ public final class Settings { * @return the corresponding value, or null if not present */ public synchronized static String getString(ContentResolver resolver, String name) { + if (MOVED_TO_SECURE.contains(name)) { + Log.w(TAG, "Setting " + name + " has moved from android.provider.Settings.System" + + " to android.provider.Settings.Secure, returning read-only value."); + return Secure.getString(resolver, name); + } if (mNameValueCache == null) { mNameValueCache = new NameValueCache(SYS_PROP_SETTING_VERSION, CONTENT_URI); } @@ -341,8 +523,12 @@ public final class Settings { * @param value to associate with the name * @return true if the value was set, false on database errors */ - public static boolean putString(ContentResolver resolver, - String name, String value) { + public static boolean putString(ContentResolver resolver, String name, String value) { + if (MOVED_TO_SECURE.contains(name)) { + Log.w(TAG, "Setting " + name + " has moved from android.provider.Settings.System" + + " to android.provider.Settings.Secure, value is unchanged."); + return false; + } return putString(resolver, CONTENT_URI, name, value); } @@ -353,6 +539,11 @@ public final class Settings { * @return the corresponding content URI, or null if not present */ public static Uri getUriFor(String name) { + if (MOVED_TO_SECURE.contains(name)) { + Log.w(TAG, "Setting " + name + " has moved from android.provider.Settings.System" + + " to android.provider.Settings.Secure, returning Secure URI."); + return Secure.getUriFor(Secure.CONTENT_URI, name); + } return getUriFor(CONTENT_URI, name); } @@ -424,6 +615,75 @@ public final class Settings { return putString(cr, name, Integer.toString(value)); } + /** + * Convenience function for retrieving a single system settings value + * as a {@code long}. Note that internally setting values are always + * stored as strings; this function converts the string to a {@code long} + * for you. The default value will be returned if the setting is + * not defined or not a {@code long}. + * + * @param cr The ContentResolver to access. + * @param name The name of the setting to retrieve. + * @param def Value to return if the setting is not defined. + * + * @return The setting's current value, or 'def' if it is not defined + * or not a valid {@code long}. + */ + public static long getLong(ContentResolver cr, String name, long def) { + String valString = getString(cr, name); + long value; + try { + value = valString != null ? Long.parseLong(valString) : def; + } catch (NumberFormatException e) { + value = def; + } + return value; + } + + /** + * Convenience function for retrieving a single system settings value + * as a {@code long}. Note that internally setting values are always + * stored as strings; this function converts the string to a {@code long} + * for you. + *

    + * This version does not take a default value. If the setting has not + * been set, or the string value is not a number, + * it throws {@link SettingNotFoundException}. + * + * @param cr The ContentResolver to access. + * @param name The name of the setting to retrieve. + * + * @return The setting's current value. + * @throws SettingNotFoundException Thrown if a setting by the given + * name can't be found or the setting value is not an integer. + */ + public static long getLong(ContentResolver cr, String name) + throws SettingNotFoundException { + String valString = getString(cr, name); + try { + return Long.parseLong(valString); + } catch (NumberFormatException e) { + throw new SettingNotFoundException(name); + } + } + + /** + * Convenience function for updating a single settings value as a long + * integer. This will either create a new entry in the table if the + * given name does not exist, or modify the value of the existing row + * with that name. Note that internally setting values are always + * stored as strings, so this function converts the given value to a + * string before storing it. + * + * @param cr The ContentResolver to access. + * @param name The name of the setting to modify. + * @param value The new value for the setting. + * @return true if the value was set, false on database errors + */ + public static boolean putLong(ContentResolver cr, String name, long value) { + return putString(cr, name, Long.toString(value)); + } + /** * Convenience function for retrieving a single system settings value * as a floating point number. Note that internally setting values are @@ -536,7 +796,13 @@ public final class Settings { /** * Whether we keep the device on while the device is plugged in. - * 0=no 1=yes + * Supported values are: + *

      + *
    • {@code 0} to never stay on while plugged in
    • + *
    • {@link BatteryManager#BATTERY_PLUGGED_AC} to stay on for AC charger
    • + *
    • {@link BatteryManager#BATTERY_PLUGGED_USB} to stay on for USB charger
    • + *
    + * These values can be OR-ed together. */ public static final String STAY_ON_WHILE_PLUGGED_IN = "stay_on_while_plugged_in"; @@ -580,190 +846,97 @@ public final class Settings { public static final String AIRPLANE_MODE_RADIOS = "airplane_mode_radios"; /** - * Whether the Wi-Fi should be on. Only the Wi-Fi service should touch this. + * The interval in milliseconds after which Wi-Fi is considered idle. + * When idle, it is possible for the device to be switched from Wi-Fi to + * the mobile data network. + * + * @hide pending API Council approval */ - public static final String WIFI_ON = "wifi_on"; + public static final String WIFI_IDLE_MS = "wifi_idle_ms"; /** - * Whether to notify the user of open networks. + * Whether to use static IP and other static network attributes. *

    - * If not connected and the scan results have an open network, we will - * put this notification up. If we attempt to connect to a network or - * the open network(s) disappear, we remove the notification. When we - * show the notification, we will not show it again for - * {@link #WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY} time. + * Set to 1 for true and 0 for false. */ - public static final String WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON = - "wifi_networks_available_notification_on"; + public static final String WIFI_USE_STATIC_IP = "wifi_use_static_ip"; /** - * Delay (in seconds) before repeating the Wi-Fi networks available notification. - * Connecting to a network will reset the timer. + * The static IP address. + *

    + * Example: "192.168.1.51" */ - public static final String WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY = - "wifi_networks_available_repeat_delay"; + public static final String WIFI_STATIC_IP = "wifi_static_ip"; /** - * When the number of open networks exceeds this number, the - * least-recently-used excess networks will be removed. + * If using static IP, the gateway's IP address. + *

    + * Example: "192.168.1.1" */ - public static final String WIFI_NUM_OPEN_NETWORKS_KEPT = "wifi_num_open_networks_kept"; + public static final String WIFI_STATIC_GATEWAY = "wifi_static_gateway"; /** - * Whether the Wi-Fi watchdog is enabled. + * If using static IP, the net mask. + *

    + * Example: "255.255.255.0" */ - public static final String WIFI_WATCHDOG_ON = "wifi_watchdog_on"; + public static final String WIFI_STATIC_NETMASK = "wifi_static_netmask"; /** - * The number of access points required for a network in order for the - * watchdog to monitor it. + * If using static IP, the primary DNS's IP address. + *

    + * Example: "192.168.1.1" */ - public static final String WIFI_WATCHDOG_AP_COUNT = "wifi_watchdog_ap_count"; + public static final String WIFI_STATIC_DNS1 = "wifi_static_dns1"; /** - * The number of initial pings to perform that *may* be ignored if they - * fail. Again, if these fail, they will *not* be used in packet loss - * calculation. For example, one network always seemed to time out for - * the first couple pings, so this is set to 3 by default. + * If using static IP, the secondary DNS's IP address. + *

    + * Example: "192.168.1.2" */ - public static final String WIFI_WATCHDOG_INITIAL_IGNORED_PING_COUNT = "wifi_watchdog_initial_ignored_ping_count"; - + public static final String WIFI_STATIC_DNS2 = "wifi_static_dns2"; + /** - * The number of pings to test if an access point is a good connection. + * The number of radio channels that are allowed in the local + * 802.11 regulatory domain. + * @hide */ - public static final String WIFI_WATCHDOG_PING_COUNT = "wifi_watchdog_ping_count"; - + public static final String WIFI_NUM_ALLOWED_CHANNELS = "wifi_num_allowed_channels"; + /** - * The timeout per ping. + * Determines whether remote devices may discover and/or connect to + * this device. + *

    Type: INT

    + * 2 -- discoverable and connectable + * 1 -- connectable but not discoverable + * 0 -- neither connectable nor discoverable */ - public static final String WIFI_WATCHDOG_PING_TIMEOUT_MS = "wifi_watchdog_ping_timeout_ms"; + public static final String BLUETOOTH_DISCOVERABILITY = + "bluetooth_discoverability"; /** - * The delay between pings. + * Bluetooth discoverability timeout. If this value is nonzero, then + * Bluetooth becomes discoverable for a certain number of seconds, + * after which is becomes simply connectable. The value is in seconds. */ - public static final String WIFI_WATCHDOG_PING_DELAY_MS = "wifi_watchdog_ping_delay_ms"; + public static final String BLUETOOTH_DISCOVERABILITY_TIMEOUT = + "bluetooth_discoverability_timeout"; /** - * The acceptable packet loss percentage (range 0 - 100) before trying - * another AP on the same network. + * Whether autolock is enabled (0 = false, 1 = true) */ - public static final String WIFI_WATCHDOG_ACCEPTABLE_PACKET_LOSS_PERCENTAGE = - "wifi_watchdog_acceptable_packet_loss_percentage"; + public static final String LOCK_PATTERN_ENABLED = "lock_pattern_autolock"; /** - * The maximum number of access points (per network) to attempt to test. - * If this number is reached, the watchdog will no longer monitor the - * initial connection state for the network. This is a safeguard for - * networks containing multiple APs whose DNS does not respond to pings. - */ - public static final String WIFI_WATCHDOG_MAX_AP_CHECKS = "wifi_watchdog_max_ap_checks"; - - /** - * Whether the Wi-Fi watchdog is enabled for background checking even - * after it thinks the user has connected to a good access point. - */ - public static final String WIFI_WATCHDOG_BACKGROUND_CHECK_ENABLED = - "wifi_watchdog_background_check_enabled"; - - /** - * The timeout for a background ping - */ - public static final String WIFI_WATCHDOG_BACKGROUND_CHECK_TIMEOUT_MS = - "wifi_watchdog_background_check_timeout_ms"; - - /** - * The delay between background checks. - */ - public static final String WIFI_WATCHDOG_BACKGROUND_CHECK_DELAY_MS = - "wifi_watchdog_background_check_delay_ms"; - - /** - * Whether to use static IP and other static network attributes. - *

    - * Set to 1 for true and 0 for false. - */ - public static final String WIFI_USE_STATIC_IP = "wifi_use_static_ip"; - - /** - * The static IP address. - *

    - * Example: "192.168.1.51" - */ - public static final String WIFI_STATIC_IP = "wifi_static_ip"; - - /** - * If using static IP, the gateway's IP address. - *

    - * Example: "192.168.1.1" - */ - public static final String WIFI_STATIC_GATEWAY = "wifi_static_gateway"; - - /** - * If using static IP, the net mask. - *

    - * Example: "255.255.255.0" - */ - public static final String WIFI_STATIC_NETMASK = "wifi_static_netmask"; - - /** - * If using static IP, the primary DNS's IP address. - *

    - * Example: "192.168.1.1" - */ - public static final String WIFI_STATIC_DNS1 = "wifi_static_dns1"; - - /** - * If using static IP, the secondary DNS's IP address. - *

    - * Example: "192.168.1.2" - */ - public static final String WIFI_STATIC_DNS2 = "wifi_static_dns2"; - - /** - * User preference for which network(s) should be used. Only the - * connectivity service should touch this. - */ - public static final String NETWORK_PREFERENCE = "network_preference"; - - /** - * Whether bluetooth is enabled/disabled - * 0=disabled. 1=enabled. - */ - public static final String BLUETOOTH_ON = "bluetooth_on"; - - /** - * Determines whether remote devices may discover and/or connect to - * this device. - *

    Type: INT

    - * 2 -- discoverable and connectable - * 1 -- connectable but not discoverable - * 0 -- neither connectable nor discoverable - */ - public static final String BLUETOOTH_DISCOVERABILITY = - "bluetooth_discoverability"; - - /** - * Bluetooth discoverability timeout. If this value is nonzero, then - * Bluetooth becomes discoverable for a certain number of seconds, - * after which is becomes simply connectable. The value is in seconds. - */ - public static final String BLUETOOTH_DISCOVERABILITY_TIMEOUT = - "bluetooth_discoverability_timeout"; - - /** - * Whether autolock is enabled (0 = false, 1 = true) - */ - public static final String LOCK_PATTERN_ENABLED = "lock_pattern_autolock"; - - /** - * Whether the device has been provisioned (0 = false, 1 = true) + * Whether lock pattern is visible as user enters (0 = false, 1 = true) */ - public static final String DEVICE_PROVISIONED = "device_provisioned"; + public static final String LOCK_PATTERN_VISIBLE = "lock_pattern_visible_pattern"; /** - * Whether lock pattern is visible as user enters (0 = false, 1 = true) + * Whether lock pattern will vibrate as user enters (0 = false, 1 = true) */ - public static final String LOCK_PATTERN_VISIBLE = "lock_pattern_visible_pattern"; + public static final String LOCK_PATTERN_TACTILE_FEEDBACK_ENABLED = + "lock_pattern_tactile_feedback_enabled"; /** @@ -772,16 +945,6 @@ public final class Settings { */ public static final String NEXT_ALARM_FORMATTED = "next_alarm_formatted"; - /** - * Comma-separated list of location providers that activities may access. - */ - public static final String LOCATION_PROVIDERS_ALLOWED = "location_providers_allowed"; - - /** - * Whether or not data roaming is enabled. (0 = false, 1 = true) - */ - public static final String DATA_ROAMING = "data_roaming"; - /** * Scaling factor for fonts, float. */ @@ -883,11 +1046,34 @@ public final class Settings { */ public static final String VOLUME_ALARM = "volume_alarm"; + /** + * Notification volume. This is used internally, changing this + * value will not change the volume. See AudioManager. + */ + public static final String VOLUME_NOTIFICATION = "volume_notification"; + + /** + * Whether the notifications should use the ring volume (value of 1) or + * a separate notification volume (value of 0). In most cases, users + * will have this enabled so the notification and ringer volumes will be + * the same. However, power users can disable this and use the separate + * notification volume control. + *

    + * Note: This is a one-off setting that will be removed in the future + * when there is profile support. For this reason, it is kept hidden + * from the public APIs. + * + * @hide + */ + public static final String NOTIFICATIONS_USE_RING_VOLUME = + "notifications_use_ring_volume"; + /** * The mapping of stream type (integer) to its setting. */ public static final String[] VOLUME_SETTINGS = { - VOLUME_VOICE, VOLUME_SYSTEM, VOLUME_RING, VOLUME_MUSIC, VOLUME_ALARM + VOLUME_VOICE, VOLUME_SYSTEM, VOLUME_RING, VOLUME_MUSIC, + VOLUME_ALARM, VOLUME_NOTIFICATION }; /** @@ -949,145 +1135,828 @@ public final class Settings { * feature converts two spaces to a "." and space. */ public static final String TEXT_AUTO_PUNCTUATE = "auto_punctuate"; - + /** * Setting to showing password characters in text editors. 1 = On, 0 = Off */ public static final String TEXT_SHOW_PASSWORD = "show_password"; - /** - * USB Mass Storage Enabled - */ - public static final String USB_MASS_STORAGE_ENABLED = - "usb_mass_storage_enabled"; public static final String SHOW_GTALK_SERVICE_STATUS = "SHOW_GTALK_SERVICE_STATUS"; /** - * Name of activity to use for wallpaper on the home screen. + * Name of activity to use for wallpaper on the home screen. + */ + public static final String WALLPAPER_ACTIVITY = "wallpaper_activity"; + + /** + * Value to specify if the user prefers the date, time and time zone + * to be automatically fetched from the network (NITZ). 1=yes, 0=no + */ + public static final String AUTO_TIME = "auto_time"; + + /** + * Display times as 12 or 24 hours + * 12 + * 24 + */ + public static final String TIME_12_24 = "time_12_24"; + + /** + * Date format string + * mm/dd/yyyy + * dd/mm/yyyy + * yyyy/mm/dd + */ + public static final String DATE_FORMAT = "date_format"; + + /** + * Whether the setup wizard has been run before (on first boot), or if + * it still needs to be run. + * + * nonzero = it has been run in the past + * 0 = it has not been run in the past + */ + public static final String SETUP_WIZARD_HAS_RUN = "setup_wizard_has_run"; + + /** + * Scaling factor for normal window animations. Setting to 0 will disable window + * animations. + */ + public static final String WINDOW_ANIMATION_SCALE = "window_animation_scale"; + + /** + * Scaling factor for activity transition animations. Setting to 0 will disable window + * animations. + */ + public static final String TRANSITION_ANIMATION_SCALE = "transition_animation_scale"; + + /** + * Control whether the accelerometer will be used to change screen + * orientation. If 0, it will not be used unless explicitly requested + * by the application; if 1, it will be used by default unless explicitly + * disabled by the application. + */ + public static final String ACCELEROMETER_ROTATION = "accelerometer_rotation"; + + /** + * Whether the audible DTMF tones are played by the dialer when dialing. The value is + * boolean (1 or 0). + */ + public static final String DTMF_TONE_WHEN_DIALING = "dtmf_tone"; + + /** + * Whether the sounds effects (key clicks, lid open ...) are enabled. The value is + * boolean (1 or 0). + */ + public static final String SOUND_EFFECTS_ENABLED = "sound_effects_enabled"; + + // Settings moved to Settings.Secure + + /** + * @deprecated Use {@link android.provider.Settings.Secure#LOCATION_PROVIDERS_ALLOWED} + * instead + */ + @Deprecated + public static final String ADB_ENABLED = Secure.ADB_ENABLED; + + /** + * @deprecated Use {@link android.provider.Settings.Secure#ANDROID_ID} instead + */ + @Deprecated + public static final String ANDROID_ID = Secure.ANDROID_ID; + + /** + * @deprecated Use {@link android.provider.Settings.Secure#BLUETOOTH_ON} instead + */ + @Deprecated + public static final String BLUETOOTH_ON = Secure.BLUETOOTH_ON; + + /** + * @deprecated Use {@link android.provider.Settings.Secure#DATA_ROAMING} instead + */ + @Deprecated + public static final String DATA_ROAMING = Secure.DATA_ROAMING; + + /** + * @deprecated Use {@link android.provider.Settings.Secure#DEVICE_PROVISIONED} instead + */ + @Deprecated + public static final String DEVICE_PROVISIONED = Secure.DEVICE_PROVISIONED; + + /** + * @deprecated Use {@link android.provider.Settings.Secure#HTTP_PROXY} instead + */ + @Deprecated + public static final String HTTP_PROXY = Secure.HTTP_PROXY; + + /** + * @deprecated Use {@link android.provider.Settings.Secure#INSTALL_NON_MARKET_APPS} instead + */ + @Deprecated + public static final String INSTALL_NON_MARKET_APPS = Secure.INSTALL_NON_MARKET_APPS; + + /** + * @deprecated Use {@link android.provider.Settings.Secure#LOCATION_PROVIDERS_ALLOWED} + * instead + */ + @Deprecated + public static final String LOCATION_PROVIDERS_ALLOWED = Secure.LOCATION_PROVIDERS_ALLOWED; + + /** + * @deprecated Use {@link android.provider.Settings.Secure#LOGGING_ID} instead + */ + @Deprecated + public static final String LOGGING_ID = Secure.LOGGING_ID; + + /** + * @deprecated Use {@link android.provider.Settings.Secure#NETWORK_PREFERENCE} instead + */ + @Deprecated + public static final String NETWORK_PREFERENCE = Secure.NETWORK_PREFERENCE; + + /** + * @deprecated Use {@link android.provider.Settings.Secure#PARENTAL_CONTROL_ENABLED} + * instead + */ + @Deprecated + public static final String PARENTAL_CONTROL_ENABLED = Secure.PARENTAL_CONTROL_ENABLED; + + /** + * @deprecated Use {@link android.provider.Settings.Secure#PARENTAL_CONTROL_LAST_UPDATE} + * instead + */ + @Deprecated + public static final String PARENTAL_CONTROL_LAST_UPDATE = Secure.PARENTAL_CONTROL_LAST_UPDATE; + + /** + * @deprecated Use {@link android.provider.Settings.Secure#PARENTAL_CONTROL_REDIRECT_URL} + * instead + */ + @Deprecated + public static final String PARENTAL_CONTROL_REDIRECT_URL = + Secure.PARENTAL_CONTROL_REDIRECT_URL; + + /** + * @deprecated Use {@link android.provider.Settings.Secure#SETTINGS_CLASSNAME} instead + */ + @Deprecated + public static final String SETTINGS_CLASSNAME = Secure.SETTINGS_CLASSNAME; + + /** + * @deprecated Use {@link android.provider.Settings.Secure#USB_MASS_STORAGE_ENABLED} instead + */ + @Deprecated + public static final String USB_MASS_STORAGE_ENABLED = Secure.USB_MASS_STORAGE_ENABLED; + + /** + * @deprecated Use {@link android.provider.Settings.Secure#USE_GOOGLE_MAIL} instead + */ + @Deprecated + public static final String USE_GOOGLE_MAIL = Secure.USE_GOOGLE_MAIL; + +// /** +// * @deprecated Use {@link android.provider.Settings.Secure#WIFI_MAX_DHCP_RETRY_COUNT} +// * instead +// */ + @Deprecated + public static final String WIFI_MAX_DHCP_RETRY_COUNT = Secure.WIFI_MAX_DHCP_RETRY_COUNT; + +// /** +// * @deprecated Use +// * {@link android.provider.Settings.Secure#WIFI_MOBILE_DATA_TRANSITION_WAKELOCK_TIMEOUT_MS} +// * instead +// */ + @Deprecated + public static final String WIFI_MOBILE_DATA_TRANSITION_WAKELOCK_TIMEOUT_MS = + Secure.WIFI_MOBILE_DATA_TRANSITION_WAKELOCK_TIMEOUT_MS; + + /** + * @deprecated Use + * {@link android.provider.Settings.Secure#WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON} instead + */ + @Deprecated + public static final String WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON = + Secure.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON; + + /** + * @deprecated Use + * {@link android.provider.Settings.Secure#WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY} instead + */ + @Deprecated + public static final String WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY = + Secure.WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY; + + /** + * @deprecated Use {@link android.provider.Settings.Secure#WIFI_NUM_OPEN_NETWORKS_KEPT} + * instead + */ + @Deprecated + public static final String WIFI_NUM_OPEN_NETWORKS_KEPT = Secure.WIFI_NUM_OPEN_NETWORKS_KEPT; + + /** + * @deprecated Use {@link android.provider.Settings.Secure#WIFI_ON} instead + */ + @Deprecated + public static final String WIFI_ON = Secure.WIFI_ON; + + /** + * @deprecated Use + * {@link android.provider.Settings.Secure#WIFI_WATCHDOG_ACCEPTABLE_PACKET_LOSS_PERCENTAGE} + * instead + */ + @Deprecated + public static final String WIFI_WATCHDOG_ACCEPTABLE_PACKET_LOSS_PERCENTAGE = + Secure.WIFI_WATCHDOG_ACCEPTABLE_PACKET_LOSS_PERCENTAGE; + + /** + * @deprecated Use {@link android.provider.Settings.Secure#WIFI_WATCHDOG_AP_COUNT} instead + */ + @Deprecated + public static final String WIFI_WATCHDOG_AP_COUNT = Secure.WIFI_WATCHDOG_AP_COUNT; + + /** + * @deprecated Use + * {@link android.provider.Settings.Secure#WIFI_WATCHDOG_BACKGROUND_CHECK_DELAY_MS} instead + */ + @Deprecated + public static final String WIFI_WATCHDOG_BACKGROUND_CHECK_DELAY_MS = + Secure.WIFI_WATCHDOG_BACKGROUND_CHECK_DELAY_MS; + + /** + * @deprecated Use + * {@link android.provider.Settings.Secure#WIFI_WATCHDOG_BACKGROUND_CHECK_ENABLED} instead + */ + @Deprecated + public static final String WIFI_WATCHDOG_BACKGROUND_CHECK_ENABLED = + Secure.WIFI_WATCHDOG_BACKGROUND_CHECK_ENABLED; + + /** + * @deprecated Use + * {@link android.provider.Settings.Secure#WIFI_WATCHDOG_BACKGROUND_CHECK_TIMEOUT_MS} + * instead + */ + @Deprecated + public static final String WIFI_WATCHDOG_BACKGROUND_CHECK_TIMEOUT_MS = + Secure.WIFI_WATCHDOG_BACKGROUND_CHECK_TIMEOUT_MS; + + /** + * @deprecated Use + * {@link android.provider.Settings.Secure#WIFI_WATCHDOG_INITIAL_IGNORED_PING_COUNT} instead + */ + @Deprecated + public static final String WIFI_WATCHDOG_INITIAL_IGNORED_PING_COUNT = + Secure.WIFI_WATCHDOG_INITIAL_IGNORED_PING_COUNT; + + /** + * @deprecated Use {@link android.provider.Settings.Secure#WIFI_WATCHDOG_MAX_AP_CHECKS} + * instead + */ + @Deprecated + public static final String WIFI_WATCHDOG_MAX_AP_CHECKS = Secure.WIFI_WATCHDOG_MAX_AP_CHECKS; + + /** + * @deprecated Use {@link android.provider.Settings.Secure#WIFI_WATCHDOG_ON} instead + */ + @Deprecated + public static final String WIFI_WATCHDOG_ON = Secure.WIFI_WATCHDOG_ON; + + /** + * @deprecated Use {@link android.provider.Settings.Secure#WIFI_WATCHDOG_PING_COUNT} instead + */ + @Deprecated + public static final String WIFI_WATCHDOG_PING_COUNT = Secure.WIFI_WATCHDOG_PING_COUNT; + + /** + * @deprecated Use {@link android.provider.Settings.Secure#WIFI_WATCHDOG_PING_DELAY_MS} + * instead + */ + @Deprecated + public static final String WIFI_WATCHDOG_PING_DELAY_MS = Secure.WIFI_WATCHDOG_PING_DELAY_MS; + + /** + * @deprecated Use {@link android.provider.Settings.Secure#WIFI_WATCHDOG_PING_TIMEOUT_MS} + * instead + */ + @Deprecated + public static final String WIFI_WATCHDOG_PING_TIMEOUT_MS = + Secure.WIFI_WATCHDOG_PING_TIMEOUT_MS; + } + + /** + * Secure system settings, containing system preferences that applications + * can read but are not allowed to write. These are for preferences that + * the user must explicitly modify through the system UI or specialized + * APIs for those values, not modified directly by applications. + */ + public static final class Secure extends NameValueTable { + public static final String SYS_PROP_SETTING_VERSION = "sys.settings_secure_version"; + + private static volatile NameValueCache mNameValueCache = null; + + /** + * Look up a name in the database. + * @param resolver to access the database with + * @param name to look up in the table + * @return the corresponding value, or null if not present + */ + public synchronized static String getString(ContentResolver resolver, String name) { + if (mNameValueCache == null) { + mNameValueCache = new NameValueCache(SYS_PROP_SETTING_VERSION, CONTENT_URI); + } + return mNameValueCache.getString(resolver, name); + } + + /** + * Store a name/value pair into the database. + * @param resolver to access the database with + * @param name to store + * @param value to associate with the name + * @return true if the value was set, false on database errors + */ + public static boolean putString(ContentResolver resolver, + String name, String value) { + return putString(resolver, CONTENT_URI, name, value); + } + + /** + * Construct the content URI for a particular name/value pair, + * useful for monitoring changes with a ContentObserver. + * @param name to look up in the table + * @return the corresponding content URI, or null if not present + */ + public static Uri getUriFor(String name) { + return getUriFor(CONTENT_URI, name); + } + + /** + * Convenience function for retrieving a single secure settings value + * as an integer. Note that internally setting values are always + * stored as strings; this function converts the string to an integer + * for you. The default value will be returned if the setting is + * not defined or not an integer. + * + * @param cr The ContentResolver to access. + * @param name The name of the setting to retrieve. + * @param def Value to return if the setting is not defined. + * + * @return The setting's current value, or 'def' if it is not defined + * or not a valid integer. + */ + public static int getInt(ContentResolver cr, String name, int def) { + String v = getString(cr, name); + try { + return v != null ? Integer.parseInt(v) : def; + } catch (NumberFormatException e) { + return def; + } + } + + /** + * Convenience function for retrieving a single secure settings value + * as an integer. Note that internally setting values are always + * stored as strings; this function converts the string to an integer + * for you. + *

    + * This version does not take a default value. If the setting has not + * been set, or the string value is not a number, + * it throws {@link SettingNotFoundException}. + * + * @param cr The ContentResolver to access. + * @param name The name of the setting to retrieve. + * + * @throws SettingNotFoundException Thrown if a setting by the given + * name can't be found or the setting value is not an integer. + * + * @return The setting's current value. + */ + public static int getInt(ContentResolver cr, String name) + throws SettingNotFoundException { + String v = getString(cr, name); + try { + return Integer.parseInt(v); + } catch (NumberFormatException e) { + throw new SettingNotFoundException(name); + } + } + + /** + * Convenience function for updating a single settings value as an + * integer. This will either create a new entry in the table if the + * given name does not exist, or modify the value of the existing row + * with that name. Note that internally setting values are always + * stored as strings, so this function converts the given value to a + * string before storing it. + * + * @param cr The ContentResolver to access. + * @param name The name of the setting to modify. + * @param value The new value for the setting. + * @return true if the value was set, false on database errors + */ + public static boolean putInt(ContentResolver cr, String name, int value) { + return putString(cr, name, Integer.toString(value)); + } + + /** + * Convenience function for retrieving a single secure settings value + * as a {@code long}. Note that internally setting values are always + * stored as strings; this function converts the string to a {@code long} + * for you. The default value will be returned if the setting is + * not defined or not a {@code long}. + * + * @param cr The ContentResolver to access. + * @param name The name of the setting to retrieve. + * @param def Value to return if the setting is not defined. + * + * @return The setting's current value, or 'def' if it is not defined + * or not a valid {@code long}. + */ + public static long getLong(ContentResolver cr, String name, long def) { + String valString = getString(cr, name); + long value; + try { + value = valString != null ? Long.parseLong(valString) : def; + } catch (NumberFormatException e) { + value = def; + } + return value; + } + + /** + * Convenience function for retrieving a single secure settings value + * as a {@code long}. Note that internally setting values are always + * stored as strings; this function converts the string to a {@code long} + * for you. + *

    + * This version does not take a default value. If the setting has not + * been set, or the string value is not a number, + * it throws {@link SettingNotFoundException}. + * + * @param cr The ContentResolver to access. + * @param name The name of the setting to retrieve. + * + * @return The setting's current value. + * @throws SettingNotFoundException Thrown if a setting by the given + * name can't be found or the setting value is not an integer. + */ + public static long getLong(ContentResolver cr, String name) + throws SettingNotFoundException { + String valString = getString(cr, name); + try { + return Long.parseLong(valString); + } catch (NumberFormatException e) { + throw new SettingNotFoundException(name); + } + } + + /** + * Convenience function for updating a secure settings value as a long + * integer. This will either create a new entry in the table if the + * given name does not exist, or modify the value of the existing row + * with that name. Note that internally setting values are always + * stored as strings, so this function converts the given value to a + * string before storing it. + * + * @param cr The ContentResolver to access. + * @param name The name of the setting to modify. + * @param value The new value for the setting. + * @return true if the value was set, false on database errors + */ + public static boolean putLong(ContentResolver cr, String name, long value) { + return putString(cr, name, Long.toString(value)); + } + + /** + * Convenience function for retrieving a single secure settings value + * as a floating point number. Note that internally setting values are + * always stored as strings; this function converts the string to an + * float for you. The default value will be returned if the setting + * is not defined or not a valid float. + * + * @param cr The ContentResolver to access. + * @param name The name of the setting to retrieve. + * @param def Value to return if the setting is not defined. + * + * @return The setting's current value, or 'def' if it is not defined + * or not a valid float. + */ + public static float getFloat(ContentResolver cr, String name, float def) { + String v = getString(cr, name); + try { + return v != null ? Float.parseFloat(v) : def; + } catch (NumberFormatException e) { + return def; + } + } + + /** + * Convenience function for retrieving a single secure settings value + * as a float. Note that internally setting values are always + * stored as strings; this function converts the string to a float + * for you. + *

    + * This version does not take a default value. If the setting has not + * been set, or the string value is not a number, + * it throws {@link SettingNotFoundException}. + * + * @param cr The ContentResolver to access. + * @param name The name of the setting to retrieve. + * + * @throws SettingNotFoundException Thrown if a setting by the given + * name can't be found or the setting value is not a float. + * + * @return The setting's current value. + */ + public static float getFloat(ContentResolver cr, String name) + throws SettingNotFoundException { + String v = getString(cr, name); + try { + return Float.parseFloat(v); + } catch (NumberFormatException e) { + throw new SettingNotFoundException(name); + } + } + + /** + * Convenience function for updating a single settings value as a + * floating point number. This will either create a new entry in the + * table if the given name does not exist, or modify the value of the + * existing row with that name. Note that internally setting values + * are always stored as strings, so this function converts the given + * value to a string before storing it. + * + * @param cr The ContentResolver to access. + * @param name The name of the setting to modify. + * @param value The new value for the setting. + * @return true if the value was set, false on database errors + */ + public static boolean putFloat(ContentResolver cr, String name, float value) { + return putString(cr, name, Float.toString(value)); + } + + /** + * The content:// style URL for this table + */ + public static final Uri CONTENT_URI = + Uri.parse("content://" + AUTHORITY + "/secure"); + + /** + * Whether ADB is enabled. + */ + public static final String ADB_ENABLED = "adb_enabled"; + + /** + * Setting to allow mock locations and location provider status to be injected into the + * LocationManager service for testing purposes during application development. These + * locations and status values override actual location and status information generated + * by network, gps, or other location providers. + */ + public static final String ALLOW_MOCK_LOCATION = "mock_location"; + + /** + * The Android ID (a unique 64-bit value) as a hex string. + * Identical to that obtained by calling + * GoogleLoginService.getAndroidId(); it is also placed here + * so you can get it without binding to a service. + */ + public static final String ANDROID_ID = "android_id"; + + /** + * Whether bluetooth is enabled/disabled + * 0=disabled. 1=enabled. + */ + public static final String BLUETOOTH_ON = "bluetooth_on"; + + /** + * Whether or not data roaming is enabled. (0 = false, 1 = true) + */ + public static final String DATA_ROAMING = "data_roaming"; + + /** + * Setting to record the input method used by default, holding the ID + * of the desired method. + */ + public static final String DEFAULT_INPUT_METHOD = "default_input_method"; + + /** + * Whether the device has been provisioned (0 = false, 1 = true) + */ + public static final String DEVICE_PROVISIONED = "device_provisioned"; + + /** + * List of input methods that are currently enabled. This is a string + * containing the IDs of all enabled input methods, each ID separated + * by ':'. + */ + public static final String ENABLED_INPUT_METHODS = "enabled_input_methods"; + + /** + * Host name and port for a user-selected proxy. + */ + public static final String HTTP_PROXY = "http_proxy"; + + /** + * Whether the package installer should allow installation of apps downloaded from + * sources other than the Android Market (vending machine). + * + * 1 = allow installing from other sources + * 0 = only allow installing from the Android Market + */ + public static final String INSTALL_NON_MARKET_APPS = "install_non_market_apps"; + + /** + * Comma-separated list of location providers that activities may access. + */ + public static final String LOCATION_PROVIDERS_ALLOWED = "location_providers_allowed"; + + /** + * The Logging ID (a unique 64-bit value) as a hex string. + * Used as a pseudonymous identifier for logging. + */ + public static final String LOGGING_ID = "logging_id"; + + /** + * User preference for which network(s) should be used. Only the + * connectivity service should touch this. + */ + public static final String NETWORK_PREFERENCE = "network_preference"; + + /** + */ + public static final String PARENTAL_CONTROL_ENABLED = "parental_control_enabled"; + + /** + */ + public static final String PARENTAL_CONTROL_LAST_UPDATE = "parental_control_last_update"; + + /** + */ + public static final String PARENTAL_CONTROL_REDIRECT_URL = "parental_control_redirect_url"; + + /** + * Settings classname to launch when Settings is clicked from All + * Applications. Needed because of user testing between the old + * and new Settings apps. + */ + // TODO: 881807 + public static final String SETTINGS_CLASSNAME = "settings_classname"; + + /** + * USB Mass Storage Enabled + */ + public static final String USB_MASS_STORAGE_ENABLED = "usb_mass_storage_enabled"; + + /** + * If this setting is set (to anything), then all references + * to Gmail on the device must change to Google Mail. + */ + public static final String USE_GOOGLE_MAIL = "use_google_mail"; + + /** + * Whether to notify the user of open networks. + *

    + * If not connected and the scan results have an open network, we will + * put this notification up. If we attempt to connect to a network or + * the open network(s) disappear, we remove the notification. When we + * show the notification, we will not show it again for + * {@link android.provider.Settings.Secure#WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY} time. + */ + public static final String WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON = + "wifi_networks_available_notification_on"; + + /** + * Delay (in seconds) before repeating the Wi-Fi networks available notification. + * Connecting to a network will reset the timer. + */ + public static final String WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY = + "wifi_networks_available_repeat_delay"; + + /** + * The number of radio channels that are allowed in the local + * 802.11 regulatory domain. + * @hide */ - public static final String WALLPAPER_ACTIVITY = "wallpaper_activity"; - + public static final String WIFI_NUM_ALLOWED_CHANNELS = "wifi_num_allowed_channels"; + /** - * Host name and port for a user-selected proxy. + * When the number of open networks exceeds this number, the + * least-recently-used excess networks will be removed. */ - public static final String HTTP_PROXY = "http_proxy"; - + public static final String WIFI_NUM_OPEN_NETWORKS_KEPT = "wifi_num_open_networks_kept"; + /** - * Value to specify if the user prefers the date, time and time zone - * to be automatically fetched from the network (NITZ). 1=yes, 0=no + * Whether the Wi-Fi should be on. Only the Wi-Fi service should touch this. */ - public static final String AUTO_TIME = "auto_time"; - + public static final String WIFI_ON = "wifi_on"; + /** - * Display times as 12 or 24 hours - * 12 - * 24 + * The acceptable packet loss percentage (range 0 - 100) before trying + * another AP on the same network. */ - public static final String TIME_12_24 = "time_12_24"; - + public static final String WIFI_WATCHDOG_ACCEPTABLE_PACKET_LOSS_PERCENTAGE = + "wifi_watchdog_acceptable_packet_loss_percentage"; + /** - * Date format string - * mm/dd/yyyy - * dd/mm/yyyy - * yyyy/mm/dd + * The number of access points required for a network in order for the + * watchdog to monitor it. */ - public static final String DATE_FORMAT = "date_format"; - + public static final String WIFI_WATCHDOG_AP_COUNT = "wifi_watchdog_ap_count"; + /** - * Settings classname to launch when Settings is clicked from All - * Applications. Needed because of user testing between the old - * and new Settings apps. TODO: 881807 + * The delay between background checks. */ - public static final String SETTINGS_CLASSNAME = "settings_classname"; - + public static final String WIFI_WATCHDOG_BACKGROUND_CHECK_DELAY_MS = + "wifi_watchdog_background_check_delay_ms"; + /** - * Whether the setup wizard has been run before (on first boot), or if - * it still needs to be run. - * - * nonzero = it has been run in the past - * 0 = it has not been run in the past + * Whether the Wi-Fi watchdog is enabled for background checking even + * after it thinks the user has connected to a good access point. */ - public static final String SETUP_WIZARD_HAS_RUN = "setup_wizard_has_run"; - + public static final String WIFI_WATCHDOG_BACKGROUND_CHECK_ENABLED = + "wifi_watchdog_background_check_enabled"; + /** - * The Android ID (a unique 64-bit value) as a hex string. - * Identical to that obtained by calling - * GoogleLoginService.getAndroidId(); it is also placed here - * so you can get it without binding to a service. + * The timeout for a background ping */ - public static final String ANDROID_ID = "android_id"; - + public static final String WIFI_WATCHDOG_BACKGROUND_CHECK_TIMEOUT_MS = + "wifi_watchdog_background_check_timeout_ms"; + /** - * The Logging ID (a unique 64-bit value) as a hex string. - * Used as a pseudonymous identifier for logging. + * The number of initial pings to perform that *may* be ignored if they + * fail. Again, if these fail, they will *not* be used in packet loss + * calculation. For example, one network always seemed to time out for + * the first couple pings, so this is set to 3 by default. */ - public static final String LOGGING_ID = "logging_id"; - + public static final String WIFI_WATCHDOG_INITIAL_IGNORED_PING_COUNT = + "wifi_watchdog_initial_ignored_ping_count"; + /** - * If this setting is set (to anything), then all references - * to Gmail on the device must change to Google Mail. + * The maximum number of access points (per network) to attempt to test. + * If this number is reached, the watchdog will no longer monitor the + * initial connection state for the network. This is a safeguard for + * networks containing multiple APs whose DNS does not respond to pings. */ - public static final String USE_GOOGLE_MAIL = "use_google_mail"; - + public static final String WIFI_WATCHDOG_MAX_AP_CHECKS = "wifi_watchdog_max_ap_checks"; + /** - * Whether the package installer should allow installation of apps downloaded from - * sources other than the Android Market (vending machine). - * - * 1 = allow installing from other sources - * 0 = only allow installing from the Android Market + * Whether the Wi-Fi watchdog is enabled. */ - public static final String INSTALL_NON_MARKET_APPS = "install_non_market_apps"; - + public static final String WIFI_WATCHDOG_ON = "wifi_watchdog_on"; + /** - * Scaling factor for normal window animations. Setting to 0 will disable window - * animations. + * The number of pings to test if an access point is a good connection. */ - public static final String WINDOW_ANIMATION_SCALE = "window_animation_scale"; - + public static final String WIFI_WATCHDOG_PING_COUNT = "wifi_watchdog_ping_count"; + /** - * Scaling factor for activity transition animations. Setting to 0 will disable window - * animations. + * The delay between pings. */ - public static final String TRANSITION_ANIMATION_SCALE = "transition_animation_scale"; - - public static final String PARENTAL_CONTROL_ENABLED = - "parental_control_enabled"; - - public static final String PARENTAL_CONTROL_REDIRECT_URL = - "parental_control_redirect_url"; - - public static final String PARENTAL_CONTROL_LAST_UPDATE = - "parental_control_last_update"; - + public static final String WIFI_WATCHDOG_PING_DELAY_MS = "wifi_watchdog_ping_delay_ms"; + /** - * Whether ADB is enabled. + * The timeout per ping. */ - public static final String ADB_ENABLED = "adb_enabled"; - + public static final String WIFI_WATCHDOG_PING_TIMEOUT_MS = "wifi_watchdog_ping_timeout_ms"; + /** - * Whether the audible DTMF tones are played by the dialer when dialing. The value is - * boolean (1 or 0). + * The maximum number of times we will retry a connection to an access + * point for which we have failed in acquiring an IP address from DHCP. + * A value of N means that we will make N+1 connection attempts in all. + * + * @hide pending API Council approval */ - public static final String DTMF_TONE_WHEN_DIALING = "dtmf_tone"; - + public static final String WIFI_MAX_DHCP_RETRY_COUNT = "wifi_max_dhcp_retry_count"; + /** - * Whether the sounds effects (key clicks, lid open ...) are enabled. The value is - * boolean (1 or 0). + * Maximum amount of time in milliseconds to hold a wakelock while waiting for mobile + * data connectivity to be established after a disconnect from Wi-Fi. + * + * @hide pending API Council approval */ - public static final String SOUND_EFFECTS_ENABLED = "sound_effects_enabled"; + public static final String WIFI_MOBILE_DATA_TRANSITION_WAKELOCK_TIMEOUT_MS = + "wifi_mobile_data_transition_wakelock_timeout_ms"; } - - + /** * Gservices settings, containing the network names for Google's * various services. This table holds simple name/addr pairs. * Addresses can be accessed through the getString() method. + * + * TODO: This should move to partner/google/... somewhere. + * * @hide */ public static final class Gservices extends NameValueTable { public static final String SYS_PROP_SETTING_VERSION = "sys.settings_gservices_version"; + /** + * Intent action broadcast when the Gservices table is updated by the server. + * This is broadcast once after settings change (so many values may have been updated). + */ + @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) + public static final String CHANGED_ACTION = + "com.google.gservices.intent.action.GSERVICES_CHANGED"; + private static volatile NameValueCache mNameValueCache = null; private static final Object mNameValueCacheLock = new Object(); @@ -1172,132 +2041,6 @@ public final class Settings { public static final String MMS_X_WAP_PROFILE_URL = "mms_x_wap_profile_url"; - /** - * YouTube - "most viewed" url - */ - public static final String YOUTUBE_MOST_VIEWED_URL - = "youtube_most_viewed_url"; - - /** - * YouTube - "most recent" url - */ - public static final String YOUTUBE_MOST_RECENT_URL - = "youtube_most_recent_url"; - - /** - * YouTube - "top favorites" url - */ - public static final String YOUTUBE_TOP_FAVORITES_URL - = "youtube_top_favorites_url"; - - /** - * YouTube - "most discussed" url - */ - public static final String YOUTUBE_MOST_DISCUSSED_URL - = "youtube_most_discussed_url"; - - /** - * YouTube - "most responded" url - */ - public static final String YOUTUBE_MOST_RESPONDED_URL - = "youtube_most_responded_url"; - - /** - * YouTube - "most linked" url - */ - public static final String YOUTUBE_MOST_LINKED_URL - = "youtube_most_linked_url"; - - /** - * YouTube - "top rated" url - */ - public static final String YOUTUBE_TOP_RATED_URL - = "youtube_top_rated_url"; - - /** - * YouTube - "recently featured" url - */ - public static final String YOUTUBE_RECENTLY_FEATURED_URL - = "youtube_recently_featured_url"; - - /** - * YouTube - my uploaded videos - */ - public static final String YOUTUBE_MY_VIDEOS_URL - = "youtube_my_videos_url"; - - /** - * YouTube - "my favorite" videos url - */ - public static final String YOUTUBE_MY_FAVORITES_URL - = "youtube_my_favorites_url"; - - /** - * YouTube - "by author" videos url -- used for My videos - */ - public static final String YOUTUBE_BY_AUTHOR_URL - = "youtube_by_author_url"; - - /** - * YouTube - save a video to favorite videos url - */ - public static final String YOUTUBE_SAVE_TO_FAVORITES_URL - = "youtube_save_to_favorites_url"; - - /** - * YouTube - "mobile" videos url - */ - public static final String YOUTUBE_MOBILE_VIDEOS_URL - = "youtube_mobile_videos_url"; - - /** - * YouTube - search videos url - */ - public static final String YOUTUBE_SEARCH_URL - = "youtube_search_url"; - - /** - * YouTube - category search videos url - */ - public static final String YOUTUBE_CATEGORY_SEARCH_URL - = "youtube_category_search_url"; - - /** - * YouTube - url to get the list of categories - */ - public static final String YOUTUBE_CATEGORY_LIST_URL - = "youtube_category_list_url"; - - /** - * YouTube - related videos url - */ - public static final String YOUTUBE_RELATED_VIDEOS_URL - = "youtube_related_videos_url"; - - /** - * YouTube - individual video url - */ - public static final String YOUTUBE_INDIVIDUAL_VIDEO_URL - = "youtube_individual_video_url"; - - /** - * YouTube - user's playlist url - */ - public static final String YOUTUBE_MY_PLAYLISTS_URL - = "youtube_my_playlists_url"; - - /** - * YouTube - user's subscriptions url - */ - public static final String YOUTUBE_MY_SUBSCRIPTIONS_URL - = "youtube_my_subscriptions_url"; - - /** - * YouTube - the url we use to contact YouTube to get a device id - */ - public static final String YOUTUBE_REGISTER_DEVICE_URL - = "youtube_register_device_url"; - /** * YouTube - the flag to indicate whether to use proxy */ @@ -1325,7 +2068,8 @@ public final class Settings { * seconds. This allows for throttling of logs when the device is * running for large amounts of time. */ - public static final String MEMCHECK_LOG_REALTIME_INTERVAL = "memcheck_log_realtime_interval"; + public static final String MEMCHECK_LOG_REALTIME_INTERVAL = + "memcheck_log_realtime_interval"; /** * Boolean indicating whether rebooting due to system memory checks @@ -1423,7 +2167,7 @@ public final class Settings { * the device is idle within the window. */ public static final String REBOOT_WINDOW = "reboot_window"; - + /** * The minimum version of the server that is required in order for the device to accept * the server's recommendations about the initial sync settings to use. When this is unset, @@ -1445,6 +2189,12 @@ public final class Settings { */ public static final String GMAIL_TIMEOUT_MS = "gmail_timeout_ms"; + /** + * Controls whether Gmail will request an expedited sync when a message is sent. Value must + * be an integer where non-zero means true. Defaults to 1. + */ + public static final String GMAIL_SEND_IMMEDIATELY = "gmail_send_immediately"; + /** * Hostname of the GTalk server. */ @@ -1667,7 +2417,28 @@ public final class Settings { */ public static final String SETTINGS_CONTRIBUTORS_PRETTY_URL = "settings_contributors_pretty_url"; - + + /** + * URL that points to the Terms Of Service for the device. + *

    + * This should be a pretty http URL. + */ + public static final String SETUP_GOOGLE_TOS_URL = "setup_google_tos_url"; + + /** + * URL that points to the Android privacy policy for the device. + *

    + * This should be a pretty http URL. + */ + public static final String SETUP_ANDROID_PRIVACY_URL = "setup_android_privacy_url"; + + /** + * URL that points to the Google privacy policy for the device. + *

    + * This should be a pretty http URL. + */ + public static final String SETUP_GOOGLE_PRIVACY_URL = "setup_google_privacy_url"; + /** * Request an MSISDN token for various Google services. */ @@ -1684,6 +2455,12 @@ public final class Settings { public static final String PARENTAL_CONTROL_CHECK_ENABLED = "parental_control_check_enabled"; + /** + * The list of applications we need to block if parental control is + * enabled. + */ + public static final String PARENTAL_CONTROL_APPS_LIST = + "parental_control_apps_list"; /** * Duration in which parental control status is valid. @@ -1712,7 +2489,7 @@ public final class Settings { */ public static final String DISK_FREE_CHANGE_REPORTING_THRESHOLD = "disk_free_change_reporting_threshold"; - + /** * Prefix for new Google services published by the checkin * server. @@ -1726,23 +2503,38 @@ public final class Settings { */ public static final String SYNC_MAX_RETRY_DELAY_IN_SECONDS = "sync_max_retry_delay_in_seconds"; - + /** * Minimum percentage of free storage on the device that is used to determine if - * the device is running low on storage. + * the device is running low on storage. * Say this value is set to 10, the device is considered running low on storage * if 90% or more of the device storage is filled up. */ - public static final String SYS_STORAGE_THRESHOLD_PERCENTAGE = + public static final String SYS_STORAGE_THRESHOLD_PERCENTAGE = "sys_storage_threshold_percentage"; - + /** - * The interval in minutes after which the amount of free storage left on the + * The interval in minutes after which the amount of free storage left on the * device is logged to the event log */ - public static final String SYS_FREE_STORAGE_LOG_INTERVAL = + public static final String SYS_FREE_STORAGE_LOG_INTERVAL = "sys_free_storage_log_interval"; + /** + * The interval in milliseconds at which to check the number of SMS sent + * out without asking for use permit, to limit the un-authorized SMS + * usage. + */ + public static final String SMS_OUTGOING_CEHCK_INTERVAL_MS = + "sms_outgoing_check_interval_ms"; + + /** + * The number of outgoing SMS sent without asking for user permit + * (of {@link #SMS_OUTGOING_CEHCK_INTERVAL_MS} + */ + public static final String SMS_OUTGOING_CEHCK_MAX_COUNT = + "sms_outgoing_check_max_count"; + /** * The interval in milliseconds at which to check packet counts on the * mobile data interface when screen is on, to detect possible data @@ -1757,22 +2549,22 @@ public final class Settings { * connection problems. */ public static final String PDP_WATCHDOG_LONG_POLL_INTERVAL_MS = - "pdp_watchdog_long_poll_interval_ms"; - + "pdp_watchdog_long_poll_interval_ms"; + /** * The interval in milliseconds at which to check packet counts on the * mobile data interface after {@link #PDP_WATCHDOG_TRIGGER_PACKET_COUNT} * outgoing packets has been reached without incoming packets. */ - public static final String PDP_WATCHDOG_ERROR_POLL_INTERVAL_MS = + public static final String PDP_WATCHDOG_ERROR_POLL_INTERVAL_MS = "pdp_watchdog_error_poll_interval_ms"; /** * The number of outgoing packets sent without seeing an incoming packet - * that triggers a countdown (of {@link #PDP_WATCHDOG_ERROR_POLL_COUNT} + * that triggers a countdown (of {@link #PDP_WATCHDOG_ERROR_POLL_COUNT} * device is logged to the event log */ - public static final String PDP_WATCHDOG_TRIGGER_PACKET_COUNT = + public static final String PDP_WATCHDOG_TRIGGER_PACKET_COUNT = "pdp_watchdog_trigger_packet_count"; /** @@ -1780,50 +2572,44 @@ public final class Settings { * after hitting {@link #PDP_WATCHDOG_TRIGGER_PACKET_COUNT} before * attempting data connection recovery. */ - public static final String PDP_WATCHDOG_ERROR_POLL_COUNT = + public static final String PDP_WATCHDOG_ERROR_POLL_COUNT = "pdp_watchdog_error_poll_count"; /** * The number of failed PDP reset attempts before moving to something more * drastic: re-registering to the network. */ - public static final String PDP_WATCHDOG_MAX_PDP_RESET_FAIL_COUNT = + public static final String PDP_WATCHDOG_MAX_PDP_RESET_FAIL_COUNT = "pdp_watchdog_max_pdp_reset_fail_count"; /** * Address to ping as a last sanity check before attempting any recovery. * Unset or set to "0.0.0.0" to skip this check. */ - public static final String PDP_WATCHDOG_PING_ADDRESS = - "pdp_watchdog_ping_address"; + public static final String PDP_WATCHDOG_PING_ADDRESS = "pdp_watchdog_ping_address"; /** * The "-w deadline" parameter for the ping, ie, the max time in * seconds to spend pinging. */ - public static final String PDP_WATCHDOG_PING_DEADLINE = - "pdp_watchdog_ping_deadline"; - - /** - * The interval in milliseconds after which Wi-Fi is considered idle. - * When idle, it is possible for the device to be switched from Wi-Fi to - * the mobile data network. - */ - public static final String WIFI_IDLE_MS = "wifi_idle_ms"; + public static final String PDP_WATCHDOG_PING_DEADLINE = "pdp_watchdog_ping_deadline"; /** - * The interval in milliseconds at which we forcefully release the - * transition-to-mobile-data wake lock. + * The interval in milliseconds at which to check gprs registration + * after the first registration mismatch of gprs and voice service, + * to detect possible data network registration problems. + * */ - public static final String WIFI_MOBILE_DATA_TRANSITION_WAKELOCK_TIMEOUT_MS = - "wifi_mobile_data_transition_wakelock_timeout_ms"; + public static final String GPRS_REGISTER_CHECK_PERIOD_MS = + "gprs_register_check_period_ms"; /** - * The maximum number of times we will retry a connection to an access - * point for which we have failed in acquiring an IP address from DHCP. - * A value of N means that we will make N+1 connection attempts in all. + * Screen timeout in milliseconds corresponding to the + * PowerManager's POKE_LOCK_SHORT_TIMEOUT flag (i.e. the fastest + * possible screen timeout behavior.) */ - public static final String WIFI_MAX_DHCP_RETRY_COUNT = "wifi_max_dhcp_retry_count"; + public static final String SHORT_KEYLIGHT_DELAY_MS = + "short_keylight_delay_ms"; /** * @deprecated diff --git a/core/java/android/provider/Sync.java b/core/java/android/provider/Sync.java index b889293c2b6b846005fb17ec09e34d294f1c748b..2086a5dd4aa66f9b37180dab1e3b578bbf46da49 100644 --- a/core/java/android/provider/Sync.java +++ b/core/java/android/provider/Sync.java @@ -489,9 +489,14 @@ public final class Sync { */ public static final Uri CONTENT_URI = Uri.parse("content://sync/settings"); - /** controls whether or not the devices listens for sync tickles */ + /** controls whether or not the device listens for sync tickles */ public static final String SETTING_LISTEN_FOR_TICKLES = "listen_for_tickles"; + /** controls whether or not the device connect to Google in background for various + * stuff, including GTalk, checkin, Market and data sync ... + */ + public static final String SETTING_BACKGROUND_DATA = "background_data"; + /** controls whether or not the individual provider is synced when tickles are received */ public static final String SETTING_SYNC_PROVIDER_PREFIX = "sync_provider_"; @@ -529,17 +534,28 @@ public final class Sync { } /** - * A convenience method to set whether or not the tickle xmpp connection - * should be established. + * A convenience method to set whether or not the device should listen to tickles. * * @param contentResolver the ContentResolver to use to access the settings table - * @param flag true if the tickle xmpp connection should be established + * @param flag true if it should listen. */ static public void setListenForNetworkTickles(ContentResolver contentResolver, boolean flag) { putBoolean(contentResolver, SETTING_LISTEN_FOR_TICKLES, flag); } + /** + * A convenience method to set whether or not the device should connect to Google + * in background. + * + * @param contentResolver the ContentResolver to use to access the settings table + * @param flag true if it should connect. + */ + static public void setBackgroundData(ContentResolver contentResolver, + boolean flag) { + putBoolean(contentResolver, SETTING_BACKGROUND_DATA, flag); + } + public static class QueryMap extends ContentQueryMap { private ContentResolver mContentResolver; @@ -570,22 +586,41 @@ public final class Sync { } /** - * Set whether or not the tickle xmpp connection should be established. + * Set whether or not the device should listen for tickles. * - * @param flag true if the tickle xmpp connection should be established + * @param flag true if it should listen. */ public void setListenForNetworkTickles(boolean flag) { Settings.setListenForNetworkTickles(mContentResolver, flag); } /** - * Check if the tickle xmpp connection should be established - * @return true if it should be stablished + * Check if the device should listen to tickles. + + * @return true if it should */ public boolean getListenForNetworkTickles() { return getBoolean(SETTING_LISTEN_FOR_TICKLES, true); } + /** + * Set whether or not the device should connect to Google in background + * + * @param flag true if it should + */ + public void setBackgroundData(boolean flag) { + Settings.setBackgroundData(mContentResolver, flag); + } + + /** + * Check if the device should connect to Google in background. + + * @return true if it should + */ + public boolean getBackgroundData() { + return getBoolean(SETTING_BACKGROUND_DATA, true); + } + /** * Convenience function for retrieving a single settings value * as a boolean. diff --git a/core/java/android/provider/Telephony.java b/core/java/android/provider/Telephony.java index 776a2664b16a27c2476b898b12b767fa6ddb6824..18c64ed182030f49af02163bb89976d8382a79d6 100644 --- a/core/java/android/provider/Telephony.java +++ b/core/java/android/provider/Telephony.java @@ -16,7 +16,6 @@ package android.provider; -import com.android.internal.telephony.CallerInfo; import com.google.android.mms.util.SqliteWrapper; import android.annotation.SdkConstant; @@ -27,8 +26,6 @@ import android.content.Context; import android.content.Intent; import android.database.Cursor; import android.net.Uri; -import android.telephony.PhoneNumberUtils; -import android.telephony.TelephonyManager; import android.telephony.gsm.SmsMessage; import android.text.TextUtils; import android.text.util.Regex; @@ -263,49 +260,6 @@ public final class Telephony { || (messageType == MESSAGE_TYPE_QUEUED); } - /** - * Returns true if the address is an email address - * - * @param address the input address to be tested - * @return true if address is an email address - */ - public static boolean isEmailAddress(String address) { - /* - * The '@' char isn't a valid char in phone numbers. However, in SMS - * messages sent by carrier, the originating-address can contain - * non-dialable alphanumeric chars. For the purpose of thread id - * grouping, we don't care about those. We only care about the - * legitmate/dialable phone numbers (which we use the special phone - * number comparison) and email addresses (which we do straight up - * string comparison). - */ - return (address != null) && (address.indexOf('@') != -1); - } - - /** - * Formats an address for displaying, doing a phone number lookup in the - * Address Book, etc. - * - * @param context the context to use - * @param address the address to format - * @return a nicely formatted version of the sender to display - */ - public static String getDisplayAddress(Context context, String address) { - String result; - int index; - if (isEmailAddress(address)) { - index = address.indexOf('@'); - if (index != -1) { - result = address.substring(0, index); - } else { - result = address; - } - } else { - result = CallerInfo.getCallerId(context, address); - } - return result; - } - /** * Contains all text based SMS messages in the SMS app's inbox. */ @@ -1166,7 +1120,7 @@ public final class Telephony { * name-addr = [display-name] angle-addr * angle-addr = [CFWS] "<" addr-spec ">" [CFWS] */ - private static final Pattern NAME_ADDR_EMAIL_PATTERN = + public static final Pattern NAME_ADDR_EMAIL_PATTERN = Pattern.compile("\\s*(\"[^\"]*\"|[^<>\"]+)\\s*<([^<>]+)>\\s*"); /** @@ -1174,7 +1128,7 @@ public final class Telephony { * DQUOTE *([FWS] qcontent) [FWS] DQUOTE * [CFWS] */ - private static final Pattern QUOTED_STRING_PATTERN = + public static final Pattern QUOTED_STRING_PATTERN = Pattern.compile("\\s*\"([^\"]*)\"\\s*"); public static final Cursor query( @@ -1231,81 +1185,6 @@ public final class Telephony { return match.matches(); } - /** - * Formats an address for displaying, doing a phone number lookup in the - * Address Book, etc. - * - * @param context the context to use - * @param address the address to format - * @return a nicely formatted version of the sender to display - */ - public static String getDisplayAddress(Context context, String address) { - if (address == null) { - return ""; - } - - String localNumber = TelephonyManager.getDefault().getLine1Number(); - String[] values = address.split(";"); - String result = ""; - for (int i = 0; i < values.length; i++) { - if (values[i].length() > 0) { - if (PhoneNumberUtils.compare(values[i], localNumber)) { - result = result + ";" - + context.getString(com.android.internal.R.string.me); - } else if (isEmailAddress(values[i])) { - result = result + ";" + getDisplayName(context, values[i]); - } else { - result = result + ";" + CallerInfo.getCallerId(context, values[i]); - } - } - } - - if (result.length() > 0) { - // Skip the first ';' - return result.substring(1); - } - return result; - } - - private static String getEmailDisplayName(String displayString) { - Matcher match = QUOTED_STRING_PATTERN.matcher(displayString); - if (match.matches()) { - return match.group(1); - } - - return displayString; - } - - private static String getDisplayName(Context context, String email) { - Matcher match = NAME_ADDR_EMAIL_PATTERN.matcher(email); - if (match.matches()) { - // email has display name - return getEmailDisplayName(match.group(1)); - } - - Cursor cursor = SqliteWrapper.query(context, context.getContentResolver(), - Contacts.ContactMethods.CONTENT_EMAIL_URI, - new String[] { Contacts.ContactMethods.NAME }, - Contacts.ContactMethods.DATA + " = \'" + email + "\'", - null, null); - - if (cursor != null) { - try { - int columnIndex = cursor.getColumnIndexOrThrow( - Contacts.ContactMethods.NAME); - while (cursor.moveToNext()) { - String name = cursor.getString(columnIndex); - if (!TextUtils.isEmpty(name)) { - return name; - } - } - } finally { - cursor.close(); - } - } - return email; - } - /** * Contains all MMS messages in the MMS app's inbox. */ @@ -1647,6 +1526,7 @@ public final class Telephony { public static final String TYPE = "type"; + public static final String CURRENT = "current"; } public static final class Intents { diff --git a/core/java/android/security/Md5MessageDigest.java b/core/java/android/security/Md5MessageDigest.java index a7221aea2318de5a9616a229a90fbd91f69a47a9..4fe0cb0e62fe3bc1ad9f839b19d1a792610c8ca6 100644 --- a/core/java/android/security/Md5MessageDigest.java +++ b/core/java/android/security/Md5MessageDigest.java @@ -17,8 +17,7 @@ package android.security; /** - * This is a temporary class to provide SHA-1 hash. - * It's not meant to be correct, and eventually doesn't belong in java.security + * Provides the MD5 hash encryption. */ public class Md5MessageDigest extends MessageDigest { diff --git a/core/java/android/security/MessageDigest.java b/core/java/android/security/MessageDigest.java index 93040b9a229c9cc4a976548d99389e94d5c1f92a..cf2d0fe6e225e07cc8abd189b81e690110c1ad73 100644 --- a/core/java/android/security/MessageDigest.java +++ b/core/java/android/security/MessageDigest.java @@ -18,8 +18,22 @@ package android.security; import java.security.NoSuchAlgorithmException; +/** + * Base class for producing a message digest from different hash encryptions. + */ public abstract class MessageDigest { + /** + * Returns a digest object of the specified type. + * + * @param algorithm The type of hash function to use. Valid values are + * SHA-1 and MD5. + * @return The respective MessageDigest object. Either a + * {@link android.security.Sha1MessageDigest} or + * {@link android.security.Md5MessageDigest} object. + * @throws NoSuchAlgorithmException If an invalid algorithm + * is given. + */ public static MessageDigest getInstance(String algorithm) throws NoSuchAlgorithmException { @@ -39,5 +53,12 @@ public abstract class MessageDigest public abstract void update(byte[] input); public abstract byte[] digest(); + + /** + * Produces a message digest for the given input. + * + * @param input The message to encrypt. + * @return The digest (hash sum). + */ public abstract byte[] digest(byte[] input); } diff --git a/core/java/android/security/Sha1MessageDigest.java b/core/java/android/security/Sha1MessageDigest.java index 3b3fd6a67f837f133e981047c08f1013614be609..aa01fa615199159e5a2ccaaa2d59295790418507 100644 --- a/core/java/android/security/Sha1MessageDigest.java +++ b/core/java/android/security/Sha1MessageDigest.java @@ -17,8 +17,7 @@ package android.security; /** - * This is a temporary class to provide SHA-1 hash. - * It's not meant to be correct, and eventually doesn't belong in java.security + * Provides the SHA-1 hash encyption. */ public class Sha1MessageDigest extends MessageDigest { diff --git a/core/java/android/security/package.html b/core/java/android/security/package.html index 26b8a328b13212437892154b970ce092e6003af6..dfc6303fe4ad56e24ef725ce75f5153f6cb58ac0 100644 --- a/core/java/android/security/package.html +++ b/core/java/android/security/package.html @@ -1,5 +1,6 @@ +Utilities for encrypting messages from hash functions. {@hide} - \ No newline at end of file + diff --git a/core/java/android/server/BluetoothA2dpService.java b/core/java/android/server/BluetoothA2dpService.java new file mode 100644 index 0000000000000000000000000000000000000000..3cbb855d08c9ca678ecbe7ada5f36a12745bdd74 --- /dev/null +++ b/core/java/android/server/BluetoothA2dpService.java @@ -0,0 +1,315 @@ +/* + * 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. + */ + +/** + * TODO: Move this to + * java/services/com/android/server/BluetoothA2dpService.java + * and make the contructor package private again. + * @hide + */ + +package android.server; + +import android.bluetooth.BluetoothA2dp; +import android.bluetooth.BluetoothDevice; +import android.bluetooth.BluetoothError; +import android.bluetooth.BluetoothIntent; +import android.bluetooth.IBluetoothA2dp; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.pm.PackageManager; +import android.media.AudioManager; +import android.os.Binder; +import android.util.Log; + +import java.io.FileDescriptor; +import java.io.PrintWriter; +import java.util.ArrayList; +import java.util.List; +import java.util.HashMap; +import java.util.Iterator; + +public class BluetoothA2dpService extends IBluetoothA2dp.Stub { + private static final String TAG = "BluetoothDeviceService"; + private static final boolean DBG = true; + + public static final String BLUETOOTH_A2DP_SERVICE = "bluetooth_a2dp"; + + private static final String BLUETOOTH_ADMIN_PERM = android.Manifest.permission.BLUETOOTH_ADMIN; + private static final String BLUETOOTH_PERM = android.Manifest.permission.BLUETOOTH; + + private final Context mContext; + private final IntentFilter mIntentFilter; + private HashMap mAudioDevices; + private final AudioManager mAudioManager; + + private class SinkState { + public String address; + public int state; + public SinkState(String a, int s) {address = a; state = s;} + } + + public BluetoothA2dpService(Context context) { + mContext = context; + + mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE); + + BluetoothDevice device = + (BluetoothDevice)mContext.getSystemService(Context.BLUETOOTH_SERVICE); + if (device == null) { + throw new RuntimeException("Platform does not support Bluetooth"); + } + + if (!initNative()) { + throw new RuntimeException("Could not init BluetoothA2dpService"); + } + + mIntentFilter = new IntentFilter(BluetoothIntent.ENABLED_ACTION); + mIntentFilter.addAction(BluetoothIntent.DISABLED_ACTION); + mContext.registerReceiver(mReceiver, mIntentFilter); + + if (device.isEnabled()) { + onBluetoothEnable(); + } + } + + @Override + protected void finalize() throws Throwable { + try { + cleanupNative(); + } finally { + super.finalize(); + } + } + + private final BroadcastReceiver mReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + String action = intent.getAction(); + if (action.equals(BluetoothIntent.ENABLED_ACTION)) { + onBluetoothEnable(); + } else if (action.equals(BluetoothIntent.DISABLED_ACTION)) { + onBluetoothDisable(); + } + } + }; + + private synchronized void onBluetoothEnable() { + mAudioDevices = new HashMap(); + String[] paths = (String[])listHeadsetsNative(); + if (paths != null) { + for (String path : paths) { + mAudioDevices.put(path, new SinkState(getAddressNative(path), + isSinkConnectedNative(path) ? BluetoothA2dp.STATE_CONNECTED : + BluetoothA2dp.STATE_DISCONNECTED)); + } + } + } + + private synchronized void onBluetoothDisable() { + mAudioDevices = null; + } + + public synchronized int connectSink(String address) { + mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, + "Need BLUETOOTH_ADMIN permission"); + if (DBG) log("connectSink(" + address + ")"); + if (!BluetoothDevice.checkBluetoothAddress(address)) { + return BluetoothError.ERROR; + } + if (mAudioDevices == null) { + return BluetoothError.ERROR; + } + String path = lookupPath(address); + if (path == null) { + path = createHeadsetNative(address); + if (DBG) log("new bluez sink: " + address + " (" + path + ")"); + } + if (path == null) { + return BluetoothError.ERROR; + } + if (!connectSinkNative(path)) { + return BluetoothError.ERROR; + } else { + updateState(path, BluetoothA2dp.STATE_CONNECTING); + return BluetoothError.SUCCESS; + } + } + + public synchronized int disconnectSink(String address) { + mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, + "Need BLUETOOTH_ADMIN permission"); + if (DBG) log("disconnectSink(" + address + ")"); + if (!BluetoothDevice.checkBluetoothAddress(address)) { + return BluetoothError.ERROR; + } + if (mAudioDevices == null) { + return BluetoothError.ERROR; + } + String path = lookupPath(address); + if (path == null) { + return BluetoothError.ERROR; + } + if (!disconnectSinkNative(path)) { + return BluetoothError.ERROR; + } else { + updateState(path, BluetoothA2dp.STATE_DISCONNECTING); + return BluetoothError.SUCCESS; + } + } + + public synchronized List listConnectedSinks() { + mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); + List connectedSinks = new ArrayList(); + if (mAudioDevices == null) { + return connectedSinks; + } + for (SinkState sink : mAudioDevices.values()) { + if (sink.state == BluetoothA2dp.STATE_CONNECTED || + sink.state == BluetoothA2dp.STATE_PLAYING) { + connectedSinks.add(sink.address); + } + } + return connectedSinks; + } + + public synchronized int getSinkState(String address) { + mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); + if (!BluetoothDevice.checkBluetoothAddress(address)) { + return BluetoothError.ERROR; + } + if (mAudioDevices == null) { + return BluetoothA2dp.STATE_DISCONNECTED; + } + for (SinkState sink : mAudioDevices.values()) { + if (address.equals(sink.address)) { + return sink.state; + } + } + return BluetoothA2dp.STATE_DISCONNECTED; + } + + public synchronized void onHeadsetCreated(String path) { + updateState(path, BluetoothA2dp.STATE_DISCONNECTED); + } + + public synchronized void onHeadsetRemoved(String path) { + if (mAudioDevices == null) return; + mAudioDevices.remove(path); + } + + public synchronized void onSinkConnected(String path) { + if (mAudioDevices == null) return; + // bluez 3.36 quietly disconnects the previous sink when a new sink + // is connected, so we need to mark all previously connected sinks as + // disconnected + for (String oldPath : mAudioDevices.keySet()) { + if (path.equals(oldPath)) { + continue; + } + int state = mAudioDevices.get(oldPath).state; + if (state == BluetoothA2dp.STATE_CONNECTED || state == BluetoothA2dp.STATE_PLAYING) { + updateState(path, BluetoothA2dp.STATE_DISCONNECTED); + } + } + + mAudioManager.setBluetoothA2dpOn(true); + updateState(path, BluetoothA2dp.STATE_CONNECTED); + } + + public synchronized void onSinkDisconnected(String path) { + mAudioManager.setBluetoothA2dpOn(false); + updateState(path, BluetoothA2dp.STATE_DISCONNECTED); + } + + public synchronized void onSinkPlaying(String path) { + updateState(path, BluetoothA2dp.STATE_PLAYING); + } + + public synchronized void onSinkStopped(String path) { + updateState(path, BluetoothA2dp.STATE_CONNECTED); + } + + private synchronized final String lookupAddress(String path) { + if (mAudioDevices == null) return null; + String address = mAudioDevices.get(path).address; + if (address == null) Log.e(TAG, "Can't find address for " + path); + return address; + } + + private synchronized final String lookupPath(String address) { + if (mAudioDevices == null) return null; + + for (String path : mAudioDevices.keySet()) { + if (address.equals(mAudioDevices.get(path).address)) { + return path; + } + } + return null; + } + + private synchronized void updateState(String path, int state) { + if (mAudioDevices == null) return; + + SinkState s = mAudioDevices.get(path); + int prevState; + String address; + if (s == null) { + address = getAddressNative(path); + mAudioDevices.put(path, new SinkState(address, state)); + prevState = BluetoothA2dp.STATE_DISCONNECTED; + } else { + address = lookupAddress(path); + prevState = s.state; + s.state = state; + } + + if (DBG) log("state " + address + " (" + path + ") " + prevState + "->" + state); + + Intent intent = new Intent(BluetoothA2dp.SINK_STATE_CHANGED_ACTION); + intent.putExtra(BluetoothIntent.ADDRESS, address); + intent.putExtra(BluetoothA2dp.SINK_PREVIOUS_STATE, prevState); + intent.putExtra(BluetoothA2dp.SINK_STATE, state); + mContext.sendBroadcast(intent, BLUETOOTH_PERM); + } + + @Override + protected synchronized void dump(FileDescriptor fd, PrintWriter pw, String[] args) { + if (mAudioDevices == null) return; + pw.println("Cached audio devices:"); + for (String path : mAudioDevices.keySet()) { + SinkState sink = mAudioDevices.get(path); + pw.println(path + " " + sink.address + " " + BluetoothA2dp.stateToString(sink.state)); + } + } + + private static void log(String msg) { + Log.d(TAG, msg); + } + + private native boolean initNative(); + private native void cleanupNative(); + private synchronized native String[] listHeadsetsNative(); + private synchronized native String createHeadsetNative(String address); + private synchronized native boolean removeHeadsetNative(String path); + private synchronized native String getAddressNative(String path); + private synchronized native boolean connectSinkNative(String path); + private synchronized native boolean disconnectSinkNative(String path); + private synchronized native boolean isSinkConnectedNative(String path); + +} diff --git a/core/java/android/server/BluetoothDeviceService.java b/core/java/android/server/BluetoothDeviceService.java index 10f9f7c15075b01e034fdc7772e29d62c514e0ec..9bdab9f2957a72a90c6ae9a1010e38565b4c4c0c 100644 --- a/core/java/android/server/BluetoothDeviceService.java +++ b/core/java/android/server/BluetoothDeviceService.java @@ -54,13 +54,17 @@ import java.util.HashMap; public class BluetoothDeviceService extends IBluetoothDevice.Stub { private static final String TAG = "BluetoothDeviceService"; private int mNativeData; - private Context mContext; private BluetoothEventLoop mEventLoop; private IntentFilter mIntentFilter; private boolean mIsAirplaneSensitive; private volatile boolean mIsEnabled; // local cache of isEnabledNative() private boolean mIsDiscovering; + private final Context mContext; + + private static final String BLUETOOTH_ADMIN_PERM = android.Manifest.permission.BLUETOOTH_ADMIN; + private static final String BLUETOOTH_PERM = android.Manifest.permission.BLUETOOTH; + static { classInitNative(); } @@ -97,7 +101,7 @@ public class BluetoothDeviceService extends IBluetoothDevice.Stub { private native void cleanupNativeDataNative(); public boolean isEnabled() { - checkPermissionBluetooth(); + mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); return mIsEnabled; } private native int isEnabledNative(); @@ -106,7 +110,8 @@ public class BluetoothDeviceService extends IBluetoothDevice.Stub { * Disable bluetooth. Returns true on success. */ public synchronized boolean disable() { - checkPermissionBluetoothAdmin(); + mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, + "Need BLUETOOTH_ADMIN permission"); if (mEnableThread != null && mEnableThread.isAlive()) { return false; @@ -117,9 +122,10 @@ public class BluetoothDeviceService extends IBluetoothDevice.Stub { mEventLoop.stop(); disableNative(); mIsEnabled = false; + Settings.Secure.putInt(mContext.getContentResolver(), Settings.Secure.BLUETOOTH_ON, 0); mIsDiscovering = false; Intent intent = new Intent(BluetoothIntent.DISABLED_ACTION); - mContext.sendBroadcast(intent); + mContext.sendBroadcast(intent, BLUETOOTH_PERM); return true; } @@ -131,7 +137,8 @@ public class BluetoothDeviceService extends IBluetoothDevice.Stub { * notified when complete. */ public synchronized boolean enable(IBluetoothDeviceCallback callback) { - checkPermissionBluetoothAdmin(); + mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, + "Need BLUETOOTH_ADMIN permission"); // Airplane mode can prevent Bluetooth radio from being turned on. if (mIsAirplaneSensitive && isAirplaneModeOn()) { @@ -164,6 +171,8 @@ public class BluetoothDeviceService extends IBluetoothDevice.Stub { }; private EnableThread mEnableThread; + private String mOutgoingBondingDevAddress = null; + private class EnableThread extends Thread { private final IBluetoothDeviceCallback mEnableCallback; public EnableThread(IBluetoothDeviceCallback callback) { @@ -185,9 +194,11 @@ public class BluetoothDeviceService extends IBluetoothDevice.Stub { if (res) { mIsEnabled = true; + Settings.Secure.putInt(mContext.getContentResolver(), + Settings.Secure.BLUETOOTH_ON, 1); mIsDiscovering = false; Intent intent = new Intent(BluetoothIntent.ENABLED_ACTION); - mContext.sendBroadcast(intent); + mContext.sendBroadcast(intent, BLUETOOTH_PERM); mHandler.sendMessageDelayed(mHandler.obtainMessage(REGISTER_SDP_RECORDS), 3000); } mEnableThread = null; @@ -198,19 +209,20 @@ public class BluetoothDeviceService extends IBluetoothDevice.Stub { private native int disableNative(); public synchronized String getAddress() { - checkPermissionBluetooth(); + mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); return getAddressNative(); } private native String getAddressNative(); public synchronized String getName() { - checkPermissionBluetooth(); + mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); return getNameNative(); } private native String getNameNative(); public synchronized boolean setName(String name) { - checkPermissionBluetoothAdmin(); + mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, + "Need BLUETOOTH_ADMIN permission"); if (name == null) { return false; } @@ -220,19 +232,19 @@ public class BluetoothDeviceService extends IBluetoothDevice.Stub { private native boolean setNameNative(String name); public synchronized String[] listBondings() { - checkPermissionBluetooth(); + mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); return listBondingsNative(); } private native String[] listBondingsNative(); public synchronized String getMajorClass() { - checkPermissionBluetooth(); + mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); return getMajorClassNative(); } private native String getMajorClassNative(); public synchronized String getMinorClass() { - checkPermissionBluetooth(); + mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); return getMinorClassNative(); } private native String getMinorClassNative(); @@ -248,7 +260,7 @@ public class BluetoothDeviceService extends IBluetoothDevice.Stub { * @return The user-friendly name of the specified remote device. */ public synchronized String getRemoteName(String address) { - checkPermissionBluetooth(); + mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); if (!BluetoothDevice.checkBluetoothAddress(address)) { return null; } @@ -277,7 +289,8 @@ public class BluetoothDeviceService extends IBluetoothDevice.Stub { * false otherwise. */ public synchronized boolean startDiscovery(boolean resolveNames) { - checkPermissionBluetoothAdmin(); + mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, + "Need BLUETOOTH_ADMIN permission"); return startDiscoveryNative(resolveNames); } private native boolean startDiscoveryNative(boolean resolveNames); @@ -289,13 +302,14 @@ public class BluetoothDeviceService extends IBluetoothDevice.Stub { * started. */ public synchronized boolean cancelDiscovery() { - checkPermissionBluetoothAdmin(); + mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, + "Need BLUETOOTH_ADMIN permission"); return cancelDiscoveryNative(); } private native boolean cancelDiscoveryNative(); public synchronized boolean isDiscovering() { - checkPermissionBluetooth(); + mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); return mIsDiscovering; } @@ -304,19 +318,21 @@ public class BluetoothDeviceService extends IBluetoothDevice.Stub { } public synchronized boolean startPeriodicDiscovery() { - checkPermissionBluetoothAdmin(); + mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, + "Need BLUETOOTH_ADMIN permission"); return startPeriodicDiscoveryNative(); } private native boolean startPeriodicDiscoveryNative(); public synchronized boolean stopPeriodicDiscovery() { - checkPermissionBluetoothAdmin(); + mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, + "Need BLUETOOTH_ADMIN permission"); return stopPeriodicDiscoveryNative(); } private native boolean stopPeriodicDiscoveryNative(); public synchronized boolean isPeriodicDiscovery() { - checkPermissionBluetooth(); + mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); return isPeriodicDiscoveryNative(); } private native boolean isPeriodicDiscoveryNative(); @@ -331,7 +347,8 @@ public class BluetoothDeviceService extends IBluetoothDevice.Stub { * @param timeout_s The discoverable timeout in seconds. */ public synchronized boolean setDiscoverableTimeout(int timeout) { - checkPermissionBluetoothAdmin(); + mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, + "Need BLUETOOTH_ADMIN permission"); return setDiscoverableTimeoutNative(timeout); } private native boolean setDiscoverableTimeoutNative(int timeout_s); @@ -345,13 +362,13 @@ public class BluetoothDeviceService extends IBluetoothDevice.Stub { * value indicates an error. */ public synchronized int getDiscoverableTimeout() { - checkPermissionBluetooth(); + mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); return getDiscoverableTimeoutNative(); } private native int getDiscoverableTimeoutNative(); public synchronized boolean isAclConnected(String address) { - checkPermissionBluetooth(); + mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); if (!BluetoothDevice.checkBluetoothAddress(address)) { return false; } @@ -378,7 +395,7 @@ public class BluetoothDeviceService extends IBluetoothDevice.Stub { * @see #setMode */ public synchronized boolean isConnectable() { - checkPermissionBluetooth(); + mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); return isConnectableNative(); } private native boolean isConnectableNative(); @@ -401,7 +418,7 @@ public class BluetoothDeviceService extends IBluetoothDevice.Stub { * @see #setMode */ public synchronized boolean isDiscoverable() { - checkPermissionBluetooth(); + mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); return isDiscoverableNative(); } private native boolean isDiscoverableNative(); @@ -415,7 +432,7 @@ public class BluetoothDeviceService extends IBluetoothDevice.Stub { * @see #setMode */ public synchronized int getMode() { - checkPermissionBluetooth(); + mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); String mode = getModeNative(); if (mode == null) { return BluetoothDevice.MODE_UNKNOWN; @@ -451,7 +468,8 @@ public class BluetoothDeviceService extends IBluetoothDevice.Stub { * @see #getMode */ public synchronized boolean setMode(int mode) { - checkPermissionBluetoothAdmin(); + mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, + "Need BLUETOOTH_ADMIN permission"); switch (mode) { case BluetoothDevice.MODE_OFF: return setModeNative("off"); @@ -477,7 +495,7 @@ public class BluetoothDeviceService extends IBluetoothDevice.Stub { * @return The alias of the remote device. */ public synchronized String getRemoteAlias(String address) { - checkPermissionBluetooth(); + mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); if (!BluetoothDevice.checkBluetoothAddress(address)) { return null; } @@ -496,7 +514,8 @@ public class BluetoothDeviceService extends IBluetoothDevice.Stub { * @param alias Alias for the remote device */ public synchronized boolean setRemoteAlias(String address, String alias) { - checkPermissionBluetoothAdmin(); + mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, + "Need BLUETOOTH_ADMIN permission"); if (alias == null || !BluetoothDevice.checkBluetoothAddress(address)) { return false; } @@ -513,7 +532,8 @@ public class BluetoothDeviceService extends IBluetoothDevice.Stub { * @param address Bluetooth address of remote device */ public synchronized boolean clearRemoteAlias(String address) { - checkPermissionBluetoothAdmin(); + mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, + "Need BLUETOOTH_ADMIN permission"); if (!BluetoothDevice.checkBluetoothAddress(address)) { return false; } @@ -522,7 +542,8 @@ public class BluetoothDeviceService extends IBluetoothDevice.Stub { private native boolean clearRemoteAliasNative(String address); public synchronized boolean disconnectRemoteDeviceAcl(String address) { - checkPermissionBluetoothAdmin(); + mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, + "Need BLUETOOTH_ADMIN permission"); if (!BluetoothDevice.checkBluetoothAddress(address)) { return false; } @@ -546,7 +567,8 @@ public class BluetoothDeviceService extends IBluetoothDevice.Stub { * @see android.bluetooth.PasskeyAgent */ public synchronized boolean createBonding(String address, IBluetoothDeviceCallback callback) { - checkPermissionBluetoothAdmin(); + mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, + "Need BLUETOOTH_ADMIN permission"); if (!BluetoothDevice.checkBluetoothAddress(address)) { return false; } @@ -568,9 +590,19 @@ public class BluetoothDeviceService extends IBluetoothDevice.Stub { callbacks.remove(address); return false; } + mOutgoingBondingDevAddress = address; return true; } + private native boolean createBondingNative(String address, int timeout_ms); + + /*package*/ String getOutgoingBondingDevAddress() { + return mOutgoingBondingDevAddress; + } + + /*package*/ void setOutgoingBondingDevAddress(String outgoingBondingDevAddress) { + mOutgoingBondingDevAddress = outgoingBondingDevAddress; + } /** * This method cancels a pending bonding request. @@ -593,7 +625,8 @@ public class BluetoothDeviceService extends IBluetoothDevice.Stub { * @see #listBondings */ public synchronized boolean cancelBondingProcess(String address) { - checkPermissionBluetoothAdmin(); + mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, + "Need BLUETOOTH_ADMIN permission"); if (!BluetoothDevice.checkBluetoothAddress(address)) { return false; } @@ -618,7 +651,8 @@ public class BluetoothDeviceService extends IBluetoothDevice.Stub { * @see #listBondings */ public synchronized boolean removeBonding(String address) { - checkPermissionBluetoothAdmin(); + mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, + "Need BLUETOOTH_ADMIN permission"); if (!BluetoothDevice.checkBluetoothAddress(address)) { return false; } @@ -627,7 +661,7 @@ public class BluetoothDeviceService extends IBluetoothDevice.Stub { private native boolean removeBondingNative(String address); public synchronized boolean hasBonding(String address) { - checkPermissionBluetooth(); + mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); if (!BluetoothDevice.checkBluetoothAddress(address)) { return false; } @@ -636,7 +670,7 @@ public class BluetoothDeviceService extends IBluetoothDevice.Stub { private native boolean hasBondingNative(String address); public synchronized String[] listAclConnections() { - checkPermissionBluetooth(); + mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); return listConnectionsNative(); } private native String[] listConnectionsNative(); @@ -652,7 +686,7 @@ public class BluetoothDeviceService extends IBluetoothDevice.Stub { * remote devices that this adapter is aware of. */ public synchronized String[] listRemoteDevices() { - checkPermissionBluetooth(); + mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); return listRemoteDevicesNative(); } private native String[] listRemoteDevicesNative(); @@ -666,7 +700,7 @@ public class BluetoothDeviceService extends IBluetoothDevice.Stub { * Bluetooth-chip version. */ public synchronized String getVersion() { - checkPermissionBluetooth(); + mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); return getVersionNative(); } private native String getVersionNative(); @@ -683,7 +717,7 @@ public class BluetoothDeviceService extends IBluetoothDevice.Stub { * @return The HCI revision of this adapter. */ public synchronized String getRevision() { - checkPermissionBluetooth(); + mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); return getRevisionNative(); } private native String getRevisionNative(); @@ -697,7 +731,7 @@ public class BluetoothDeviceService extends IBluetoothDevice.Stub { * @return Manufacturer name. */ public synchronized String getManufacturer() { - checkPermissionBluetooth(); + mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); return getManufacturerNative(); } private native String getManufacturerNative(); @@ -716,7 +750,7 @@ public class BluetoothDeviceService extends IBluetoothDevice.Stub { * @return company name */ public synchronized String getCompany() { - checkPermissionBluetooth(); + mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); return getCompanyNative(); } private native String getCompanyNative(); @@ -731,7 +765,7 @@ public class BluetoothDeviceService extends IBluetoothDevice.Stub { * @see #getVersion */ public synchronized String getRemoteVersion(String address) { - checkPermissionBluetooth(); + mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); if (!BluetoothDevice.checkBluetoothAddress(address)) { return null; } @@ -749,7 +783,7 @@ public class BluetoothDeviceService extends IBluetoothDevice.Stub { * @see #getRevision */ public synchronized String getRemoteRevision(String address) { - checkPermissionBluetooth(); + mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); if (!BluetoothDevice.checkBluetoothAddress(address)) { return null; } @@ -767,7 +801,7 @@ public class BluetoothDeviceService extends IBluetoothDevice.Stub { * @see #getManufacturer */ public synchronized String getRemoteManufacturer(String address) { - checkPermissionBluetooth(); + mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); if (!BluetoothDevice.checkBluetoothAddress(address)) { return null; } @@ -785,7 +819,7 @@ public class BluetoothDeviceService extends IBluetoothDevice.Stub { * @see #getCompany */ public synchronized String getRemoteCompany(String address) { - checkPermissionBluetooth(); + mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); if (!BluetoothDevice.checkBluetoothAddress(address)) { return null; } @@ -801,7 +835,7 @@ public class BluetoothDeviceService extends IBluetoothDevice.Stub { * @return a String with the timestamp. */ public synchronized String lastSeen(String address) { - checkPermissionBluetooth(); + mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); if (!BluetoothDevice.checkBluetoothAddress(address)) { return null; } @@ -817,7 +851,7 @@ public class BluetoothDeviceService extends IBluetoothDevice.Stub { * @return a String with the timestamp. */ public synchronized String lastUsed(String address) { - checkPermissionBluetooth(); + mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); if (!BluetoothDevice.checkBluetoothAddress(address)) { return null; } @@ -841,7 +875,7 @@ public class BluetoothDeviceService extends IBluetoothDevice.Stub { */ public synchronized String getRemoteMajorClass(String address) { if (!BluetoothDevice.checkBluetoothAddress(address)) { - checkPermissionBluetooth(); + mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); return null; } return getRemoteMajorClassNative(address); @@ -863,7 +897,7 @@ public class BluetoothDeviceService extends IBluetoothDevice.Stub { * @see #getRemoteClass */ public synchronized String getRemoteMinorClass(String address) { - checkPermissionBluetooth(); + mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); if (!BluetoothDevice.checkBluetoothAddress(address)) { return null; } @@ -880,7 +914,7 @@ public class BluetoothDeviceService extends IBluetoothDevice.Stub { * @see #getRemoteClass */ public synchronized String[] getRemoteServiceClasses(String address) { - checkPermissionBluetooth(); + mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); if (!BluetoothDevice.checkBluetoothAddress(address)) { return null; } @@ -904,7 +938,7 @@ public class BluetoothDeviceService extends IBluetoothDevice.Stub { */ public synchronized int getRemoteClass(String address) { if (!BluetoothDevice.checkBluetoothAddress(address)) { - checkPermissionBluetooth(); + mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); return -1; } return getRemoteClassNative(address); @@ -919,7 +953,7 @@ public class BluetoothDeviceService extends IBluetoothDevice.Stub { * @return byte array of features. */ public synchronized byte[] getRemoteFeatures(String address) { - checkPermissionBluetooth(); + mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); if (!BluetoothDevice.checkBluetoothAddress(address)) { return null; } @@ -944,7 +978,7 @@ public class BluetoothDeviceService extends IBluetoothDevice.Stub { * @see #getRemoteServiceRecord */ public synchronized int[] getRemoteServiceHandles(String address, String match) { - checkPermissionBluetooth(); + mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); if (!BluetoothDevice.checkBluetoothAddress(address)) { return null; } @@ -974,7 +1008,7 @@ public class BluetoothDeviceService extends IBluetoothDevice.Stub { * @see #getRemoteServiceHandles */ public synchronized byte[] getRemoteServiceRecord(String address, int handle) { - checkPermissionBluetooth(); + mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); if (!BluetoothDevice.checkBluetoothAddress(address)) { return null; } @@ -985,7 +1019,7 @@ public class BluetoothDeviceService extends IBluetoothDevice.Stub { // AIDL does not yet support short's public synchronized boolean getRemoteServiceChannel(String address, int uuid16, IBluetoothDeviceCallback callback) { - checkPermissionBluetooth(); + mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); if (!BluetoothDevice.checkBluetoothAddress(address)) { return false; } @@ -1011,7 +1045,8 @@ public class BluetoothDeviceService extends IBluetoothDevice.Stub { private native boolean getRemoteServiceChannelNative(String address, short uuid16); public synchronized boolean setPin(String address, byte[] pin) { - checkPermissionBluetoothAdmin(); + mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, + "Need BLUETOOTH_ADMIN permission"); if (pin == null || pin.length <= 0 || pin.length > 16 || !BluetoothDevice.checkBluetoothAddress(address)) { return false; @@ -1036,7 +1071,8 @@ public class BluetoothDeviceService extends IBluetoothDevice.Stub { private native boolean setPinNative(String address, String pin, int nativeData); public synchronized boolean cancelPin(String address) { - checkPermissionBluetoothAdmin(); + mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, + "Need BLUETOOTH_ADMIN permission"); if (!BluetoothDevice.checkBluetoothAddress(address)) { return false; } @@ -1061,7 +1097,7 @@ public class BluetoothDeviceService extends IBluetoothDevice.Stub { // some random app is not sending this intent and disabling bluetooth boolean enabled = !isAirplaneModeOn(); // If bluetooth is currently expected to be on, then enable or disable bluetooth - if (Settings.System.getInt(resolver, Settings.System.BLUETOOTH_ON, 0) > 0) { + if (Settings.Secure.getInt(resolver, Settings.Secure.BLUETOOTH_ON, 0) > 0) { if (enabled) { enable(null); } else { @@ -1089,25 +1125,6 @@ public class BluetoothDeviceService extends IBluetoothDevice.Stub { Settings.System.AIRPLANE_MODE_ON, 0) == 1; } - private static final String BLUETOOTH_ADMIN = android.Manifest.permission.BLUETOOTH_ADMIN; - private static final String BLUETOOTH = android.Manifest.permission.BLUETOOTH; - - private void checkPermissionBluetoothAdmin() { - if (mContext.checkCallingOrSelfPermission(BLUETOOTH_ADMIN) != - PackageManager.PERMISSION_GRANTED) { - throw new SecurityException("Requires BLUETOOTH_ADMIN permission"); - } - } - - private void checkPermissionBluetooth() { - if (mContext.checkCallingOrSelfPermission(BLUETOOTH_ADMIN) != - PackageManager.PERMISSION_GRANTED && - mContext.checkCallingOrSelfPermission(BLUETOOTH) != - PackageManager.PERMISSION_GRANTED ) { - throw new SecurityException("Requires BLUETOOTH or BLUETOOTH_ADMIN permission"); - } - } - private static final String DISABLE_ESCO_PATH = "/sys/module/sco/parameters/disable_esco"; private static void disableEsco() { try { @@ -1124,7 +1141,7 @@ public class BluetoothDeviceService extends IBluetoothDevice.Stub { pw.println("\nBluetooth ENABLED: " + getAddress() + " (" + getName() + ")"); pw.println("\nisDiscovering() = " + isDiscovering()); - BluetoothHeadset headset = new BluetoothHeadset(mContext); + BluetoothHeadset headset = new BluetoothHeadset(mContext, null); pw.println("\n--Bondings--"); String[] addresses = listBondings(); diff --git a/core/java/android/server/BluetoothEventLoop.java b/core/java/android/server/BluetoothEventLoop.java index 5722f51a68f260c92b5cb2728074071062b4cdb9..2d8aaccfb9bfea2d265b693fc62128acbe41e6cc 100644 --- a/core/java/android/server/BluetoothEventLoop.java +++ b/core/java/android/server/BluetoothEventLoop.java @@ -16,6 +16,7 @@ package android.server; +import android.bluetooth.BluetoothClass.Device; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothIntent; import android.bluetooth.IBluetoothDeviceCallback; @@ -24,8 +25,6 @@ import android.content.Intent; import android.os.RemoteException; import android.util.Log; -import java.io.IOException; -import java.lang.Thread; import java.util.HashMap; /** @@ -45,10 +44,13 @@ class BluetoothEventLoop { private HashMap mCreateBondingCallbacks; private HashMap mPasskeyAgentRequestData; private HashMap mGetRemoteServiceChannelCallbacks; - private BluetoothDeviceService mBluetoothService; - + private HashMap mDefaultPinData; + private BluetoothDeviceService mBluetoothService; private Context mContext; + private static final String BLUETOOTH_ADMIN_PERM = android.Manifest.permission.BLUETOOTH_ADMIN; + private static final String BLUETOOTH_PERM = android.Manifest.permission.BLUETOOTH; + static { classInitNative(); } private static native void classInitNative(); @@ -58,6 +60,7 @@ class BluetoothEventLoop { mCreateBondingCallbacks = new HashMap(); mPasskeyAgentRequestData = new HashMap(); mGetRemoteServiceChannelCallbacks = new HashMap(); + mDefaultPinData = new HashMap(); initializeNativeDataNative(); } private native void initializeNativeDataNative(); @@ -146,27 +149,28 @@ class BluetoothEventLoop { intMode = BluetoothDevice.MODE_DISCOVERABLE; } intent.putExtra(BluetoothIntent.MODE, intMode); - mContext.sendBroadcast(intent); + mContext.sendBroadcast(intent, BLUETOOTH_PERM); } public void onDiscoveryStarted() { mBluetoothService.setIsDiscovering(true); Intent intent = new Intent(BluetoothIntent.DISCOVERY_STARTED_ACTION); - mContext.sendBroadcast(intent); + mContext.sendBroadcast(intent, BLUETOOTH_PERM); } public void onDiscoveryCompleted() { mBluetoothService.setIsDiscovering(false); Intent intent = new Intent(BluetoothIntent.DISCOVERY_COMPLETED_ACTION); - mContext.sendBroadcast(intent); + mContext.sendBroadcast(intent, BLUETOOTH_PERM); } public void onPairingRequest() { Intent intent = new Intent(BluetoothIntent.PAIRING_REQUEST_ACTION); - mContext.sendBroadcast(intent); + mContext.sendBroadcast(intent, BLUETOOTH_ADMIN_PERM); } + public void onPairingCancel() { Intent intent = new Intent(BluetoothIntent.PAIRING_CANCEL_ACTION); - mContext.sendBroadcast(intent); + mContext.sendBroadcast(intent, BLUETOOTH_ADMIN_PERM); } public void onRemoteDeviceFound(String address, int deviceClass, short rssi) { @@ -174,64 +178,65 @@ class BluetoothEventLoop { intent.putExtra(BluetoothIntent.ADDRESS, address); intent.putExtra(BluetoothIntent.CLASS, deviceClass); intent.putExtra(BluetoothIntent.RSSI, rssi); - mContext.sendBroadcast(intent); + mContext.sendBroadcast(intent, BLUETOOTH_PERM); } public void onRemoteDeviceDisappeared(String address) { Intent intent = new Intent(BluetoothIntent.REMOTE_DEVICE_DISAPPEARED_ACTION); intent.putExtra(BluetoothIntent.ADDRESS, address); - mContext.sendBroadcast(intent); + mContext.sendBroadcast(intent, BLUETOOTH_PERM); } public void onRemoteClassUpdated(String address, int deviceClass) { Intent intent = new Intent(BluetoothIntent.REMOTE_DEVICE_CLASS_UPDATED_ACTION); intent.putExtra(BluetoothIntent.ADDRESS, address); intent.putExtra(BluetoothIntent.CLASS, deviceClass); - mContext.sendBroadcast(intent); + mContext.sendBroadcast(intent, BLUETOOTH_PERM); } public void onRemoteDeviceConnected(String address) { Intent intent = new Intent(BluetoothIntent.REMOTE_DEVICE_CONNECTED_ACTION); intent.putExtra(BluetoothIntent.ADDRESS, address); - mContext.sendBroadcast(intent); + mContext.sendBroadcast(intent, BLUETOOTH_PERM); } public void onRemoteDeviceDisconnectRequested(String address) { Intent intent = new Intent(BluetoothIntent.REMOTE_DEVICE_DISCONNECT_REQUESTED_ACTION); intent.putExtra(BluetoothIntent.ADDRESS, address); - mContext.sendBroadcast(intent); + mContext.sendBroadcast(intent, BLUETOOTH_PERM); } public void onRemoteDeviceDisconnected(String address) { Intent intent = new Intent(BluetoothIntent.REMOTE_DEVICE_DISCONNECTED_ACTION); intent.putExtra(BluetoothIntent.ADDRESS, address); - mContext.sendBroadcast(intent); + mContext.sendBroadcast(intent, BLUETOOTH_PERM); } public void onRemoteNameUpdated(String address, String name) { Intent intent = new Intent(BluetoothIntent.REMOTE_NAME_UPDATED_ACTION); intent.putExtra(BluetoothIntent.ADDRESS, address); intent.putExtra(BluetoothIntent.NAME, name); - mContext.sendBroadcast(intent); + mContext.sendBroadcast(intent, BLUETOOTH_PERM); } public void onRemoteNameFailed(String address) { Intent intent = new Intent(BluetoothIntent.REMOTE_NAME_FAILED_ACTION); intent.putExtra(BluetoothIntent.ADDRESS, address); - mContext.sendBroadcast(intent); + mContext.sendBroadcast(intent, BLUETOOTH_PERM); } public void onRemoteNameChanged(String address, String name) { Intent intent = new Intent(BluetoothIntent.REMOTE_NAME_UPDATED_ACTION); intent.putExtra(BluetoothIntent.ADDRESS, address); intent.putExtra(BluetoothIntent.NAME, name); - mContext.sendBroadcast(intent); + mContext.sendBroadcast(intent, BLUETOOTH_PERM); } public void onRemoteAliasChanged(String address, String alias) { Intent intent = new Intent(BluetoothIntent.REMOTE_ALIAS_CHANGED_ACTION); intent.putExtra(BluetoothIntent.ADDRESS, address); intent.putExtra(BluetoothIntent.ALIAS, alias); - mContext.sendBroadcast(intent); + mContext.sendBroadcast(intent, BLUETOOTH_PERM); } public void onRemoteAliasCleared(String address) { Intent intent = new Intent(BluetoothIntent.REMOTE_ALIAS_CLEARED_ACTION); intent.putExtra(BluetoothIntent.ADDRESS, address); - mContext.sendBroadcast(intent); + mContext.sendBroadcast(intent, BLUETOOTH_PERM); } private void onCreateBondingResult(String address, boolean result) { + mBluetoothService.setOutgoingBondingDevAddress(null); IBluetoothDeviceCallback callback = mCreateBondingCallbacks.get(address); if (callback != null) { try { @@ -240,39 +245,71 @@ class BluetoothEventLoop { BluetoothDevice.RESULT_FAILURE); } catch (RemoteException e) {} mCreateBondingCallbacks.remove(address); - } + } } + public void onBondingCreated(String address) { Intent intent = new Intent(BluetoothIntent.BONDING_CREATED_ACTION); intent.putExtra(BluetoothIntent.ADDRESS, address); - mContext.sendBroadcast(intent); + mContext.sendBroadcast(intent, BLUETOOTH_PERM); } + public void onBondingRemoved(String address) { Intent intent = new Intent(BluetoothIntent.BONDING_REMOVED_ACTION); intent.putExtra(BluetoothIntent.ADDRESS, address); - mContext.sendBroadcast(intent); + mContext.sendBroadcast(intent, BLUETOOTH_PERM); + + if (mDefaultPinData.containsKey(address)) { + mDefaultPinData.remove(address); + } } public void onNameChanged(String name) { Intent intent = new Intent(BluetoothIntent.NAME_CHANGED_ACTION); intent.putExtra(BluetoothIntent.NAME, name); - mContext.sendBroadcast(intent); + mContext.sendBroadcast(intent, BLUETOOTH_PERM); } public void onPasskeyAgentRequest(String address, int nativeData) { - mPasskeyAgentRequestData.put(address, new Integer(nativeData)); + mPasskeyAgentRequestData.put(address, new Integer(nativeData)); + + if (address.equals(mBluetoothService.getOutgoingBondingDevAddress())) { + int btClass = mBluetoothService.getRemoteClass(address); + int remoteDeviceClass = Device.getDevice(btClass); + if (remoteDeviceClass == Device.AUDIO_VIDEO_WEARABLE_HEADSET || + remoteDeviceClass == Device.AUDIO_VIDEO_HANDSFREE || + remoteDeviceClass == Device.AUDIO_VIDEO_HEADPHONES || + remoteDeviceClass == Device.AUDIO_VIDEO_PORTABLE_AUDIO || + remoteDeviceClass == Device.AUDIO_VIDEO_CAR_AUDIO || + remoteDeviceClass == Device.AUDIO_VIDEO_HIFI_AUDIO) { + if (!mDefaultPinData.containsKey(address)) { + mDefaultPinData.put(address, false); + } + if (!mDefaultPinData.get(address)) { + mDefaultPinData.remove(address); + mDefaultPinData.put(address, true); + mBluetoothService.setPin(address, BluetoothDevice.convertPinToBytes("0000")); + return; + } + } + } Intent intent = new Intent(BluetoothIntent.PAIRING_REQUEST_ACTION); intent.putExtra(BluetoothIntent.ADDRESS, address); - mContext.sendBroadcast(intent); + mContext.sendBroadcast(intent, BLUETOOTH_ADMIN_PERM); } + public void onPasskeyAgentCancel(String address) { mPasskeyAgentRequestData.remove(address); - + if (mDefaultPinData.containsKey(address)) { + mDefaultPinData.remove(address); + mDefaultPinData.put(address, false); + } Intent intent = new Intent(BluetoothIntent.PAIRING_CANCEL_ACTION); intent.putExtra(BluetoothIntent.ADDRESS, address); - mContext.sendBroadcast(intent); + mContext.sendBroadcast(intent, BLUETOOTH_ADMIN_PERM); } + private void onGetRemoteServiceChannelResult(String address, int channel) { IBluetoothDeviceCallback callback = mGetRemoteServiceChannelCallbacks.get(address); if (callback != null) { diff --git a/core/java/android/server/checkin/FallbackCheckinService.java b/core/java/android/server/checkin/FallbackCheckinService.java index b450913cf5e62c7cc9c669d59d24e849d279f8f4..65921af5038b5cad19f59582eeea6b98b63b683c 100644 --- a/core/java/android/server/checkin/FallbackCheckinService.java +++ b/core/java/android/server/checkin/FallbackCheckinService.java @@ -42,4 +42,8 @@ public final class FallbackCheckinService extends ICheckinService.Stub { state.isEnabled = false; p.onResult(state); } + + public void getParentalControlState(IParentalControlCallback p, String requestingApp) + throws android.os.RemoteException { + } } diff --git a/core/java/android/server/search/SearchableInfo.java b/core/java/android/server/search/SearchableInfo.java index 5b9942e2224df146ca937c6f48f9f10a4c038328..6c8f55487c0e702bf0fb96398ce921011c9b9393 100644 --- a/core/java/android/server/search/SearchableInfo.java +++ b/core/java/android/server/search/SearchableInfo.java @@ -402,7 +402,7 @@ public final class SearchableInfo implements Parcelable { // initialize as an "unsearchable" object mSearchable = false; mSearchActivity = cName; - + // to access another activity's resources, I need its context. // BE SURE to release the cache sometime after construction - it's a large object to hold mCacheActivityContext = getActivityContext(context); @@ -415,6 +415,7 @@ public final class SearchableInfo implements Parcelable { mIconId = a.getResourceId(com.android.internal.R.styleable.Searchable_icon, 0); mSearchButtonText = a.getResourceId( com.android.internal.R.styleable.Searchable_searchButtonText, 0); + setSearchModeFlags(); if (DBG_INHIBIT_SUGGESTIONS == 0) { mSuggestAuthority = a.getString( diff --git a/core/java/android/speech/recognition/AbstractEmbeddedGrammarListener.java b/core/java/android/speech/recognition/AbstractEmbeddedGrammarListener.java deleted file mode 100644 index c25a7e3983498701658e22e73700add5399e629a..0000000000000000000000000000000000000000 --- a/core/java/android/speech/recognition/AbstractEmbeddedGrammarListener.java +++ /dev/null @@ -1,51 +0,0 @@ -/*---------------------------------------------------------------------------* - * AbstractEmbeddedGrammarListener.java * - * * - * Copyright 2007, 2008 Nuance Communciations, Inc. * - * * - * 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 android.speech.recognition; - -/** - * An EmbeddedGrammarListener whose methods are empty. This class exists as - * convenience for creating listener objects. - */ -public abstract class AbstractEmbeddedGrammarListener implements EmbeddedGrammarListener -{ - public void onCompileAllSlots() - { - } - - public void onError(Exception e) - { - } - - public void onLoaded() - { - } - - public void onResetAllSlots() - { - } - - public void onSaved(String path) - { - } - - public void onUnloaded() - { - } -} diff --git a/core/java/android/speech/recognition/AbstractGrammarListener.java b/core/java/android/speech/recognition/AbstractGrammarListener.java deleted file mode 100644 index fe6229086fcd598ed96e593b1e309d22cda6851f..0000000000000000000000000000000000000000 --- a/core/java/android/speech/recognition/AbstractGrammarListener.java +++ /dev/null @@ -1,39 +0,0 @@ -/*---------------------------------------------------------------------------* - * AbstractGrammarListener.java * - * * - * Copyright 2007, 2008 Nuance Communciations, Inc. * - * * - * 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 android.speech.recognition; - -/** - * A GrammarListener whose methods are empty. This class exists as convenience - * for creating listener objects. - */ -public abstract class AbstractGrammarListener implements GrammarListener -{ - public void onError(Exception e) - { - } - - public void onLoaded() - { - } - - public void onUnloaded() - { - } -} diff --git a/core/java/android/speech/recognition/AbstractRecognizerListener.java b/core/java/android/speech/recognition/AbstractRecognizerListener.java deleted file mode 100644 index ee2b8d14d06682aadc03040d5d56e055368f6920..0000000000000000000000000000000000000000 --- a/core/java/android/speech/recognition/AbstractRecognizerListener.java +++ /dev/null @@ -1,83 +0,0 @@ -/*---------------------------------------------------------------------------* - * AbstractRecognizerListener.java * - * * - * Copyright 2007, 2008 Nuance Communciations, Inc. * - * * - * 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 android.speech.recognition; - -import java.util.Hashtable; -import java.util.Vector; - -/** - * A RecognizerListener whose methods are empty. This class exists as - * convenience for creating listener objects. - */ -public abstract class AbstractRecognizerListener implements RecognizerListener -{ - public void onBeginningOfSpeech() - { - } - - public void onEndOfSpeech() - { - } - - public void onRecognitionSuccess(RecognitionResult result) - { - } - - public void onRecognitionFailure(FailureReason reason) - { - } - - public void onError(Exception e) - { - } - - public void onParametersGetError(Vector parameters, Exception e) - { - } - - public void onParametersSetError(Hashtable parameters, - Exception e) - { - } - - public void onParametersGet(Hashtable parameters) - { - } - - public void onParametersSet(Hashtable parameters) - { - } - - public void onStartOfSpeechTimeout() - { - } - - public void onAcousticStateReset() - { - } - - public void onStarted() - { - } - - public void onStopped() - { - } -} diff --git a/core/java/android/speech/recognition/AbstractSrecGrammarListener.java b/core/java/android/speech/recognition/AbstractSrecGrammarListener.java deleted file mode 100644 index e62e4bab1626150ef4c65aa3d24de24e9eb583c0..0000000000000000000000000000000000000000 --- a/core/java/android/speech/recognition/AbstractSrecGrammarListener.java +++ /dev/null @@ -1,59 +0,0 @@ -/*---------------------------------------------------------------------------* - * AbstractSrecGrammarListener.java * - * * - * Copyright 2007, 2008 Nuance Communciations, Inc. * - * * - * 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 android.speech.recognition; - -/** - * An SrecGrammarListener whose methods are empty. This class exists as - * convenience for creating listener objects. - */ -public abstract class AbstractSrecGrammarListener implements SrecGrammarListener -{ - public void onCompileAllSlots() - { - } - - public void onError(Exception e) - { - } - - public void onLoaded() - { - } - - public void onResetAllSlots() - { - } - - public void onSaved(String path) - { - } - - public void onUnloaded() - { - } - - public void onAddItemList() - { - } - - public void onAddItemListFailure(int index, Exception e) - { - } -} diff --git a/core/java/android/speech/recognition/AudioAlreadyInUseException.java b/core/java/android/speech/recognition/AudioAlreadyInUseException.java deleted file mode 100644 index 90698a7014fcb71011054c4ef725654fa491658b..0000000000000000000000000000000000000000 --- a/core/java/android/speech/recognition/AudioAlreadyInUseException.java +++ /dev/null @@ -1,34 +0,0 @@ -/*---------------------------------------------------------------------------* - * AudioAlreadyInUseException.java * - * * - * Copyright 2007, 2008 Nuance Communciations, Inc. * - * * - * 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 android.speech.recognition; - -/** - * Thrown when an AudioStream is passed into a component when another component - * is already using it. - */ -public class AudioAlreadyInUseException extends IllegalArgumentException -{ - private static final long serialVersionUID = 0L; - - public AudioAlreadyInUseException(String msg) - { - super(msg); - } -} diff --git a/core/java/android/speech/recognition/AudioDriverErrorException.java b/core/java/android/speech/recognition/AudioDriverErrorException.java deleted file mode 100644 index a755e7f1a1a4dcce7936c81c001402625b47b345..0000000000000000000000000000000000000000 --- a/core/java/android/speech/recognition/AudioDriverErrorException.java +++ /dev/null @@ -1,33 +0,0 @@ -/*---------------------------------------------------------------------------* - * AudioDriverErrorException.java * - * * - * Copyright 2007, 2008 Nuance Communciations, Inc. * - * * - * 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 android.speech.recognition; - -/** - * Thrown if an error occurs in the audio driver. - */ -public class AudioDriverErrorException extends Exception -{ - private static final long serialVersionUID = 0L; - - public AudioDriverErrorException(String msg) - { - super(msg); - } -} diff --git a/core/java/android/speech/recognition/AudioSource.java b/core/java/android/speech/recognition/AudioSource.java deleted file mode 100644 index c4cd8020c4847387bd740e51f31fa181ddee5b9e..0000000000000000000000000000000000000000 --- a/core/java/android/speech/recognition/AudioSource.java +++ /dev/null @@ -1,45 +0,0 @@ -/*---------------------------------------------------------------------------* - * AudioSource.java * - * * - * Copyright 2007, 2008 Nuance Communciations, Inc. * - * * - * 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 android.speech.recognition; - -/** - * Generates audio data. - */ -public interface AudioSource -{ - /** - * Returns an object that contains the audio samples. This object - * is passed to other components that consumes it, such a Recognizer - * or a DeviceSpeaker. - * - * @return an AudioStream instance - */ - AudioStream createAudio(); - - /** - * Tells the audio source to start collecting audio samples. - */ - void start(); - - /** - * Tells the audio source to stop collecting audio samples. - */ - void stop(); -} diff --git a/core/java/android/speech/recognition/AudioSourceListener.java b/core/java/android/speech/recognition/AudioSourceListener.java deleted file mode 100644 index 42e8ebe5ef2e969d7fb8db2e1226c060a43595bc..0000000000000000000000000000000000000000 --- a/core/java/android/speech/recognition/AudioSourceListener.java +++ /dev/null @@ -1,44 +0,0 @@ -/*---------------------------------------------------------------------------* - * AudioSourceListener.java * - * * - * Copyright 2007, 2008 Nuance Communciations, Inc. * - * * - * 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 android.speech.recognition; - -/** - * Listens for Microphone events. - */ -public interface AudioSourceListener -{ - /** - * Invoked after the microphone starts recording. - */ - void onStarted(); - - /** - * Invoked after the microphone stops recording. - */ - void onStopped(); - - /** - * Invoked when an unexpected error occurs. This is normally followed by - * onStopped() if the component shuts down successfully. - * - * @param e the cause of the failure - */ - void onError(Exception e); -} diff --git a/core/java/android/speech/recognition/AudioStream.java b/core/java/android/speech/recognition/AudioStream.java deleted file mode 100644 index 36afe213ad4ffd6d3255b2deb25569130aaf5f8f..0000000000000000000000000000000000000000 --- a/core/java/android/speech/recognition/AudioStream.java +++ /dev/null @@ -1,35 +0,0 @@ -/*---------------------------------------------------------------------------* - * AudioStream.java * - * * - * Copyright 2007, 2008 Nuance Communciations, Inc. * - * * - * 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 android.speech.recognition; - -/** - * Stream used to read audio data. - */ -public interface AudioStream -{ - /** - * Releases resources associated with the object. - * - * @deprecated this method is deprecated and has no replacement. It will be - * removed in a future release of the API. - */ - @Deprecated - void dispose(); -} diff --git a/core/java/android/speech/recognition/Codec.java b/core/java/android/speech/recognition/Codec.java deleted file mode 100644 index 18d9e150313b6cde5ebd07df8f1f200b113c35ae..0000000000000000000000000000000000000000 --- a/core/java/android/speech/recognition/Codec.java +++ /dev/null @@ -1,126 +0,0 @@ -/*---------------------------------------------------------------------------* - * Codec.java * - * * - * Copyright 2007, 2008 Nuance Communciations, Inc. * - * * - * 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 android.speech.recognition; - -/** - * Audio formats. - */ -public abstract class Codec -{ - /** - * PCM, 16 bits, 8KHz. - */ - public static final Codec PCM_16BIT_8K = new Codec("PCM/16bit/8KHz") - { - @Override - public byte getBitsPerSample() - { - return 16; - } - - @Override - public int getSampleRate() - { - return 8000; - } - }; - /** - * PCM, 16 bits, 11KHz. - */ - public static final Codec PCM_16BIT_11K = new Codec("PCM/16bit/11KHz") - { - @Override - public byte getBitsPerSample() - { - return 16; - } - - @Override - public int getSampleRate() - { - return 11025; - } - }; - /** - * PCM, 16 bits, 22KHz. - */ - public static final Codec PCM_16BIT_22K = new Codec("PCM/16bit/22KHz") - { - @Override - public byte getBitsPerSample() - { - return 16; - } - - @Override - public int getSampleRate() - { - return 22050; - } - }; - /** - * ULAW, 8 bits, 8KHz. - */ - public static final Codec ULAW_8BIT_8K = new Codec("ULAW/8bit/8KHz") - { - @Override - public byte getBitsPerSample() - { - return 8; - } - - @Override - public int getSampleRate() - { - return 8000; - } - }; - private final String message; - - /** - * Creates a new Codec. - * - * @param message the message to associate with the codec - */ - private Codec(String message) - { - this.message = message; - } - - @Override - public String toString() - { - return message; - } - - /** - * Returns the codec sample-rate. - * - * @return the codec sample-rate - */ - public abstract int getSampleRate(); - - /** - * Returns the codec bitrate. - * - * @return the codec bitrate - */ - public abstract byte getBitsPerSample(); -} diff --git a/core/java/android/speech/recognition/DeviceSpeaker.java b/core/java/android/speech/recognition/DeviceSpeaker.java deleted file mode 100644 index bd1868714166e9f7f1928fa8db0ac13d375149d7..0000000000000000000000000000000000000000 --- a/core/java/android/speech/recognition/DeviceSpeaker.java +++ /dev/null @@ -1,77 +0,0 @@ -/*---------------------------------------------------------------------------* - * DeviceSpeaker.java * - * * - * Copyright 2007, 2008 Nuance Communciations, Inc. * - * * - * 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 android.speech.recognition; - -import android.speech.recognition.impl.DeviceSpeakerImpl; - -/** - * A device for transforming electric signals into audible sound, most - * frequently used to reproduce speech and music. - */ -public abstract class DeviceSpeaker -{ - private static DeviceSpeaker instance; - - /** - * Returns the device speaker instance. - * - * @return an instance of a DeviceSpeaker class. - */ - public static DeviceSpeaker getInstance() - { - instance = DeviceSpeakerImpl.getInstance(); - return instance; - } - - /** - * Starts the audio playback. - * - * @param source the audio to play - * @throws IllegalStateException if the component is already started - * @throws IllegalArgumentException if source audio is null, in-use by - * another component or is empty. - * - */ - public abstract void start(AudioStream source) throws IllegalStateException, - IllegalArgumentException; - - /** - * Stops audio playback. - */ - public abstract void stop(); - - /** - * Sets the playback codec. This must be called before start() is called. - * - * @param playbackCodec the codec to use for the playback operation. - * @throws IllegalStateException if the component is already stopped - * @throws IllegalArgumentException if the specified codec is not supported - */ - public abstract void setCodec(Codec playbackCodec) throws IllegalStateException, - IllegalArgumentException; - - /** - * Sets the microphone listener. - * - * @param listener the device speaker listener. - * @throws IllegalStateException if the component is started - */ - public abstract void setListener(DeviceSpeakerListener listener) throws IllegalStateException; -} diff --git a/core/java/android/speech/recognition/DeviceSpeakerListener.java b/core/java/android/speech/recognition/DeviceSpeakerListener.java deleted file mode 100644 index e2baa2e115c7c79bb23e6993f8266aac8860fd63..0000000000000000000000000000000000000000 --- a/core/java/android/speech/recognition/DeviceSpeakerListener.java +++ /dev/null @@ -1,44 +0,0 @@ -/*---------------------------------------------------------------------------* - * DeviceSpeakerListener.java * - * * - * Copyright 2007, 2008 Nuance Communciations, Inc. * - * * - * 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 android.speech.recognition; - -/** - * Listens for DeviceSpeaker events. - */ -public interface DeviceSpeakerListener -{ - /** - * Invoked after playback begins. - */ - void onStarted(); - - /** - * Invoked after playback terminates. - */ - void onStopped(); - - /** - * Invoked when an unexpected error occurs. This is normally followed by - * onStopped() if the component shuts down successfully. - * - * @param e the cause of the failure - */ - void onError(Exception e); -} diff --git a/core/java/android/speech/recognition/EmbeddedGrammar.java b/core/java/android/speech/recognition/EmbeddedGrammar.java deleted file mode 100644 index c6f037b5fa73c2250df8a833fc2028a702e985b0..0000000000000000000000000000000000000000 --- a/core/java/android/speech/recognition/EmbeddedGrammar.java +++ /dev/null @@ -1,43 +0,0 @@ -/*---------------------------------------------------------------------------* - * EmbeddedGrammar.java * - * * - * Copyright 2007, 2008 Nuance Communciations, Inc. * - * * - * 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 android.speech.recognition; - -/** - * Grammar on an embedded recognizer. - */ -public interface EmbeddedGrammar extends Grammar -{ - /** - * Compiles items that were added to any of the grammar slots. - */ - void compileAllSlots(); - - /** - * Removes all words added to all slots. - */ - void resetAllSlots(); - - /** - * Saves the compiled grammar. - * - * @param url the url to save the grammar to - */ - void save(String url); -} diff --git a/core/java/android/speech/recognition/EmbeddedGrammarListener.java b/core/java/android/speech/recognition/EmbeddedGrammarListener.java deleted file mode 100644 index 5b8c1a49b2d001567f70abb46eec984170473e11..0000000000000000000000000000000000000000 --- a/core/java/android/speech/recognition/EmbeddedGrammarListener.java +++ /dev/null @@ -1,58 +0,0 @@ -/*---------------------------------------------------------------------------* - * EmbeddedGrammarListener.java * - * * - * Copyright 2007, 2008 Nuance Communciations, Inc. * - * * - * 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 android.speech.recognition; - -/** - * Listens for EmbeddedGrammar events. - */ -public interface EmbeddedGrammarListener extends GrammarListener -{ - /** - * Invoked after the grammar is saved. - * - * @param path the path the grammar was saved to - */ - void onSaved(String path); - - /** - * Invoked when a grammar operation fails. - * - * @param e the cause of the failure.
    - * {@link GrammarOverflowException} if the grammar slot is full and no - * further items may be added to it.
    - * {@link java.lang.UnsupportedOperationException} if different words with - * the same pronunciation are added.
    - * {@link java.lang.IllegalStateException} if reseting or compiling the - * slots fails.
    - * {@link java.io.IOException} if the grammar could not be loaded or - * saved.

    - */ - void onError(Exception e); - - /** - * Invokes after all grammar slots have been compiled. - */ - void onCompileAllSlots(); - - /** - * Invokes after all grammar slots have been reset. - */ - void onResetAllSlots(); -} diff --git a/core/java/android/speech/recognition/EmbeddedRecognizer.java b/core/java/android/speech/recognition/EmbeddedRecognizer.java deleted file mode 100644 index cd79edc68e8f8bf0530ae57a2c7bd3a00186f03f..0000000000000000000000000000000000000000 --- a/core/java/android/speech/recognition/EmbeddedRecognizer.java +++ /dev/null @@ -1,66 +0,0 @@ -/*---------------------------------------------------------------------------* - * EmbeddedRecognizer.java * - * * - * Copyright 2007, 2008 Nuance Communciations, Inc. * - * * - * 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 android.speech.recognition; - -import java.io.FileNotFoundException; -import java.io.IOException; -import android.speech.recognition.impl.EmbeddedRecognizerImpl; - -/** - * Embedded recognizer. - */ -public abstract class EmbeddedRecognizer implements Recognizer -{ - private static EmbeddedRecognizer instance; - - /** - * Returns the embedded recognizer. - * - * @return the embedded recognizer - */ - public static EmbeddedRecognizer getInstance() - { - instance = EmbeddedRecognizerImpl.getInstance(); - return instance; - } - - /** - * Configures the recognizer. - * - * @param config recognizer configuration file - * @throws IllegalArgumentException if config is null or an empty string - * @throws FileNotFoundException if the specified file could not be found - * @throws IOException if the specified file could not be opened - * @throws UnsatisfiedLinkError if the recognizer plugin could not be loaded - * @throws ClassNotFoundException if the recognizer plugin could not be found - */ - public abstract void configure(String config) throws IllegalArgumentException, - FileNotFoundException, IOException, UnsatisfiedLinkError, - ClassNotFoundException; - - /** - * The recognition accuracy improves over time as the recognizer adapts to - * the surrounding environment. This method enables developers to reset the - * adaptation when the environment is known to have changed. - * - * @throws IllegalArgumentException if recognizer instance is null - */ - public abstract void resetAcousticState() throws IllegalArgumentException; -} diff --git a/core/java/android/speech/recognition/Grammar.java b/core/java/android/speech/recognition/Grammar.java deleted file mode 100644 index 9f1b624b7c4ac8a9a8992abf84f7ce650e094785..0000000000000000000000000000000000000000 --- a/core/java/android/speech/recognition/Grammar.java +++ /dev/null @@ -1,43 +0,0 @@ -/*---------------------------------------------------------------------------* - * Grammar.java * - * * - * Copyright 2007, 2008 Nuance Communciations, Inc. * - * * - * 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 android.speech.recognition; - -/** - * Speech recognition grammar. - */ -public interface Grammar { - /** - * Load the grammar sets the grammar state to active, indicating that can be used in a recognition process. - * Multiple grammars can be loaded, but only one at a time can be used by the recognizer. - * - */ - void load(); - - /** - * Unload the grammar sets the grammar state to inactive (inactive grammars can not be used as a parameter of a recognition). - */ - void unload(); - - /** - * (Optional operation) Releases resources associated with the object. The - * grammar may not be used past this point. - */ - void dispose(); -} diff --git a/core/java/android/speech/recognition/GrammarErrorException.java b/core/java/android/speech/recognition/GrammarErrorException.java deleted file mode 100644 index 607075839e2ee3fb50d33536a60cdd7adacfde96..0000000000000000000000000000000000000000 --- a/core/java/android/speech/recognition/GrammarErrorException.java +++ /dev/null @@ -1,33 +0,0 @@ -/*---------------------------------------------------------------------------* - * GrammarErrorException.java * - * * - * Copyright 2007, 2008 Nuance Communciations, Inc. * - * * - * 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 android.speech.recognition; - -/** - * Thrown if an error occurs in the audio driver. - */ -public class GrammarErrorException extends Exception -{ - private static final long serialVersionUID = 0L; - - public GrammarErrorException(String msg) - { - super(msg); - } -} diff --git a/core/java/android/speech/recognition/GrammarListener.java b/core/java/android/speech/recognition/GrammarListener.java deleted file mode 100644 index 871cbcbe423bebc6d7daa4a979fd7fe7cb56318f..0000000000000000000000000000000000000000 --- a/core/java/android/speech/recognition/GrammarListener.java +++ /dev/null @@ -1,45 +0,0 @@ -/*---------------------------------------------------------------------------* - * GrammarListener.java * - * * - * Copyright 2007, 2008 Nuance Communciations, Inc. * - * * - * 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 android.speech.recognition; - -/** - * Listens for Grammar events. - */ -public interface GrammarListener -{ - /** - * Invoked after the Grammar is loaded. - */ - void onLoaded(); - - /** - * Invoked after the Grammar is unloaded. - */ - void onUnloaded(); - - /** - * Invoked when a grammar operation fails. - * - * @param e the cause of the failure.
    - * {@link java.io.IOException} if the grammar could not be loaded or - * saved.

    - */ - void onError(Exception e); -} diff --git a/core/java/android/speech/recognition/GrammarOverflowException.java b/core/java/android/speech/recognition/GrammarOverflowException.java deleted file mode 100644 index 227820bbdb9c957054b7180e501b5e7bbd51478e..0000000000000000000000000000000000000000 --- a/core/java/android/speech/recognition/GrammarOverflowException.java +++ /dev/null @@ -1,33 +0,0 @@ -/*---------------------------------------------------------------------------* - * GrammarOverflowException.java * - * * - * Copyright 2007, 2008 Nuance Communciations, Inc. * - * * - * 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 android.speech.recognition; - -/** - * Thrown if a SlotItem is added into a grammar slot that is filled to capacity. - */ -public class GrammarOverflowException extends Exception -{ - private static final long serialVersionUID = 0L; - - public GrammarOverflowException(String message) - { - super(message); - } -} diff --git a/core/java/android/speech/recognition/InvalidURLException.java b/core/java/android/speech/recognition/InvalidURLException.java deleted file mode 100644 index fec9411faf4bacc99bc91f8cc2261f68653d1200..0000000000000000000000000000000000000000 --- a/core/java/android/speech/recognition/InvalidURLException.java +++ /dev/null @@ -1,34 +0,0 @@ -/*---------------------------------------------------------------------------* - * InvalidURLException.java * - * * - * Copyright 2007, 2008 Nuance Communciations, Inc. * - * * - * 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 android.speech.recognition; - -/** - */ -public class InvalidURLException extends Exception { - - private static final long serialVersionUID = 0L; - - /** Creates a new instance of InvalidURLException */ - public InvalidURLException(String msg) - { - super(msg); - } - -} diff --git a/core/java/android/speech/recognition/Logger.java b/core/java/android/speech/recognition/Logger.java deleted file mode 100644 index 8a09cb36960a7d2174bf15b0c9a6e10832dc8018..0000000000000000000000000000000000000000 --- a/core/java/android/speech/recognition/Logger.java +++ /dev/null @@ -1,127 +0,0 @@ -/*---------------------------------------------------------------------------* - * Logger.java * - * * - * Copyright 2007, 2008 Nuance Communciations, Inc. * - * * - * 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 android.speech.recognition; - -import android.speech.recognition.impl.LoggerImpl; - -/** - * Logs debugging information. - */ -public abstract class Logger -{ - /** - * Logging level - */ - public static class LogLevel - { - /** - * Does not log. - */ - public static LogLevel LEVEL_NONE = new LogLevel("Do not log"); - /** - * Logs fatal issues. This level only logs ERROR. - */ - public static LogLevel LEVEL_ERROR = new LogLevel("log UAPI_ERROR logs"); - /** - * Logs non-fatal issues. This level also logs ERROR. - */ - public static LogLevel LEVEL_WARN = - new LogLevel("log UAPI_ERROR, UAPI_WARN logs"); - /** - * Logs debugging information, such as the values of variables. This level also logs ERROR, WARN. - */ - public static LogLevel LEVEL_INFO = - new LogLevel("log UAPI_ERROR, UAPI_WARN, UAPI_INFO logs"); - /** - * Logs when loggers are created or destroyed. This level also logs INFO, WARN, ERROR. - */ - public static LogLevel LEVEL_TRACE = - new LogLevel("log UAPI_ERROR, UAPI_WARN, UAPI_INFO, UAPI_TRACE logs"); - private String message; - - /** - * Creates a new LogLevel. - * - * @param message the message associated with the LogLevel. - */ - private LogLevel(String message) - { - this.message = message; - } - - @Override - public String toString() - { - return message; - } - } - - /** - * Returns the singleton instance. - * - * @return the singleton instance - */ - public static Logger getInstance() - { - return LoggerImpl.getInstance(); - } - - /** - * Sets the logging level. - * - * @param level the logging level - */ - public abstract void setLoggingLevel(LogLevel level); - - /** - * Sets the log path. - * - * @param path the path of the log file - */ - public abstract void setPath(String path); - - /** - * Logs an error message. - * - * @param message the message to log - */ - public abstract void error(String message); - - /** - * Logs a warning message. - * - * @param message the message to log - */ - public abstract void warn(String message); - - /** - * Logs an informational message. - * - * @param message the message to log - */ - public abstract void info(String message); - - /** - * Logs a method tracing message. - * - * @param message the message to log - */ - public abstract void trace(String message); -} diff --git a/core/java/android/speech/recognition/MediaFileReader.java b/core/java/android/speech/recognition/MediaFileReader.java deleted file mode 100644 index 216511f951b05598d291dd2c5573729f924a2054..0000000000000000000000000000000000000000 --- a/core/java/android/speech/recognition/MediaFileReader.java +++ /dev/null @@ -1,90 +0,0 @@ -/*---------------------------------------------------------------------------* - * MediaFileReader.java * - * * - * Copyright 2007, 2008 Nuance Communciations, Inc. * - * * - * 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 android.speech.recognition; - -import android.speech.recognition.impl.MediaFileReaderImpl; - -/** - * Reads audio from a file. - */ -public abstract class MediaFileReader implements AudioSource -{ - /** - * Reading mode - */ - public static class Mode - { - /** - * Read the file in "real time". - */ - public static Mode REAL_TIME = new Mode("real-time"); - /** - * Read the file all at once. - */ - public static Mode ALL_AT_ONCE = new Mode("all at once"); - private String message; - - /** - * Creates a new Mode. - * - * @param message the message associated with the reading mode. - */ - private Mode(String message) - { - this.message = message; - } - } - - /** - * Creates a new MediaFileReader to read audio samples from a file. - * - * @param filename the name of the file to read from Note: The file MUST be of type Microsoft WAVE RIFF - * format (PCM 16 bits 8000 Hz or PCM 16 bits 11025 Hz). - * @param listener listens for MediaFileReader events - * @return a new MediaFileReader - * @throws IllegalArgumentException if filename is null or is an empty string. Or if offset > file length. Or if codec is null or invalid - */ - public static MediaFileReader create(String filename, AudioSourceListener listener) throws IllegalArgumentException - { - return new MediaFileReaderImpl(filename, listener); - } - - /** - * Sets the reading mode. - * - * @param mode the reading mode - */ - public abstract void setMode(Mode mode); - - /** - * Creates an audio source. - */ - public abstract AudioStream createAudio(); - - /** - * Starts collecting audio samples. - */ - public abstract void start(); - - /** - * Stops collecting audio samples. - */ - public abstract void stop(); -} diff --git a/core/java/android/speech/recognition/MediaFileReaderListener.java b/core/java/android/speech/recognition/MediaFileReaderListener.java deleted file mode 100644 index f76e65f86057d7b2d310a7f5c12f1dd834503971..0000000000000000000000000000000000000000 --- a/core/java/android/speech/recognition/MediaFileReaderListener.java +++ /dev/null @@ -1,29 +0,0 @@ -/*---------------------------------------------------------------------------* - * MediaFileReaderListener.java * - * * - * Copyright 2007, 2008 Nuance Communciations, Inc. * - * * - * 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 android.speech.recognition; - -import android.speech.recognition.AudioSourceListener; - -/** - * Listens for MediaFileReader events. - */ -public interface MediaFileReaderListener extends AudioSourceListener -{ -} diff --git a/core/java/android/speech/recognition/MediaFileWriter.java b/core/java/android/speech/recognition/MediaFileWriter.java deleted file mode 100644 index b2d627c07b93e12f488475f6eee2efe49bf74684..0000000000000000000000000000000000000000 --- a/core/java/android/speech/recognition/MediaFileWriter.java +++ /dev/null @@ -1,49 +0,0 @@ -/*---------------------------------------------------------------------------* - * MediaFileWriter.java * - * * - * Copyright 2007, 2008 Nuance Communciations, Inc. * - * * - * 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 android.speech.recognition; - -import android.speech.recognition.impl.MediaFileWriterImpl; - -/** - * Writes audio to a file. - */ -public abstract class MediaFileWriter -{ - /** - * Creates a new MediaFileWriter to write audio samples into a file. - * - * @param listener listens for MediaFileWriter events - * @return a new MediaFileWriter - */ - public static MediaFileWriter create(MediaFileWriterListener listener) - { - return new MediaFileWriterImpl(listener); - } - - /** - * Saves audio to a file. - * - * @param source the audio stream to write - * @param filename the file to write to - * @throws IllegalArgumentException if source is null, in-use by another - * component or contains no data. Or if filename is null or is empty. - */ - public abstract void save(AudioStream source, String filename) throws IllegalArgumentException; -} diff --git a/core/java/android/speech/recognition/MediaFileWriterListener.java b/core/java/android/speech/recognition/MediaFileWriterListener.java deleted file mode 100644 index e2104c874e1a83596d3502fa564ec6730b9307be..0000000000000000000000000000000000000000 --- a/core/java/android/speech/recognition/MediaFileWriterListener.java +++ /dev/null @@ -1,40 +0,0 @@ -/*---------------------------------------------------------------------------* - * MediaFileWriterListener.java * - * * - * Copyright 2007, 2008 Nuance Communciations, Inc. * - * * - * 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 android.speech.recognition; - -/** - * Listens for MediaFileWriter events. - */ -public interface MediaFileWriterListener -{ - /** - * Invoked after the save() operation terminates - */ - void onStopped(); - - /** - * Invoked when an unexpected error occurs. This is normally followed by - * onStopped() if the component shuts down successfully. - * - * @param e the cause of the failure.
    - * {@link java.io.IOException} if an error occured opening or writing to the file - */ - void onError(Exception e); -} diff --git a/core/java/android/speech/recognition/Microphone.java b/core/java/android/speech/recognition/Microphone.java deleted file mode 100644 index 1b713f547b13f2dfef1803a48ded0e9ba0653bea..0000000000000000000000000000000000000000 --- a/core/java/android/speech/recognition/Microphone.java +++ /dev/null @@ -1,76 +0,0 @@ -/*---------------------------------------------------------------------------* - * Microphone.java * - * * - * Copyright 2007, 2008 Nuance Communciations, Inc. * - * * - * 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 android.speech.recognition; - -import android.speech.recognition.impl.MicrophoneImpl; - -/** - * Records live audio. - */ -public abstract class Microphone implements AudioSource -{ - private static Microphone instance; - - /** - * Returns the microphone instance - * - * @return an instance of a Microphone class. - */ - public static Microphone getInstance() - { - instance = MicrophoneImpl.getInstance(); - return instance; - } - - /** - * Sets the recording codec. This must be called before start() is called. - * - * @param recordingCodec the codec in which the samples will be recorded. - * @throws IllegalStateException if Microphone is started - * @throws IllegalArgumentException if codec is not supported - */ - public abstract void setCodec(Codec recordingCodec) throws IllegalStateException, - IllegalArgumentException; - - /** - * Sets the microphone listener. - * - * @param listener the microphone listener. - * @throws IllegalStateException if Microphone is started - */ - public abstract void setListener(AudioSourceListener listener) throws IllegalStateException; - - /** - * Creates an audio source - */ - public abstract AudioStream createAudio(); - - /** - * Start recording audio. - * - * @throws IllegalStateException if Microphone is already started - */ - public abstract void start() throws IllegalStateException; - - /** - * Stops recording audio. - */ - public abstract void stop(); -} diff --git a/core/java/android/speech/recognition/MicrophoneListener.java b/core/java/android/speech/recognition/MicrophoneListener.java deleted file mode 100644 index f43eff9ad2183b4d733125a9452cb7f3eefef7a2..0000000000000000000000000000000000000000 --- a/core/java/android/speech/recognition/MicrophoneListener.java +++ /dev/null @@ -1,29 +0,0 @@ -/*---------------------------------------------------------------------------* - * MicrophoneListener.java * - * * - * Copyright 2007, 2008 Nuance Communciations, Inc. * - * * - * 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 android.speech.recognition; - -import android.speech.recognition.AudioSourceListener; - -/** - * Listens for Microphone events. - */ -public interface MicrophoneListener extends AudioSourceListener -{ -} diff --git a/core/java/android/speech/recognition/NBestRecognitionResult.java b/core/java/android/speech/recognition/NBestRecognitionResult.java deleted file mode 100644 index e679c193ba5c3ebfff035be872f759a759a099f0..0000000000000000000000000000000000000000 --- a/core/java/android/speech/recognition/NBestRecognitionResult.java +++ /dev/null @@ -1,113 +0,0 @@ -/*---------------------------------------------------------------------------* - * NBestRecognitionResult.java * - * * - * Copyright 2007, 2008 Nuance Communciations, Inc. * - * * - * 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 android.speech.recognition; - -import java.util.Enumeration; - -/** - * N-Best recognition results. Entries are sorted in decreasing order according - * to their probability, from the most probable result to the least probable - * result. - */ -public interface NBestRecognitionResult extends RecognitionResult -{ - /** - * Recognition result entry - */ - public static interface Entry - { - /** - * Returns the semantic meaning of a recognition result (i.e. the application-specific value - * associated with what the user said). In an example where a person's name is mapped - * to a phone-number, the phone-number is the semantic meaning. - * - * @return the semantic meaning of a recognition result. - * @throws IllegalStateException if the object has been disposed - */ - String getSemanticMeaning() throws IllegalStateException; - - /** - * The confidence score of a recognition result. Values range from 0 to 100 - * (inclusive). - * - * @return the confidence score of a recognition result. - * @throws IllegalStateException if the object has been disposed - */ - byte getConfidenceScore() throws IllegalStateException; - - /** - * Returns the literal meaning of a recognition result (i.e. literally - * what the user said). In an example where a person's name is mapped to a - * phone-number, the person's name is the literal meaning. - * - * @return the literal meaning of a recognition result. - * @throws IllegalStateException if the object has been disposed - */ - String getLiteralMeaning() throws IllegalStateException; - - /** - * Returns the value associated with the specified key. - * - * @param key the key to look up - * @return the associated value or null if this entry does not contain - * any mapping for the key - */ - String get(String key); - - /** - * Returns an enumeration of the keys in this Entry. - * - * @return an enumeration of the keys in this Entry. - */ - Enumeration keys(); - } - - /** - * Returns the number of entries in the n-best list. - * - * @return the number of entries in the n-best list - */ - int getSize(); - - /** - * Returns the n-best entry that contains key-value pairs associated with the - * recognition result. - * - * @param index the index of the n-best entry - * @return null if all active GrammarConfiguration.grammarToMeaning() return - * null - * @throws ArrayIndexOutOfBoundsException if index is greater than size of - * entries - */ - Entry getEntry(int index) throws ArrayIndexOutOfBoundsException; - - /** - * Creates a new VoicetagItem if the last recognition was an enrollment - * operation. - * - * @param VoicetagId string voicetag unique id value. - * @param listener listens for Voicetag events - * @return the resulting VoicetagItem - * @throws IllegalArgumentException if VoicetagId is null or an empty string. - * @throws IllegalStateException if the last recognition was not an - * enrollment operation - */ - VoicetagItem createVoicetagItem(String VoicetagId, VoicetagItemListener listener) throws IllegalArgumentException,IllegalStateException; -} diff --git a/core/java/android/speech/recognition/ParameterErrorException.java b/core/java/android/speech/recognition/ParameterErrorException.java deleted file mode 100644 index 042ed31bf9f6b29b4e1a2d831b7119a1bee5696d..0000000000000000000000000000000000000000 --- a/core/java/android/speech/recognition/ParameterErrorException.java +++ /dev/null @@ -1,33 +0,0 @@ -/*---------------------------------------------------------------------------* - * ParameterErrorException.java * - * * - * Copyright 2007, 2008 Nuance Communciations, Inc. * - * * - * 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 android.speech.recognition; - -/** - * Thrown if an error occurs in the audio driver. - */ -public class ParameterErrorException extends Exception -{ - private static final long serialVersionUID = 0L; - - public ParameterErrorException(String msg) - { - super(msg); - } -} diff --git a/core/java/android/speech/recognition/ParametersListener.java b/core/java/android/speech/recognition/ParametersListener.java deleted file mode 100644 index bdb551ebab19f2640c7192feddb6b39c8599be02..0000000000000000000000000000000000000000 --- a/core/java/android/speech/recognition/ParametersListener.java +++ /dev/null @@ -1,63 +0,0 @@ -/*---------------------------------------------------------------------------* - * ParametersListener.java * - * * - * Copyright 2007, 2008 Nuance Communciations, Inc. * - * * - * 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 android.speech.recognition; - -import java.util.Hashtable; -import java.util.Vector; - -/** - * Listens for parameter events. - */ -public interface ParametersListener -{ - /** - * Invoked if retrieving parameters has failed. - * - * @param parameters the parameters that could not be retrieved - * @param e the failure reason - */ - void onParametersGetError(Vector parameters, Exception e); - - /** - * Invoked if setting parameters has failed. - * - * @param parameters the parameters that could not be set - * @param e the failure reason - */ - void onParametersSetError(Hashtable parameters, Exception e); - - /** - * This method is called when the parameters specified in setParameters have - * successfully been set. This method is guaranteed to be invoked after - * onParametersSetError, even if count==0. - * - * @param parameters the set parameters - */ - void onParametersSet(Hashtable parameters); - - /** - * This method is called when the parameters specified in getParameters have - * successfully been retrieved. This method is guaranteed to be invoked after - * onParametersGetError, even if count==0. - * - * @param parameters the retrieved parameters - */ - void onParametersGet(Hashtable parameters); -} diff --git a/core/java/android/speech/recognition/ParseErrorException.java b/core/java/android/speech/recognition/ParseErrorException.java deleted file mode 100644 index 2288a90bec39cbf9277fbf6be4405f9ef76aad76..0000000000000000000000000000000000000000 --- a/core/java/android/speech/recognition/ParseErrorException.java +++ /dev/null @@ -1,33 +0,0 @@ -/*---------------------------------------------------------------------------* - * ParseErrorException.java * - * * - * Copyright 2007, 2008 Nuance Communciations, Inc. * - * * - * 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 android.speech.recognition; - -/** - * Thrown if an error occurs in the audio driver. - */ -public class ParseErrorException extends Exception -{ - private static final long serialVersionUID = 0L; - - public ParseErrorException(String msg) - { - super(msg); - } -} diff --git a/core/java/android/speech/recognition/RecognitionResult.java b/core/java/android/speech/recognition/RecognitionResult.java deleted file mode 100644 index cbbc938bdec571fe6f6c41e5bd1d8200d07ea972..0000000000000000000000000000000000000000 --- a/core/java/android/speech/recognition/RecognitionResult.java +++ /dev/null @@ -1,27 +0,0 @@ -/*---------------------------------------------------------------------------* - * RecognitionResult.java * - * * - * Copyright 2007, 2008 Nuance Communciations, Inc. * - * * - * 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 android.speech.recognition; - -/** - * Recognition result interface. - */ -public interface RecognitionResult -{ -} diff --git a/core/java/android/speech/recognition/Recognizer.java b/core/java/android/speech/recognition/Recognizer.java deleted file mode 100644 index ab7f8f442f4f8056775867f29b97a5f82b4f3585..0000000000000000000000000000000000000000 --- a/core/java/android/speech/recognition/Recognizer.java +++ /dev/null @@ -1,102 +0,0 @@ -/*---------------------------------------------------------------------------* - * Recognizer.java * - * * - * Copyright 2007, 2008 Nuance Communciations, Inc. * - * * - * 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 android.speech.recognition; - -import java.util.Hashtable; -import java.util.Vector; - -/** - * Speech recognizer interface. - */ -public interface Recognizer -{ - /** - * Sets the recognizer event listener. - * - * @param listener listens for recognizer events - */ - void setListener(RecognizerListener listener); - - /** - * Creates an embedded grammar. - * - * @param value value of that grammarType. Could be a URL or an inline grammar. - * @return a grammar - * @throws IllegalArgumentException if value is null or listener is not of type - * GrammarListener. - */ - Grammar createGrammar(String value, GrammarListener listener) throws IllegalArgumentException; - - /** - * Begins speech recognition. - * - * @param audio the audio stream to recognizer - * @param grammars a collection of grammar sets to recognize against - * @see #recognize(AudioStream, Grammar) - * @throws IllegalStateException if any of the grammars are not loaded - * @throws IllegalArgumentException if audio is null, in-use by another - * component or empty. Or if grammars is null or grammars count is less than - * one. Or if the audio codec differs from recognizer codec. - * @throws UnsupportedOperationException if the recognizer does not support - * the number of grammars specified. - */ - void recognize(AudioStream audio, - Vector grammars) throws IllegalStateException, - IllegalArgumentException, UnsupportedOperationException; - - /** - * This convenience method is equivalent to invoking - * recognize(audio, grammars) with a single grammar. - * - * @param audio the audio to recognizer - * @param grammar a grammar to recognize against - * @see #recognize(AudioStream, Vector) - * @throws IllegalStateException if grammar is not loaded - * @throws IllegalArgumentException if audio is null, in-use by another - * component or is empty. Or if grammar is null or if the audio codec differs - * from the recognizer codec. - */ - void recognize(AudioStream audio, Grammar grammar) throws IllegalStateException, - IllegalArgumentException; - - /** - * Terminates a recognition if one is in-progress. - * This must not be called until the recognize method - * returns; otherwise the result is not defined. - * - * @see RecognizerListener#onStopped - */ - void stop(); - - /** - * Sets the values of recognition parameters. - * - * @param parameters the parameter key-value pairs to set - */ - void setParameters(Hashtable parameters); - - /** - * Retrieves the values of recognition parameters. - * - * @param parameters the names of the parameters to retrieve - */ - void getParameters(Vector parameters); - -} diff --git a/core/java/android/speech/recognition/RecognizerListener.java b/core/java/android/speech/recognition/RecognizerListener.java deleted file mode 100644 index d7bbda9558df5c24ecc142588627b498f3df1f42..0000000000000000000000000000000000000000 --- a/core/java/android/speech/recognition/RecognizerListener.java +++ /dev/null @@ -1,142 +0,0 @@ -/*---------------------------------------------------------------------------* - * RecognizerListener.java * - * * - * Copyright 2007, 2008 Nuance Communciations, Inc. * - * * - * 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 android.speech.recognition; - -/** - * Listens for recognizer events. - */ -public interface RecognizerListener extends ParametersListener -{ - /** - * Recognition failure. - */ - public static class FailureReason - { - /** - * The audio did not generate any results. - */ - public static FailureReason NO_MATCH = - new FailureReason("The audio did not generate any results"); - /** - * Beginning of speech occured too soon. - */ - public static FailureReason SPOKE_TOO_SOON = - new FailureReason("Beginning of speech occurred too soon"); - /** - * A timeout occured before the beginning of speech. - */ - public static FailureReason BEGINNING_OF_SPEECH_TIMEOUT = - new FailureReason("A timeout occurred before the beginning of " + "speech"); - /** - * A timeout occured before the recognition could complete. - */ - public static FailureReason RECOGNITION_TIMEOUT = - new FailureReason("A timeout occurred before the recognition " + - "could complete"); - /** - * The recognizer encountered more audio than was acceptable according to - * its configuration. - */ - public static FailureReason TOO_MUCH_SPEECH = - new FailureReason("The " + - "recognizer encountered more audio than was acceptable according to " + - "its configuration"); - - public static FailureReason UNKNOWN = - new FailureReason("unknown failure reason"); - - private final String message; - - private FailureReason(String message) - { - this.message = message; - } - - @Override - public String toString() - { - return message; - } - } - - /** - * Invoked after recognition begins. - */ - void onStarted(); - - /** - * Invoked if the recognizer detects the beginning of speech. - */ - void onBeginningOfSpeech(); - - /** - * Invoked if the recognizer detects the end of speech. - */ - void onEndOfSpeech(); - - /** - * Invoked if the recognizer does not detect speech within the configured - * timeout period. - */ - void onStartOfSpeechTimeout(); - - /** - * Invoked when the recognizer acoustic state is reset. - * - * @see android.speech.recognition.EmbeddedRecognizer#resetAcousticState() - */ - void onAcousticStateReset(); - - /** - * Invoked when a recognition result is generated. - * - * @param result the recognition result. The result object can not be - * used outside of the scope of the onRecognitionSuccess() callback method. - * To be able to do so, copy it's contents to an user-defined object.
    - * An example of this object could be a vector of string arrays; where the - * vector represents a list of recognition result entries and each entry - * is an array of strings to hold the entry's values (the semantic - * meaning, confidence score and literal meaning). - */ - void onRecognitionSuccess(RecognitionResult result); - - /** - * Invoked when a recognition failure occurs. - * - * @param reason the failure reason - */ - void onRecognitionFailure(FailureReason reason); - - /** - * Invoked when an unexpected error occurs. This is normally followed by - * onStopped() if the component shuts down successfully. - * - * @param e the cause of the failure - */ - void onError(Exception e); - - /** - * Invoked when the recognizer stops (due to normal termination or an error). - * - * Invoking stop() on a recognizer that is already stopped will not result - * in a onStopped() event. - */ - void onStopped(); -} diff --git a/core/java/android/speech/recognition/SlotItem.java b/core/java/android/speech/recognition/SlotItem.java deleted file mode 100644 index 3abd27a255a1fef3f41bf72732bf8d8963b3f969..0000000000000000000000000000000000000000 --- a/core/java/android/speech/recognition/SlotItem.java +++ /dev/null @@ -1,27 +0,0 @@ -/*---------------------------------------------------------------------------* - * SlotItem.java * - * * - * Copyright 2007, 2008 Nuance Communciations, Inc. * - * * - * 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 android.speech.recognition; - -/** - * Item that may be inserted into an embedded grammar slot. - */ -public interface SlotItem -{ -} diff --git a/core/java/android/speech/recognition/SrecGrammar.java b/core/java/android/speech/recognition/SrecGrammar.java deleted file mode 100644 index c591e05e428b82b925407625c699f38876aa2c33..0000000000000000000000000000000000000000 --- a/core/java/android/speech/recognition/SrecGrammar.java +++ /dev/null @@ -1,81 +0,0 @@ -/*---------------------------------------------------------------------------* - * SrecGrammar.java * - * * - * Copyright 2007, 2008 Nuance Communciations, Inc. * - * * - * 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 android.speech.recognition; -import java.util.Vector; - -/** - * Grammar on an SREC recognizer. - */ -public interface SrecGrammar extends EmbeddedGrammar -{ - /** - * SrecGrammar Item - */ - public class Item - { - public SlotItem _item; - public int _weight; - public String _semanticMeaning; - - /** - * Creates a grammar item. - * - * @param item the Slotitem. - * @param weight the weight of the item. Smaller values are more likely to get recognized. This should be >= 0. - * @param semanticMeaning the value that will be returned if this item is recognized. - * @throws IllegalArgumentException if item or semanticMeaning are null; if semanticMeaning is empty." - */ - public Item(SlotItem item, int weight, String semanticMeaning) - throws IllegalArgumentException - { - if (item == null) - throw new IllegalArgumentException("Item(): item can't be null."); - if (semanticMeaning == null || semanticMeaning.length()==0) - throw new IllegalArgumentException("Item(): semanticMeaning is null or empty."); - _item = item; - _weight = weight; - _semanticMeaning = semanticMeaning; - - } - } - - /** - * Adds an item to a slot. - * - * @param slotName the name of the slot - * @param item the item to add to the slot. - * @param weight the weight of the item. Smaller values are more likely to get recognized. This should be >= 0. - * @param semanticMeaning the value that will be returned if this item is recognized. - * @throws IllegalArgumentException if slotName, item or semanticMeaning are null; if semanticMeaning is not of the format "V='Jen_Parker'" - */ - public void addItem(String slotName, SlotItem item, int weight, - String semanticMeaning) throws IllegalArgumentException; - - /** - * Add a list of item to a slot. - * - * @param slotName the name of the slot - * @param items the vector of SrecGrammar.Item to add to the slot. - * @throws IllegalArgumentException if slotName,items are null or any element in the items(_item, _semanticMeaning) is null; if any semanticMeaning of the list is not of the format "key='value'" - */ - public void addItemList(String slotName, Vector items) - throws IllegalArgumentException; - -} diff --git a/core/java/android/speech/recognition/SrecGrammarListener.java b/core/java/android/speech/recognition/SrecGrammarListener.java deleted file mode 100644 index e1f7d3f5f1edf55d8c6821720ce7f8128e8141b1..0000000000000000000000000000000000000000 --- a/core/java/android/speech/recognition/SrecGrammarListener.java +++ /dev/null @@ -1,58 +0,0 @@ -/*---------------------------------------------------------------------------* - * SrecGrammarListener.java * - * * - * Copyright 2007, 2008 Nuance Communciations, Inc. * - * * - * 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 android.speech.recognition; - -/** - * Listens for SrecGrammar events. - */ -public interface SrecGrammarListener extends EmbeddedGrammarListener { - - /** - * Invokes after all items of the list have been added. - */ - void onAddItemList(); - - /** - * Invoked when adding a SlotItem from a list fails. - * This callback will be trigger for each element in the list that fails to be - * add in the slot, unless there is a grammar fail operation, which will be - * reported in the onError callback. - * @param index of the list that could not be added to the slot - * @param e the cause of the failure. - */ - void onAddItemListFailure(int index, Exception e); - - - /** - * Invoked when a grammar related operation fails. - * - * @param e the cause of the failure.
    - * {@link GrammarOverflowException} if the grammar slot is full and no - * further items may be added to it.
    - * {@link java.lang.UnsupportedOperationException} if different words with - * the same pronunciation are added.
    - * {@link java.lang.IllegalStateException} if reseting or compiling the - * slots fails.
    - * {@link java.io.IOException} if the grammar could not be loaded or - * saved.

    - */ - void onError(Exception e); - -} diff --git a/core/java/android/speech/recognition/VoicetagItem.java b/core/java/android/speech/recognition/VoicetagItem.java deleted file mode 100644 index 0b89639d0389093cc30b6d0e0d04bdc73cfa2675..0000000000000000000000000000000000000000 --- a/core/java/android/speech/recognition/VoicetagItem.java +++ /dev/null @@ -1,82 +0,0 @@ -/*---------------------------------------------------------------------------* - * VoicetagItem.java * - * * - * Copyright 2007, 2008 Nuance Communciations, Inc. * - * * - * 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 android.speech.recognition; - -import android.speech.recognition.impl.VoicetagItemImpl; -import java.io.FileNotFoundException; -import java.io.IOException; -/** - * Voicetag that may be inserted into an embedded grammar slot. - */ -public abstract class VoicetagItem implements SlotItem -{ - /** - * Creates a VoicetagItem from a file - * - * @param filename filename for Voicetag - * @param listener listens for Voicetag events - * @return the resulting VoicetagItem - * @throws IllegalArgumentException if filename is null or an empty string. - * @throws FileNotFoundException if the specified filename could not be found - * @throws IOException if the specified filename could not be opened - */ - public static VoicetagItem create(String filename, VoicetagItemListener listener) throws IllegalArgumentException,FileNotFoundException,IOException - { - return VoicetagItemImpl.create(filename,listener); - } - /** - * Returns the audio used to construct the VoicetagItem. - * The audio is in PCM format and is start-pointed and end-pointed. The audio - * is only generated if the enableGetWaveform recognition parameter - * is set prior to recognition. - * - * @throws IllegalStateException if the recognition parameter 'enableGetWaveform' is not set - * @return the audio used to construct the VoicetagItem. - */ - public abstract byte[] getAudio() throws IllegalStateException; - - /** - * Sets the audio used to construct the Voicetag. The - * audio is in PCM format and is start-pointed and end-pointed. The audio is - * only generated if the enableGetWaveform recognition parameter is set - * prior to recognition. - * - * @param waveform the endpointed waveform - * @throws IllegalArgumentException if waveform is null or empty. - * @throws IllegalStateException if the recognition parameter 'enableGetWaveform' is not set - */ - public abstract void setAudio(byte[] waveform) throws IllegalArgumentException,IllegalStateException; - - /** - * Save the Voicetag Item. - * - * @param path where the Voicetag will be saved. We strongly recommend to set the filename with the same value of the VoicetagId. - * @throws IllegalArgumentException if path is null or an empty string. - */ - public abstract void save(String path) throws IllegalArgumentException,IllegalStateException; - - /** - * Load a Voicetag Item. - * - * @throws IllegalStateException if voicetag has not been created from a file. - */ - public abstract void load() throws IllegalStateException; - -} diff --git a/core/java/android/speech/recognition/VoicetagItemListener.java b/core/java/android/speech/recognition/VoicetagItemListener.java deleted file mode 100644 index 610d1c79ca319167d99865ed4ead1b1bdffc78d6..0000000000000000000000000000000000000000 --- a/core/java/android/speech/recognition/VoicetagItemListener.java +++ /dev/null @@ -1,49 +0,0 @@ -/*---------------------------------------------------------------------------* - * VoicetagItemListener.java * - * * - * Copyright 2007, 2008 Nuance Communciations, Inc. * - * * - * 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 android.speech.recognition; - -/** - * Listens for VoicetagItem events. - */ -public interface VoicetagItemListener -{ - /** - * Invoked after the Voicetag is saved. - * - * @param path the path the Voicetag was saved to - */ - void onSaved(String path); - - /** - * Invoked after the Voicetag is loaded. - */ - void onLoaded(); - - /** - * Invoked when a grammar operation fails. - * - * @param e the cause of the failure.
    - * {@link java.io.IOException} if the Voicetag could not be loaded or - * saved.

    - * {@link java.io.FileNotFoundException} if the specified file could not be found - */ - void onError(Exception e); - -} diff --git a/core/java/android/speech/recognition/WordItem.java b/core/java/android/speech/recognition/WordItem.java deleted file mode 100644 index 5c21c989865bfde964961cbfe46ee1c1d452949d..0000000000000000000000000000000000000000 --- a/core/java/android/speech/recognition/WordItem.java +++ /dev/null @@ -1,58 +0,0 @@ -/*---------------------------------------------------------------------------* - * WordItem.java * - * * - * Copyright 2007, 2008 Nuance Communciations, Inc. * - * * - * 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 android.speech.recognition; - -import android.speech.recognition.impl.WordItemImpl; - -/** - * Word that may be inserted into an embedded grammar slot. - */ -public abstract class WordItem implements SlotItem -{ - /** - * Creates a new WordItem. - * - * @param word the word to insert - * @param pronunciations the pronunciations to associated with the item. If the list is - * is empty (example:new String[0]) the recognizer will attempt to guess the pronunciations. - * @return the WordItem - * @throws IllegalArgumentException if word is null or if pronunciations is - * null or pronunciations contains an element equal to null or empty string. - */ - public static WordItem valueOf(String word, String[] pronunciations) throws IllegalArgumentException - { - return WordItemImpl.valueOf(word, pronunciations); - } - - /** - * Creates a new WordItem. - * - * @param word the word to insert - * @param pronunciation the pronunciation to associate with the item. If it - * is null the recognizer will attempt to guess the pronunciations. - * @return the WordItem - * @throws IllegalArgumentException if word is null or if pronunciation is - * an empty string - */ - public static WordItem valueOf(String word, String pronunciation) throws IllegalArgumentException - { - return WordItemImpl.valueOf(word, pronunciation); - } -} diff --git a/core/java/android/speech/recognition/impl/AudioStreamImpl.java b/core/java/android/speech/recognition/impl/AudioStreamImpl.java deleted file mode 100644 index 730e2d937349c83051a5ad338e330b0f0ad05641..0000000000000000000000000000000000000000 --- a/core/java/android/speech/recognition/impl/AudioStreamImpl.java +++ /dev/null @@ -1,84 +0,0 @@ -/*---------------------------------------------------------------------------* - * AudioStreamImpl.java * - * * - * Copyright 2007, 2008 Nuance Communciations, Inc. * - * * - * 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 android.speech.recognition.impl; - -import android.speech.recognition.AudioStream; - -/** - */ -public class AudioStreamImpl implements AudioStream, Runnable -{ - /** - * Reference to the native object. - */ - private long nativeObject; - - /** - * Creates a new AudioStreamImpl. - * - * @param nativeObj a reference to the native object - */ - public AudioStreamImpl(long nativeObj) - { - nativeObject = nativeObj; - } - - public synchronized void run() - { - dispose(); - } - - public long getNativeObject() { - synchronized (AudioStreamImpl.class) - { - return nativeObject; - } - } - - /** - * Releases the native resources associated with the object. - */ - @SuppressWarnings("deprecation") - public void dispose() - { - synchronized (AudioStreamImpl.class) - { - if (nativeObject != 0) - { - deleteNativeObject(nativeObject); - nativeObject = 0; - } - } - } - - @Override - protected void finalize() throws Throwable - { - dispose(); - super.finalize(); - } - - /** - * Deletes a native object. - * - * @param nativeObject pointer to the native object - */ - private native void deleteNativeObject(long nativeObject); -} diff --git a/core/java/android/speech/recognition/impl/DeviceSpeakerImpl.java b/core/java/android/speech/recognition/impl/DeviceSpeakerImpl.java deleted file mode 100644 index 5d721102f81d3a376ed99e92fc2473591b5aec07..0000000000000000000000000000000000000000 --- a/core/java/android/speech/recognition/impl/DeviceSpeakerImpl.java +++ /dev/null @@ -1,164 +0,0 @@ -/*---------------------------------------------------------------------------* - * DeviceSpeakerImpl.java * - * * - * Copyright 2007, 2008 Nuance Communciations, Inc. * - * * - * 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 android.speech.recognition.impl; - -import android.speech.recognition.AudioStream; -import android.speech.recognition.Codec; -import android.speech.recognition.DeviceSpeaker; -import android.speech.recognition.DeviceSpeakerListener; - -/** - */ -public class DeviceSpeakerImpl extends DeviceSpeaker implements Runnable -{ - private static DeviceSpeakerImpl instance; - /** - * Reference to the native object. - */ - private long nativeObject; - private DeviceSpeakerListener locallistener; - - /** - * Private constructor - */ - private DeviceSpeakerImpl() - { - System system = System.getInstance(); - nativeObject = initNativeObject(); - if (nativeObject != 0) - system.register(this); - } - - public void run() - { - dispose(); - } - - /** - * Returns the singleton instance. - * - * @return the singleton instance - */ - public static DeviceSpeakerImpl getInstance() - { - synchronized (DeviceSpeakerImpl.class) - { - if (instance == null) - instance = new DeviceSpeakerImpl(); - return instance; - } - } - - /** - * Start audio playback. - * - * @param source the audio to play - */ - public void start(AudioStream source) - { - synchronized (DeviceSpeakerImpl.class) - { - if (nativeObject == 0) - throw new IllegalStateException("Object was destroyed."); - AudioStreamImpl src = (AudioStreamImpl)source; - startProxy(nativeObject,src.getNativeObject()); - src = null; - } - } - - /** - * Stops audio playback. - */ - public void stop() - { - synchronized (DeviceSpeakerImpl.class) - { - if (nativeObject == 0) - throw new IllegalStateException("Object was destroyed."); - stopProxy(nativeObject); - } - } - - /** - * Set the playback codec. This must be called before start is called. - * @param playbackCodec the codec to use for the playback operation. - */ - public void setCodec(Codec playbackCodec) - { - synchronized (DeviceSpeakerImpl.class) - { - if (nativeObject == 0) - throw new IllegalStateException("Object was destroyed."); - setCodecProxy(nativeObject,playbackCodec); - } - } - - /** - * set the microphone listener. - * @param listener the device speaker listener. - */ - public void setListener(DeviceSpeakerListener listener) - { - synchronized (DeviceSpeakerImpl.class) - { - if (nativeObject == 0) - throw new IllegalStateException("Object was destroyed."); - locallistener = listener; - setListenerProxy(nativeObject,listener); - } - } - - /** - * Releases the native resources associated with the object. - */ - private void dispose() - { - synchronized (DeviceSpeakerImpl.class) - { - if (nativeObject != 0) - { - deleteNativeObject(nativeObject); - nativeObject = 0; - instance = null; - locallistener = null; - System.getInstance().unregister(this); - } - } - } - - @Override - protected void finalize() throws Throwable - { - dispose(); - super.finalize(); - } - - private native long initNativeObject(); - - private native void startProxy(long nativeObject, long audioNativeObject); - - private native void stopProxy(long nativeObject); - - private native void setCodecProxy(long nativeObject,Codec playbackCodec); - - private native void setListenerProxy(long nativeObject,DeviceSpeakerListener listener); - - private native void deleteNativeObject(long nativeObject); -} diff --git a/core/java/android/speech/recognition/impl/EmbeddedGrammarImpl.java b/core/java/android/speech/recognition/impl/EmbeddedGrammarImpl.java deleted file mode 100644 index 0b88cb2e110b6a64141155d696c48267da2a09f3..0000000000000000000000000000000000000000 --- a/core/java/android/speech/recognition/impl/EmbeddedGrammarImpl.java +++ /dev/null @@ -1,73 +0,0 @@ -/*---------------------------------------------------------------------------* - * EmbeddedGrammarImpl.java * - * * - * Copyright 2007, 2008 Nuance Communciations, Inc. * - * * - * 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 android.speech.recognition.impl; - -import android.speech.recognition.EmbeddedGrammar; - -/** - */ -public class EmbeddedGrammarImpl extends GrammarImpl implements EmbeddedGrammar -{ - /** - * Creates a new EmbeddedGrammarImpl. - * - * @param nativeObject a reference to the native object - */ - public EmbeddedGrammarImpl(long nativeObject) - { - super(nativeObject); - } - - public void compileAllSlots() - { - synchronized (GrammarImpl.class) - { - if (nativeObject == 0) - throw new IllegalStateException("Object was destroyed."); - compileAllSlotsProxy(nativeObject); - } - } - - public void resetAllSlots() - { - synchronized (GrammarImpl.class) - { - if (nativeObject == 0) - throw new IllegalStateException("Object was destroyed."); - resetAllSlotsProxy(nativeObject); - } - } - - public void save(String url) - { - synchronized (GrammarImpl.class) - { - if (nativeObject == 0) - throw new IllegalStateException("Object was destroyed."); - saveProxy(nativeObject, url.toString()); - } - } - - private native void compileAllSlotsProxy(long nativeObject); - - private native void resetAllSlotsProxy(long nativeObject); - - private native void saveProxy(long nativeObject, String url); -} diff --git a/core/java/android/speech/recognition/impl/EmbeddedRecognizerImpl.java b/core/java/android/speech/recognition/impl/EmbeddedRecognizerImpl.java deleted file mode 100644 index f04bfe4e17d9d436692febb18edae3e06312a7c7..0000000000000000000000000000000000000000 --- a/core/java/android/speech/recognition/impl/EmbeddedRecognizerImpl.java +++ /dev/null @@ -1,246 +0,0 @@ -/*---------------------------------------------------------------------------* - * EmbeddedRecognizerImpl.java * - * * - * Copyright 2007, 2008 Nuance Communciations, Inc. * - * * - * 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 android.speech.recognition.impl; - -import java.io.FileNotFoundException; -import java.io.IOException; -import java.util.Hashtable; -import java.util.Vector; -import android.speech.recognition.EmbeddedRecognizer; -import android.speech.recognition.Grammar; -import android.speech.recognition.AudioStream; -import android.speech.recognition.Grammar; -import android.speech.recognition.RecognizerListener; -import android.speech.recognition.GrammarListener; - -/** - */ -public class EmbeddedRecognizerImpl extends EmbeddedRecognizer implements Runnable -{ - /** - * Reference to the native object. - */ - private long nativeObject; - /** - * The singleton instance. - */ - private static EmbeddedRecognizerImpl instance; - - /** - * Creates a new instance. - */ - EmbeddedRecognizerImpl() - { - System system = System.getInstance(); - nativeObject = getInstanceProxy(); - if (nativeObject != 0) - system.register(this); - } - - /** - * Returns the singleton instance. - * - * @return the singleton instance - */ - public synchronized static EmbeddedRecognizerImpl getInstance() - { - synchronized (EmbeddedRecognizerImpl.class) - { - if (instance == null) - instance = new EmbeddedRecognizerImpl(); - return instance; - } - } - - public void run() - { - dispose(); - } - - /** - * Releases the native resources associated with the object. - */ - private void dispose() - { - synchronized (EmbeddedRecognizerImpl.class) - { - if (instance != null) - { - deleteNativeObject(nativeObject); - nativeObject = 0; - instance = null; - System.getInstance().unregister(this); - } - } - } - - public void configure(String config) throws IllegalArgumentException, - FileNotFoundException, IOException, UnsatisfiedLinkError, - ClassNotFoundException - { - synchronized (EmbeddedRecognizerImpl.class) - { - if (nativeObject == 0) - throw new IllegalStateException("Object was destroyed."); - if (config == null) - throw new IllegalArgumentException("Configuration Is Null."); - configureProxy(nativeObject,config); - } - } - - public void setListener(RecognizerListener listener) - { - synchronized (EmbeddedRecognizerImpl.class) - { - if (nativeObject == 0) - throw new IllegalStateException("Object was destroyed."); - setListenerProxy(nativeObject,listener); - } - } - - public Grammar createGrammar(String value, GrammarListener listener) - throws IllegalArgumentException - { - synchronized (EmbeddedRecognizerImpl.class) - { - if (nativeObject == 0) - throw new IllegalStateException("Object was destroyed."); - long nativeGrammar = createEmbeddedGrammarProxy(nativeObject,value.toString(), listener); - return new SrecGrammarImpl(nativeGrammar); - } - } - - public void resetAcousticState() - { - synchronized (EmbeddedRecognizerImpl.class) - { - if (nativeObject == 0) - throw new IllegalStateException("Object was destroyed."); - resetAcousticStateProxy(nativeObject); - } - } - - public void recognize(AudioStream audio, - Vector grammars) - { - synchronized (EmbeddedRecognizerImpl.class) - { - if (nativeObject == 0) - throw new IllegalStateException("Object was destroyed."); - - if (audio == null) - throw new IllegalArgumentException("AudioStream cannot be null."); - - if (grammars == null || grammars.isEmpty() == true) - throw new IllegalArgumentException("Grammars are null or empty."); - int grammarCount = grammars.size(); - - long[] nativeGrammars = new long[grammarCount]; - - for (int i = 0; i < grammarCount; ++i) - nativeGrammars[i] = ((GrammarImpl) grammars.get(i)).getNativeObject(); - - recognizeProxy(nativeObject,((AudioStreamImpl)audio).getNativeObject(), nativeGrammars); - } - } - - public void recognize(AudioStream audio, - Grammar grammar) - { - synchronized (EmbeddedRecognizerImpl.class) - { - if (nativeObject == 0) - throw new IllegalStateException("Object was destroyed."); - } - Vector grammars = new Vector(); - grammars.add(grammar); - recognize(audio, grammars); - } - - public void stop() - { - synchronized (EmbeddedRecognizerImpl.class) - { - if (nativeObject == 0) - throw new IllegalStateException("Object was destroyed."); - stopProxy(nativeObject); - } - } - - public void setParameters(Hashtable params) - { - synchronized (EmbeddedRecognizerImpl.class) - { - if (nativeObject == 0) - throw new IllegalStateException("Object was destroyed."); - setParametersProxy(nativeObject,params); - } - } - - public void getParameters(Vector params) - { - synchronized (EmbeddedRecognizerImpl.class) - { - if (nativeObject == 0) - throw new IllegalStateException("Object was destroyed."); - getParametersProxy(nativeObject,params); - } - } - - /** - * Returns the native EmbeddedRecognizer. - * - * @return a reference to the native object - */ - private native long getInstanceProxy(); - - /** - * Configures the recognizer instance. - * - * @param config the recognizer configuration file - */ - private native void configureProxy(long nativeObject, String config) throws IllegalArgumentException, - FileNotFoundException, IOException, UnsatisfiedLinkError, - ClassNotFoundException; - - /** - * Sets the recognizer listener. - * - * @param listener listens for recognizer events - */ - private native void setListenerProxy(long nativeObject, RecognizerListener listener); - - private native void recognizeProxy(long nativeObject, long audioNativeObject, - long[] pGrammars); - - private native long createEmbeddedGrammarProxy(long nativeObject, String url, - GrammarListener listener); - - private native void stopProxy(long nativeObject); - - private native void deleteNativeObject(long nativeObject); - - private native void setParametersProxy(long nativeObject, Hashtable params); - - private native void getParametersProxy(long nativeObject, Vector params); - - private native void resetAcousticStateProxy(long nativeObject); - -} diff --git a/core/java/android/speech/recognition/impl/EntryImpl.java b/core/java/android/speech/recognition/impl/EntryImpl.java deleted file mode 100644 index 91b2b788013e3511b613db3bb9ed26fa8a3c9fd9..0000000000000000000000000000000000000000 --- a/core/java/android/speech/recognition/impl/EntryImpl.java +++ /dev/null @@ -1,147 +0,0 @@ -/*---------------------------------------------------------------------------* - * EntryImpl.java * - * * - * Copyright 2007, 2008 Nuance Communciations, Inc. * - * * - * 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 android.speech.recognition.impl; - -import android.speech.recognition.NBestRecognitionResult; -import java.util.Enumeration; - -/** - */ -public class EntryImpl implements NBestRecognitionResult.Entry, Runnable -{ - private long nativeObject; - - /** - * This implementation is a work-around to solve Q bug with - * nested classes. - * - * @param nativeObject the native NBestRecognitionResult.Entry object - */ - public EntryImpl(long nativeObject) - { - this.nativeObject = nativeObject; - } - - public void run() - { - dispose(); - } - - public byte getConfidenceScore() throws IllegalStateException - { - synchronized (EntryImpl.class) - { - if (nativeObject == 0) - throw new IllegalStateException("Object has been disposed"); - return getConfidenceScoreProxy(nativeObject); - } - } - - public String getLiteralMeaning() throws IllegalStateException - { - synchronized (EntryImpl.class) - { - if (nativeObject == 0) - throw new IllegalStateException("Object has been disposed"); - return getLiteralMeaningProxy(nativeObject); - } - } - - public String getSemanticMeaning() throws IllegalStateException - { - synchronized (EntryImpl.class) - { - if (nativeObject == 0) - throw new IllegalStateException("Object has been disposed"); - return getSemanticMeaningProxy(nativeObject); - } - } - - public String get(String key) - { - synchronized (EntryImpl.class) - { - if (nativeObject == 0) - throw new IllegalStateException("Object has been disposed"); - return getProxy(nativeObject,key); - } - } - - public Enumeration keys() - { - synchronized (EntryImpl.class) - { - if (nativeObject == 0) - throw new IllegalStateException("Object has been disposed"); - - return new Enumeration() - { - private String[] keys = keysProxy(nativeObject); - private int indexOfNextRead = 0; - - public boolean hasMoreElements() - { - return indexOfNextRead <= keys.length-1; - } - - public Object nextElement() - { - return keys[indexOfNextRead++]; - } - }; - } - } - - - /** - * Releases the native resources associated with the object. - */ - private void dispose() - { - synchronized (EntryImpl.class) - { - if (nativeObject != 0) - { - deleteNativeObject(nativeObject); - nativeObject = 0; - } - } - } - - @Override - protected void finalize() throws Throwable - { - dispose(); - super.finalize(); - } - - private native void deleteNativeObject(long nativeObject); - - private native String getLiteralMeaningProxy(long nativeObject); - - private native String getSemanticMeaningProxy(long nativeObject); - - private native byte getConfidenceScoreProxy(long nativeObject); - - private native String getProxy(long nativeObject,String key); - - private native String[] keysProxy(long nativeObject); - -} diff --git a/core/java/android/speech/recognition/impl/GrammarImpl.java b/core/java/android/speech/recognition/impl/GrammarImpl.java deleted file mode 100644 index 563d5d9db76870698ccf6c2fa704f1b3b1505d0c..0000000000000000000000000000000000000000 --- a/core/java/android/speech/recognition/impl/GrammarImpl.java +++ /dev/null @@ -1,114 +0,0 @@ -/*---------------------------------------------------------------------------* - * GrammarImpl.java * - * * - * Copyright 2007, 2008 Nuance Communciations, Inc. * - * * - * 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 android.speech.recognition.impl; - -import android.speech.recognition.Grammar; - -/** - */ -public class GrammarImpl implements Grammar, Runnable -{ - /** - * Reference to the native object. - */ - protected long nativeObject; - - /** - * Creates a new GrammarImpl. - * - * @param nativeObj a reference to the native object - */ - public GrammarImpl(long nativeObj) - { - nativeObject = nativeObj; - } - - public void run() - { - dispose(); - } - - public long getNativeObject() - { - synchronized (GrammarImpl.class) - { - return nativeObject; - } - } - - /** - * Indicates that the grammar will be used in the near future. - */ - public void load() - { - synchronized (GrammarImpl.class) - { - if (nativeObject == 0) - throw new IllegalStateException("Object has been disposed"); - loadProxy(nativeObject); - } - } - - /** - * The grammar will be removed from use. - */ - public void unload() - { - synchronized (GrammarImpl.class) - { - if (nativeObject == 0) - throw new IllegalStateException("Object has been disposed"); - unloadProxy(nativeObject); - } - } - - /** - * Releases the native resources associated with the object. - */ - public void dispose() - { - synchronized (GrammarImpl.class) - { - if (nativeObject != 0) - { - deleteNativeObject(nativeObject); - nativeObject = 0; - } - } - } - - @Override - protected void finalize() throws Throwable - { - dispose(); - super.finalize(); - } - - /** - * Deletes a native object. - * - * @param nativeObject pointer to the native object - */ - private native void deleteNativeObject(long nativeObject); - - private native void loadProxy(long nativeObject); - - private native void unloadProxy(long nativeObject); -} diff --git a/core/java/android/speech/recognition/impl/LoggerImpl.java b/core/java/android/speech/recognition/impl/LoggerImpl.java deleted file mode 100644 index 9933c56b9be98a454b487b88f9def189ba68ac35..0000000000000000000000000000000000000000 --- a/core/java/android/speech/recognition/impl/LoggerImpl.java +++ /dev/null @@ -1,166 +0,0 @@ -/*---------------------------------------------------------------------------* - * LoggerImpl.java * - * * - * Copyright 2007, 2008 Nuance Communciations, Inc. * - * * - * 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 android.speech.recognition.impl; - -import android.speech.recognition.Logger; - -/** - */ -public class LoggerImpl extends Logger implements Runnable -{ - private static LoggerImpl instance; - /** - * Reference to the native object. - */ - private long nativeObject; - - /** - * Creates a new instance of LoggerImpl. - * - * @param function the name of the enclosing function - */ - private LoggerImpl() - { - System system = System.getInstance(); - nativeObject = initNativeObject(); - if (nativeObject!=0) - system.register(this); - } - - public void run() - { - dispose(); - } - - /** - * Returns the singleton instance. - * - * @return the singleton instance - */ - public static LoggerImpl getInstance() - { - synchronized (LoggerImpl.class) - { - if (instance == null) - instance = new LoggerImpl(); - return instance; - } - } - - public void setLoggingLevel(LogLevel level) - { - synchronized (LoggerImpl.class) - { - if (nativeObject == 0) - throw new IllegalStateException("Object has been disposed"); - setLoggingLevelProxy(nativeObject,level); - } - } - - public void setPath(String path) - { - synchronized (LoggerImpl.class) - { - if (nativeObject == 0) - throw new IllegalStateException("Object has been disposed"); - setPathProxy(nativeObject,path); - } - } - - public void error(String message) - { - synchronized (LoggerImpl.class) - { - if (nativeObject == 0) - throw new IllegalStateException("Object has been disposed"); - errorProxy(nativeObject,message); - } - } - - public void warn(String message) - { - synchronized (LoggerImpl.class) - { - if (nativeObject == 0) - throw new IllegalStateException("Object has been disposed"); - warnProxy(nativeObject,message); - } - } - - public void info(String message) - { - synchronized (LoggerImpl.class) - { - if (nativeObject == 0) - throw new IllegalStateException("Object has been disposed"); - infoProxy(nativeObject,message); - } - } - - public void trace(String message) - { - synchronized (LoggerImpl.class) - { - if (nativeObject == 0) - throw new IllegalStateException("Object has been disposed"); - traceProxy(nativeObject,message); - } - } - - /** - * Releases the native resources associated with the object. - */ - private void dispose() - { - synchronized (LoggerImpl.class) - { - if (nativeObject!=0) - { - deleteNativeObject(nativeObject); - System.getInstance().unregister(this); - } - nativeObject = 0; - instance = null; - } - } - - @Override - protected void finalize() throws Throwable - { - dispose(); - super.finalize(); - } - - private native long initNativeObject(); - - private native void setLoggingLevelProxy(long nativeObject, LogLevel level); - - private native void setPathProxy(long nativeObject, String filename); - - private native void errorProxy(long nativeObject, String message); - - private native void warnProxy(long nativeObject, String message); - - private native void infoProxy(long nativeObject, String message); - - private native void traceProxy(long nativeObject,String message); - - private native void deleteNativeObject(long nativeObject); -} diff --git a/core/java/android/speech/recognition/impl/MediaFileReaderImpl.java b/core/java/android/speech/recognition/impl/MediaFileReaderImpl.java deleted file mode 100644 index 8ce643df0c729c1f8f3f20b2519f105ff21ff5d2..0000000000000000000000000000000000000000 --- a/core/java/android/speech/recognition/impl/MediaFileReaderImpl.java +++ /dev/null @@ -1,156 +0,0 @@ -/*---------------------------------------------------------------------------* - * MediaFileReaderImpl.java * - * * - * Copyright 2007, 2008 Nuance Communciations, Inc. * - * * - * 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 android.speech.recognition.impl; - -import android.speech.recognition.MediaFileReader; -import android.speech.recognition.AudioStream; -import android.speech.recognition.Codec; -import android.speech.recognition.AudioSourceListener; - -/** - */ -public class MediaFileReaderImpl extends MediaFileReader implements Runnable -{ - /** - * Reference to the native object. - */ - private long nativeObject; - - /** - * Creates a new MediaFileReaderImpl. - * - * @param filename the name of the file to read from - * @param listener listens for MediaFileReader events - */ - public MediaFileReaderImpl(String filename, AudioSourceListener listener) - { - System system = System.getInstance(); - nativeObject = - createMediaFileReaderProxy(filename, listener); - if (nativeObject != 0) - system.register(this); - } - - public void run() - { - dispose(); - } - - /** - * Set the reading mode - */ - public void setMode(Mode mode) - { - synchronized (MediaFileReaderImpl.class) - { - if (nativeObject == 0) - throw new IllegalStateException("Object has been disposed"); - setModeProxy(nativeObject,mode); - } - } - - /** - * Creates an audioStream source - */ - public AudioStream createAudio() - { - synchronized (MediaFileReaderImpl.class) - { - if (nativeObject == 0) - throw new IllegalStateException("Object has been disposed"); - return new AudioStreamImpl(createAudioProxy(nativeObject)); - } - } - - /** - * Tells the audio source to start collecting audio samples. - */ - public void start() - { - synchronized (MediaFileReaderImpl.class) - { - if (nativeObject == 0) - throw new IllegalStateException("Object has been disposed"); - startProxy(nativeObject); - } - } - - /** - * Stops this source from collecting audio samples. - */ - public void stop() - { - synchronized (MediaFileReaderImpl.class) - { - if (nativeObject == 0) - throw new IllegalStateException("Object has been disposed"); - stopProxy(nativeObject); - } - } - - /** - * Releases the native resources associated with the object. - */ - public void dispose() - { - synchronized (MediaFileReaderImpl.class) - { - if (nativeObject != 0) - { - deleteNativeObject(nativeObject); - nativeObject = 0; - System.getInstance().unregister(this); - } - } - } - - @Override - protected void finalize() throws Throwable - { - dispose(); - super.finalize(); - } - - /** - * Deletes a native object. - * - * @param nativeObject pointer to the native object - */ - private native void deleteNativeObject(long nativeObject); - - /** - * Creates a native MediaFileReader. - * - * @param filename the name of the file to read from - * @param offset the offset to begin reading from - * @param codec the file audio format - * @param listener listens for MediaFileReader events - * @return a reference to the native object - */ - private native long createMediaFileReaderProxy(String filename, AudioSourceListener listener); - - private native void setModeProxy(long nativeObject,Mode mode); - - private native long createAudioProxy(long nativeObject); - - private native void startProxy(long nativeObject); - - private native void stopProxy(long nativeObject); -} diff --git a/core/java/android/speech/recognition/impl/MediaFileWriterImpl.java b/core/java/android/speech/recognition/impl/MediaFileWriterImpl.java deleted file mode 100644 index c4bd836b396c23c509e2e71e7e041cdb5b30136e..0000000000000000000000000000000000000000 --- a/core/java/android/speech/recognition/impl/MediaFileWriterImpl.java +++ /dev/null @@ -1,102 +0,0 @@ -/*---------------------------------------------------------------------------* - * MediaFileWriterImpl.java * - * * - * Copyright 2007, 2008 Nuance Communciations, Inc. * - * * - * 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 android.speech.recognition.impl; - -import android.speech.recognition.AudioStream; -import android.speech.recognition.MediaFileWriter; -import android.speech.recognition.MediaFileWriterListener; - -/** - */ -public class MediaFileWriterImpl extends MediaFileWriter implements Runnable -{ - /** - * Reference to the native object. - */ - private long nativeObject; - - /** - * Creates a new MediaFileWriterImpl. - * - * @param listener listens for MediaFileWriter events - */ - public MediaFileWriterImpl(MediaFileWriterListener listener) - { - System system = System.getInstance(); - nativeObject = createMediaFileWriterProxy(listener); - if (nativeObject != 0) - system.register(this); - } - - public void run() - { - dispose(); - } - - public void save(AudioStream source, String filename) - { - synchronized (MediaFileWriterImpl.class) - { - if (nativeObject == 0) - throw new IllegalStateException("Object has been disposed"); - saveProxy(nativeObject,((AudioStreamImpl)source).getNativeObject(), filename); - } - } - - /** - * Releases the native resources associated with the object. - */ - public synchronized void dispose() - { - synchronized (MediaFileWriterImpl.class) - { - if (nativeObject != 0) - { - deleteNativeObject(nativeObject); - nativeObject = 0; - System.getInstance().unregister(this); - } - } - } - - @Override - protected void finalize() throws Throwable - { - dispose(); - super.finalize(); - } - - /** - * Creates a native MediaFileWriter. - * - * @param listener listens for MediaFileReader events - * @return a reference to the native object - */ - private native long createMediaFileWriterProxy(MediaFileWriterListener listener); - - /** - * Deletes a native object. - * - * @param nativeObject pointer to the native object - */ - private native void deleteNativeObject(long nativeObject); - - private native void saveProxy(long nativeObject, long audioNativeObject, String filename); -} diff --git a/core/java/android/speech/recognition/impl/MicrophoneImpl.java b/core/java/android/speech/recognition/impl/MicrophoneImpl.java deleted file mode 100644 index a91548404cfb3bf9557080506dfa75b6b8aae815..0000000000000000000000000000000000000000 --- a/core/java/android/speech/recognition/impl/MicrophoneImpl.java +++ /dev/null @@ -1,165 +0,0 @@ -/*---------------------------------------------------------------------------* - * MicrophoneImpl.java * - * * - * Copyright 2007, 2008 Nuance Communciations, Inc. * - * * - * 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 android.speech.recognition.impl; - -import android.speech.recognition.AudioStream; -import android.speech.recognition.Codec; -import android.speech.recognition.Microphone; -import android.speech.recognition.AudioSourceListener; - -/** - */ -public class MicrophoneImpl extends Microphone implements Runnable -{ - private static MicrophoneImpl instance; - /** - * Reference to the native object. - */ - private long nativeObject; - - /** - * Creates a new MicrophoneImpl. - * - * @param nativeObj a reference to the native object - */ - private MicrophoneImpl() - { - System system = System.getInstance(); - nativeObject = initNativeObject(); - if (nativeObject != 0) - system.register(this); - } - - public void run() - { - dispose(); - } - - /** - * Returns the singleton instance. - * - * @return the singleton instance - */ - public static MicrophoneImpl getInstance() - { - synchronized (MicrophoneImpl.class) - { - if (instance == null) - instance = new MicrophoneImpl(); - return instance; - } - } - - /** - * set the recording codec. This must be called before Start is called. - * @param recordingCodec the codec in which the samples will be recorded. - */ - public void setCodec(Codec recordingCodec) - { - synchronized (MicrophoneImpl.class) - { - if (nativeObject == 0) - throw new IllegalStateException("Object has been disposed"); - setCodecProxy(nativeObject,recordingCodec); - } - } - - /** - * set the microphone listener. - * @param listener the microphone listener. - */ - public void setListener(AudioSourceListener listener) - { - synchronized (MicrophoneImpl.class) - { - if (nativeObject == 0) - throw new IllegalStateException("Object has been disposed"); - setListenerProxy(nativeObject,listener); - } - } - - public AudioStream createAudio() - { - synchronized (MicrophoneImpl.class) - { - if (nativeObject == 0) - throw new IllegalStateException("Object has been disposed"); - return new AudioStreamImpl(createAudioProxy(nativeObject)); - } - } - - public void start() - { - synchronized (MicrophoneImpl.class) - { - if (nativeObject == 0) - throw new IllegalStateException("Object has been disposed"); - startProxy(nativeObject); - } - } - - public void stop() - { - synchronized (MicrophoneImpl.class) - { - if (nativeObject == 0) - throw new IllegalStateException("Object has been disposed"); - stopProxy(nativeObject); - } - } - - /** - * Releases the native resources associated with the object. - */ - private void dispose() - { - synchronized (MicrophoneImpl.class) - { - if (nativeObject != 0) - { - deleteNativeObject(nativeObject); - nativeObject = 0; - instance = null; - System.getInstance().unregister(this); - } - } - } - - @Override - protected void finalize() throws Throwable - { - dispose(); - super.finalize(); - } - - private native long initNativeObject(); - - private native void setCodecProxy(long nativeObject,Codec recordingCodec); - - private native void setListenerProxy(long nativeObject, AudioSourceListener listener); - - private native long createAudioProxy(long nativeObject); - - private native void startProxy(long nativeObject); - - private native void stopProxy(long nativeObject); - - private native void deleteNativeObject(long nativeObject); -} diff --git a/core/java/android/speech/recognition/impl/NBestRecognitionResultImpl.java b/core/java/android/speech/recognition/impl/NBestRecognitionResultImpl.java deleted file mode 100644 index 4d2e00a38353d986a8f8c0f6d156afe9cfdd81af..0000000000000000000000000000000000000000 --- a/core/java/android/speech/recognition/impl/NBestRecognitionResultImpl.java +++ /dev/null @@ -1,106 +0,0 @@ -/*---------------------------------------------------------------------------* - * NBestRecognitionResultImpl.java * - * * - * Copyright 2007, 2008 Nuance Communciations, Inc. * - * * - * 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 android.speech.recognition.impl; - -import android.speech.recognition.NBestRecognitionResult; -import android.speech.recognition.VoicetagItem; -import android.speech.recognition.VoicetagItemListener; -/** - */ -public class NBestRecognitionResultImpl implements NBestRecognitionResult -{ - /** - * Reference to the native object. - */ - private long nativeObject; - - /** - * Creates a new NBestRecognitionResultImpl. - * - * @param nativeObject a reference to the native object - */ - public NBestRecognitionResultImpl(long nativeObject) - { - this.nativeObject = nativeObject; - } - - public int getSize() - { - synchronized (NBestRecognitionResultImpl.class) - { - if (nativeObject == 0) - throw new IllegalStateException("Object has been disposed"); - return getSizeProxy(nativeObject); - } - } - - public Entry getEntry(int index) - { - synchronized (NBestRecognitionResultImpl.class) - { - if (nativeObject == 0) - throw new IllegalStateException("Object has been disposed"); - long nativeEntryObject = getEntryProxy(nativeObject,index); - if (nativeEntryObject==0) - return null; - else - return new EntryImpl(nativeEntryObject); - } - } - - public VoicetagItem createVoicetagItem(String VoicetagId, VoicetagItemListener listener) - { - synchronized (NBestRecognitionResultImpl.class) - { - if (nativeObject == 0) - throw new IllegalStateException("Object has been disposed"); - if ((VoicetagId == null) || (VoicetagId.length() == 0)) - throw new IllegalArgumentException("VoicetagId may not be null or empty string."); - return new VoicetagItemImpl(createVoicetagItemProxy(nativeObject,VoicetagId,listener),false); - } - } - - /** - * Releases the native resources associated with the object. - */ - private void dispose() - { - synchronized (NBestRecognitionResultImpl.class) - { - nativeObject = 0; - } - } - - @Override - protected void finalize() throws Throwable - { - dispose(); - super.finalize(); - } - - /** - * Returns a reference to the native VoicetagItem. - */ - private native long createVoicetagItemProxy(long nativeObject, String VoicetagId, VoicetagItemListener listener); - - private native long getEntryProxy(long nativeObject, int index); - - private native int getSizeProxy(long nativeObject); -} diff --git a/core/java/android/speech/recognition/impl/SrecGrammarImpl.java b/core/java/android/speech/recognition/impl/SrecGrammarImpl.java deleted file mode 100644 index cb6f4c65930b2cc6d291605b8aff87e4bdcf737b..0000000000000000000000000000000000000000 --- a/core/java/android/speech/recognition/impl/SrecGrammarImpl.java +++ /dev/null @@ -1,120 +0,0 @@ -/*---------------------------------------------------------------------------* - * SrecGrammarImpl.java * - * * - * Copyright 2007, 2008 Nuance Communciations, Inc. * - * * - * 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 android.speech.recognition.impl; - -import android.speech.recognition.SrecGrammar; -import android.speech.recognition.SlotItem; -import android.speech.recognition.VoicetagItem; -import android.speech.recognition.WordItem; - -import java.util.Vector; - -/** - */ -public class SrecGrammarImpl extends EmbeddedGrammarImpl implements SrecGrammar -{ - /** - * Creates a new SrecGrammarImpl. - * - * @param nativeObject the native object - */ - public SrecGrammarImpl(long nativeObject) - { - super(nativeObject); - } - - public void addItem(String slotName, SlotItem item, int weight, - String semanticValue) - { - synchronized (GrammarImpl.class) - { - if (nativeObject == 0) - throw new IllegalStateException("Object has been disposed"); - - if (slotName == null || slotName.length()==0) - throw new IllegalArgumentException("addItem() - Slot name is null or empty."); - if (item == null) - throw new IllegalArgumentException("addItem() - item can't be null."); - if (semanticValue == null || semanticValue.length()==0) - throw new IllegalArgumentException("addItem() - semanticValue is null or empty."); - - long itemNativeObject = 0; - if (item instanceof VoicetagItem) - itemNativeObject = ((VoicetagItemImpl)item).getNativeObject(); - else if (item instanceof WordItem) - itemNativeObject = ((WordItemImpl)item).getNativeObject(); - else - throw new IllegalArgumentException("SlotItem - should be a WordItem or a VoicetagItem object."); - - addItemProxy(nativeObject, slotName, itemNativeObject, weight, semanticValue); - } - } - - public void addItemList(String slotName, Vector items) - { - synchronized (GrammarImpl.class) - { - if (nativeObject == 0) - throw new IllegalStateException("Object has been disposed"); - - if (slotName == null || slotName.length()==0) - throw new IllegalArgumentException("addItemList - Slot name is null or empty."); - if (items == null || items.isEmpty() == true) - throw new IllegalArgumentException("addItemList - Items is null or empty."); - - int itemsCount = items.size(); - - long[] nativeSlots = new long[itemsCount]; - int[] nativeWeights = new int[itemsCount]; - String[] nativeSemantic = new String[itemsCount]; - - Item element = null; - long itemNativeObject = 0; - SlotItem item = null; - for (int i = 0; i < itemsCount; ++i) - { - element = items.get(i); - - item = element._item; - if (item instanceof VoicetagItem) - itemNativeObject = ((VoicetagItemImpl)item).getNativeObject(); - else if (item instanceof WordItem) - itemNativeObject = ((WordItemImpl)item).getNativeObject(); - else - { - throw new IllegalArgumentException("SlotItem ["+i+"] - should be a WordItem or a VoicetagItem object."); - } - nativeSlots[i] = itemNativeObject; - nativeWeights[i] = element._weight; - nativeSemantic[i]= element._semanticMeaning; - itemNativeObject = 0; - item = null; - } - addItemListProxy(nativeObject, slotName,nativeSlots,nativeWeights,nativeSemantic); - } - } - - private native void addItemProxy(long nativeObject, String slotName, long item, int weight, - String semanticValue); - - private native void addItemListProxy(long nativeObject, String slotName, long[] items, - int[] weights, String[] semanticValues); - -} diff --git a/core/java/android/speech/recognition/impl/System.java b/core/java/android/speech/recognition/impl/System.java deleted file mode 100644 index 23418feab258afda60de059af8b6af2309a30688..0000000000000000000000000000000000000000 --- a/core/java/android/speech/recognition/impl/System.java +++ /dev/null @@ -1,179 +0,0 @@ -/*---------------------------------------------------------------------------* - * System.java * - * * - * Copyright 2007, 2008 Nuance Communciations, Inc. * - * * - * 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 android.speech.recognition.impl; - -import java.lang.ref.WeakReference; -import java.util.WeakHashMap; - - -/** - */ -public class System -{ - private static boolean libraryLoaded; - private static System instance; - private static WeakHashMap registerMap; - /** - * Reference to the native object. - */ - private long nativeObject; - private boolean shutdownRequested; - - /** - * Creates a new instance of System - */ - private System() - { - shutdownRequested = false; - registerMap = - new WeakHashMap(); - initLibrary(); - nativeObject = initNativeObject(); - Runtime.getRuntime(). - addShutdownHook(new Thread() - { - @Override - public void run() - { - try - { - dispose(); - } - catch (Exception e) - { - e.printStackTrace(); - } - } - }); - - } - - /** - * Returns the singleton instance. - * - * @return the singleton instance - */ - public static System getInstance() - { - synchronized (System.class) - { - if (instance == null) - instance = new System(); - return instance; - } - } - - /** - * Loads the native library if necessary. - */ - private void initLibrary() - { - if (!libraryLoaded) - { - java.lang.System.loadLibrary("UAPI_jni"); - libraryLoaded = true; - } - } - - /** - * Registers an object for shutdown when System.dispose() is invoked. - * - * @param r the code to run on shutdown - * @throws IllegalStateException if the System is shutting down - */ - public void register(Runnable r) throws IllegalStateException - { - synchronized (System.class) - { - if (shutdownRequested) - throw new IllegalStateException("System is shutting down"); - registerMap.put(r, - new WeakReference(r)); - } - } - - /** - * Registers an object for shutdown when System.dispose() is invoked. - * - * @param r the code to run on shutdown - */ - public void unregister(Runnable r) - { - synchronized (System.class) - { - if (shutdownRequested) - { - // System.dispose() will end up removing all entries - return; - } - if (r!=null) registerMap.remove(r); - } - } - - /** - * Releases the native resources associated with the object. - * - * @throws java.util.concurrent.TimeoutException if the operation timeouts - * @throws IllegalThreadStateException if a native thread error occurs - */ - public void dispose() throws java.util.concurrent.TimeoutException, - IllegalThreadStateException - { - synchronized (System.class) - { - if (nativeObject == 0) - return; - shutdownRequested = true; - } - - // Traverse the list of WeakReferences - // cast to a Runnable object if the weakrerefence is not null - // then call the run method. - for (Object o: registerMap.keySet()) - { - WeakReference weakReference = registerMap.get(o); - Runnable r = (Runnable) weakReference.get(); - if (r != null) - r.run(); - } - registerMap.clear(); - - // Call the native dispose method - disposeProxy(); - synchronized (System.class) - { - nativeObject = 0; - instance = null; - } - } - - @Override - protected void finalize() throws Throwable - { - dispose(); - super.finalize(); - } - - public static native String getAPIVersion(); - - private static native long initNativeObject(); - - private static native void disposeProxy(); -} diff --git a/core/java/android/speech/recognition/impl/VoicetagItemImpl.java b/core/java/android/speech/recognition/impl/VoicetagItemImpl.java deleted file mode 100644 index f9db3992835c0e9127b6281f6c63efe3deac49bb..0000000000000000000000000000000000000000 --- a/core/java/android/speech/recognition/impl/VoicetagItemImpl.java +++ /dev/null @@ -1,206 +0,0 @@ -/*---------------------------------------------------------------------------* - * VoicetagItemImpl.java * - * * - * Copyright 2007, 2008 Nuance Communciations, Inc. * - * * - * 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 android.speech.recognition.impl; - -import android.speech.recognition.VoicetagItem; -import android.speech.recognition.VoicetagItemListener; -import java.io.FileNotFoundException; -import java.io.IOException; -/** - */ -public class VoicetagItemImpl extends VoicetagItem implements Runnable -{ - /** - * Reference to the native object. - */ - private long nativeObject; - /** - * Voicetag has a filename need to be loaded before use it. - */ - private boolean needToBeLoaded; - - /** - * Creates a new VoicetagItemImpl. - * - * @param nativeObject the pointer to the native object - */ - public VoicetagItemImpl(long nativeObject, boolean fromfile) - { - this.nativeObject = nativeObject; - needToBeLoaded = fromfile; - } - - public void run() - { - dispose(); - } - - /** - * Creates a VoicetagItem from a file - * - * @param filename filename for Voicetag - * @param listener listens for Voicetag events - * @return the resulting VoicetagItem - * @throws IllegalArgumentException if filename is null or an empty string. - * @throws FileNotFoundException if the specified filename could not be found - * @throws IOException if the specified filename could not be opened - */ - public static VoicetagItem create(String filename, VoicetagItemListener listener) throws IllegalArgumentException,FileNotFoundException,IOException - { - if ((filename == null) || (filename.length() == 0)) - throw new IllegalArgumentException("Filename may not be null or empty string."); - - VoicetagItemImpl voicetag = null; - long nativeVoicetag = createVoicetagProxy(filename,listener); - if (nativeVoicetag!=0) - { - voicetag = new VoicetagItemImpl(nativeVoicetag,true); - } - return voicetag; - } - /** - * Returns the audio used to construct the VoicetagItem. - */ - public byte[] getAudio() throws IllegalStateException - { - synchronized (VoicetagItem.class) - { - if (nativeObject == 0) - throw new IllegalStateException("Object was destroyed."); - - return getAudioProxy(nativeObject); - } - } - - /** - * Sets the audio used to construct the Voicetag. - */ - public void setAudio(byte[] waveform) throws IllegalArgumentException,IllegalStateException - { - synchronized (VoicetagItem.class) - { - if (nativeObject == 0) - throw new IllegalStateException("Object was destroyed."); - - if ((waveform == null) || (waveform.length == 0)) - throw new IllegalArgumentException("Waveform may not be null or empty."); - setAudioProxy(nativeObject,waveform); - } - } - - /** - * Save the Voicetag. - */ - public void save(String path) throws IllegalArgumentException - { - synchronized (VoicetagItem.class) - { - if (nativeObject == 0) - throw new IllegalStateException("Object was destroyed."); - if ((path == null) || (path.length() == 0)) - throw new IllegalArgumentException("Path may not be null or empty string."); - saveVoicetagProxy(nativeObject,path); - } - } - - /** - * Load a Voicetag. - */ - public void load() throws IllegalStateException - { - synchronized (VoicetagItem.class) - { - if (nativeObject == 0) - throw new IllegalStateException("Object was destroyed."); - if (!needToBeLoaded) - throw new IllegalStateException("This Voicetag was not created from a file, does not need to be loaded."); - loadVoicetagProxy(nativeObject); - } - } - - public long getNativeObject() - { - synchronized (VoicetagItem.class) - { - return nativeObject; - } - } - - /** - * Releases the native resources associated with the object. - */ - private void dispose() - { - synchronized (VoicetagItem.class) - { - if (nativeObject != 0) - { - deleteNativeObject(nativeObject); - nativeObject = 0; - } - } - } - - @Override - protected void finalize() throws Throwable - { - dispose(); - super.finalize(); - } - - - private static native long createVoicetagProxy(String filename, VoicetagItemListener listener); - /** - * (Optional operation) Returns the audio used to construct the Voicetag. The - * audio is in PCM format and is start-pointed and end-pointed. The audio is - * only generated if the enableGetWaveform recognition parameter is set - * prior to recognition. - * - * @see RecognizerParameters.enableGetWaveform - */ - private native byte[] getAudioProxy(long nativeObject); - - /** - * (Optional operation) Sets the audio used to construct the Voicetag. The - * audio is in PCM format and is start-pointed and end-pointed. The audio is - * only generated if the enableGetWaveform recognition parameter is set - * prior to recognition. - * - * @param waveform the endpointed waveform - */ - private native void setAudioProxy(long nativeObject, byte[] waveform); - - /** - * Save the Voicetag Item. - */ - private native void saveVoicetagProxy(long nativeObject, String path); - - /** - * Load a Voicetag Item. - */ - private native void loadVoicetagProxy(long nativeObject); - - /** - * Deletes a native object. - * - * @param nativeObject pointer to the native object - */ - private native void deleteNativeObject(long nativeObject); -} diff --git a/core/java/android/speech/recognition/impl/WordItemImpl.java b/core/java/android/speech/recognition/impl/WordItemImpl.java deleted file mode 100644 index f0daa345e98f69818f81eef196b9246c0615e85d..0000000000000000000000000000000000000000 --- a/core/java/android/speech/recognition/impl/WordItemImpl.java +++ /dev/null @@ -1,157 +0,0 @@ -/*---------------------------------------------------------------------------* - * WordItemImpl.java * - * * - * Copyright 2007, 2008 Nuance Communciations, Inc. * - * * - * 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 android.speech.recognition.impl; - -import android.speech.recognition.WordItem; - -/** - */ -public class WordItemImpl extends WordItem implements Runnable -{ - /** - * Empty array that gets reused whenever the code requests that the underlying - * recognizer guess the pronunciations. - */ - private static final String[] guessPronunciations = new String[0]; - /** - * Reference to the native object. - */ - private long nativeObject; - - /** - * Creates a new WordItem. - * - * @param word the word to insert - * @throws IllegalArgumentException if word or pronunciations are null - */ - private WordItemImpl(String word, String[] pronunciations) throws IllegalArgumentException - { - initNativeObject(word, pronunciations); - } - - public void run() - { - dispose(); - } - - /** - * Creates a new WordItem. - * - * @param word the word to insert - * @param pronunciations the pronunciations to associated with the item. If the list is - * is empty (example:new String[0]) the recognizer will attempt to guess the pronunciations. - * @return the WordItem - * @throws IllegalArgumentException if word is null or if pronunciations is - * null or pronunciations contains an element equal to null or empty string. - */ - public static WordItemImpl valueOf(String word, String[] pronunciations) - throws IllegalArgumentException - { - if (word == null) - throw new IllegalArgumentException("Word may not be null"); - else if (pronunciations == null) - throw new IllegalArgumentException("Pronunciations may not be null"); - for (int i = 0, size = pronunciations.length; i < size; ++i) - { - if (pronunciations[i]==null) - { - throw new IllegalArgumentException( - "Pronunciations element may not be null"); - } - else - { - if (pronunciations[i].trim().equals("")) - throw new IllegalArgumentException( - "Pronunciations may not contain empty strings"); - } - } - return new WordItemImpl(word, pronunciations); - } - - /** - * Creates a new WordItem. - * - * @param word the word to insert - * @param pronunciation the pronunciation to associate with the item. If it - * is null the recognizer will attempt to guess the pronunciations. - * @return the WordItem - * @throws IllegalArgumentException if word is null or if pronunciation is - * an empty string - */ - public static WordItemImpl valueOf(String word, String pronunciation) - throws IllegalArgumentException - { - String[] pronunciations; - if (word == null) - throw new IllegalArgumentException("Word may not be null"); - else if (pronunciation == null) - pronunciations = guessPronunciations; - else if (pronunciation.trim().equals("")) - throw new IllegalArgumentException( - "Pronunciation may not be an empty string"); - else - pronunciations = new String[]{pronunciation}; - return new WordItemImpl(word, pronunciations); - } - - /** - * Allocates a reference to the native object. - * - * @param word the word to insert - */ - private native void initNativeObject(String word, String[] pronunciations); - - public long getNativeObject() - { - synchronized (WordItemImpl.class) - { - return nativeObject; - } - } - - /** - * Releases the native resources associated with the object. - */ - private void dispose() - { - synchronized (WordItemImpl.class) - { - if (nativeObject != 0) - { - deleteNativeObject(nativeObject); - nativeObject = 0; - } - } - } - - @Override - protected void finalize() throws Throwable - { - dispose(); - super.finalize(); - } - - /** - * Deletes a native object. - * - * @param nativeObject pointer to the native object - */ - private native void deleteNativeObject(long nativeObject); -} diff --git a/core/java/android/speech/recognition/impl/package.html b/core/java/android/speech/recognition/impl/package.html deleted file mode 100755 index 1c9bf9dad8350012996a920f64cbd577fdf72bb7..0000000000000000000000000000000000000000 --- a/core/java/android/speech/recognition/impl/package.html +++ /dev/null @@ -1,5 +0,0 @@ - - - {@hide} - - diff --git a/core/java/android/speech/recognition/package.html b/core/java/android/speech/recognition/package.html deleted file mode 100644 index 3c59962ccd671430ac1de9601684bded946f347c..0000000000000000000000000000000000000000 --- a/core/java/android/speech/recognition/package.html +++ /dev/null @@ -1,6 +0,0 @@ - - -{@hide} -Provides classes for speech recogntion. - - diff --git a/core/java/android/speech/srec/MicrophoneInputStream.java b/core/java/android/speech/srec/MicrophoneInputStream.java new file mode 100644 index 0000000000000000000000000000000000000000..160a0034a5ddacd63c7c8ce0957317314bd48f91 --- /dev/null +++ b/core/java/android/speech/srec/MicrophoneInputStream.java @@ -0,0 +1,106 @@ +/*---------------------------------------------------------------------------* + * MicrophoneInputStream.java * + * * + * Copyright 2007 Nuance Communciations, Inc. * + * * + * 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 android.speech.srec; + +import java.io.IOException; +import java.io.InputStream; +import java.lang.IllegalStateException; + + +/** + * PCM input stream from the microphone, 16 bits per sample. + */ +public final class MicrophoneInputStream extends InputStream { + static { + System.loadLibrary("srec_jni"); + } + + private final static String TAG = "MicrophoneInputStream"; + private int mAudioRecord = 0; + private byte[] mOneByte = new byte[1]; + + /** + * MicrophoneInputStream constructor. + * @param sampleRate sample rate of the microphone, typically 11025 or 8000. + * @param fifoDepth depth of the real time fifo, measured in sampleRate clock ticks. + * This determines how long an application may delay before losing data. + */ + public MicrophoneInputStream(int sampleRate, int fifoDepth) throws IOException { + mAudioRecord = AudioRecordNew(sampleRate, fifoDepth); + if (mAudioRecord == 0) throw new IllegalStateException("not open"); + AudioRecordStart(mAudioRecord); + } + + @Override + public int read() throws IOException { + if (mAudioRecord == 0) throw new IllegalStateException("not open"); + int rtn = AudioRecordRead(mAudioRecord, mOneByte, 0, 1); + return rtn == 1 ? ((int)mOneByte[0] & 0xff) : -1; + } + + @Override + public int read(byte[] b) throws IOException { + if (mAudioRecord == 0) throw new IllegalStateException("not open"); + return AudioRecordRead(mAudioRecord, b, 0, b.length); + } + + @Override + public int read(byte[] b, int offset, int length) throws IOException { + if (mAudioRecord == 0) throw new IllegalStateException("not open"); + // TODO: should we force all reads to be a multiple of the sample size? + return AudioRecordRead(mAudioRecord, b, offset, length); + } + + /** + * Closes this stream. + */ + @Override + public void close() throws IOException { + if (mAudioRecord != 0) { + try { + AudioRecordStop(mAudioRecord); + } finally { + try { + AudioRecordDelete(mAudioRecord); + } finally { + mAudioRecord = 0; + } + } + } + } + + @Override + protected void finalize() throws Throwable { + if (mAudioRecord != 0) { + close(); + throw new IOException("someone forgot to close MicrophoneInputStream"); + } + } + + // + // AudioRecord JNI interface + // + private static native int AudioRecordNew(int sampleRate, int fifoDepth); + private static native void AudioRecordStart(int audioRecord); + private static native int AudioRecordRead(int audioRecord, byte[] b, int offset, int length) throws IOException; + private static native void AudioRecordStop(int audioRecord) throws IOException; + private static native void AudioRecordDelete(int audioRecord) throws IOException; +} diff --git a/core/java/android/speech/srec/Recognizer.java b/core/java/android/speech/srec/Recognizer.java new file mode 100644 index 0000000000000000000000000000000000000000..749c9235cd38aa9c450814cb6f8228d82907d45d --- /dev/null +++ b/core/java/android/speech/srec/Recognizer.java @@ -0,0 +1,679 @@ +/* + * --------------------------------------------------------------------------- + * Recognizer.java + * + * Copyright 2007 Nuance Communciations, Inc. + * + * 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 android.speech.srec; + +import android.util.Config; +import android.util.Log; + +import java.io.File; +import java.io.InputStream; +import java.io.IOException; +import java.util.Locale; + +/** + * Simple, synchronous speech recognizer, using the Nuance SREC package. + * Usages proceeds as follows: + * + *
      + *
    • Create a Recognizer. + *
    • Create a Recognizer.Grammar. + *
    • Setup the Recognizer.Grammar. + *
    • Reset the Recognizer.Grammar slots, if needed. + *
    • Fill the Recognizer.Grammar slots, if needed. + *
    • Compile the Recognizer.Grammar, if needed. + *
    • Save the filled Recognizer.Grammar, if needed. + *
    • Start the Recognizer. + *
    • Loop over advance and putAudio until recognition complete. + *
    • Fetch and process results, or notify of failure. + *
    • Stop the Recognizer. + *
    • Destroy the Recognizer. + *
    + * + *

    Below is example code

    + * + *
    + * 
    + * // create and start audio input
    + * InputStream audio = new MicrophoneInputStream(11025, 11025*5);
    + * // create a Recognizer
    + * String cdir = Recognizer.getConfigDir(null);
    + * Recognizer recognizer = new Recognizer(cdir + "/baseline11k.par");
    + * // create and load a Grammar
    + * Recognizer.Grammar grammar = recognizer.new Grammar(cdir + "/grammars/VoiceDialer.g2g");
    + * // setup the Grammar to work with the Recognizer
    + * grammar.setupRecognizer();
    + * // fill the Grammar slots with names and save, if required
    + * grammar.resetAllSlots();
    + * for (String name : names) grammar.addWordToSlot("@Names", name, null, 1, "V=1");
    + * grammar.compile();
    + * grammar.save(".../foo.g2g");
    + * // start the Recognizer
    + * recognizer.start();
    + * // loop over Recognizer events
    + * while (true) {
    + *     switch (recognizer.advance()) {
    + *     case Recognizer.EVENT_INCOMPLETE:
    + *     case Recognizer.EVENT_STARTED:
    + *     case Recognizer.EVENT_START_OF_VOICING:
    + *     case Recognizer.EVENT_END_OF_VOICING:
    + *         // let the Recognizer continue to run
    + *         continue;
    + *     case Recognizer.EVENT_RECOGNITION_RESULT:
    + *         // success, so fetch results here!
    + *         for (int i = 0; i < recognizer.getResultCount(); i++) {
    + *             String result = recognizer.getResult(i, Recognizer.KEY_LITERAL);
    + *         }
    + *         break;
    + *     case Recognizer.EVENT_NEED_MORE_AUDIO:
    + *         // put more audio in the Recognizer
    + *         recognizer.putAudio(audio);
    + *         continue;
    + *     default:
    + *         notifyFailure();
    + *         break;
    + *     }
    + *     break;
    + * }
    + * // stop the Recognizer
    + * recognizer.stop();
    + * // destroy the Recognizer
    + * recognizer.destroy();
    + * // stop the audio device
    + * audio.close();
    + * 
    + * 
    + */ +public final class Recognizer { + static { + System.loadLibrary("srec_jni"); + } + + private static String TAG = "Recognizer"; + + /** + * Result key corresponding to confidence score. + */ + public static final String KEY_CONFIDENCE = "conf"; + + /** + * Result key corresponding to literal text. + */ + public static final String KEY_LITERAL = "literal"; + + /** + * Result key corresponding to semantic meaning text. + */ + public static final String KEY_MEANING = "meaning"; + + // handle to SR_Vocabulary object + private int mVocabulary = 0; + + // handle to SR_Recognizer object + private int mRecognizer = 0; + + // Grammar currently associated with Recognizer via SR_GrammarSetupRecognizer + private Grammar mActiveGrammar = null; + + /** + * Get the pathname of the SREC configuration directory corresponding to the + * language indicated by the Locale. + * This directory contains dictionaries, speech models, + * configuration files, and other data needed by the Recognizer. + * @param locale Locale corresponding to the desired language, + * or null for default, currently Locale.US. + * @return Pathname of the configuration directory. + */ + public static String getConfigDir(Locale locale) { + if (locale == null) locale = Locale.US; + String dir = "/system/usr/srec/config/" + + locale.toString().replace('_', '.').toLowerCase(); + if ((new File(dir)).isDirectory()) return dir; + return null; + } + + /** + * Create an instance of a SREC speech recognizer. + * + * @param configFile pathname of the baseline*.par configuration file, + * which in turn contains references to dictionaries, speech models, + * and other data needed to configure and operate the recognizer. + * A separate config file is needed for each audio sample rate. + * Two files, baseline11k.par and baseline8k.par, which correspond to + * 11025 and 8000 hz, are present in the directory indicated by + * {@link #getConfigDir}. + * @throws IOException + */ + public Recognizer(String configFile) throws IOException { + PMemInit(); + SR_SessionCreate(configFile); + mRecognizer = SR_RecognizerCreate(); + SR_RecognizerSetup(mRecognizer); + mVocabulary = SR_VocabularyLoad(); + } + + /** + * Represents a grammar loaded into the Recognizer. + */ + public class Grammar { + private int mGrammar = 0; + + /** + * Create a Grammar instance. + * @param g2gFileName pathname of g2g file. + */ + public Grammar(String g2gFileName) throws IOException { + mGrammar = SR_GrammarLoad(g2gFileName); + SR_GrammarSetupVocabulary(mGrammar, mVocabulary); + } + + /** + * Reset all slots. + */ + public void resetAllSlots() { + SR_GrammarResetAllSlots(mGrammar); + } + + /** + * Add a word to a slot. + * + * @param slot slot name. + * @param word word to insert. + * @param pron pronunciation, or null to derive from word. + * @param weight weight to give the word. One is normal, 50 is low. + * @param tag semantic meaning tag string. + */ + public void addWordToSlot(String slot, String word, String pron, int weight, String tag) { + SR_GrammarAddWordToSlot(mGrammar, slot, word, pron, weight, tag); + } + + /** + * Compile all slots. + */ + public void compile() { + SR_GrammarCompile(mGrammar); + } + + /** + * Setup Grammar with Recognizer. + */ + public void setupRecognizer() { + SR_GrammarSetupRecognizer(mGrammar, mRecognizer); + mActiveGrammar = this; + } + + /** + * Save Grammar to g2g file. + * + * @param g2gFileName + * @throws IOException + */ + public void save(String g2gFileName) throws IOException { + SR_GrammarSave(mGrammar, g2gFileName); + } + + /** + * Release resources associated with this Grammar. + */ + public void destroy() { + // TODO: need to do cleanup and disassociation with Recognizer + if (mGrammar != 0) { + SR_GrammarDestroy(mGrammar); + mGrammar = 0; + } + } + + /** + * Clean up resources. + */ + protected void finalize() { + if (mGrammar != 0) { + destroy(); + throw new IllegalStateException("someone forgot to destroy Grammar"); + } + } + } + + /** + * Start recognition + */ + public void start() { + // TODO: shouldn't be here? + SR_RecognizerActivateRule(mRecognizer, mActiveGrammar.mGrammar, "trash", 1); + SR_RecognizerStart(mRecognizer); + } + + /** + * Process some audio and return the current status. + * @return recognition event, one of: + *
      + *
    • EVENT_INVALID + *
    • EVENT_NO_MATCH + *
    • EVENT_INCOMPLETE + *
    • EVENT_STARTED + *
    • EVENT_STOPPED + *
    • EVENT_START_OF_VOICING + *
    • EVENT_END_OF_VOICING + *
    • EVENT_SPOKE_TOO_SOON + *
    • EVENT_RECOGNITION_RESULT + *
    • EVENT_START_OF_UTTERANCE_TIMEOUT + *
    • EVENT_RECOGNITION_TIMEOUT + *
    • EVENT_NEED_MORE_AUDIO + *
    • EVENT_MAX_SPEECH + *
    + */ + public int advance() { + return SR_RecognizerAdvance(mRecognizer); + } + + /** + * Put audio samples into the Recognizer. + * @param buf holds the audio samples. + * @param offset offset of the first sample. + * @param length number of bytes containing samples. + * @param isLast indicates no more audio data, normally false. + * @return number of bytes accepted. + */ + public int putAudio(byte[] buf, int offset, int length, boolean isLast) { + return SR_RecognizerPutAudio(mRecognizer, buf, offset, length, isLast); + } + + /** + * Read audio samples from an InputStream and put them in the + * Recognizer. + * @param audio InputStream containing PCM audio samples. + */ + public void putAudio(InputStream audio) throws IOException { + // make sure the audio buffer is allocated + if (mPutAudioBuffer == null) mPutAudioBuffer = new byte[512]; + // read some data + int nbytes = audio.read(mPutAudioBuffer); + // eof, so signal Recognizer + if (nbytes == -1) { + SR_RecognizerPutAudio(mRecognizer, mPutAudioBuffer, 0, 0, true); + } + // put it into the Recognizer + else if (nbytes != SR_RecognizerPutAudio(mRecognizer, mPutAudioBuffer, 0, nbytes, false)) { + throw new IOException("SR_RecognizerPutAudio failed nbytes=" + nbytes); + } + } + + // audio buffer for putAudio(InputStream) + private byte[] mPutAudioBuffer = null; + + /** + * Get the number of recognition results. Must be called after + * EVENT_RECOGNITION_RESULT is returned by + * advance, but before stop. + * + * @return number of results in nbest list. + */ + public int getResultCount() { + return SR_RecognizerResultGetSize(mRecognizer); + } + + /** + * Get a set of keys for the result. Must be called after + * EVENT_RECOGNITION_RESULT is returned by + * advance, but before stop. + * + * @param index index of result. + * @return array of keys. + */ + public String[] getResultKeys(int index) { + return SR_RecognizerResultGetKeyList(mRecognizer, index); + } + + /** + * Get a result value. Must be called after + * EVENT_RECOGNITION_RESULT is returned by + * advance, but before stop. + * + * @param index index of the result. + * @param key key of the result. This is typically one of + * KEY_CONFIDENCE, KEY_LITERAL, or + * KEY_MEANING, but the user can also define their own keys + * in a grxml file, or in the tag slot of + * Grammar.addWordToSlot. + * @return the result. + */ + public String getResult(int index, String key) { + return SR_RecognizerResultGetValue(mRecognizer, index, key); + } + + /** + * Stop the Recognizer. + */ + public void stop() { + SR_RecognizerStop(mRecognizer); + SR_RecognizerDeactivateRule(mRecognizer, mActiveGrammar.mGrammar, "trash"); + } + + /** + * Clean up resources. + */ + public void destroy() { + try { + if (mVocabulary != 0) SR_VocabularyDestroy(mVocabulary); + } finally { + mVocabulary = 0; + try { + if (mRecognizer != 0) SR_RecognizerUnsetup(mRecognizer); + } finally { + try { + if (mRecognizer != 0) SR_RecognizerDestroy(mRecognizer); + } finally { + mRecognizer = 0; + try { + SR_SessionDestroy(); + } finally { + PMemShutdown(); + } + } + } + } + } + + /** + * Clean up resources. + */ + protected void finalize() throws Throwable { + if (mVocabulary != 0 || mRecognizer != 0) { + destroy(); + throw new IllegalStateException("someone forgot to destroy Recognizer"); + } + } + + /* an example session captured, for reference + void doall() { + if (PMemInit ( ) + || lhs_audioinOpen ( WAVE_MAPPER, SREC_TEST_DEFAULT_AUDIO_FREQUENCY, &audio_in_handle ) + || srec_test_init_application_data ( &applicationData, argc, argv ) + || SR_SessionCreate ( "/system/usr/srec/config/en.us/baseline11k.par" ) + || SR_RecognizerCreate ( &applicationData.recognizer ) + || SR_RecognizerSetup ( applicationData.recognizer) + || ESR_SessionGetLCHAR ( L("cmdline.vocabulary"), filename, &flen ) + || SR_VocabularyLoad ( filename, &applicationData.vocabulary ) + || SR_VocabularyGetLanguage ( applicationData.vocabulary, &applicationData.locale ) + || (applicationData.nametag = NULL) + || SR_NametagsCreate ( &applicationData.nametags ) + || (LSTRCPY ( applicationData.grammars [0].grammar_path, "/system/usr/srec/config/en.us/grammars/VoiceDialer.g2g" ), 0) + || (LSTRCPY ( applicationData.grammars [0].grammarID, "BothTags" ), 0) + || (LSTRCPY ( applicationData.grammars [0].ruleName, "trash" ), 0) + || (applicationData.grammars [0].is_ve_grammar = ESR_FALSE, 0) + || SR_GrammarLoad (applicationData.grammars [0].grammar_path, &applicationData.grammars [applicationData.grammarCount].grammar ) + || SR_GrammarSetupVocabulary ( applicationData.grammars [0].grammar, applicationData.vocabulary ) + || SR_GrammarSetupRecognizer( applicationData.grammars [0].grammar, applicationData.recognizer ) + || SR_GrammarSetDispatchFunction ( applicationData.grammars [0].grammar, L("myDSMCallback"), NULL, myDSMCallback ) + || (applicationData.grammarCount++, 0) + || SR_RecognizerActivateRule ( applicationData.recognizer, applicationData.grammars [0].grammar, + applicationData.grammars [0].ruleName, 1 ) + || (applicationData.active_grammar_num = 0, 0) + || lhs_audioinStart ( audio_in_handle ) + || SR_RecognizerStart ( applicationData.recognizer ) + || strl ( applicationData.grammars [0].grammar, &applicationData, audio_in_handle, &recognition_count ) + || SR_RecognizerStop ( applicationData.recognizer ) + || lhs_audioinStop ( audio_in_handle ) + || SR_RecognizerDeactivateRule ( applicationData.recognizer, applicationData.grammars [0].grammar, applicationData.grammars [0].ruleName ) + || (applicationData.active_grammar_num = -1, 0) + || SR_GrammarDestroy ( applicationData.grammars [0].grammar ) + || (applicationData.grammarCount--, 0) + || SR_NametagsDestroy ( applicationData.nametags ) + || (applicationData.nametags = NULL, 0) + || SR_VocabularyDestroy ( applicationData.vocabulary ) + || (applicationData.vocabulary = NULL) + || SR_RecognizerUnsetup ( applicationData.recognizer) // releases acoustic models + || SR_RecognizerDestroy ( applicationData.recognizer ) + || (applicationData.recognizer = NULL) + || SR_SessionDestroy ( ) + || srec_test_shutdown_application_data ( &applicationData ) + || lhs_audioinClose ( &audio_in_handle ) + || PMemShutdown ( ) + } + */ + + + // + // PMem native methods + // + private static native void PMemInit(); + private static native void PMemShutdown(); + + + // + // SR_Session native methods + // + private static native void SR_SessionCreate(String filename); + private static native void SR_SessionDestroy(); + + + // + // SR_Recognizer native methods + // + + /** + * Reserved value. + */ + public final static int EVENT_INVALID = 0; + + /** + * Recognizer could not find a match for the utterance. + */ + public final static int EVENT_NO_MATCH = 1; + + /** + * Recognizer processed one frame of audio. + */ + public final static int EVENT_INCOMPLETE = 2; + + /** + * Recognizer has just been started. + */ + public final static int EVENT_STARTED = 3; + + /** + * Recognizer is stopped. + */ + public final static int EVENT_STOPPED = 4; + + /** + * Beginning of speech detected. + */ + public final static int EVENT_START_OF_VOICING = 5; + + /** + * End of speech detected. + */ + public final static int EVENT_END_OF_VOICING = 6; + + /** + * Beginning of utterance occured too soon. + */ + public final static int EVENT_SPOKE_TOO_SOON = 7; + + /** + * Recognition match detected. + */ + public final static int EVENT_RECOGNITION_RESULT = 8; + + /** + * Timeout occured before beginning of utterance. + */ + public final static int EVENT_START_OF_UTTERANCE_TIMEOUT = 9; + + /** + * Timeout occured before speech recognition could complete. + */ + public final static int EVENT_RECOGNITION_TIMEOUT = 10; + + /** + * Not enough samples to process one frame. + */ + public final static int EVENT_NEED_MORE_AUDIO = 11; + + /** + * More audio encountered than is allowed by 'swirec_max_speech_duration'. + */ + public final static int EVENT_MAX_SPEECH = 12; + + /** + * Produce a displayable string from an advance event. + * @param event + * @return String representing the event. + */ + public static String eventToString(int event) { + switch (event) { + case EVENT_INVALID: + return "EVENT_INVALID"; + case EVENT_NO_MATCH: + return "EVENT_NO_MATCH"; + case EVENT_INCOMPLETE: + return "EVENT_INCOMPLETE"; + case EVENT_STARTED: + return "EVENT_STARTED"; + case EVENT_STOPPED: + return "EVENT_STOPPED"; + case EVENT_START_OF_VOICING: + return "EVENT_START_OF_VOICING"; + case EVENT_END_OF_VOICING: + return "EVENT_END_OF_VOICING"; + case EVENT_SPOKE_TOO_SOON: + return "EVENT_SPOKE_TOO_SOON"; + case EVENT_RECOGNITION_RESULT: + return "EVENT_RECOGNITION_RESULT"; + case EVENT_START_OF_UTTERANCE_TIMEOUT: + return "EVENT_START_OF_UTTERANCE_TIMEOUT"; + case EVENT_RECOGNITION_TIMEOUT: + return "EVENT_RECOGNITION_TIMEOUT"; + case EVENT_NEED_MORE_AUDIO: + return "EVENT_NEED_MORE_AUDIO"; + case EVENT_MAX_SPEECH: + return "EVENT_MAX_SPEECH"; + } + return "EVENT_" + event; + } + + private static native void SR_RecognizerStart(int recognizer); + private static native void SR_RecognizerStop(int recognizer); + private static native int SR_RecognizerCreate(); + private static native void SR_RecognizerDestroy(int recognizer); + private static native void SR_RecognizerSetup(int recognizer); + private static native void SR_RecognizerUnsetup(int recognizer); + private static native boolean SR_RecognizerIsSetup(int recognizer); + private static native String SR_RecognizerGetParameter(int recognizer, String key); + private static native int SR_RecognizerGetSize_tParameter(int recognizer, String key); + private static native boolean SR_RecognizerGetBoolParameter(int recognizer, String key); + private static native void SR_RecognizerSetParameter(int recognizer, String key, String value); + private static native void SR_RecognizerSetSize_tParameter(int recognizer, + String key, int value); + private static native void SR_RecognizerSetBoolParameter(int recognizer, String key, + boolean value); + private static native void SR_RecognizerSetupRule(int recognizer, int grammar, + String ruleName); + private static native boolean SR_RecognizerHasSetupRules(int recognizer); + private static native void SR_RecognizerActivateRule(int recognizer, int grammar, + String ruleName, int weight); + private static native void SR_RecognizerDeactivateRule(int recognizer, int grammar, + String ruleName); + private static native void SR_RecognizerDeactivateAllRules(int recognizer); + private static native boolean SR_RecognizerIsActiveRule(int recognizer, int grammar, + String ruleName); + private static native boolean SR_RecognizerCheckGrammarConsistency(int recognizer, + int grammar); + private static native int SR_RecognizerPutAudio(int recognizer, byte[] buffer, int offset, + int length, boolean isLast); + private static native int SR_RecognizerAdvance(int recognizer); + // private static native void SR_RecognizerLoadUtterance(int recognizer, + // const LCHAR* filename); + // private static native void SR_RecognizerLoadWaveFile(int recognizer, + // const LCHAR* filename); + // private static native void SR_RecognizerSetLockFunction(int recognizer, + // SR_RecognizerLockFunction function, void* data); + private static native boolean SR_RecognizerIsSignalClipping(int recognizer); + private static native boolean SR_RecognizerIsSignalDCOffset(int recognizer); + private static native boolean SR_RecognizerIsSignalNoisy(int recognizer); + private static native boolean SR_RecognizerIsSignalTooQuiet(int recognizer); + private static native boolean SR_RecognizerIsSignalTooFewSamples(int recognizer); + private static native boolean SR_RecognizerIsSignalTooManySamples(int recognizer); + // private static native void SR_Recognizer_Change_Sample_Rate (size_t new_sample_rate); + + + // + // SR_Grammar native methods + // + private static native void SR_GrammarCompile(int grammar); + private static native void SR_GrammarAddWordToSlot(int grammar, String slot, + String word, String pronunciation, int weight, String tag); + private static native void SR_GrammarResetAllSlots(int grammar); + // private static native void SR_GrammarAddNametagToSlot(int grammar, String slot, + // const struct SR_Nametag_t* nametag, int weight, String tag); + private static native void SR_GrammarSetupVocabulary(int grammar, int vocabulary); + // private static native void SR_GrammarSetupModels(int grammar, SR_AcousticModels* models); + private static native void SR_GrammarSetupRecognizer(int grammar, int recognizer); + private static native void SR_GrammarUnsetupRecognizer(int grammar); + // private static native void SR_GrammarGetModels(int grammar,SR_AcousticModels** models); + private static native int SR_GrammarCreate(); + private static native void SR_GrammarDestroy(int grammar); + private static native int SR_GrammarLoad(String filename); + private static native void SR_GrammarSave(int grammar, String filename); + // private static native void SR_GrammarSetDispatchFunction(int grammar, + // const LCHAR* name, void* userData, SR_GrammarDispatchFunction function); + // private static native void SR_GrammarSetParameter(int grammar, const + // LCHAR* key, void* value); + // private static native void SR_GrammarSetSize_tParameter(int grammar, + // const LCHAR* key, size_t value); + // private static native void SR_GrammarGetParameter(int grammar, const + // LCHAR* key, void** value); + // private static native void SR_GrammarGetSize_tParameter(int grammar, + // const LCHAR* key, size_t* value); + // private static native void SR_GrammarCheckParse(int grammar, const LCHAR* + // transcription, SR_SemanticResult** result, size_t* resultCount); + private static native void SR_GrammarAllowOnly(int grammar, String transcription); + private static native void SR_GrammarAllowAll(int grammar); + + + // + // SR_Vocabulary native methods + // + // private static native int SR_VocabularyCreate(); + private static native int SR_VocabularyLoad(); + // private static native void SR_VocabularySave(SR_Vocabulary* self, + // const LCHAR* filename); + // private static native void SR_VocabularyAddWord(SR_Vocabulary* self, + // const LCHAR* word); + // private static native void SR_VocabularyGetLanguage(SR_Vocabulary* self, + // ESR_Locale* locale); + private static native void SR_VocabularyDestroy(int vocabulary); + private static native String SR_VocabularyGetPronunciation(int vocabulary, String word); + + + // + // SR_RecognizerResult native methods + // + private static native byte[] SR_RecognizerResultGetWaveform(int recognizer); + private static native int SR_RecognizerResultGetSize(int recognizer); + private static native int SR_RecognizerResultGetKeyCount(int recognizer, int nbest); + private static native String[] SR_RecognizerResultGetKeyList(int recognizer, int nbest); + private static native String SR_RecognizerResultGetValue(int recognizer, + int nbest, String key); + // private static native void SR_RecognizerResultGetLocale(int recognizer, ESR_Locale* locale); +} diff --git a/core/java/android/speech/srec/Srec.java b/core/java/android/speech/srec/Srec.java deleted file mode 100644 index a629214bf5791892b96b59019ec0f896ce4a54e4..0000000000000000000000000000000000000000 --- a/core/java/android/speech/srec/Srec.java +++ /dev/null @@ -1,162 +0,0 @@ -/*---------------------------------------------------------------------------* - * EmbeddedRecognizerImpl.java * - * * - * Copyright 2007 Nuance Communciations, Inc. * - * * - * 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 android.speech.srec; - -import java.io.IOException; - -/** - * Simple, synchronous speech recognizer, using the SREC package. - * - * @hide - */ -public class Srec -{ - private int mNative; - - - /** - * Create an instance of a SREC speech recognizer. - * @param configFile pathname of the baseline*.par configuration file. - * @throws IOException - */ - Srec(String configFile) throws IOException { - - } - - /** - * Creates a Srec recognizer. - * @param g2gFileName pathname of a g2g grammar file. - * @return - * @throws IOException - */ - public Grammar loadGrammar(String g2gFileName) throws IOException { - return null; - } - - /** - * Represents a grammar loaded into the recognizer. - */ - public class Grammar { - private int mId = -1; - - /** - * Add a word to a slot - * @param slot slot name - * @param word word - * @param pron pronunciation, or null to derive from word - * @param weight weight to give the word - * @param meaning meaning string - */ - public void addToSlot(String slot, String word, String pron, int weight, String meaning) { - - } - - /** - * Compile all slots. - */ - public void compileSlots() { - - } - - /** - * Reset all slots. - */ - public void resetAllSlots() { - - } - - /** - * Save grammar to g2g file. - * @param g2gFileName - * @throws IOException - */ - public void save(String g2gFileName) throws IOException { - - } - - /** - * Release resources associated with this grammar. - */ - public void unload() { - - } - } - - /** - * Start recognition - */ - public void start() { - - } - - /** - * Process some audio and return the next state. - * @return true if complete - */ - public boolean process() { - return false; - } - - /** - * Get the number of recognition results. - * @return - */ - public int getResultCount() { - return 0; - } - - /** - * Get a set of keys for the result. - * @param index index of result. - * @return array of keys. - */ - public String[] getResultKeys(int index) { - return null; - } - - /** - * Get a result value - * @param index index of the result. - * @param key key of the result. - * @return the result. - */ - public String getResult(int index, String key) { - return null; - } - - /** - * Reset the recognizer to the idle state. - */ - public void reset() { - - } - - /** - * Clean up resources. - */ - public void dispose() { - - } - - protected void finalize() { - - } - -} diff --git a/core/java/android/speech/srec/UlawEncoderInputStream.java b/core/java/android/speech/srec/UlawEncoderInputStream.java new file mode 100644 index 0000000000000000000000000000000000000000..132fe0273eb8269209faeb8ef3b09764d88c7e90 --- /dev/null +++ b/core/java/android/speech/srec/UlawEncoderInputStream.java @@ -0,0 +1,186 @@ +/* + * --------------------------------------------------------------------------- + * UlawEncoderInputStream.java + * + * Copyright 2008 Nuance Communciations, Inc. + * + * 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 android.speech.srec; + +import java.io.IOException; +import java.io.InputStream; + +/** + * InputStream which transforms 16 bit pcm data to ulaw data. + * + * @hide pending API council approval + */ +public final class UlawEncoderInputStream extends InputStream { + private final static String TAG = "UlawEncoderInputStream"; + + private final static int MAX_ULAW = 8192; + private final static int SCALE_BITS = 16; + + private InputStream mIn; + + private int mMax = 0; + + private final byte[] mBuf = new byte[1024]; + private int mBufCount = 0; // should be 0 or 1 + + private final byte[] mOneByte = new byte[1]; + + + public static void encode(byte[] pcmBuf, int pcmOffset, + byte[] ulawBuf, int ulawOffset, int length, int max) { + + // from 'ulaw' in wikipedia + // +8191 to +8159 0x80 + // +8158 to +4063 in 16 intervals of 256 0x80 + interval number + // +4062 to +2015 in 16 intervals of 128 0x90 + interval number + // +2014 to +991 in 16 intervals of 64 0xA0 + interval number + // +990 to +479 in 16 intervals of 32 0xB0 + interval number + // +478 to +223 in 16 intervals of 16 0xC0 + interval number + // +222 to +95 in 16 intervals of 8 0xD0 + interval number + // +94 to +31 in 16 intervals of 4 0xE0 + interval number + // +30 to +1 in 15 intervals of 2 0xF0 + interval number + // 0 0xFF + + // -1 0x7F + // -31 to -2 in 15 intervals of 2 0x70 + interval number + // -95 to -32 in 16 intervals of 4 0x60 + interval number + // -223 to -96 in 16 intervals of 8 0x50 + interval number + // -479 to -224 in 16 intervals of 16 0x40 + interval number + // -991 to -480 in 16 intervals of 32 0x30 + interval number + // -2015 to -992 in 16 intervals of 64 0x20 + interval number + // -4063 to -2016 in 16 intervals of 128 0x10 + interval number + // -8159 to -4064 in 16 intervals of 256 0x00 + interval number + // -8192 to -8160 0x00 + + // set scale factors + if (max <= 0) max = MAX_ULAW; + + int coef = MAX_ULAW * (1 << SCALE_BITS) / max; + + for (int i = 0; i < length; i++) { + int pcm = (0xff & pcmBuf[pcmOffset++]) + (pcmBuf[pcmOffset++] << 8); + pcm = (pcm * coef) >> SCALE_BITS; + + int ulaw; + if (pcm >= 0) { + ulaw = pcm <= 0 ? 0xff : + pcm <= 30 ? 0xf0 + (( 30 - pcm) >> 1) : + pcm <= 94 ? 0xe0 + (( 94 - pcm) >> 2) : + pcm <= 222 ? 0xd0 + (( 222 - pcm) >> 3) : + pcm <= 478 ? 0xc0 + (( 478 - pcm) >> 4) : + pcm <= 990 ? 0xb0 + (( 990 - pcm) >> 5) : + pcm <= 2014 ? 0xa0 + ((2014 - pcm) >> 6) : + pcm <= 4062 ? 0x90 + ((4062 - pcm) >> 7) : + pcm <= 8158 ? 0x80 + ((8158 - pcm) >> 8) : + 0x80; + } else { + ulaw = -1 <= pcm ? 0x7f : + -31 <= pcm ? 0x70 + ((pcm - -31) >> 1) : + -95 <= pcm ? 0x60 + ((pcm - -95) >> 2) : + -223 <= pcm ? 0x50 + ((pcm - -223) >> 3) : + -479 <= pcm ? 0x40 + ((pcm - -479) >> 4) : + -991 <= pcm ? 0x30 + ((pcm - -991) >> 5) : + -2015 <= pcm ? 0x20 + ((pcm - -2015) >> 6) : + -4063 <= pcm ? 0x10 + ((pcm - -4063) >> 7) : + -8159 <= pcm ? 0x00 + ((pcm - -8159) >> 8) : + 0x00; + } + ulawBuf[ulawOffset++] = (byte)ulaw; + } + } + + /** + * Compute the maximum of the absolute value of the pcm samples. + * The return value can be used to set ulaw encoder scaling. + * @param pcmBuf array containing 16 bit pcm data. + * @param offset offset of start of 16 bit pcm data. + * @param length number of pcm samples (not number of input bytes) + * @return maximum abs of pcm data values + */ + public static int maxAbsPcm(byte[] pcmBuf, int offset, int length) { + int max = 0; + for (int i = 0; i < length; i++) { + int pcm = (0xff & pcmBuf[offset++]) + (pcmBuf[offset++] << 8); + if (pcm < 0) pcm = -pcm; + if (pcm > max) max = pcm; + } + return max; + } + + /** + * Create an InputStream which takes 16 bit pcm data and produces ulaw data. + * @param in InputStream containing 16 bit pcm data. + * @param max pcm value corresponding to maximum ulaw value. + */ + public UlawEncoderInputStream(InputStream in, int max) { + mIn = in; + mMax = max; + } + + @Override + public int read(byte[] buf, int offset, int length) throws IOException { + if (mIn == null) throw new IllegalStateException("not open"); + + // return at least one byte, but try to fill 'length' + while (mBufCount < 2) { + int n = mIn.read(mBuf, mBufCount, Math.min(length * 2, mBuf.length - mBufCount)); + if (n == -1) return -1; + mBufCount += n; + } + + // compand data + int n = Math.min(mBufCount / 2, length); + encode(mBuf, 0, buf, offset, n, mMax); + + // move data to bottom of mBuf + mBufCount -= n * 2; + for (int i = 0; i < mBufCount; i++) mBuf[i] = mBuf[i + n * 2]; + + return n; + } + + @Override + public int read(byte[] buf) throws IOException { + return read(buf, 0, buf.length); + } + + @Override + public int read() throws IOException { + int n = read(mOneByte, 0, 1); + if (n == -1) return -1; + return 0xff & (int)mOneByte[0]; + } + + @Override + public void close() throws IOException { + if (mIn != null) { + InputStream in = mIn; + mIn = null; + in.close(); + } + } + + @Override + public int available() throws IOException { + return (mIn.available() + mBufCount) / 2; + } +} diff --git a/core/java/android/speech/srec/package.html b/core/java/android/speech/srec/package.html new file mode 100644 index 0000000000000000000000000000000000000000..723b30bb6e9e676814aacbaf56bd34dbe7a4a7d9 --- /dev/null +++ b/core/java/android/speech/srec/package.html @@ -0,0 +1,5 @@ + + +Simple, synchronous SREC speech recognition API. + + diff --git a/core/java/android/test/InstrumentationTestCase.java b/core/java/android/test/InstrumentationTestCase.java index 08a8ad1346777b9c99c1f1346919fcdd004ae28d..82f2ef9dd8ebb84d8c5dcc8befb90410415aa8ec 100644 --- a/core/java/android/test/InstrumentationTestCase.java +++ b/core/java/android/test/InstrumentationTestCase.java @@ -31,8 +31,7 @@ import java.lang.reflect.Modifier; import java.lang.reflect.InvocationTargetException; /** - * A test case that has access to {@link Instrumentation}. See - * InstrumentationTestRunner. + * A test case that has access to {@link Instrumentation}. */ public class InstrumentationTestCase extends TestCase { @@ -57,7 +56,13 @@ public class InstrumentationTestCase extends TestCase { } /** - * Utility method for launching an activity. + * Utility method for launching an activity. + * + *

    The {@link Intent} used to launch the Activity is: + * action = {@link Intent#ACTION_MAIN} + * extras = null, unless a custom bundle is provided here + * All other fields are null or empty. + * * @param pkg The package hosting the activity to be launched. * @param activityCls The activity class to launch. * @param extras Optional extra stuff to pass to the activity. @@ -69,20 +74,61 @@ public class InstrumentationTestCase extends TestCase { Class activityCls, Bundle extras) { Intent intent = new Intent(Intent.ACTION_MAIN); - intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - intent.setClassName(pkg, activityCls.getName()); if (extras != null) { intent.putExtras(extras); } + return launchActivityWithIntent(pkg, activityCls, intent); + } + + /** + * Utility method for launching an activity with a specific Intent. + * @param pkg The package hosting the activity to be launched. + * @param activityCls The activity class to launch. + * @param intent The intent to launch with + * @return The activity, or null if non launched. + */ + @SuppressWarnings("unchecked") + public final T launchActivityWithIntent( + String pkg, + Class activityCls, + Intent intent) { + intent.setClassName(pkg, activityCls.getName()); + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); T activity = (T) getInstrumentation().startActivitySync(intent); getInstrumentation().waitForIdleSync(); return activity; } + + /** + * Helper for running portions of a test on the UI thread. + * + * Note, in most cases it is simpler to annotate the test method with + * {@link android.test.UiThreadTest}, which will run the entire test method on the UI thread. + * Use this method if you need to switch in and out of the UI thread to perform your test. + * + * @param r runnable containing test code in the {@link Runnable#run()} method + */ + public void runTestOnUiThread(final Runnable r) throws Throwable { + final Throwable[] exceptions = new Throwable[1]; + getInstrumentation().runOnMainSync(new Runnable() { + public void run() { + try { + r.run(); + } catch (Throwable throwable) { + exceptions[0] = throwable; + } + } + }); + if (exceptions[0] != null) { + throw exceptions[0]; + } + } /** * Runs the current unit test. If the unit test is annotated with * {@link android.test.UiThreadTest}, the test is run on the UI thread. */ + @Override protected void runTest() throws Throwable { String fName = getName(); assertNotNull(fName); diff --git a/core/java/android/test/suitebuilder/annotation/LargeTest.java b/core/java/android/test/suitebuilder/annotation/LargeTest.java new file mode 100644 index 0000000000000000000000000000000000000000..a6269e787556588736a453b81d9357bd84308828 --- /dev/null +++ b/core/java/android/test/suitebuilder/annotation/LargeTest.java @@ -0,0 +1,30 @@ +/* + * 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 android.test.suitebuilder.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Marks a test that should run as part of the large tests. + */ +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.METHOD, ElementType.TYPE}) +public @interface LargeTest { +} diff --git a/core/java/android/test/suitebuilder/annotation/MediumTest.java b/core/java/android/test/suitebuilder/annotation/MediumTest.java new file mode 100644 index 0000000000000000000000000000000000000000..8afeb911d065cbdab5fe99d94ecbe1edefa87a8c --- /dev/null +++ b/core/java/android/test/suitebuilder/annotation/MediumTest.java @@ -0,0 +1,31 @@ +/* + * 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 android.test.suitebuilder.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Marks a test that should run as part of the medium tests. + * + */ +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.METHOD, ElementType.TYPE}) +public @interface MediumTest { +} diff --git a/core/java/android/test/suitebuilder/annotation/SmallTest.java b/core/java/android/test/suitebuilder/annotation/SmallTest.java new file mode 100644 index 0000000000000000000000000000000000000000..ad530e287343d6467ac87206fb7e47c4eff93818 --- /dev/null +++ b/core/java/android/test/suitebuilder/annotation/SmallTest.java @@ -0,0 +1,30 @@ +/* + * 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 android.test.suitebuilder.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Marks a test that should run as part of the small tests. + */ +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.METHOD, ElementType.TYPE}) +public @interface SmallTest { +} diff --git a/core/java/android/text/BoringLayout.java b/core/java/android/text/BoringLayout.java index 2ee4f62262a311a9a5a3398c2946b3406446f954..843754b7713c08dd227cabc21b12f0b9cb84b040 100644 --- a/core/java/android/text/BoringLayout.java +++ b/core/java/android/text/BoringLayout.java @@ -92,7 +92,7 @@ public class BoringLayout extends Layout implements TextUtils.EllipsizeCallback int ellipsizedWidth) { boolean trust; - if (ellipsize == null) { + if (ellipsize == null || ellipsize == TextUtils.TruncateAt.MARQUEE) { replaceWith(source, paint, outerwidth, align, spacingmult, spacingadd); @@ -145,7 +145,7 @@ public class BoringLayout extends Layout implements TextUtils.EllipsizeCallback boolean trust; - if (ellipsize == null) { + if (ellipsize == null || ellipsize == TextUtils.TruncateAt.MARQUEE) { mEllipsizedWidth = outerwidth; mEllipsizedStart = 0; mEllipsizedCount = 0; diff --git a/core/java/android/text/InputFilter.java b/core/java/android/text/InputFilter.java index e1563ae9fd9ac5ca81c3e96defb6e4f5d656bab4..2f55677ee24fae3bfcb487f357835f7df53bb130 100644 --- a/core/java/android/text/InputFilter.java +++ b/core/java/android/text/InputFilter.java @@ -33,6 +33,11 @@ public interface InputFilter * as this is what happens when you delete text. Also beware that * you should not attempt to make any changes to dest * from this method; you may only examine it for context. + * + * Note: If source is an instance of {@link Spanned} or + * {@link Spannable}, the span objects in the source should be + * copied into the filtered result (i.e. the non-null return value). + * {@link TextUtils#copySpansFrom} can be used for convenience. */ public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend); diff --git a/core/java/android/text/InputType.java b/core/java/android/text/InputType.java new file mode 100644 index 0000000000000000000000000000000000000000..0ffe4acaffbf60c78e705db84e91eb3d82c3723e --- /dev/null +++ b/core/java/android/text/InputType.java @@ -0,0 +1,227 @@ +package android.text; + +import android.text.TextUtils; + +/** + * Bit definitions for an integer defining the basic content type of text + * held in an {@link Editable} object. + */ +public interface InputType { + /** + * Mask of bits that determine the overall class + * of text being given. Currently supported classes are: + * {@link #TYPE_CLASS_TEXT}, {@link #TYPE_CLASS_NUMBER}, + * {@link #TYPE_CLASS_PHONE}, {@link #TYPE_CLASS_DATETIME}. + * If the class is not one you + * understand, assume {@link #TYPE_CLASS_TEXT} with NO variation + * or flags. + */ + public static final int TYPE_MASK_CLASS = 0x0000000f; + + /** + * Mask of bits that determine the variation of + * the base content class. + */ + public static final int TYPE_MASK_VARIATION = 0x00000ff0; + + /** + * Mask of bits that provide addition bit flags + * of options. + */ + public static final int TYPE_MASK_FLAGS = 0x00fff000; + + /** + * Special content type for when no explicit type has been specified. + * This should be interpreted to mean that the target input connection + * is not rich, it can not process and show things like candidate text nor + * retrieve the current text, so the input method will need to run in a + * limited "generate key events" mode. + */ + public static final int TYPE_NULL = 0x00000000; + + // ---------------------------------------------------------------------- + // ---------------------------------------------------------------------- + // ---------------------------------------------------------------------- + + /** + * Class for normal text. This class supports the following flags (only + * one of which should be set): + * {@link #TYPE_TEXT_FLAG_CAP_CHARACTERS}, + * {@link #TYPE_TEXT_FLAG_CAP_WORDS}, and. + * {@link #TYPE_TEXT_FLAG_CAP_SENTENCES}. It also supports the + * following variations: + * {@link #TYPE_TEXT_VARIATION_NORMAL}, and + * {@link #TYPE_TEXT_VARIATION_URI}. If you do not recognize the + * variation, normal should be assumed. + */ + public static final int TYPE_CLASS_TEXT = 0x00000001; + + /** + * Flag for {@link #TYPE_CLASS_TEXT}: capitalize all characters. Overrides + * {@link #TYPE_TEXT_FLAG_CAP_WORDS} and + * {@link #TYPE_TEXT_FLAG_CAP_SENTENCES}. This value is explicitly defined + * to be the same as {@link TextUtils#CAP_MODE_CHARACTERS}. + */ + public static final int TYPE_TEXT_FLAG_CAP_CHARACTERS = 0x00001000; + + /** + * Flag for {@link #TYPE_CLASS_TEXT}: capitalize first character of + * all words. Overrides {@link #TYPE_TEXT_FLAG_CAP_SENTENCES}. This + * value is explicitly defined + * to be the same as {@link TextUtils#CAP_MODE_WORDS}. + */ + public static final int TYPE_TEXT_FLAG_CAP_WORDS = 0x00002000; + + /** + * Flag for {@link #TYPE_CLASS_TEXT}: capitalize first character of + * each sentence. This value is explicitly defined + * to be the same as {@link TextUtils#CAP_MODE_SENTENCES}. + */ + public static final int TYPE_TEXT_FLAG_CAP_SENTENCES = 0x00004000; + + /** + * Flag for {@link #TYPE_CLASS_TEXT}: the user is entering free-form + * text that should have auto-correction applied to it. + */ + public static final int TYPE_TEXT_FLAG_AUTO_CORRECT = 0x00008000; + + /** + * Flag for {@link #TYPE_CLASS_TEXT}: the text editor is performing + * auto-completion of the text being entered based on its own semantics, + * which it will present to the user as they type. This generally means + * that the input method should not be showing candidates itself, but can + * expect for the editor to supply its own completions/candidates from + * {@link android.view.inputmethod.InputMethodSession#displayCompletions + * InputMethodSession.displayCompletions()} as a result of the editor calling + * {@link android.view.inputmethod.InputMethodManager#displayCompletions + * InputMethodManager.displayCompletions()}. + */ + public static final int TYPE_TEXT_FLAG_AUTO_COMPLETE = 0x00010000; + + /** + * Flag for {@link #TYPE_CLASS_TEXT}: multiple lines of text can be + * entered into the field. + */ + public static final int TYPE_TEXT_FLAG_MULTI_LINE = 0x00020000; + + // ---------------------------------------------------------------------- + + /** + * Default variation of {@link #TYPE_CLASS_TEXT}: plain old normal text. + */ + public static final int TYPE_TEXT_VARIATION_NORMAL = 0x00000000; + + /** + * Variation of {@link #TYPE_CLASS_TEXT}: entering a URI. + */ + public static final int TYPE_TEXT_VARIATION_URI = 0x00000010; + + /** + * Variation of {@link #TYPE_CLASS_TEXT}: entering an e-mail address. + */ + public static final int TYPE_TEXT_VARIATION_EMAIL_ADDRESS = 0x00000020; + + /** + * Variation of {@link #TYPE_CLASS_TEXT}: entering the subject line of + * an e-mail. + */ + public static final int TYPE_TEXT_VARIATION_EMAIL_SUBJECT = 0x00000030; + + /** + * Variation of {@link #TYPE_CLASS_TEXT}: entering the content of + * an e-mail. + */ + public static final int TYPE_TEXT_VARIATION_EMAIL_CONTENT = 0x00000040; + + /** + * Variation of {@link #TYPE_CLASS_TEXT}: entering the name of a person. + */ + public static final int TYPE_TEXT_VARIATION_PERSON_NAME = 0x00000050; + + /** + * Variation of {@link #TYPE_CLASS_TEXT}: entering a postal mailing + * address. + */ + public static final int TYPE_TEXT_VARIATION_POSTAL_ADDRESS = 0x00000060; + + /** + * Variation of {@link #TYPE_CLASS_TEXT}: entering a password. + */ + public static final int TYPE_TEXT_VARIATION_PASSWORD = 0x00000070; + + /** + * Variation of {@link #TYPE_CLASS_TEXT}: entering a search string + * for a web search. + */ + public static final int TYPE_TEXT_VARIATION_WEB_SEARCH = 0x00000080; + + /** + * Variation of {@link #TYPE_CLASS_TEXT}: entering text inside of + * a web form. + */ + public static final int TYPE_TEXT_VARIATION_WEB_EDIT_TEXT = 0x00000090; + + // ---------------------------------------------------------------------- + // ---------------------------------------------------------------------- + // ---------------------------------------------------------------------- + + /** + * Class for numeric text. This class supports the following flag: + * {@link #TYPE_NUMBER_FLAG_SIGNED} and + * {@link #TYPE_NUMBER_FLAG_DECIMAL}. + */ + public static final int TYPE_CLASS_NUMBER = 0x00000002; + + /** + * Flag of {@link #TYPE_CLASS_NUMBER}: the number is signed, allowing + * a positive or negative sign at the start. + */ + public static final int TYPE_NUMBER_FLAG_SIGNED = 0x00001000; + + /** + * Flag of {@link #TYPE_CLASS_NUMBER}: the number is decimal, allowing + * a decimal point to provide fractional values. + */ + public static final int TYPE_NUMBER_FLAG_DECIMAL = 0x00002000; + + // ---------------------------------------------------------------------- + // ---------------------------------------------------------------------- + // ---------------------------------------------------------------------- + + /** + * Class for a phone number. This class currently supports no variations + * or flags. + */ + public static final int TYPE_CLASS_PHONE = 0x00000003; + + // ---------------------------------------------------------------------- + // ---------------------------------------------------------------------- + // ---------------------------------------------------------------------- + + /** + * Class for dates and times. It supports the + * following variations: + * {@link #TYPE_DATETIME_VARIATION_NORMAL} + * {@link #TYPE_DATETIME_VARIATION_DATE}, and + * {@link #TYPE_DATETIME_VARIATION_TIME},. + */ + public static final int TYPE_CLASS_DATETIME = 0x00000004; + + /** + * Default variation of {@link #TYPE_CLASS_DATETIME}: allows entering + * both a date and time. + */ + public static final int TYPE_DATETIME_VARIATION_NORMAL = 0x00000000; + + /** + * Default variation of {@link #TYPE_CLASS_DATETIME}: allows entering + * only a date. + */ + public static final int TYPE_DATETIME_VARIATION_DATE = 0x00000010; + + /** + * Default variation of {@link #TYPE_CLASS_DATETIME}: allows entering + * only a time. + */ + public static final int TYPE_DATETIME_VARIATION_TIME = 0x00000020; +} diff --git a/core/java/android/text/LoginFilter.java b/core/java/android/text/LoginFilter.java index dd2d77ffbf1696ca11c116dfbf52b81411ddcc1b..27c703f1f083adf2fda1520be2726fd9f42d10e0 100644 --- a/core/java/android/text/LoginFilter.java +++ b/core/java/android/text/LoginFilter.java @@ -83,8 +83,21 @@ public abstract class LoginFilter implements InputFilter { } onStop(); + + if (!changed) { + return null; + } - return changed ? new String(out, 0, outidx) : null; + String s = new String(out, 0, outidx); + + if (source instanceof Spanned) { + SpannableString sp = new SpannableString(s); + TextUtils.copySpansFrom((Spanned) source, + start, end, null, sp, 0); + return sp; + } else { + return s; + } } /** diff --git a/core/java/android/text/Selection.java b/core/java/android/text/Selection.java index 0f4916ab1eb8659da214dbe9ea86e65e51b3e0fe..44469eced07e96006de7a9ff1e427e9b2742f478 100644 --- a/core/java/android/text/Selection.java +++ b/core/java/android/text/Selection.java @@ -417,10 +417,13 @@ public class Selection { } } + private static final class START { }; + private static final class END { }; + /* * Public constants */ - public static final Object SELECTION_START = new Object(); - public static final Object SELECTION_END = new Object(); + public static final Object SELECTION_START = new START(); + public static final Object SELECTION_END = new END(); } diff --git a/core/java/android/text/Spanned.java b/core/java/android/text/Spanned.java index 2b4b4d230ebd820f16fc71a0bf27736f960fc314..bd0a16b7e26fb74e43e5d9156cd45ad1d8240227 100644 --- a/core/java/android/text/Spanned.java +++ b/core/java/android/text/Spanned.java @@ -25,6 +25,12 @@ package android.text; public interface Spanned extends CharSequence { + /** + * Bitmask of bits that are relevent for controlling point/mark behavior + * of spans. + */ + public static final int SPAN_POINT_MARK_MASK = 0x33; + /** * 0-length spans with type SPAN_MARK_MARK behave like text marks: * they remain at their original offset when text is inserted @@ -91,6 +97,14 @@ extends CharSequence */ public static final int SPAN_EXCLUSIVE_INCLUSIVE = SPAN_POINT_POINT; + /** + * This flag is set on spans that are being used to apply temporary + * styling information on the composing text of an input method, so that + * they can be found and removed when the composing text is being + * replaced. + */ + public static final int SPAN_COMPOSING = 0x100; + /** * The bits numbered SPAN_USER_SHIFT and above are available * for callers to use to store scalar data associated with their diff --git a/core/java/android/text/StaticLayout.java b/core/java/android/text/StaticLayout.java index 2d185758a1ef4dfe8f4662059fb4444b22f4382a..ceb9f4fab43be89de3da6b134751c006beb0a190 100644 --- a/core/java/android/text/StaticLayout.java +++ b/core/java/android/text/StaticLayout.java @@ -907,7 +907,8 @@ extends Layout mLineDirections[j] = linedirs; - if (ellipsize != null) { + // If ellipsize is in marquee mode, do not apply ellipsis on the first line + if (ellipsize != null && (ellipsize != TextUtils.TruncateAt.MARQUEE || j != 0)) { calculateEllipsis(start, end, widths, widstart, widoff, ellipsiswidth, ellipsize, j, textwidth, paint); @@ -950,7 +951,7 @@ extends Layout ellipsisStart = 0; ellipsisCount = i; - } else if (where == TextUtils.TruncateAt.END) { + } else if (where == TextUtils.TruncateAt.END || where == TextUtils.TruncateAt.MARQUEE) { float sum = 0; int i; diff --git a/core/java/android/text/TextUtils.java b/core/java/android/text/TextUtils.java index e791aaf74681b6c5b907f781821427f701a56e10..64356d547152e1c9ef51498a9dbc226e93c42331 100644 --- a/core/java/android/text/TextUtils.java +++ b/core/java/android/text/TextUtils.java @@ -22,6 +22,7 @@ import android.content.res.ColorStateList; import android.content.res.Resources; import android.os.Parcel; import android.os.Parcelable; +import android.text.method.TextKeyListener.Capitalize; import android.text.style.AbsoluteSizeSpan; import android.text.style.AlignmentSpan; import android.text.style.BackgroundColorSpan; @@ -42,13 +43,14 @@ import android.text.style.TextAppearanceSpan; import android.text.style.TypefaceSpan; import android.text.style.URLSpan; import android.text.style.UnderlineSpan; +import android.util.Printer; + import com.android.internal.util.ArrayUtils; import java.util.regex.Pattern; import java.util.Iterator; -public class TextUtils -{ +public class TextUtils { private TextUtils() { /* cannot be instantiated */ } private static String[] EMPTY_STRING_ARRAY = new String[]{}; @@ -826,6 +828,30 @@ public class TextUtils } }; + /** + * Debugging tool to print the spans in a CharSequence. The output will + * be printed one span per line. If the CharSequence is not a Spanned, + * then the entire string will be printed on a single line. + */ + public static void dumpSpans(CharSequence cs, Printer printer, String prefix) { + if (cs instanceof Spanned) { + Spanned sp = (Spanned) cs; + Object[] os = sp.getSpans(0, cs.length(), Object.class); + + for (int i = 0; i < os.length; i++) { + Object o = os[i]; + printer.println(prefix + cs.subSequence(sp.getSpanStart(o), + sp.getSpanEnd(o)) + ": " + + Integer.toHexString(System.identityHashCode(o)) + + " " + o.getClass().getCanonicalName() + + " (" + sp.getSpanStart(o) + "-" + sp.getSpanEnd(o) + + ") fl=#" + sp.getSpanFlags(o)); + } + } else { + printer.println(prefix + cs + ": (no spans)"); + } + } + /** * Return a new CharSequence in which each of the source strings is * replaced by the corresponding element of the destinations. @@ -1021,6 +1047,7 @@ public class TextUtils START, MIDDLE, END, + MARQUEE, } public interface EllipsizeCallback { @@ -1460,7 +1487,7 @@ public class TextUtils case '&': sb.append("&"); //$NON-NLS-1$ break; - case '\\': + case '\'': sb.append("'"); //$NON-NLS-1$ break; case '"': @@ -1565,6 +1592,132 @@ public class TextUtils return true; } + /** + * Capitalization mode for {@link #getCapsMode}: capitalize all + * characters. This value is explicitly defined to be the same as + * {@link InputType#TYPE_TEXT_FLAG_CAP_CHARACTERS}. + */ + public static final int CAP_MODE_CHARACTERS + = InputType.TYPE_TEXT_FLAG_CAP_CHARACTERS; + + /** + * Capitalization mode for {@link #getCapsMode}: capitalize the first + * character of all words. This value is explicitly defined to be the same as + * {@link InputType#TYPE_TEXT_FLAG_CAP_WORDS}. + */ + public static final int CAP_MODE_WORDS + = InputType.TYPE_TEXT_FLAG_CAP_WORDS; + + /** + * Capitalization mode for {@link #getCapsMode}: capitalize the first + * character of each sentence. This value is explicitly defined to be the same as + * {@link InputType#TYPE_TEXT_FLAG_CAP_SENTENCES}. + */ + public static final int CAP_MODE_SENTENCES + = InputType.TYPE_TEXT_FLAG_CAP_SENTENCES; + + /** + * Determine what caps mode should be in effect at the current offset in + * the text. Only the mode bits set in reqModes will be + * checked. Note that the caps mode flags here are explicitly defined + * to match those in {@link InputType}. + * + * @param cs The text that should be checked for caps modes. + * @param off Location in the text at which to check. + * @param reqModes The modes to be checked: may be any combination of + * {@link #CAP_MODE_CHARACTERS}, {@link #CAP_MODE_WORDS}, and + * {@link #CAP_MODE_SENTENCES}. + * + * @return Returns the actual capitalization modes that can be in effect + * at the current position, which is any combination of + * {@link #CAP_MODE_CHARACTERS}, {@link #CAP_MODE_WORDS}, and + * {@link #CAP_MODE_SENTENCES}. + */ + public static int getCapsMode(CharSequence cs, int off, int reqModes) { + int i; + char c; + int mode = 0; + + if ((reqModes&CAP_MODE_CHARACTERS) != 0) { + mode |= CAP_MODE_CHARACTERS; + } + if ((reqModes&(CAP_MODE_WORDS|CAP_MODE_SENTENCES)) == 0) { + return mode; + } + + // Back over allowed opening punctuation. + + for (i = off; i > 0; i--) { + c = cs.charAt(i - 1); + + if (c != '"' && c != '\'' && + Character.getType(c) != Character.START_PUNCTUATION) { + break; + } + } + + // Start of paragraph, with optional whitespace. + + int j = i; + while (j > 0 && ((c = cs.charAt(j - 1)) == ' ' || c == '\t')) { + j--; + } + if (j == 0 || cs.charAt(j - 1) == '\n') { + return mode | CAP_MODE_WORDS; + } + + // Or start of word if we are that style. + + if ((reqModes&CAP_MODE_SENTENCES) == 0) { + if (i != j) mode |= CAP_MODE_WORDS; + return mode; + } + + // There must be a space if not the start of paragraph. + + if (i == j) { + return mode; + } + + // Back over allowed closing punctuation. + + for (; j > 0; j--) { + c = cs.charAt(j - 1); + + if (c != '"' && c != '\'' && + Character.getType(c) != Character.END_PUNCTUATION) { + break; + } + } + + if (j > 0) { + c = cs.charAt(j - 1); + + if (c == '.' || c == '?' || c == '!') { + // Do not capitalize if the word ends with a period but + // also contains a period, in which case it is an abbreviation. + + if (c == '.') { + for (int k = j - 2; k >= 0; k--) { + c = cs.charAt(k); + + if (c == '.') { + return mode; + } + + if (!Character.isLetter(c)) { + break; + } + } + } + + return mode | CAP_MODE_SENTENCES; + } + } + + return mode; + } + private static Object sLock = new Object(); private static char[] sTemp = null; } diff --git a/core/java/android/pim/DateFormat.java b/core/java/android/text/format/DateFormat.java similarity index 82% rename from core/java/android/pim/DateFormat.java rename to core/java/android/text/format/DateFormat.java index 802e045e2ae585e8a28a87ec75c41d30747ce141..34379781dcedf77074597955f94fc80a71f0b66d 100644 --- a/core/java/android/pim/DateFormat.java +++ b/core/java/android/text/format/DateFormat.java @@ -14,19 +14,21 @@ * limitations under the License. */ -package android.pim; +package android.text.format; import android.content.Context; import android.provider.Settings; -import android.provider.Settings.SettingNotFoundException; import android.text.SpannableStringBuilder; import android.text.Spanned; import android.text.SpannedString; +import com.android.internal.R; + import java.util.Calendar; import java.util.Date; import java.util.GregorianCalendar; import java.util.TimeZone; +import java.text.SimpleDateFormat; /** Utility class for producing strings with formatted date/time. @@ -187,12 +189,32 @@ public class DateFormat { public static final char YEAR = 'y'; /** - * @return true if the user has set the system to use a 24 hour time - * format, else false. + * Returns true if user preference is set to 24-hour format. + * @param context the context to use for the content resolver + * @return true if 24 hour time format is selected, false otherwise. */ public static boolean is24HourFormat(Context context) { String value = Settings.System.getString(context.getContentResolver(), Settings.System.TIME_12_24); + + if (value == null) { + java.text.DateFormat natural = + java.text.DateFormat.getTimeInstance( + java.text.DateFormat.LONG, + context.getResources().getConfiguration().locale); + + if (natural instanceof SimpleDateFormat) { + SimpleDateFormat sdf = (SimpleDateFormat) natural; + String pattern = sdf.toPattern(); + + if (pattern.indexOf('H') >= 0) { + return true; + } else { + return false; + } + } + } + boolean b24 = !(value == null || value.equals("12")); return b24; } @@ -205,7 +227,15 @@ public class DateFormat { */ public static final java.text.DateFormat getTimeFormat(Context context) { boolean b24 = is24HourFormat(context); - return new java.text.SimpleDateFormat(b24 ? "H:mm" : "h:mm a"); + int res; + + if (b24) { + res = R.string.twenty_four_hour_time_format; + } else { + res = R.string.twelve_hour_time_format; + } + + return new java.text.SimpleDateFormat(context.getString(res)); } /** @@ -228,13 +258,29 @@ public class DateFormat { public static final java.text.DateFormat getLongDateFormat(Context context) { String value = getDateFormatString(context); if (value.indexOf('M') < value.indexOf('d')) { - value = "MMMM dd, yyyy"; + value = context.getString(R.string.full_date_month_first); } else { - value = "dd MMMM, yyyy"; + value = context.getString(R.string.full_date_day_first); } return new java.text.SimpleDateFormat(value); } - + + /** + * Returns a {@link java.text.DateFormat} object that can format the date + * in medium form (such as Dec. 31, 1999) based on user preference. + * @param context the application context + * @return the {@link java.text.DateFormat} object that formats the date in long form. + */ + public static final java.text.DateFormat getMediumDateFormat(Context context) { + String value = getDateFormatString(context); + if (value.indexOf('M') < value.indexOf('d')) { + value = context.getString(R.string.medium_date_month_first); + } else { + value = context.getString(R.string.medium_date_day_first); + } + return new java.text.SimpleDateFormat(value); + } + /** * Gets the current date format stored as a char array. The array will contain * 3 elements ({@link #DATE}, {@link #MONTH}, and {@link #YEAR}) in the order @@ -274,15 +320,33 @@ public class DateFormat { String value = Settings.System.getString(context.getContentResolver(), Settings.System.DATE_FORMAT); if (value == null || value.length() < 6) { + /* + * No need to localize -- this is an emergency fallback in case + * the setting is missing, but it should always be set. + */ value = "MM-dd-yyyy"; } return value; } + /** + * Given a format string and a time in milliseconds since Jan 1, 1970 GMT, returns a + * CharSequence containing the requested date. + * @param inFormat the format string, as described in {@link android.text.format.DateFormat} + * @param inTimeInMillis in milliseconds since Jan 1, 1970 GMT + * @return a {@link CharSequence} containing the requested text + */ public static final CharSequence format(CharSequence inFormat, long inTimeInMillis) { return format(inFormat, new Date(inTimeInMillis)); } + /** + * Given a format string and a {@link java.util.Date} object, returns a CharSequence containing + * the requested date. + * @param inFormat the format string, as described in {@link android.text.format.DateFormat} + * @param inDate the date to format + * @return a {@link CharSequence} containing the requested text + */ public static final CharSequence format(CharSequence inFormat, Date inDate) { Calendar c = new GregorianCalendar(); @@ -291,6 +355,13 @@ public class DateFormat { return format(inFormat, c); } + /** + * Given a format string and a {@link java.util.Calendar} object, returns a CharSequence + * containing the requested date. + * @param inFormat the format string, as described in {@link android.text.format.DateFormat} + * @param inDate the date to format + * @return a {@link CharSequence} containing the requested text + */ public static final CharSequence format(CharSequence inFormat, Calendar inDate) { SpannableStringBuilder s = new SpannableStringBuilder(inFormat); int c; diff --git a/core/java/android/pim/DateUtils.java b/core/java/android/text/format/DateUtils.java similarity index 82% rename from core/java/android/pim/DateUtils.java rename to core/java/android/text/format/DateUtils.java index 2a01f125f0207907fa54245c467f8db1add8f8ae..48f65c6c3d646c58f5795fddab9dc69f479d8333 100644 --- a/core/java/android/pim/DateUtils.java +++ b/core/java/android/text/format/DateUtils.java @@ -14,25 +14,26 @@ * limitations under the License. */ -package android.pim; +package android.text.format; + +import com.android.internal.R; import android.content.Context; import android.content.res.Configuration; import android.content.res.Resources; +import android.pim.DateException; import java.util.Calendar; import java.util.Date; import java.util.GregorianCalendar; import java.util.TimeZone; -import com.android.internal.R; - /** + * This class contains various date-related utilities for creating text for things like + * elapsed time and date ranges, strings for days of the week and months, and AM/PM text etc. */ public class DateUtils { - private static final String TAG = "DateUtils"; - private static final Object sLock = new Object(); private static final int[] sDaysLong = new int[] { com.android.internal.R.string.day_of_week_long_sunday, @@ -125,9 +126,7 @@ public class DateUtils com.android.internal.R.string.am, com.android.internal.R.string.pm, }; - private static int sFirstDay; private static Configuration sLastConfig; - private static String sStatusDateFormat; private static String sStatusTimeFormat; private static String sElapsedFormatMMSS; private static String sElapsedFormatHMMSS; @@ -153,17 +152,18 @@ public class DateUtils public static final int FORMAT_NO_YEAR = 0x00008; public static final int FORMAT_SHOW_DATE = 0x00010; public static final int FORMAT_NO_MONTH_DAY = 0x00020; - public static final int FORMAT_24HOUR = 0x00040; - public static final int FORMAT_CAP_AMPM = 0x00080; - public static final int FORMAT_NO_NOON = 0x00100; - public static final int FORMAT_CAP_NOON = 0x00200; - public static final int FORMAT_NO_MIDNIGHT = 0x00400; - public static final int FORMAT_CAP_MIDNIGHT = 0x00800; - public static final int FORMAT_UTC = 0x01000; - public static final int FORMAT_ABBREV_TIME = 0x02000; - public static final int FORMAT_ABBREV_WEEKDAY = 0x04000; - public static final int FORMAT_ABBREV_MONTH = 0x08000; - public static final int FORMAT_NUMERIC_DATE = 0x10000; + public static final int FORMAT_12HOUR = 0x00040; + public static final int FORMAT_24HOUR = 0x00080; + public static final int FORMAT_CAP_AMPM = 0x00100; + public static final int FORMAT_NO_NOON = 0x00200; + public static final int FORMAT_CAP_NOON = 0x00400; + public static final int FORMAT_NO_MIDNIGHT = 0x00800; + public static final int FORMAT_CAP_MIDNIGHT = 0x01000; + public static final int FORMAT_UTC = 0x02000; + public static final int FORMAT_ABBREV_TIME = 0x04000; + public static final int FORMAT_ABBREV_WEEKDAY = 0x08000; + public static final int FORMAT_ABBREV_MONTH = 0x10000; + public static final int FORMAT_NUMERIC_DATE = 0x20000; public static final int FORMAT_ABBREV_ALL = (FORMAT_ABBREV_TIME | FORMAT_ABBREV_WEEKDAY | FORMAT_ABBREV_MONTH); public static final int FORMAT_CAP_NOON_MIDNIGHT = (FORMAT_CAP_NOON | FORMAT_CAP_MIDNIGHT); @@ -172,10 +172,6 @@ public class DateUtils // Date and time format strings that are constant and don't need to be // translated. public static final String HOUR_MINUTE_24 = "%H:%M"; - public static final String HOUR_MINUTE_AMPM = "%-l:%M%P"; - public static final String HOUR_MINUTE_CAP_AMPM = "%-l:%M%p"; - public static final String HOUR_AMPM = "%-l%P"; - public static final String HOUR_CAP_AMPM = "%-l%p"; public static final String MONTH_FORMAT = "%B"; public static final String ABBREV_MONTH_FORMAT = "%b"; public static final String NUMERIC_MONTH_FORMAT = "%m"; @@ -238,7 +234,7 @@ public class DateUtils /** * Request the full spelled-out name. - * For use with the 'abbrev' parameter of {@link #getDayOfWeekStr} and {@link #getMonthStr}. + * For use with the 'abbrev' parameter of {@link #getDayOfWeekString} and {@link #getMonthString}. * @more *

    e.g. "Sunday" or "January" */ @@ -246,7 +242,7 @@ public class DateUtils /** * Request an abbreviated version of the name. - * For use with the 'abbrev' parameter of {@link #getDayOfWeekStr} and {@link #getMonthStr}. + * For use with the 'abbrev' parameter of {@link #getDayOfWeekString} and {@link #getMonthString}. * @more *

    e.g. "Sun" or "Jan" */ @@ -254,7 +250,7 @@ public class DateUtils /** * Request a shorter abbreviated version of the name. - * For use with the 'abbrev' parameter of {@link #getDayOfWeekStr} and {@link #getMonthStr}. + * For use with the 'abbrev' parameter of {@link #getDayOfWeekString} and {@link #getMonthString}. * @more *

    e.g. "Su" or "Jan" *

    In some languages, the results returned for LENGTH_SHORT may be the same as @@ -264,7 +260,7 @@ public class DateUtils /** * Request an even shorter abbreviated version of the name. - * For use with the 'abbrev' parameter of {@link #getDayOfWeekStr} and {@link #getMonthStr}. + * For use with the 'abbrev' parameter of {@link #getDayOfWeekString} and {@link #getMonthString}. * @more *

    e.g. "M", "Tu", "Th" or "J" *

    In some languages, the results returned for LENGTH_SHORTEST may be the same as @@ -274,7 +270,7 @@ public class DateUtils /** * Request an even shorter abbreviated version of the name. - * For use with the 'abbrev' parameter of {@link #getDayOfWeekStr} and {@link #getMonthStr}. + * For use with the 'abbrev' parameter of {@link #getDayOfWeekString} and {@link #getMonthString}. * @more *

    e.g. "S", "T", "T" or "J" *

    In some languages, the results returned for LENGTH_SHORTEST may be the same as @@ -282,11 +278,10 @@ public class DateUtils */ public static final int LENGTH_SHORTEST = 50; - /** * Return a string for the day of the week. - * @param dayOfWeek One of {@link #Calendar.SUNDAY Calendar.SUNDAY}, - * {@link #Calendar.MONDAY Calendar.MONDAY}, etc. + * @param dayOfWeek One of {@link Calendar#SUNDAY Calendar.SUNDAY}, + * {@link Calendar#MONDAY Calendar.MONDAY}, etc. * @param abbrev One of {@link #LENGTH_LONG}, {@link #LENGTH_SHORT}, {@link #LENGTH_SHORTER} * or {@link #LENGTH_SHORTEST}. For forward compatibility, anything else * will return the same as {#LENGTH_MEDIUM}. @@ -308,9 +303,10 @@ public class DateUtils } /** - * Return a string for AM or PM. + * Return a localized string for AM or PM. * @param ampm Either {@link Calendar#AM Calendar.AM} or {@link Calendar#PM Calendar.PM}. * @throws IndexOutOfBoundsException if the ampm is out of bounds. + * @return Localized version of "AM" or "PM". */ public static String getAMPMString(int ampm) { Resources r = Resources.getSystem(); @@ -318,12 +314,13 @@ public class DateUtils } /** - * Return a string for the day of the week. - * @param month One of {@link #Calendar.JANUARY Calendar.JANUARY}, - * {@link #Calendar.FEBRUARY Calendar.FEBRUARY}, etc. + * Return a localized string for the day of the week. + * @param month One of {@link Calendar#JANUARY Calendar.JANUARY}, + * {@link Calendar#FEBRUARY Calendar.FEBRUARY}, etc. * @param abbrev One of {@link #LENGTH_LONG}, {@link #LENGTH_SHORT}, {@link #LENGTH_SHORTER} * or {@link #LENGTH_SHORTEST}. For forward compatibility, anything else * will return the same as {#LENGTH_MEDIUM}. + * @return Localized day of the week. */ public static String getMonthString(int month, int abbrev) { // Note that here we use sMonthsMedium for MEDIUM, SHORT and SHORTER. @@ -344,6 +341,12 @@ public class DateUtils return r.getString(list[month - Calendar.JANUARY]); } + /** + * Returns a string describing the elapsed time since startTime. + * @param startTime some time in the past. + * @return a String object containing the elapsed time. + * @see #getRelativeTimeSpanString(long, long, long) + */ public static CharSequence getRelativeTimeSpanString(long startTime) { return getRelativeTimeSpanString(startTime, System.currentTimeMillis(), MINUTE_IN_MILLIS); } @@ -363,67 +366,50 @@ public class DateUtils public static CharSequence getRelativeTimeSpanString(long time, long now, long minResolution) { Resources r = Resources.getSystem(); - // TODO: Assembling strings by hand like this is bad style for i18n. - boolean past = (now > time); - String prefix = past ? null : r.getString(com.android.internal.R.string.in); - String postfix = past ? r.getString(com.android.internal.R.string.ago) : null; - return getRelativeTimeSpanString(time, now, minResolution, prefix, postfix); - } - - public static CharSequence getRelativeTimeSpanString(long time, long now, long minResolution, - String prefix, String postfix) { - Resources r = Resources.getSystem(); - + boolean past = (now >= time); long duration = Math.abs(now - time); + int resId; + long count; if (duration < MINUTE_IN_MILLIS && minResolution < MINUTE_IN_MILLIS) { - long count = duration / SECOND_IN_MILLIS; - String singular = r.getString(com.android.internal.R.string.second); - String plural = r.getString(com.android.internal.R.string.seconds); - return pluralizedSpan(count, singular, plural, prefix, postfix); - } - - if (duration < HOUR_IN_MILLIS && minResolution < HOUR_IN_MILLIS) { - long count = duration / MINUTE_IN_MILLIS; - String singular = r.getString(com.android.internal.R.string.minute); - String plural = r.getString(com.android.internal.R.string.minutes); - return pluralizedSpan(count, singular, plural, prefix, postfix); - } - - if (duration < DAY_IN_MILLIS && minResolution < DAY_IN_MILLIS) { - long count = duration / HOUR_IN_MILLIS; - String singular = r.getString(com.android.internal.R.string.hour); - String plural = r.getString(com.android.internal.R.string.hours); - return pluralizedSpan(count, singular, plural, prefix, postfix); - } - - if (duration < WEEK_IN_MILLIS && minResolution < WEEK_IN_MILLIS) { - return getRelativeDayString(r, time, now); - } - - return dateString(time); - } - - - private static final String pluralizedSpan(long count, String singular, String plural, - String prefix, String postfix) { - StringBuilder s = new StringBuilder(); - - if (prefix != null) { - s.append(prefix); - s.append(" "); + count = duration / SECOND_IN_MILLIS; + if (past) { + resId = com.android.internal.R.plurals.num_seconds_ago; + } else { + resId = com.android.internal.R.plurals.in_num_seconds; + } + } else if (duration < HOUR_IN_MILLIS && minResolution < HOUR_IN_MILLIS) { + count = duration / MINUTE_IN_MILLIS; + if (past) { + resId = com.android.internal.R.plurals.num_minutes_ago; + } else { + resId = com.android.internal.R.plurals.in_num_minutes; + } + } else if (duration < DAY_IN_MILLIS && minResolution < DAY_IN_MILLIS) { + count = duration / HOUR_IN_MILLIS; + if (past) { + resId = com.android.internal.R.plurals.num_hours_ago; + } else { + resId = com.android.internal.R.plurals.in_num_hours; + } + } else if (duration < WEEK_IN_MILLIS && minResolution < WEEK_IN_MILLIS) { + count = duration / DAY_IN_MILLIS; + if (past) { + resId = com.android.internal.R.plurals.num_days_ago; + } else { + resId = com.android.internal.R.plurals.in_num_days; + } + } else { + // Longer than a week ago, so just show the date. + int flags = FORMAT_SHOW_DATE | FORMAT_SHOW_YEAR | FORMAT_ABBREV_MONTH; + + // We know that we won't be showing the time, so it is safe to pass + // in a null context. + return formatDateRange(null, time, time, flags); } - s.append(count); - s.append(' '); - s.append(count == 0 || count > 1 ? plural : singular); - - if (postfix != null) { - s.append(" "); - s.append(postfix); - } - - return s.toString(); + String format = r.getQuantityString(resId, (int) count); + return String.format(format, count); } /** @@ -457,12 +443,16 @@ public class DateUtils } else if (days == 0) { return r.getString(com.android.internal.R.string.today); } - - if (!past) { - return r.getString(com.android.internal.R.string.daysDurationFuturePlural, days); + + int resId; + if (past) { + resId = com.android.internal.R.plurals.num_days_ago; } else { - return r.getString(com.android.internal.R.string.daysDurationPastPlural, days); + resId = com.android.internal.R.plurals.in_num_days; } + + String format = r.getQuantityString(resId, days); + return String.format(format, days); } private static void initFormatStrings() { @@ -472,7 +462,6 @@ public class DateUtils if (sLastConfig == null || !sLastConfig.equals(cfg)) { sLastConfig = cfg; sStatusTimeFormat = r.getString(com.android.internal.R.string.status_bar_time_format); - sStatusDateFormat = r.getString(com.android.internal.R.string.status_bar_date_format); sElapsedFormatMMSS = r.getString(com.android.internal.R.string.elapsed_time_short_format_mm_ss); sElapsedFormatHMMSS = r.getString(com.android.internal.R.string.elapsed_time_short_format_h_mm_ss); } @@ -488,20 +477,11 @@ public class DateUtils initFormatStrings(); return DateFormat.format(sStatusTimeFormat, millis); } - - /** - * Format a date so it appears like it would in the status bar clock. - * @deprecated use {@link #DateFormat.getDateFormat(Context)} instead. - * @hide - */ - public static final CharSequence dateString(long startTime) { - initFormatStrings(); - return DateFormat.format(sStatusDateFormat, startTime); - } /** - * Formats an elapsed time like MM:SS or H:MM:SS + * Formats an elapsed time in the form "MM:SS" or "H:MM:SS" * for display on the call-in-progress screen. + * @param elapsedSeconds the elapsed time in seconds. */ public static String formatElapsedTime(long elapsedSeconds) { initFormatStrings(); @@ -584,7 +564,7 @@ public class DateUtils return (char) (digit + '0'); } - /* + /** * Format a date / time such that if the then is on the same day as now, it shows * just the time and if it's a different day, it shows just the date. * @@ -623,7 +603,7 @@ public class DateUtils /** * @hide - * @deprecated use {@link android.pim.Time} + * @deprecated use {@link android.text.format.Time} */ public static Calendar newCalendar(boolean zulu) { @@ -652,7 +632,7 @@ public class DateUtils /** * @hide - * @deprecated use {@link android.pim.Time} + * @deprecated use {@link android.text.format.Time} */ private static final int ctoi(String str, int index) throws DateException @@ -667,7 +647,7 @@ public class DateUtils /** * @hide - * @deprecated use {@link android.pim.Time} + * @deprecated use {@link android.text.format.Time} */ private static final int check(int lowerBound, int upperBound, int value) throws DateException @@ -681,7 +661,7 @@ public class DateUtils /** * @hide - * @deprecated use {@link android.pim.Time} + * @deprecated use {@link android.text.format.Time} * Return true if this date string is local time */ public static boolean isUTC(String s) @@ -702,7 +682,7 @@ public class DateUtils // Returns if the Z was present, meaning that the time is in UTC /** * @hide - * @deprecated use {@link android.pim.Time} + * @deprecated use {@link android.text.format.Time} */ public static boolean parseDateTime(String str, Calendar cal) throws DateException @@ -748,7 +728,7 @@ public class DateUtils * Given a timezone string which can be null, and a dateTime string, * set that time into a calendar. * @hide - * @deprecated use {@link android.pim.Time} + * @deprecated use {@link android.text.format.Time} */ public static void parseDateTime(String tz, String dateTime, Calendar out) throws DateException @@ -778,7 +758,7 @@ public class DateUtils * * @param cal the date and time to write * @hide - * @deprecated use {@link android.pim.Time} + * @deprecated use {@link android.text.format.Time} */ public static String writeDateTime(Calendar cal) { @@ -796,7 +776,7 @@ public class DateUtils * be written at the end as per RFC2445. Otherwise, the time is * considered in localtime. * @hide - * @deprecated use {@link android.pim.Time} + * @deprecated use {@link android.text.format.Time} */ public static String writeDateTime(Calendar cal, boolean zulu) { @@ -819,7 +799,7 @@ public class DateUtils * has already been called on sb to the appropriate length * which is sb.setLength(zulu ? 16 : 15) * @hide - * @deprecated use {@link android.pim.Time} + * @deprecated use {@link android.text.format.Time} */ public static String writeDateTime(Calendar cal, StringBuilder sb) { @@ -866,7 +846,7 @@ public class DateUtils /** * @hide - * @deprecated use {@link android.pim.Time} + * @deprecated use {@link android.text.format.Time} */ public static void assign(Calendar lval, Calendar rval) { @@ -876,8 +856,31 @@ public class DateUtils } /** - * Creates a string describing a date/time range. The flags argument - * is a bitmask of options from the following list: + * Formats a date or a time range according to the local conventions. + * + *

    + * Example output strings (date formats in these examples are shown using + * the US date format convention but that may change depending on the + * local settings): + *

      + *
    • 10:15am
    • + *
    • 3:00pm - 4:00pm
    • + *
    • 3pm - 4pm
    • + *
    • 3PM - 4PM
    • + *
    • 08:00 - 17:00
    • + *
    • Oct 9
    • + *
    • Tue, Oct 9
    • + *
    • October 9, 2007
    • + *
    • Oct 9 - 10
    • + *
    • Oct 9 - 10, 2007
    • + *
    • Oct 28 - Nov 3, 2007
    • + *
    • Dec 31, 2007 - Jan 1, 2008
    • + *
    • Oct 9, 8:00am - Oct 10, 5:00pm
    • + *
    • 12/31/2007 - 01/01/2008
    • + *
    + * + *

    + * The flags argument is a bitmask of options from the following list: * *

      *
    • FORMAT_SHOW_TIME
    • @@ -886,6 +889,7 @@ public class DateUtils *
    • FORMAT_NO_YEAR
    • *
    • FORMAT_SHOW_DATE
    • *
    • FORMAT_NO_MONTH_DAY
    • + *
    • FORMAT_12HOUR
    • *
    • FORMAT_24HOUR
    • *
    • FORMAT_CAP_AMPM
    • *
    • FORMAT_NO_NOON
    • @@ -946,15 +950,25 @@ public class DateUtils * shown instead of "midnight". * *

      + * If FORMAT_12HOUR is set and the time is shown, then the time is + * shown in the 12-hour time format. You should not normally set this. + * Instead, let the time format be chosen automatically according to the + * system settings. If both FORMAT_12HOUR and FORMAT_24HOUR are set, then + * FORMAT_24HOUR takes precedence. + * + *

      * If FORMAT_24HOUR is set and the time is shown, then the time is - * shown in the 24-hour time format. + * shown in the 24-hour time format. You should not normally set this. + * Instead, let the time format be chosen automatically according to the + * system settings. If both FORMAT_12HOUR and FORMAT_24HOUR are set, then + * FORMAT_24HOUR takes precedence. * *

      * If FORMAT_UTC is set, then the UTC timezone is used for the start * and end milliseconds. * *

      - * If FORMAT_ABBREV_TIME is set and FORMAT_24HOUR is not set, then the + * If FORMAT_ABBREV_TIME is set and 12-hour time format is used, then the * start and end times (if shown) are abbreviated by not showing the minutes * if they are zero. For example, instead of "3:00pm" the time would be * abbreviated to "3pm". @@ -976,30 +990,15 @@ public class DateUtils * instead of using the name of the month. For example, "12/31/2008" * instead of "December 31, 2008". * - *

      - * Example output strings: - *

        - *
      • 10:15am
      • - *
      • 3:00pm - 4:00pm
      • - *
      • 3pm - 4pm
      • - *
      • 3PM - 4PM
      • - *
      • 08:00 - 17:00
      • - *
      • Oct 9
      • - *
      • Tue, Oct 9
      • - *
      • October 9, 2007
      • - *
      • Oct 9 - 10
      • - *
      • Oct 9 - 10, 2007
      • - *
      • Oct 28 - Nov 3, 2007
      • - *
      • Dec 31, 2007 - Jan 1, 2008
      • - *
      • Oct 9, 8:00am - Oct 10, 5:00pm
      • - *
      + * @param context the context is required only if the time is shown * @param startMillis the start time in UTC milliseconds * @param endMillis the end time in UTC milliseconds * @param flags a bit mask of options * - * @return a string with the formatted date/time range. + * @return a string containing the formatted date/time range. */ - public static String formatDateRange(long startMillis, long endMillis, int flags) { + public static String formatDateRange(Context context, long startMillis, + long endMillis, int flags) { Resources res = Resources.getSystem(); boolean showTime = (flags & FORMAT_SHOW_TIME) != 0; boolean showWeekDay = (flags & FORMAT_SHOW_WEEKDAY) != 0; @@ -1008,7 +1007,6 @@ public class DateUtils boolean useUTC = (flags & FORMAT_UTC) != 0; boolean abbrevWeekDay = (flags & FORMAT_ABBREV_WEEKDAY) != 0; boolean abbrevMonth = (flags & FORMAT_ABBREV_MONTH) != 0; - boolean use24Hour = (flags & FORMAT_24HOUR) != 0; boolean noMonthDay = (flags & FORMAT_NO_MONTH_DAY) != 0; boolean numericDate = (flags & FORMAT_NUMERIC_DATE) != 0; @@ -1039,7 +1037,7 @@ public class DateUtils // the end of Nov 11?). // If we are not showing the time then also adjust the end date // for multiple-day events. This is to allow us to display, for - // example, "Nov 10 -11" for an event with an start date of Nov 10 + // example, "Nov 10 -11" for an event with a start date of Nov 10 // and an end date of Nov 12 at 00:00. // If the start and end time are the same, then skip this and don't // adjust the date. @@ -1075,6 +1073,16 @@ public class DateUtils if (showTime) { String startTimeFormat = ""; String endTimeFormat = ""; + boolean force24Hour = (flags & FORMAT_24HOUR) != 0; + boolean force12Hour = (flags & FORMAT_12HOUR) != 0; + boolean use24Hour; + if (force24Hour) { + use24Hour = true; + } else if (force12Hour) { + use24Hour = false; + } else { + use24Hour = DateFormat.is24HourFormat(context); + } if (use24Hour) { startTimeFormat = HOUR_MINUTE_24; endTimeFormat = HOUR_MINUTE_24; @@ -1090,28 +1098,28 @@ public class DateUtils boolean endOnTheHour = endDate.minute == 0 && endDate.second == 0; if (abbrevTime && startOnTheHour) { if (capAMPM) { - startTimeFormat = HOUR_CAP_AMPM; + startTimeFormat = res.getString(com.android.internal.R.string.hour_cap_ampm); } else { - startTimeFormat = HOUR_AMPM; + startTimeFormat = res.getString(com.android.internal.R.string.hour_ampm); } } else { if (capAMPM) { - startTimeFormat = HOUR_MINUTE_CAP_AMPM; + startTimeFormat = res.getString(com.android.internal.R.string.hour_minute_cap_ampm); } else { - startTimeFormat = HOUR_MINUTE_AMPM; + startTimeFormat = res.getString(com.android.internal.R.string.hour_minute_ampm); } } if (abbrevTime && endOnTheHour) { if (capAMPM) { - endTimeFormat = HOUR_CAP_AMPM; + endTimeFormat = res.getString(com.android.internal.R.string.hour_cap_ampm); } else { - endTimeFormat = HOUR_AMPM; + endTimeFormat = res.getString(com.android.internal.R.string.hour_ampm); } } else { if (capAMPM) { - endTimeFormat = HOUR_MINUTE_CAP_AMPM; + endTimeFormat = res.getString(com.android.internal.R.string.hour_minute_cap_ampm); } else { - endTimeFormat = HOUR_MINUTE_AMPM; + endTimeFormat = res.getString(com.android.internal.R.string.hour_minute_ampm); } } @@ -1345,64 +1353,118 @@ public class DateUtils return dateRange; } + /** + * Formats a date or a time according to the local conventions. There are + * lots of options that allow the caller to control, for example, if the + * time is shown, if the day of the week is shown, if the month name is + * abbreviated, if noon is shown instead of 12pm, and so on. For the + * complete list of options, see the documentation for + * {@link #formatDateRange}. + *

      + * Example output strings (date formats in these examples are shown using + * the US date format convention but that may change depending on the + * local settings): + *

        + *
      • 10:15am
      • + *
      • 3:00pm
      • + *
      • 3pm
      • + *
      • 3PM
      • + *
      • 08:00
      • + *
      • 17:00
      • + *
      • noon
      • + *
      • Noon
      • + *
      • midnight
      • + *
      • Midnight
      • + *
      • Oct 31
      • + *
      • Oct 31, 2007
      • + *
      • October 31, 2007
      • + *
      • 10am, Oct 31
      • + *
      • 17:00, Oct 31
      • + *
      • Wed
      • + *
      • Wednesday
      • + *
      • 10am, Wed, Oct 31
      • + *
      • Wed, Oct 31
      • + *
      • Wednesday, Oct 31
      • + *
      • Wed, Oct 31, 2007
      • + *
      • Wed, October 31
      • + *
      • 10/31/2007
      • + *
      + * + * @param context the context is required only if the time is shown + * @param millis a point in time in UTC milliseconds + * @param flags a bit mask of formatting options + * @return a string containing the formatted date/time. + */ + public static String formatDateTime(Context context, long millis, int flags) { + return formatDateRange(context, millis, millis, flags); + } + /** * @return a relative time string to display the time expressed by millis. Times * are counted starting at midnight, which means that assuming that the current * time is March 31st, 0:30: - * "millis=0:10 today" will be displayed as "0:10" - * "millis=11:30pm the day before" will be displayed as "Mar 30" - * A similar scheme is used to dates that are a week, a month or more than a year old. + *
        + *
      • "millis=0:10 today" will be displayed as "0:10"
      • + *
      • "millis=11:30pm the day before" will be displayed as "Mar 30"
      • + *
      + * If the given millis is in a different year, then the full date is + * returned in numeric format (e.g., "10/12/2008"). * * @param withPreposition If true, the string returned will include the correct - * preposition ("at 9:20am", "in 2008" or "on May 29"). + * preposition ("at 9:20am", "on 10/12/2008" or "on May 29"). */ public static CharSequence getRelativeTimeSpanString(Context c, long millis, boolean withPreposition) { - long span = System.currentTimeMillis() - millis; + long now = System.currentTimeMillis(); + long span = now - millis; Resources res = c.getResources(); if (sNowTime == null) { sNowTime = new Time(); sThenTime = new Time(); - sMonthDayFormat = res.getString(com.android.internal.R.string.abbrev_month_day); } - sNowTime.setToNow(); + sNowTime.set(now); sThenTime.set(millis); + String result; + int prepositionId; if (span < DAY_IN_MILLIS && sNowTime.weekDay == sThenTime.weekDay) { // Same day - return getPrepositionDate(res, sThenTime, R.string.preposition_for_time, - HOUR_MINUTE_CAP_AMPM, withPreposition); + int flags = FORMAT_SHOW_TIME; + result = formatDateRange(c, millis, millis, flags); + prepositionId = R.string.preposition_for_time; } else if (sNowTime.year != sThenTime.year) { // Different years - // TODO: take locale into account so that the display will adjust correctly. - return getPrepositionDate(res, sThenTime, R.string.preposition_for_year, - NUMERIC_MONTH_FORMAT + "/" + MONTH_DAY_FORMAT + "/" + YEAR_FORMAT_TWO_DIGITS, - withPreposition); + int flags = FORMAT_SHOW_DATE | FORMAT_SHOW_YEAR | FORMAT_NUMERIC_DATE; + result = formatDateRange(c, millis, millis, flags); + + // This is a date (like "10/31/2008" so use the date preposition) + prepositionId = R.string.preposition_for_date; } else { // Default - return getPrepositionDate(res, sThenTime, R.string.preposition_for_date, - sMonthDayFormat, withPreposition); + int flags = FORMAT_SHOW_DATE | FORMAT_ABBREV_MONTH; + result = formatDateRange(c, millis, millis, flags); + prepositionId = R.string.preposition_for_date; } + if (withPreposition) { + result = res.getString(prepositionId, result); + } + return result; } /** - * @return A date string suitable for display based on the format and including the - * date preposition if withPreposition is true. + * Convenience function to return relative time string without preposition. + * @param c context for resources + * @param millis time in milliseconds + * @return {@link CharSequence} containing relative time. + * @see #getRelativeTimeSpanString(Context, long, boolean) */ - private static String getPrepositionDate(Resources res, Time thenTime, int id, - String formatString, boolean withPreposition) { - String result = thenTime.format(formatString); - return withPreposition ? res.getString(id, result) : result; - } - public static CharSequence getRelativeTimeSpanString(Context c, long millis) { return getRelativeTimeSpanString(c, millis, false /* no preposition */); } private static Time sNowTime; private static Time sThenTime; - private static String sMonthDayFormat; } diff --git a/core/java/android/content/Formatter.java b/core/java/android/text/format/Formatter.java similarity index 71% rename from core/java/android/content/Formatter.java rename to core/java/android/text/format/Formatter.java index 8ad9f40f9a680ae13bbd92f116a786d4e08b93f3..1b30aa0a218c3ee72048d5051a6ab7aa63bf9646 100644 --- a/core/java/android/content/Formatter.java +++ b/core/java/android/text/format/Formatter.java @@ -14,18 +14,18 @@ * limitations under the License. */ -package android.content; +package android.text.format; + +import android.content.Context; /** * Utility class to aid in formatting common values that are not covered - * by the standard java.util.Formatter - * @hide + * by the standard java.util.Formatter. */ public final class Formatter { /** - * Formats a content size to be in the form of bytes, kilobytes, - * megabytes, etc + * Formats a content size to be in the form of bytes, kilobytes, megabytes, etc * * @param context Context to use to load the localized units * @param number size value to be formated @@ -63,4 +63,21 @@ public final class Formatter { } return String.format("%.0f%s", result, context.getText(suffix).toString()); } + + /** + * Returns a string in the canonical IP format ###.###.###.### from a packed integer containing + * the IP address. The IP address is expected to be in little-endian format (LSB first). That + * is, 0x01020304 will return "4.3.2.1". + * + * @param addr the IP address as a packed integer with LSB first. + * @return string with canonical IP address format. + */ + public static String formatIpAddress(int addr) { + StringBuffer buf = new StringBuffer(); + buf.append(addr & 0xff).append('.'). + append((addr >>>= 8) & 0xff).append('.'). + append((addr >>>= 8) & 0xff).append('.'). + append((addr >>>= 8) & 0xff); + return buf.toString(); + } } diff --git a/core/java/android/pim/Time.java b/core/java/android/text/format/Time.java similarity index 64% rename from core/java/android/pim/Time.java rename to core/java/android/text/format/Time.java index 59ba87b48368d95448ecda30c8214a071274ecaa..5bf9b205a6c68580f520bcfc3ad37dc5fbdf68e6 100644 --- a/core/java/android/pim/Time.java +++ b/core/java/android/text/format/Time.java @@ -14,15 +14,14 @@ * limitations under the License. */ -package android.pim; - +package android.text.format; +import android.content.res.Resources; +import java.util.Locale; import java.util.TimeZone; /** - * {@hide} - * * The Time class is a faster replacement for the java.util.Calendar and * java.util.GregorianCalendar classes. An instance of the Time class represents * a moment in time, specified with second precision. It is modelled after @@ -30,6 +29,10 @@ import java.util.TimeZone; * functionality. */ public class Time { + private static final String Y_M_D_T_H_M_S_000 = "%Y-%m-%dT%H:%M:%S.000"; + private static final String Y_M_D_T_H_M_S_000_Z = "%Y-%m-%dT%H:%M:%S.000Z"; + private static final String Y_M_D = "%Y-%m-%d"; + public static final String TIMEZONE_UTC = "UTC"; /** @@ -90,6 +93,7 @@ public class Time { *
    • positive - in dst
    • *
    • 0 - not in dst
    • *
    • negative - unknown
    • + *
    */ public int isDst; @@ -125,9 +129,26 @@ public class Time { public static final int FRIDAY = 5; public static final int SATURDAY = 6; + /* + * The Locale for which date formatting strings have been loaded. + */ + private static Locale sLocale; + private static String[] sShortMonths; + private static String[] sLongMonths; + private static String[] sShortWeekdays; + private static String[] sLongWeekdays; + private static String sTimeOnlyFormat; + private static String sDateOnlyFormat; + private static String sDateTimeFormat; + private static String sAm; + private static String sPm; + private static String sDateCommand = "%a %b %e %H:%M:%S %Z %Y"; + /** * Construct a Time object in the timezone named by the string * argument "timezone". The time is initialized to Jan 1, 1970. + * @param timezone string containing the timezone to use. + * @see TimeZone */ public Time(String timezone) { if (timezone == null) { @@ -142,7 +163,7 @@ public class Time { } /** - * Construct a Time object in the local timezone. The time is initialized to + * Construct a Time object in the default timezone. The time is initialized to * Jan 1, 1970. */ public Time() { @@ -191,6 +212,8 @@ public class Time { * Return the maximum possible value for the given field given the value of * the other fields. Requires that it be normalized for MONTH_DAY and * YEAR_DAY. + * @param field one of the constants for HOUR, MINUTE, SECOND, etc. + * @return the maximum value for the field. */ public int getActualMaximum(int field) { switch (field) { @@ -230,6 +253,7 @@ public class Time { /** * Clears all values, setting the timezone to the given timezone. Sets isDst * to a negative value to mean "unknown". + * @param timezone the timezone to use. */ public void clear(String timezone) { if (timezone == null) { @@ -259,8 +283,76 @@ public class Time { * Print the current value given the format string provided. See man * strftime for what means what. The final string must be less than 256 * characters. - */ - native public String format(String format); + * @param format a string containing the desired format. + * @return a String containing the current time expressed in the current locale. + */ + public String format(String format) { + synchronized (Time.class) { + Locale locale = Locale.getDefault(); + + if (sLocale == null || locale == null || !(locale.equals(sLocale))) { + Resources r = Resources.getSystem(); + + sShortMonths = new String[] { + r.getString(com.android.internal.R.string.month_medium_january), + r.getString(com.android.internal.R.string.month_medium_february), + r.getString(com.android.internal.R.string.month_medium_march), + r.getString(com.android.internal.R.string.month_medium_april), + r.getString(com.android.internal.R.string.month_medium_may), + r.getString(com.android.internal.R.string.month_medium_june), + r.getString(com.android.internal.R.string.month_medium_july), + r.getString(com.android.internal.R.string.month_medium_august), + r.getString(com.android.internal.R.string.month_medium_september), + r.getString(com.android.internal.R.string.month_medium_october), + r.getString(com.android.internal.R.string.month_medium_november), + r.getString(com.android.internal.R.string.month_medium_december), + }; + sLongMonths = new String[] { + r.getString(com.android.internal.R.string.month_long_january), + r.getString(com.android.internal.R.string.month_long_february), + r.getString(com.android.internal.R.string.month_long_march), + r.getString(com.android.internal.R.string.month_long_april), + r.getString(com.android.internal.R.string.month_long_may), + r.getString(com.android.internal.R.string.month_long_june), + r.getString(com.android.internal.R.string.month_long_july), + r.getString(com.android.internal.R.string.month_long_august), + r.getString(com.android.internal.R.string.month_long_september), + r.getString(com.android.internal.R.string.month_long_october), + r.getString(com.android.internal.R.string.month_long_november), + r.getString(com.android.internal.R.string.month_long_december), + }; + sShortWeekdays = new String[] { + r.getString(com.android.internal.R.string.day_of_week_medium_sunday), + r.getString(com.android.internal.R.string.day_of_week_medium_monday), + r.getString(com.android.internal.R.string.day_of_week_medium_tuesday), + r.getString(com.android.internal.R.string.day_of_week_medium_wednesday), + r.getString(com.android.internal.R.string.day_of_week_medium_thursday), + r.getString(com.android.internal.R.string.day_of_week_medium_friday), + r.getString(com.android.internal.R.string.day_of_week_medium_saturday), + }; + sLongWeekdays = new String[] { + r.getString(com.android.internal.R.string.day_of_week_long_sunday), + r.getString(com.android.internal.R.string.day_of_week_long_monday), + r.getString(com.android.internal.R.string.day_of_week_long_tuesday), + r.getString(com.android.internal.R.string.day_of_week_long_wednesday), + r.getString(com.android.internal.R.string.day_of_week_long_thursday), + r.getString(com.android.internal.R.string.day_of_week_long_friday), + r.getString(com.android.internal.R.string.day_of_week_long_saturday), + }; + sTimeOnlyFormat = r.getString(com.android.internal.R.string.time_of_day); + sDateOnlyFormat = r.getString(com.android.internal.R.string.month_day_year); + sDateTimeFormat = r.getString(com.android.internal.R.string.date_and_time); + sAm = r.getString(com.android.internal.R.string.am); + sPm = r.getString(com.android.internal.R.string.pm); + + sLocale = locale; + } + + return format1(format); + } + } + + native private String format1(String format); /** * Return the current time in YYYYMMDDTHHMMSS format @@ -269,33 +361,79 @@ public class Time { native public String toString(); /** - * Parse a time in the current zone in YYYYMMDDTHHMMSS format. - */ - native public void parse(String s); - - /** - * Parse a time in RFC 2445 format. Returns whether or not the time is in - * UTC (ends with Z). + * Parses a date-time string in either the RFC 2445 format or an abbreviated + * format that does not include the "time" field. For example, all of the + * following strings are valid: + * + *
      + *
    • "20081013T160000Z"
    • + *
    • "20081013T160000"
    • + *
    • "20081013"
    • + *
    + * + * Returns whether or not the time is in UTC (ends with Z). If the string + * ends with "Z" then the timezone is set to UTC. If the date-time string + * included only a date and no time field, then the allDay + * field of this Time class is set to true and the hour, + * minute, and second fields are set to zero; + * otherwise (a time field was included in the date-time string) + * allDay is set to false. The fields weekDay, + * yearDay, and gmtoff are always set to zero, + * and the field isDst is set to -1 (unknown). To set those + * fields, call {@link #normalize(boolean)} after parsing. + * + * To parse a date-time string and convert it to UTC milliseconds, do + * something like this: + * + *
    +     *   Time time = new Time();
    +     *   String date = "20081013T160000Z";
    +     *   time.parse(date);
    +     *   long millis = time.normalize(false);
    +     * 
    * * @param s the string to parse * @return true if the resulting time value is in UTC time */ - public boolean parse2445(String s) { - if (nativeParse2445(s)) { + public boolean parse(String s) { + if (nativeParse(s)) { timezone = TIMEZONE_UTC; return true; } return false; } - native private boolean nativeParse2445(String s); + /** + * Parse a time in the current zone in YYYYMMDDTHHMMSS format. + */ + native private boolean nativeParse(String s); /** * Parse a time in RFC 3339 format. This method also parses simple dates - * (that is, strings that contain no time or time offset). If the string - * contains a time and time offset, then the time offset will be used to - * convert the time value to UTC. + * (that is, strings that contain no time or time offset). For example, + * all of the following strings are valid: + * + *
      + *
    • "2008-10-13T16:00:00.000Z"
    • + *
    • "2008-10-13T16:00:00.000+07:00"
    • + *
    • "2008-10-13T16:00:00.000-07:00"
    • + *
    • "2008-10-13"
    • + *
    + * + *

    + * If the string contains a time and time offset, then the time offset will + * be used to convert the time value to UTC. + *

    + * + *

    + * If the given string contains just a date (with no time field), then + * the {@link #allDay} field is set to true and the {@link #hour}, + * {@link #minute}, and {@link #second} fields are set to zero. + *

    + * + *

    * Returns true if the resulting time value is in UTC time. + *

    * * @param s the string to parse * @return true if the resulting time value is in UTC time @@ -408,8 +546,8 @@ public class Time { } /** - * Set the fields. Sets weekDay, yearDay and gmtoff to 0. Call - * normalize() if you need those. + * Sets the fields. Sets weekDay, yearDay and gmtoff to 0, and isDst to -1. + * Call {@link #normalize(boolean)} if you need those. */ public void set(int second, int minute, int hour, int monthDay, int month, int year) { this.allDay = false; @@ -425,6 +563,15 @@ public class Time { this.gmtoff = 0; } + /** + * Sets the date from the given fields. Also sets allDay to true. + * Sets weekDay, yearDay and gmtoff to 0, and isDst to -1. + * Call {@link #normalize(boolean)} if you need those. + * + * @param monthDay the day of the month (in the range [1,31]) + * @param month the zero-based month number (in the range [0,11]) + * @param year the year + */ public void set(int monthDay, int month, int year) { this.allDay = true; this.second = 0; @@ -439,10 +586,25 @@ public class Time { this.gmtoff = 0; } + /** + * Returns true if the time represented by this Time object occurs before + * the given time. + * + * @param that a given Time object to compare against + * @return true if this time is less than the given time + */ public boolean before(Time that) { return Time.compare(this, that) < 0; } + + /** + * Returns true if the time represented by this Time object occurs after + * the given time. + * + * @param that a given Time object to compare against + * @return true if this time is greater than the given time + */ public boolean after(Time that) { return Time.compare(this, that) > 0; } @@ -459,14 +621,18 @@ public class Time { * object must already be normalized because this method uses the * yearDay and weekDay fields. * + *

    * In IS0 8601, weeks start on Monday. * The first week of the year (week 1) is defined by ISO 8601 as the * first week with four or more of its days in the starting year. * Or equivalently, the week containing January 4. Or equivalently, * the week with the year's first Thursday in it. + *

    * + *

    * The week number can be calculated by counting Thursdays. Week N * contains the Nth Thursday of the year. + *

    * * @return the ISO week number. */ @@ -486,13 +652,24 @@ public class Time { return temp.yearDay / 7 + 1; } + /** + * Return a string in the RFC 3339 format. + *

    + * If allDay is true, expresses the time as Y-M-D

    + *

    + * Otherwise, if the timezone is UTC, expresses the time as Y-M-D-T-H-M-S UTC

    + *

    + * Otherwise the time is expressed the time as Y-M-D-T-H-M-S +- GMT

    + * @param allDay + * @return string in the RFC 3339 format. + */ public String format3339(boolean allDay) { if (allDay) { - return format("%Y-%m-%d"); + return format(Y_M_D); } else if (TIMEZONE_UTC.equals(timezone)) { - return format("%Y-%m-%dT%H:%M:%S.000Z"); + return format(Y_M_D_T_H_M_S_000_Z); } else { - String base = format("%Y-%m-%dT%H:%M:%S.000"); + String base = format(Y_M_D_T_H_M_S_000); String sign = (gmtoff < 0) ? "-" : "+"; int offset = (int)Math.abs(gmtoff); int minutes = (offset % 3600) / 60; @@ -502,6 +679,13 @@ public class Time { } } + /** + * Returns true if the day of the given time is the epoch on the Julian Calendar + * (January 1, 1970 on the Gregorian calendar). + * + * @param time the time to test + * @return true if epoch. + */ public static boolean isEpoch(Time time) { long millis = time.toMillis(true); return getJulianDay(millis, 0) == EPOCH_JULIAN_DAY; @@ -536,6 +720,7 @@ public class Time { * GMT offset than whatever is currently stored in this Time object anyway. * After this method returns all the fields will be normalized and the time * will be set to 12am at the beginning of the given Julian day. + *

    * *

    * The only exception to this is if 12am does not exist for that day because @@ -543,6 +728,7 @@ public class Time { * hour at 12am on April 25, 2008 and there are a few other places that * also change daylight saving time at 12am. In those cases, the time * will be set to 1am. + *

    * * @param julianDay the Julian day in the timezone for this Time object * @return the UTC milliseconds for the beginning of the Julian day diff --git a/core/java/android/text/method/ArrowKeyMovementMethod.java b/core/java/android/text/method/ArrowKeyMovementMethod.java index ac2e499c4a8c9bc1ca058fa5ddde6627be4f5c1b..652413eb168ab76c1c858ece5393f295e3284fb2 100644 --- a/core/java/android/text/method/ArrowKeyMovementMethod.java +++ b/core/java/android/text/method/ArrowKeyMovementMethod.java @@ -155,34 +155,11 @@ implements MovementMethod return false; } - public boolean onTrackballEvent(TextView widget, Spannable buffer, - MotionEvent event) { - boolean handled = false; - int x = (int) event.getX(); - int y = (int) event.getY(); - - for (; y < 0; y++) { - handled |= up(widget, buffer); - } - for (; y > 0; y--) { - handled |= down(widget, buffer); - } - - for (; x < 0; x++) { - handled |= left(widget, buffer); - } - for (; x > 0; x--) { - handled |= right(widget, buffer); - } - - if (handled) { - MetaKeyKeyListener.adjustMetaAfterKeypress(buffer); - MetaKeyKeyListener.resetLockedMeta(buffer); - } - - return handled; + public boolean onTrackballEvent(TextView widget, Spannable text, + MotionEvent event) { + return false; } - + public boolean onTouchEvent(TextView widget, Spannable buffer, MotionEvent event) { boolean handled = Touch.onTouchEvent(widget, buffer, event); diff --git a/core/java/android/text/method/BaseKeyListener.java b/core/java/android/text/method/BaseKeyListener.java index 3e92b7b5ae6f7b38ecc75e21d66fa16340f637fe..a875368834490469bd33d0757210588dfb2121bc 100644 --- a/core/java/android/text/method/BaseKeyListener.java +++ b/core/java/android/text/method/BaseKeyListener.java @@ -18,9 +18,9 @@ package android.text.method; import android.view.KeyEvent; import android.view.View; -import android.os.Message; -import android.util.Log; +import android.text.InputType; import android.text.*; +import android.text.method.TextKeyListener.Capitalize; import android.widget.TextView; public abstract class BaseKeyListener @@ -99,6 +99,25 @@ implements KeyListener { return true; } + static int makeTextContentType(Capitalize caps, boolean autoText) { + int contentType = InputType.TYPE_CLASS_TEXT; + switch (caps) { + case CHARACTERS: + contentType |= InputType.TYPE_TEXT_FLAG_CAP_CHARACTERS; + break; + case WORDS: + contentType |= InputType.TYPE_TEXT_FLAG_CAP_WORDS; + break; + case SENTENCES: + contentType |= InputType.TYPE_TEXT_FLAG_CAP_SENTENCES; + break; + } + if (autoText) { + contentType |= InputType.TYPE_TEXT_FLAG_AUTO_CORRECT; + } + return contentType; + } + public boolean onKeyDown(View view, Editable content, int keyCode, KeyEvent event) { if (keyCode == KeyEvent.KEYCODE_DEL) { diff --git a/core/java/android/text/method/CharacterPickerDialog.java b/core/java/android/text/method/CharacterPickerDialog.java index d787132fa9d4dd3bbc45b9b9439fa00873093b67..3c4067511804970c62fa97f255e2d7f1941e31a3 100644 --- a/core/java/android/text/method/CharacterPickerDialog.java +++ b/core/java/android/text/method/CharacterPickerDialog.java @@ -69,7 +69,7 @@ public class CharacterPickerDialog extends Dialog WindowManager.LayoutParams params = getWindow().getAttributes(); params.token = mView.getApplicationWindowToken(); - params.type = params.TYPE_APPLICATION_PANEL; + params.type = params.TYPE_APPLICATION_ATTACHED_DIALOG; setTitle(R.string.select_character); setContentView(R.layout.character_picker); diff --git a/core/java/android/text/method/DateKeyListener.java b/core/java/android/text/method/DateKeyListener.java index 0ca0332540f79635a8adbb54c4723bca131012f0..7c114344537e34cc0471b4e92249563a0b8f4d7d 100644 --- a/core/java/android/text/method/DateKeyListener.java +++ b/core/java/android/text/method/DateKeyListener.java @@ -17,12 +17,18 @@ package android.text.method; import android.view.KeyEvent; +import android.text.InputType; /** * For entering dates in a text field. */ public class DateKeyListener extends NumberKeyListener { + public int getInputType() { + return InputType.TYPE_CLASS_DATETIME + | InputType.TYPE_DATETIME_VARIATION_DATE; + } + @Override protected char[] getAcceptedChars() { diff --git a/core/java/android/text/method/DateTimeKeyListener.java b/core/java/android/text/method/DateTimeKeyListener.java index 304d3261b043fcb881ba927452cf495e939a9b17..f8ebc406719e38ceda982e24d5661851dd498257 100644 --- a/core/java/android/text/method/DateTimeKeyListener.java +++ b/core/java/android/text/method/DateTimeKeyListener.java @@ -16,6 +16,7 @@ package android.text.method; +import android.text.InputType; import android.view.KeyEvent; /** @@ -23,6 +24,11 @@ import android.view.KeyEvent; */ public class DateTimeKeyListener extends NumberKeyListener { + public int getInputType() { + return InputType.TYPE_CLASS_DATETIME + | InputType.TYPE_DATETIME_VARIATION_NORMAL; + } + @Override protected char[] getAcceptedChars() { diff --git a/core/java/android/text/method/DialerKeyListener.java b/core/java/android/text/method/DialerKeyListener.java index e805ad7a42cf5aa2d14ac7ecd92df8adc7819570..b121e608b5b5440ad10b41b2c73b22b54ab5589d 100644 --- a/core/java/android/text/method/DialerKeyListener.java +++ b/core/java/android/text/method/DialerKeyListener.java @@ -18,7 +18,7 @@ package android.text.method; import android.view.KeyEvent; import android.view.KeyCharacterMap.KeyData; -import android.util.SparseIntArray; +import android.text.InputType; import android.text.Spannable; /** @@ -40,6 +40,10 @@ public class DialerKeyListener extends NumberKeyListener return sInstance; } + public int getInputType() { + return InputType.TYPE_CLASS_PHONE; + } + /** * Overrides the superclass's lookup method to prefer the number field * from the KeyEvent. diff --git a/core/java/android/text/method/DigitsKeyListener.java b/core/java/android/text/method/DigitsKeyListener.java index 99a3f1ad1b0ec24ccf0b252ba81b04d12adc290e..f0f072c16ae9cda3c6d21c214104656bbe1022d9 100644 --- a/core/java/android/text/method/DigitsKeyListener.java +++ b/core/java/android/text/method/DigitsKeyListener.java @@ -16,6 +16,7 @@ package android.text.method; +import android.text.InputType; import android.text.Spanned; import android.text.SpannableStringBuilder; import android.view.KeyEvent; @@ -109,6 +110,17 @@ public class DigitsKeyListener extends NumberKeyListener return dim; } + public int getInputType() { + int contentType = InputType.TYPE_CLASS_NUMBER; + if (mSign) { + contentType |= InputType.TYPE_NUMBER_FLAG_SIGNED; + } + if (mDecimal) { + contentType |= InputType.TYPE_NUMBER_FLAG_DECIMAL; + } + return contentType; + } + @Override public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) { diff --git a/core/java/android/text/method/KeyListener.java b/core/java/android/text/method/KeyListener.java index 05ab72d630543a285d6e25673158a9eaa6e09dc5..4ae6191ef69e857fc95f04d274b2b04c0e5199f8 100644 --- a/core/java/android/text/method/KeyListener.java +++ b/core/java/android/text/method/KeyListener.java @@ -16,14 +16,39 @@ package android.text.method; +import android.text.Editable; import android.view.KeyEvent; import android.view.View; -import android.os.Message; -import android.text.*; -import android.widget.TextView; -public interface KeyListener -{ +/** + * Interface for converting text key events into edit operations on an + * Editable class. Note that for must cases this interface has been + * superceded by general soft input methods as defined by + * {@link android.view.inputmethod.InputMethod}; it should only be used + * for cases where an application has its own on-screen keypad and also wants + * to process hard keyboard events to match it. + */ +public interface KeyListener { + /** + * Return the type of text that this key listener is manipulating, + * as per {@link android.text.InputType}. This is used to + * determine the mode of the soft keyboard that is shown for the editor. + * + *

    If you return + * {@link android.text.InputType#TYPE_NULL} + * then no soft keyboard will provided. In other words, you + * must be providing your own key pad for on-screen input and the key + * listener will be used to handle input from a hard keyboard. + * + *

    If you + * return any other value, a soft input method will be created when the + * user puts focus in the editor, which will provide a keypad and also + * consume hard key events. This means that the key listener will generally + * not be used, instead the soft input method will take care of managing + * key input as per the content type returned here. + */ + public int getInputType(); + /** * If the key listener wants to handle this key, return true, * otherwise return false and the caller (i.e. the widget host) @@ -39,4 +64,9 @@ public interface KeyListener */ public boolean onKeyUp(View view, Editable text, int keyCode, KeyEvent event); + + /** + * Remove the given shift states from the edited text. + */ + public void clearMetaKeyState(View view, Editable content, int states); } diff --git a/core/java/android/text/method/MetaKeyKeyListener.java b/core/java/android/text/method/MetaKeyKeyListener.java index 2d75b873183312c53d8bccd063a7872a362959f2..f0305d9480e26aa8696caccb079311425409bbe3 100644 --- a/core/java/android/text/method/MetaKeyKeyListener.java +++ b/core/java/android/text/method/MetaKeyKeyListener.java @@ -221,6 +221,12 @@ public abstract class MetaKeyKeyListener { content.setSpan(what, 0, 0, RELEASED); } + public void clearMetaKeyState(View view, Editable content, int states) { + if ((states&META_SHIFT_ON) != 0) resetLock(content, CAP); + if ((states&META_ALT_ON) != 0) resetLock(content, ALT); + if ((states&META_SYM_ON) != 0) resetLock(content, SYM); + } + /** * The meta key has been pressed but has not yet been used. */ diff --git a/core/java/android/text/method/MultiTapKeyListener.java b/core/java/android/text/method/MultiTapKeyListener.java index 7137d40783ace43e1a74d6ac8d1b188a548e4f17..6d94788d3b5bf17d21241f6b2d80b7e9ccb9592d 100644 --- a/core/java/android/text/method/MultiTapKeyListener.java +++ b/core/java/android/text/method/MultiTapKeyListener.java @@ -18,14 +18,11 @@ package android.text.method; import android.view.KeyEvent; import android.view.View; -import android.os.Message; import android.os.Handler; import android.os.SystemClock; import android.text.*; import android.text.method.TextKeyListener.Capitalize; -import android.widget.TextView; import android.util.SparseArray; -import android.util.SparseIntArray; /** * This is the standard key listener for alphabetic input on 12-key @@ -77,6 +74,10 @@ public class MultiTapKeyListener extends BaseKeyListener return sInstance[off]; } + public int getInputType() { + return makeTextContentType(mCapitalize, mAutoText); + } + public boolean onKeyDown(View view, Editable content, int keyCode, KeyEvent event) { int selStart, selEnd; diff --git a/core/java/android/text/method/QwertyKeyListener.java b/core/java/android/text/method/QwertyKeyListener.java index ae7ba8f0ebb385b79a8407e504a650d4debbbcbf..863b2e2deacdd488c473f29c5d7862f0b28a3a5b 100644 --- a/core/java/android/text/method/QwertyKeyListener.java +++ b/core/java/android/text/method/QwertyKeyListener.java @@ -58,6 +58,10 @@ public class QwertyKeyListener extends BaseKeyListener { return sInstance[off]; } + public int getInputType() { + return makeTextContentType(mAutoCap, mAutoText); + } + public boolean onKeyDown(View view, Editable content, int keyCode, KeyEvent event) { int selStart, selEnd; @@ -219,7 +223,7 @@ public class QwertyKeyListener extends BaseKeyListener { if ((pref & TextKeyListener.AUTO_TEXT) != 0 && mAutoText && (i == ' ' || i == '\t' || i == '\n' || i == ',' || i == '.' || i == '!' || i == '?' || - i == '"' || i == ')' || i == ']') && + i == '"' || Character.getType(i) == Character.END_PUNCTUATION) && content.getSpanEnd(TextKeyListener.INHIBIT_REPLACEMENT) != oldStart) { int x; @@ -257,7 +261,16 @@ public class QwertyKeyListener extends BaseKeyListener { content.charAt(selEnd - 2) == ' ') { char c = content.charAt(selEnd - 3); - if (Character.isLetter(c)) { + for (int j = selEnd - 3; j > 0; j--) { + if (c == '"' || + Character.getType(c) == Character.END_PUNCTUATION) { + c = content.charAt(j - 1); + } else { + break; + } + } + + if (Character.isLetter(c) || Character.isDigit(c)) { content.replace(selEnd - 2, selEnd - 1, "."); } } diff --git a/core/java/android/text/method/ScrollingMovementMethod.java b/core/java/android/text/method/ScrollingMovementMethod.java index 0438e1efe3c9a733874a04f0d3e38ff8b0c2eaf7..db470beed0a392867aa33fff23f66401ed3c9e95 100644 --- a/core/java/android/text/method/ScrollingMovementMethod.java +++ b/core/java/android/text/method/ScrollingMovementMethod.java @@ -171,34 +171,16 @@ implements MovementMethod return false; } + public boolean onTrackballEvent(TextView widget, Spannable text, + MotionEvent event) { + return false; + } + public boolean onTouchEvent(TextView widget, Spannable buffer, MotionEvent event) { return Touch.onTouchEvent(widget, buffer, event); } - public boolean onTrackballEvent(TextView widget, Spannable buffer, - MotionEvent event) { - boolean handled = false; - int x = (int) event.getX(); - int y = (int) event.getY(); - - for (; y < 0; y++) { - handled |= up(widget, buffer); - } - for (; y > 0; y--) { - handled |= down(widget, buffer); - } - - for (; x < 0; x++) { - handled |= left(widget, buffer); - } - for (; x > 0; x--) { - handled |= right(widget, buffer); - } - - return handled; - } - public void initialize(TextView widget, Spannable text) { } public boolean canSelectArbitrarily() { diff --git a/core/java/android/text/method/TextKeyListener.java b/core/java/android/text/method/TextKeyListener.java index 012e41d5e97cfca7e8641009b6eafb91e496feaa..b1c380ab70e33a293dcd00b8529617692b12a1b2 100644 --- a/core/java/android/text/method/TextKeyListener.java +++ b/core/java/android/text/method/TextKeyListener.java @@ -26,6 +26,7 @@ import android.text.*; import android.view.KeyCharacterMap; import android.view.KeyEvent; import android.view.View; +import android.text.InputType; import java.lang.ref.WeakReference; @@ -114,76 +115,15 @@ public class TextKeyListener extends BaseKeyListener implements SpanWatcher { return true; } - // Back over allowed opening punctuation. - - for (i = off; i > 0; i--) { - c = cs.charAt(i - 1); - - if (c != '"' && c != '(' && c != '[' && c != '\'') { - break; - } - } - - // Start of paragraph, with optional whitespace. - - int j = i; - while (j > 0 && ((c = cs.charAt(j - 1)) == ' ' || c == '\t')) { - j--; - } - if (j == 0 || cs.charAt(j - 1) == '\n') { - return true; - } - - // Or start of word if we are that style. - - if (cap == Capitalize.WORDS) { - return i != j; - } - - // There must be a space if not the start of paragraph. - - if (i == j) { - return false; - } - - // Back over allowed closing punctuation. - - for (; j > 0; j--) { - c = cs.charAt(j - 1); - - if (c != '"' && c != ')' && c != ']' && c != '\'') { - break; - } - } - - if (j > 0) { - c = cs.charAt(j - 1); - - if (c == '.' || c == '?' || c == '!') { - // Do not capitalize if the word ends with a period but - // also contains a period, in which case it is an abbreviation. - - if (c == '.') { - for (int k = j - 2; k >= 0; k--) { - c = cs.charAt(k); - - if (c == '.') { - return false; - } - - if (!Character.isLetter(c)) { - break; - } - } - } - - return true; - } - } - - return false; + return TextUtils.getCapsMode(cs, off, cap == Capitalize.WORDS + ? TextUtils.CAP_MODE_WORDS : TextUtils.CAP_MODE_SENTENCES) + != 0; } + public int getInputType() { + return makeTextContentType(mAutoCap, mAutoText); + } + @Override public boolean onKeyDown(View view, Editable content, int keyCode, KeyEvent event) { @@ -251,6 +191,10 @@ public class TextKeyListener extends BaseKeyListener implements SpanWatcher { private static class NullKeyListener implements KeyListener { + public int getInputType() { + return InputType.TYPE_NULL; + } + public boolean onKeyDown(View view, Editable content, int keyCode, KeyEvent event) { return false; @@ -261,6 +205,9 @@ public class TextKeyListener extends BaseKeyListener implements SpanWatcher { return false; } + public void clearMetaKeyState(View view, Editable content, int states) { + } + public static NullKeyListener getInstance() { if (sInstance != null) return sInstance; diff --git a/core/java/android/text/method/TimeKeyListener.java b/core/java/android/text/method/TimeKeyListener.java index 9ba1fe6439426f5072da93f3c2ec2880700b9249..3fbfd8c10a4cbab1ca6fcdf93916bdbebd485b09 100644 --- a/core/java/android/text/method/TimeKeyListener.java +++ b/core/java/android/text/method/TimeKeyListener.java @@ -17,12 +17,18 @@ package android.text.method; import android.view.KeyEvent; +import android.text.InputType; /** * For entering times in a text field. */ public class TimeKeyListener extends NumberKeyListener { + public int getInputType() { + return InputType.TYPE_CLASS_DATETIME + | InputType.TYPE_DATETIME_VARIATION_TIME; + } + @Override protected char[] getAcceptedChars() { diff --git a/core/java/android/text/method/Touch.java b/core/java/android/text/method/Touch.java index bd017289f2b53a896f9973e8270c3bc478c58599..8b097c5b3fa25f3a80f5688c25a9e29d8e1b67bf 100644 --- a/core/java/android/text/method/Touch.java +++ b/core/java/android/text/method/Touch.java @@ -17,6 +17,7 @@ package android.text.method; import android.text.Layout; +import android.text.Layout.Alignment; import android.text.Spannable; import android.view.MotionEvent; import android.view.View; @@ -41,15 +42,31 @@ public class Touch { int left = Integer.MAX_VALUE; int right = 0; + Alignment a = null; for (int i = top; i <= bottom; i++) { left = (int) Math.min(left, layout.getLineLeft(i)); right = (int) Math.max(right, layout.getLineRight(i)); + + if (a == null) { + a = layout.getParagraphAlignment(i); + } } padding = widget.getTotalPaddingLeft() + widget.getTotalPaddingRight(); - x = Math.min(x, right - (widget.getWidth() - padding)); - x = Math.max(x, left); + int width = widget.getWidth(); + int diff = 0; + + if (right - left < width - padding) { + if (a == Alignment.ALIGN_CENTER) { + diff = (width - padding - (right - left)) / 2; + } else if (a == Alignment.ALIGN_OPPOSITE) { + diff = width - padding - (right - left); + } + } + + x = Math.min(x, right - (width - padding) - diff); + x = Math.max(x, left - diff); widget.scrollTo(x, y); } diff --git a/core/java/android/text/style/DynamicDrawableSpan.java b/core/java/android/text/style/DynamicDrawableSpan.java index 3bcc335a1d542aab154d0505647fc9d6c32ee14b..dd89b68a88855dd765cd754fbd7a50504ab5f082 100644 --- a/core/java/android/text/style/DynamicDrawableSpan.java +++ b/core/java/android/text/style/DynamicDrawableSpan.java @@ -16,11 +16,12 @@ package android.text.style; -import java.lang.ref.WeakReference; - -import android.graphics.drawable.Drawable; import android.graphics.Canvas; import android.graphics.Paint; +import android.graphics.Rect; +import android.graphics.drawable.Drawable; + +import java.lang.ref.WeakReference; /** * @@ -35,48 +36,51 @@ extends ReplacementSpan */ public abstract Drawable getDrawable(); + @Override public int getSize(Paint paint, CharSequence text, int start, int end, Paint.FontMetricsInt fm) { - Drawable b = getCachedDrawable(); + Drawable d = getCachedDrawable(); + Rect rect = d.getBounds(); if (fm != null) { - fm.ascent = -b.getIntrinsicHeight(); - fm.descent = 0; + fm.ascent = -rect.bottom; + fm.descent = 0; fm.top = fm.ascent; fm.bottom = 0; } - return b.getIntrinsicWidth(); + return rect.right; } + @Override public void draw(Canvas canvas, CharSequence text, int start, int end, float x, int top, int y, int bottom, Paint paint) { Drawable b = getCachedDrawable(); canvas.save(); - canvas.translate(x, bottom-b.getIntrinsicHeight());; + canvas.translate(x, bottom - b.getBounds().bottom); b.draw(canvas); canvas.restore(); } private Drawable getCachedDrawable() { - WeakReference wr = mDrawableRef; - Drawable b = null; + WeakReference wr = mDrawableRef; + Drawable d = null; if (wr != null) - b = (Drawable) wr.get(); + d = wr.get(); - if (b == null) { - b = getDrawable(); - mDrawableRef = new WeakReference(b); + if (d == null) { + d = getDrawable(); + mDrawableRef = new WeakReference(d); } - return b; + return d; } - private WeakReference mDrawableRef; + private WeakReference mDrawableRef; } diff --git a/core/java/android/text/util/Linkify.java b/core/java/android/text/util/Linkify.java index 79ecfbda0160a6dfda6c302ec79f14af6a18048a..d61e888e18158fa0242912925162f8ea03ae0ce5 100644 --- a/core/java/android/text/util/Linkify.java +++ b/core/java/android/text/util/Linkify.java @@ -69,7 +69,7 @@ public class Linkify { public static final int PHONE_NUMBERS = 0x04; /** - * Bit field indicating that phone numbers should be matched in methods that + * Bit field indicating that street addresses should be matched in methods that * take an options mask */ public static final int MAP_ADDRESSES = 0x08; @@ -78,8 +78,7 @@ public class Linkify { * Bit mask indicating that all available patterns should be matched in * methods that take an options mask */ - public static final int ALL = WEB_URLS | EMAIL_ADDRESSES | PHONE_NUMBERS - | MAP_ADDRESSES; + public static final int ALL = WEB_URLS | EMAIL_ADDRESSES | PHONE_NUMBERS | MAP_ADDRESSES; /** * Don't treat anything with fewer than this many digits as a @@ -109,8 +108,7 @@ public class Linkify { * Filters out URL matches that don't have enough digits to be a * phone number. */ - public static final MatchFilter sPhoneNumberMatchFilter = - new MatchFilter() { + public static final MatchFilter sPhoneNumberMatchFilter = new MatchFilter() { public final boolean acceptMatch(CharSequence s, int start, int end) { int digitCount = 0; @@ -133,8 +131,7 @@ public class Linkify { * '+1 (919) 555-1212' * becomes '+19195551212' */ - public static final TransformFilter sPhoneNumberTransformFilter = - new TransformFilter() { + public static final TransformFilter sPhoneNumberTransformFilter = new TransformFilter() { public final String transformUrl(final Matcher match, String url) { return Regex.digitsAndPlusOnly(match); } @@ -300,8 +297,7 @@ public class Linkify { * prepended to the url of links that do not have * a scheme specified in the link text */ - public static final void addLinks(TextView text, Pattern pattern, - String scheme) { + public static final void addLinks(TextView text, Pattern pattern, String scheme) { addLinks(text, pattern, scheme, null, null); } @@ -341,8 +337,7 @@ public class Linkify { * prepended to the url of links that do not have * a scheme specified in the link text */ - public static final boolean addLinks(Spannable text, Pattern pattern, - String scheme) { + public static final boolean addLinks(Spannable text, Pattern pattern, String scheme) { return addLinks(text, pattern, scheme, null, null); } @@ -388,8 +383,7 @@ public class Linkify { return hasMatches; } - private static final void applyLink(String url, int start, int end, - Spannable text) { + private static final void applyLink(String url, int start, int end, Spannable text) { URLSpan span = new URLSpan(url); text.setSpan(span, start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); @@ -402,13 +396,22 @@ public class Linkify { } boolean hasPrefix = false; + for (int i = 0; i < prefixes.length; i++) { if (url.regionMatches(true, 0, prefixes[i], 0, prefixes[i].length())) { hasPrefix = true; + + // Fix capitalization if necessary + if (!url.regionMatches(false, 0, prefixes[i], 0, + prefixes[i].length())) { + url = prefixes[i] + url.substring(prefixes[i].length()); + } + break; } } + if (!hasPrefix) { url = prefixes[0] + url; } @@ -438,30 +441,35 @@ public class Linkify { } } - private static final void gatherMapLinks(ArrayList links, - Spannable s) { + private static final void gatherMapLinks(ArrayList links, Spannable s) { String string = s.toString(); String address; int base = 0; + while ((address = WebView.findAddress(string)) != null) { int start = string.indexOf(address); + if (start < 0) { break; } + LinkSpec spec = new LinkSpec(); int length = address.length(); int end = start + length; + spec.start = base + start; spec.end = base + end; string = string.substring(end); base += end; String encodedAddress = null; + try { encodedAddress = URLEncoder.encode(address,"UTF-8"); } catch (UnsupportedEncodingException e) { continue; } + spec.url = "geo:0,0?q=" + encodedAddress; links.add(spec); } diff --git a/core/java/android/text/util/Regex.java b/core/java/android/text/util/Regex.java index 55ad14034ffdfdf980fb7ab8f070a7e2f8c992b3..4c128ad19e1f58a2e37a88fe34c8e405f1f03d4f 100644 --- a/core/java/android/text/util/Regex.java +++ b/core/java/android/text/util/Regex.java @@ -65,7 +65,7 @@ public class Regex { */ public static final Pattern WEB_URL_PATTERN = Pattern.compile( - "((?:(http|https):\\/\\/(?:(?:[a-zA-Z0-9\\$\\-\\_\\.\\+\\!\\*\\'\\(\\)" + "((?:(http|https|Http|Https):\\/\\/(?:(?:[a-zA-Z0-9\\$\\-\\_\\.\\+\\!\\*\\'\\(\\)" + "\\,\\;\\?\\&\\=]|(?:\\%[a-fA-F0-9]{2}))+(?:\\:(?:[a-zA-Z0-9\\$\\-\\_" + "\\.\\+\\!\\*\\'\\(\\)\\,\\;\\?\\&\\=]|(?:\\%[a-fA-F0-9]{2}))+)?\\@)?)?" + "((?:(?:[a-zA-Z0-9][a-zA-Z0-9\\-]*\\.)+" // named host @@ -103,7 +103,9 @@ public class Regex { + "(?:\\:\\d{1,5})?)" // plus option port number + "(\\/(?:(?:[a-zA-Z0-9\\;\\/\\?\\:\\@\\&\\=\\#\\~" // plus option query params + "\\-\\.\\+\\!\\*\\'\\(\\)\\,\\_])|(?:\\%[a-fA-F0-9]{2}))*)?" - + "\\b"); // and finally, a word boundary this is to stop foo.sure from matching as foo.su + + "(?:\\b|$)"); // and finally, a word boundary or end of + // input. This is to stop foo.sure from + // matching as foo.su public static final Pattern IP_ADDRESS_PATTERN = Pattern.compile( @@ -134,10 +136,20 @@ public class Regex { * might be phone numbers in arbitrary text, not for validating whether * something is in fact a phone number. It will miss many things that * are legitimate phone numbers. + * + *

    The pattern matches the following: + *

      + *
    • Optionally, a + sign followed immediately by one or more digits. Spaces, dots, or dashes + * may follow. + *
    • Optionally, sets of digits in parentheses, separated by spaces, dots, or dashes. + *
    • A string starting and ending with a digit, containing digits, spaces, dots, and/or dashes. + *
    */ public static final Pattern PHONE_PATTERN - = Pattern.compile( - "(?:\\+[0-9]+)|(?:[0-9()][0-9()\\- \\.][0-9()\\- \\.]+[0-9])"); + = Pattern.compile( // sdd = space, dot, or dash + "(\\+[0-9]+[\\- \\.]*)?" // +* + + "(\\([0-9]+\\)[\\- \\.]*)?" // ()* + + "([0-9][0-9\\- \\.][0-9\\- \\.]+[0-9])"); // + /** * Convenience method to take all of the non-null matching groups in a diff --git a/core/java/android/util/TimeUtils.java b/core/java/android/util/TimeUtils.java index 3c4e337e033b5674c50ba67f074caab47e334176..0fc70d52b878a93e4da4cc6076278af0067ef075 100644 --- a/core/java/android/util/TimeUtils.java +++ b/core/java/android/util/TimeUtils.java @@ -19,6 +19,7 @@ package android.util; import android.content.res.Resources; import android.content.res.XmlResourceParser; +import org.apache.harmony.luni.internal.util.ZoneInfoDB; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; @@ -28,14 +29,18 @@ import java.util.Date; import com.android.internal.util.XmlUtils; +/** + * A class containing utility methods related to time zones. + */ public class TimeUtils { + private static final String TAG = "TimeUtils"; + /** * Tries to return a time zone that would have had the specified offset * and DST value at the specified moment in the specified country. * Returns null if no suitable zone could be found. */ - public static TimeZone getTimeZone(int offset, boolean dst, long when, - String country) { + public static TimeZone getTimeZone(int offset, boolean dst, long when, String country) { if (country == null) { return null; } @@ -50,18 +55,18 @@ public class TimeUtils { String currentName = current.getID(); int currentOffset = current.getOffset(when); boolean currentDst = current.inDaylightTime(d); - + try { XmlUtils.beginDocument(parser, "timezones"); - + while (true) { XmlUtils.nextElement(parser); - + String element = parser.getName(); if (element == null || !(element.equals("timezone"))) { break; } - + String code = parser.getAttributeValue(null, "code"); if (country.equals(code)) { @@ -95,15 +100,34 @@ public class TimeUtils { } } } catch (XmlPullParserException e) { - Log.e("TimeUtils", - "Got exception while getting preferred time zone.", e); + Log.e(TAG, "Got exception while getting preferred time zone.", e); } catch (IOException e) { - Log.e("TimeUtils", - "Got exception while getting preferred time zone.", e); + Log.e(TAG, "Got exception while getting preferred time zone.", e); } finally { parser.close(); } - + return best; } + + /** + * Returns a String indicating the version of the time zone database currently + * in use. The format of the string is dependent on the underlying time zone + * database implementation, but will typically contain the year in which the database + * was updated plus a letter from a to z indicating changes made within that year. + * + *

    Time zone database updates should be expected to occur periodically due to + * political and legal changes that cannot be anticipated in advance. Therefore, + * when computing the UTC time for a future event, applications should be aware that + * the results may differ following a time zone database update. This method allows + * applications to detect that a database change has occurred, and to recalculate any + * cached times accordingly. + * + *

    The time zone database may be assumed to change only when the device runtime + * is restarted. Therefore, it is not necessary to re-query the database version + * during the lifetime of an activity. + */ + public static String getTimeZoneDatabaseVersion() { + return ZoneInfoDB.getVersion(); + } } diff --git a/core/java/android/view/ContextMenu.java b/core/java/android/view/ContextMenu.java index 9bfda401b0ebc95b8bcff364b6a46968f19dd02b..dd1d7db0e7a08adbe8dc5713550e293fb060b160 100644 --- a/core/java/android/view/ContextMenu.java +++ b/core/java/android/view/ContextMenu.java @@ -24,7 +24,7 @@ import android.widget.AdapterView; * Extension of {@link Menu} for context menus providing functionality to modify * the header of the context menu. *

    - * Context menus do not support item shortcuts, item icons, and sub menus. + * Context menus do not support item shortcuts and item icons. *

    * To show a context menu on long click, most clients will want to call * {@link Activity#registerForContextMenu} and override diff --git a/core/java/android/view/Gravity.java b/core/java/android/view/Gravity.java index ff9ab185a4a68106619048d25b37222d8c8b93cc..36d8ce615daca2ccf01fe23dc2a653c0daaaa81e 100644 --- a/core/java/android/view/Gravity.java +++ b/core/java/android/view/Gravity.java @@ -23,7 +23,7 @@ import android.graphics.Rect; */ public class Gravity { - /** Contstant indicating that no gravity has been set **/ + /** Constant indicating that no gravity has been set **/ public static final int NO_GRAVITY = 0x0000; /** Raw bit indicating the gravity for an axis has been specified. */ @@ -33,6 +33,9 @@ public class Gravity public static final int AXIS_PULL_BEFORE = 0x0002; /** Raw bit controlling how the right/bottom edge is placed. */ public static final int AXIS_PULL_AFTER = 0x0004; + /** Raw bit controlling whether the right/bottom edge is clipped to its + * container, based on the gravity direction being applied. */ + public static final int AXIS_CLIP = 0x0008; /** Bits defining the horizontal axis. */ public static final int AXIS_X_SHIFT = 0; @@ -66,10 +69,18 @@ public class Gravity * and horizontal axis, not changing its size. */ public static final int CENTER = CENTER_VERTICAL|CENTER_HORIZONTAL; - /** Grow the horizontal and vertical size of the obejct if needed so it + /** Grow the horizontal and vertical size of the object if needed so it * completely fills its container. */ public static final int FILL = FILL_VERTICAL|FILL_HORIZONTAL; + /** Flag to clip the edges of the object to its container along the + * vertical axis. */ + public static final int CLIP_VERTICAL = AXIS_CLIP<>AXIS_X_SHIFT, w, container.left, container.right, xAdj); - outRect.right = outRect.left + w; + switch (gravity&((AXIS_PULL_BEFORE|AXIS_PULL_AFTER)< container.right) { + outRect.right = container.right; + } + } + break; + case AXIS_PULL_BEFORE< container.right) { + outRect.right = container.right; + } + } + break; + case AXIS_PULL_AFTER< container.bottom) { + outRect.bottom = container.bottom; + } + } + break; + case AXIS_PULL_BEFORE< container.bottom) { + outRect.bottom = container.bottom; + } + } + break; + case AXIS_PULL_AFTER< display.bottom) inoutObj.bottom = display.bottom; } else { - outRect.top = applyMovement( - gravity>>AXIS_Y_SHIFT, h, container.top, container.bottom, yAdj); - outRect.bottom = outRect.top + h; + int off = 0; + if (inoutObj.top < display.top) off = display.top-inoutObj.top; + else if (inoutObj.bottom > display.bottom) off = display.bottom-inoutObj.bottom; + if (off != 0) { + if (inoutObj.height() > (display.bottom-display.top)) { + inoutObj.top = display.top; + inoutObj.bottom = display.bottom; + } else { + inoutObj.top += off; + inoutObj.bottom += off; + } + } + } + + if ((gravity&DISPLAY_CLIP_HORIZONTAL) != 0) { + if (inoutObj.left < display.left) inoutObj.left = display.left; + if (inoutObj.right > display.right) inoutObj.right = display.right; + } else { + int off = 0; + if (inoutObj.left < display.left) off = display.left-inoutObj.left; + else if (inoutObj.right > display.right) off = display.right-inoutObj.right; + if (off != 0) { + if (inoutObj.width() > (display.right-display.left)) { + inoutObj.left = display.left; + inoutObj.right = display.right; + } else { + inoutObj.left += off; + inoutObj.right += off; + } + } } } - + /** *

    Indicate whether the supplied gravity has a vertical pull.

    * @@ -162,18 +303,4 @@ public class Gravity public static boolean isHorizontal(int gravity) { return gravity > 0 && (gravity & HORIZONTAL_GRAVITY_MASK) != 0; } - - private static int applyMovement(int mode, int size, - int start, int end, int adj) { - if ((mode & AXIS_PULL_BEFORE) != 0) { - return start + adj; - } - - if ((mode & AXIS_PULL_AFTER) != 0) { - return end - size - adj; - } - - return start + ((end - start - size)/2) + adj; - } } - diff --git a/core/java/android/view/IWindow.aidl b/core/java/android/view/IWindow.aidl index b4a3067ea1af1257e02a1299ae3a536cb96a1b4b..99d5c0caee36f75e0f497887e242bd80d887e648 100644 --- a/core/java/android/view/IWindow.aidl +++ b/core/java/android/view/IWindow.aidl @@ -17,6 +17,7 @@ package android.view; +import android.graphics.Rect; import android.view.KeyEvent; import android.view.MotionEvent; @@ -42,7 +43,8 @@ oneway interface IWindow { */ void executeCommand(String command, String parameters, in ParcelFileDescriptor descriptor); - void resized(int w, int h, boolean reportDraw); + void resized(int w, int h, in Rect coveredInsets, in Rect visibleInsets, + boolean reportDraw); void dispatchKey(in KeyEvent event); void dispatchPointer(in MotionEvent event, long eventTime); void dispatchTrackball(in MotionEvent event, long eventTime); diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl index e6d52e2957ac13190935249b6f92f34f7aad6fba..d89c7b45f9393c74d26ba186fb66c10169f06325 100644 --- a/core/java/android/view/IWindowManager.aidl +++ b/core/java/android/view/IWindowManager.aidl @@ -17,6 +17,9 @@ package android.view; +import com.android.internal.view.IInputContext; +import com.android.internal.view.IInputMethodClient; + import android.content.res.Configuration; import android.view.IApplicationToken; import android.view.IOnKeyguardExitResult; @@ -42,8 +45,10 @@ interface IWindowManager boolean stopViewServer(); // Transaction #2 boolean isViewServerRunning(); // Transaction #3 - IWindowSession openSession(IBinder token); - + IWindowSession openSession(in IInputMethodClient client, + in IInputContext inputContext); + boolean inputMethodClientHasFocus(IInputMethodClient client); + // These can only be called when injecting events to your own window, // or by holding the INJECT_EVENTS permission. boolean injectKeyEvent(in KeyEvent ev, boolean sync); @@ -74,6 +79,8 @@ interface IWindowManager void moveAppToken(int index, IBinder token); void moveAppTokensToTop(in List tokens); void moveAppTokensToBottom(in List tokens); + void addWindowToken(IBinder token, int type); + void removeWindowToken(IBinder token); // these require DISABLE_KEYGUARD permission void disableKeyguard(IBinder token, String tag); diff --git a/core/java/android/view/IWindowSession.aidl b/core/java/android/view/IWindowSession.aidl index c2c0b9780ea74d8b4b299bf30960a69e58fb55d5..7276f173cf3f50c0960a41c2b8249b9383c3af1c 100644 --- a/core/java/android/view/IWindowSession.aidl +++ b/core/java/android/view/IWindowSession.aidl @@ -31,7 +31,7 @@ import android.view.Surface; */ interface IWindowSession { int add(IWindow window, in WindowManager.LayoutParams attrs, - in int viewVisibility, out Rect outCoveredInsets); + in int viewVisibility, out Rect outContentInsets); void remove(IWindow window); /** @@ -46,10 +46,22 @@ interface IWindowSession { * @param requestedWidth The width the window wants to be. * @param requestedHeight The height the window wants to be. * @param viewVisibility Window root view's visibility. - * @param outFrame Object in which is placed the new position/size on - * screen. - * @param outCoveredInsets Object in which is placed the insets for the areas covered by - * system windows (e.g. status bar) + * @param insetsPending Set to true if the client will be later giving + * internal insets; as a result, the window will not impact other window + * layouts until the insets are given. + * @param outFrame Rect in which is placed the new position/size on + * screen. + * @param outContentInsets Rect in which is placed the offsets from + * outFrame in which the content of the window should be + * placed. This can be used to modify the window layout to ensure its + * contents are visible to the user, taking into account system windows + * like the status bar or a soft keyboard. + * @param outVisibleInsets Rect in which is placed the offsets from + * outFrame in which the window is actually completely visible + * to the user. This can be used to temporarily scroll the window's + * contents to make sure the user can see it. This is different than + * outContentInsets in that these insets change transiently, + * so complex relayout of the window should not happen based on them. * @param outSurface Object in which is placed the new display surface. * * @return int Result flags: {@link WindowManagerImpl#RELAYOUT_SHOW_FOCUS}, @@ -57,16 +69,41 @@ interface IWindowSession { */ int relayout(IWindow window, in WindowManager.LayoutParams attrs, int requestedWidth, int requestedHeight, int viewVisibility, - out Rect outFrame, out Rect outCoveredInsets, out Surface outSurface); + boolean insetsPending, out Rect outFrame, out Rect outContentInsets, + out Rect outVisibleInsets, out Surface outSurface); + /** + * Give the window manager a hint of the part of the window that is + * completely transparent, allowing it to work with the surface flinger + * to optimize compositing of this part of the window. + */ + void setTransparentRegion(IWindow window, in Region region); + + /** + * Tell the window manager about the content and visible insets of the + * given window, which can be used to adjust the outContentInsets + * and outVisibleInsets values returned by + * {@link #relayout relayout()} for windows behind this one. + * + * @param touchableInsets Controls which part of the window inside of its + * frame can receive pointer events, as defined by + * {@link android.view.ViewTreeObserver.InternalInsetsInfo}. + */ + void setInsets(IWindow window, int touchableInsets, in Rect contentInsets, + in Rect visibleInsets); + + /** + * Return the current display size in which the window is being laid out, + * accounting for screen decorations around it. + */ + void getDisplayFrame(IWindow window, out Rect outDisplayFrame); + void finishDrawing(IWindow window); void finishKey(IWindow window); MotionEvent getPendingPointerMove(IWindow window); MotionEvent getPendingTrackballMove(IWindow window); - void setTransparentRegion(IWindow window, in Region region); - void setInTouchMode(boolean showFocus); boolean getInTouchMode(); } diff --git a/core/java/android/view/KeyEvent.java b/core/java/android/view/KeyEvent.java index 24b0316dc323d615922e5cfbedf38b36878cc86a..1575aad11059ca9f29d193b35a5dc17e5e84e6a8 100644 --- a/core/java/android/view/KeyEvent.java +++ b/core/java/android/view/KeyEvent.java @@ -111,15 +111,27 @@ public class KeyEvent implements Parcelable { public static final int KEYCODE_MENU = 82; public static final int KEYCODE_NOTIFICATION = 83; public static final int KEYCODE_SEARCH = 84; + public static final int KEYCODE_PLAYPAUSE = 85; + public static final int KEYCODE_STOP = 86; + public static final int KEYCODE_NEXTSONG = 87; + public static final int KEYCODE_PREVIOUSSONG = 88; + public static final int KEYCODE_REWIND = 89; + public static final int KEYCODE_FORWARD = 90; + private static final int LAST_KEYCODE = KEYCODE_FORWARD; // NOTE: If you add a new keycode here you must also add it to: // isSystem() - // include/ui/KeycodeLabels.h + // frameworks/base/include/ui/KeycodeLabels.h // tools/puppet_master/PuppetMaster/nav_keys.py - // apps/common/res/values/attrs.xml + // frameworks/base/core/res/res/values/attrs.xml // commands/monkey/Monkey.java // emulator? - + + /** + * @deprecated There are now more than MAX_KEYCODE keycodes. + * Use {@link #getMaxKeyCode()} instead. + */ + @Deprecated public static final int MAX_KEYCODE = 84; /** @@ -206,6 +218,18 @@ public class KeyEvent implements Parcelable { */ public static final int FLAG_WOKE_HERE = 0x1; + /** + * This mask is set if the key event was generated by a software keyboard. + */ + public static final int FLAG_SOFT_KEYBOARD = 0x2; + + /** + * Returns the maximum keycode. + */ + public static int getMaxKeyCode() { + return LAST_KEYCODE; + } + /** * Get the character that is produced by putting accent on the character * c. @@ -401,6 +425,24 @@ public class KeyEvent implements Parcelable { mFlags = origEvent.mFlags; } + /** + * Copy an existing key event, modifying its action. + * + * @param origEvent The existing event to be copied. + * @param action The new action code of the event. + */ + public KeyEvent(KeyEvent origEvent, int action) { + mDownTime = origEvent.mDownTime; + mEventTime = origEvent.mEventTime; + mAction = action; + mKeyCode = origEvent.mKeyCode; + mRepeatCount = origEvent.mRepeatCount; + mMetaState = origEvent.mMetaState; + mDeviceId = origEvent.mDeviceId; + mScancode = origEvent.mScancode; + mFlags = origEvent.mFlags; + } + /** * Don't use in new code, instead explicitly check * {@link #getAction()}. @@ -432,6 +474,12 @@ public class KeyEvent implements Parcelable { case KEYCODE_VOLUME_DOWN: case KEYCODE_POWER: case KEYCODE_HEADSETHOOK: + case KEYCODE_PLAYPAUSE: + case KEYCODE_STOP: + case KEYCODE_NEXTSONG: + case KEYCODE_PREVIOUSSONG: + case KEYCODE_REWIND: + case KEYCODE_FORWARD: case KEYCODE_CAMERA: case KEYCODE_FOCUS: case KEYCODE_SEARCH: diff --git a/core/java/android/view/Menu.java b/core/java/android/view/Menu.java index f2ec0769d1768f702878b5bad6e75dcdfa8eac21..ca2140b4ee6b23cc2b9846fa0fd35a67698c05de 100644 --- a/core/java/android/view/Menu.java +++ b/core/java/android/view/Menu.java @@ -32,8 +32,7 @@ import android.content.Intent; *

    * Different menu types support different features: *

      - *
    1. Context menus: Do not support item shortcuts, item icons, and sub - * menus. + *
    2. Context menus: Do not support item shortcuts and item icons. *
    3. Options menus: The icon menus do not support item check * marks and only show the item's * {@link MenuItem#setTitleCondensed(CharSequence) condensed title}. The @@ -379,6 +378,24 @@ public interface Menu { */ public int size(); + /** + * Gets the menu item at the given index. + * + * @param index The index of the menu item to return. + * @return The menu item. + * @exception IndexOutOfBoundsException + * when {@code index < 0 || >= size()} + * @hide pending API council + */ + public MenuItem getItem(int index); + + /** + * Closes the menu, if open. + * + * @hide pending API council + */ + public void close(); + /** * Execute the menu item action associated with the given shortcut * character. diff --git a/core/java/android/view/MenuItem.java b/core/java/android/view/MenuItem.java index 92cf4afc5f979624f19af9385e7478fcadc3bca2..fcebec5d8766f1bd2eb5822e093a74c6531f7a30 100644 --- a/core/java/android/view/MenuItem.java +++ b/core/java/android/view/MenuItem.java @@ -1,3 +1,19 @@ +/* + * 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 android.view; import android.app.Activity; diff --git a/core/java/android/view/MotionEvent.java b/core/java/android/view/MotionEvent.java index ab05e160951403e89dbea4bbb4b71e73d6256b6e..882a07903741fa4c278f151b0d99c8e7aef09a98 100644 --- a/core/java/android/view/MotionEvent.java +++ b/core/java/android/view/MotionEvent.java @@ -27,10 +27,36 @@ import android.util.Config; * it is being used for. */ public final class MotionEvent implements Parcelable { + /** + * Constant for {@link #getAction}: A pressed gesture has started, the + * motion contains the initial starting location. + */ public static final int ACTION_DOWN = 0; + /** + * Constant for {@link #getAction}: A pressed gesture has finished, the + * motion contains the final release location as well as any intermediate + * points since the last down or move event. + */ public static final int ACTION_UP = 1; + /** + * Constant for {@link #getAction}: A change has happened during a + * press gesture (between {@link #ACTION_DOWN} and {@link #ACTION_UP}). + * The motion contains the most recent point, as well as any intermediate + * points since the last down or move event. + */ public static final int ACTION_MOVE = 2; + /** + * Constant for {@link #getAction}: The current gesture has been aborted. + * You will not receive any more points in it. You should treat this as + * an up event, but not perform any action that you normally would. + */ public static final int ACTION_CANCEL = 3; + /** + * Constant for {@link #getAction}: A movement has happened outside of the + * normal bounds of the UI element. This does not provide a full gesture, + * but only the initial location of the movement/touch. + */ + public static final int ACTION_OUTSIDE = 4; private static final boolean TRACK_RECYCLED_LOCATION = false; diff --git a/core/java/android/view/OrientationListener.java b/core/java/android/view/OrientationListener.java index 0add025ae8ecf44cf200cca623c1adca5ada9090..974c2e83565a356b739e18228c0de0b3affb8ac0 100644 --- a/core/java/android/view/OrientationListener.java +++ b/core/java/android/view/OrientationListener.java @@ -34,6 +34,7 @@ public abstract class OrientationListener implements SensorListener { private SensorManager mSensorManager; private int mOrientation = ORIENTATION_UNKNOWN; private boolean mEnabled = false; + private int mRate; /** * Returned from onOrientationChanged when the device orientation cannot be determined @@ -50,6 +51,21 @@ public abstract class OrientationListener implements SensorListener { */ public OrientationListener(Context context) { mSensorManager = (SensorManager)context.getSystemService(Context.SENSOR_SERVICE); + mRate = SensorManager.SENSOR_DELAY_NORMAL; + } + + /** + * Creates a new OrientationListener. + * + * @param context for the OrientationListener. + * @param rate at which sensor events are processed (see also + * {@link android.hardware.SensorManager SensorManager}). Use the default + * value of {@link android.hardware.SensorManager#SENSOR_DELAY_NORMAL + * SENSOR_DELAY_NORMAL} for simple screen orientation change detection. + */ + public OrientationListener(Context context, int rate) { + mSensorManager = (SensorManager)context.getSystemService(Context.SENSOR_SERVICE); + mRate = rate; } /** @@ -59,7 +75,7 @@ public abstract class OrientationListener implements SensorListener { public void enable() { if (mEnabled == false) { if (localLOGV) Log.d(TAG, "OrientationListener enabled"); - mSensorManager.registerListener(this, SensorManager.SENSOR_ACCELEROMETER); + mSensorManager.registerListener(this, SensorManager.SENSOR_ACCELEROMETER, mRate); mEnabled = true; } } @@ -106,7 +122,6 @@ public abstract class OrientationListener implements SensorListener { public void onAccuracyChanged(int sensor, int accuracy) { // TODO Auto-generated method stub - } /** diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java index 57689f277f15d35cd583d979c20f2c1745beb8c8..0d9e2218329c4961274bb06739491ae164b6b439 100644 --- a/core/java/android/view/SurfaceView.java +++ b/core/java/android/view/SurfaceView.java @@ -82,6 +82,8 @@ public class SurfaceView extends View { final ArrayList mCallbacks = new ArrayList(); + final int[] mLocation = new int[2]; + final ReentrantLock mSurfaceLock = new ReentrantLock(); final Surface mSurface = new Surface(); boolean mDrawingStopped = true; @@ -90,8 +92,9 @@ public class SurfaceView extends View { = new WindowManager.LayoutParams(); IWindowSession mSession; MyWindow mWindow; + final Rect mVisibleInsets = new Rect(); final Rect mWinFrame = new Rect(); - final Rect mCoveredInsets = new Rect(); + final Rect mContentInsets = new Rect(); static final int KEEP_SCREEN_ON_MSG = 1; static final int GET_NEW_SURFACE_MSG = 2; @@ -309,7 +312,7 @@ public class SurfaceView extends View { mLayout.type = WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA; mLayout.gravity = Gravity.LEFT|Gravity.TOP; mSession.add(mWindow, mLayout, - mVisible ? VISIBLE : GONE, mCoveredInsets); + mVisible ? VISIBLE : GONE, mContentInsets); } if (visibleChanged && (!visible || mNewSurfaceNeeded)) { @@ -321,8 +324,9 @@ public class SurfaceView extends View { mSurfaceLock.lock(); mDrawingStopped = !visible; final int relayoutResult = mSession.relayout( - mWindow, mLayout, mWidth, mHeight, - visible ? VISIBLE : GONE, mWinFrame, mCoveredInsets, mSurface); + mWindow, mLayout, mWidth, mHeight, + visible ? VISIBLE : GONE, false, mWinFrame, mContentInsets, + mVisibleInsets, mSurface); if (localLOGV) Log.i(TAG, "New surface: " + mSurface + ", vis=" + visible + ", frame=" + mWinFrame); mSurfaceFrame.left = 0; @@ -390,7 +394,8 @@ public class SurfaceView extends View { } private class MyWindow extends IWindow.Stub { - public void resized(int w, int h, boolean reportDraw) { + public void resized(int w, int h, Rect coveredInsets, + Rect visibleInsets, boolean reportDraw) { if (localLOGV) Log.v( "SurfaceView", SurfaceView.this + " got resized: w=" + w + " h=" + h + ", cur w=" + mCurWidth + " h=" + mCurHeight); diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index 30402f81844be94849a85d011b3f5d0652da7582..f948b33fb179f699552bb08b1aacc986e08941f5 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -38,13 +38,18 @@ import android.os.IBinder; import android.os.Message; import android.os.Parcel; import android.os.Parcelable; +import android.os.RemoteException; import android.os.SystemClock; +import android.os.SystemProperties; import android.util.AttributeSet; import android.util.EventLog; import android.util.Log; import android.util.SparseArray; import android.view.ContextMenu.ContextMenuInfo; import android.view.animation.Animation; +import android.view.inputmethod.InputConnection; +import android.view.inputmethod.InputMethodManager; +import android.view.inputmethod.EditorInfo; import android.widget.ScrollBarDrawable; import com.android.internal.R; @@ -58,9 +63,9 @@ import java.util.Arrays; * The View class represents the basic UI building block. A view * occupies a rectangular area on the screen and is responsible for drawing and * event handling. View is the base class for widgets, - * used to create interactive graphical user interfaces. + * used to create interactive graphical user interfaces. *

      - * + * * *

      Using Views

      *

      @@ -98,7 +103,7 @@ import java.util.Arrays; * views yourself unless you are actually implementing a * {@link android.view.ViewGroup}. *

      - * + * * *

      Implementing a Custom View

      * @@ -111,7 +116,7 @@ import java.util.Arrays; * * Category Methods Description * - * + * * * * Creation @@ -127,7 +132,7 @@ import java.util.Arrays; * Called after a view and all of its children has been inflated * from XML. * - * + * * * Layout * {@link #onMeasure} @@ -146,7 +151,7 @@ import java.util.Arrays; * Called when the size of this view has changed. * * - * + * * * Drawing * {@link #onDraw} @@ -164,31 +169,31 @@ import java.util.Arrays; * {@link #onKeyUp} * Called when a key up event occurs. * - * + * * * {@link #onTrackballEvent} * Called when a trackball motion event occurs. * - * + * * * {@link #onTouchEvent} * Called when a touch screen motion event occurs. * - * - * + * + * * * Focus * {@link #onFocusChanged} * Called when the view gains or loses focus. * * - * + * * * {@link #onWindowFocusChanged} * Called when the window containing the view gains or loses focus. * * - * + * * * Attaching * {@link #onAttachedToWindow()} @@ -200,26 +205,26 @@ import java.util.Arrays; * {@link #onDetachedFromWindow} * Called when the view is detached from its window. * - * + * * * * {@link #onWindowVisibilityChanged} * Called when the visibility of the window containing the view * has changed. * - * + * * - * + * * *

      - * + * * *

      IDs

      * Views may have an integer id associated with them. These ids are typically * assigned in the layout XML files, and are used to find specific views within * the view tree. A common pattern is to: *
        - *
      • Define a Button in the layout file and assign it a unique ID. + *
      • Define a Button in the layout file and assign it a unique ID. *
          * <Button id="@+id/my_button"
          *     android:layout_width="wrap_content"
        @@ -232,11 +237,11 @@ import java.util.Arrays;
          * 
      • *
      *

      - * View IDs need not be unique throughout the tree, but it is good practice to + * View IDs need not be unique throughout the tree, but it is good practice to * ensure that they are at least unique within the part of the tree you are * searching. *

      - * + * * *

      Position

      *

      @@ -264,7 +269,7 @@ import java.util.Arrays; * is similar to the following computation: getLeft() + getWidth() * (see Size for more information about the width.) *

      - * + * * *

      Size, padding and margins

      *

      @@ -286,7 +291,7 @@ import java.util.Arrays; * dimensions define the actual size of the view on screen, at drawing time and * after layout. These values may, but do not have to, be different from the * measured width and height. The width and height can be obtained by calling - * {@link #getWidth()} and {@link #getHeight()}. + * {@link #getWidth()} and {@link #getHeight()}. *

      * *

      @@ -297,7 +302,7 @@ import java.util.Arrays; * 2 pixels to the right of the left edge. Padding can be set using the * {@link #setPadding(int, int, int, int)} method and queried by calling * {@link #getPaddingLeft()}, {@link #getPaddingTop()}, - * {@link #getPaddingRight()} and {@link #getPaddingBottom()}. + * {@link #getPaddingRight()} and {@link #getPaddingBottom()}. *

      * *

      @@ -306,7 +311,7 @@ import java.util.Arrays; * {@link android.view.ViewGroup} and * {@link android.view.ViewGroup.MarginLayoutParams} for further information. *

      - * + * * *

      Layout

      *

      @@ -319,7 +324,7 @@ import java.util.Arrays; * this pass each parent is responsible for positioning all of its children * using the sizes computed in the measure pass. *

      - * + * *

      * When a view's measure() method returns, its {@link #getMeasuredWidth()} and * {@link #getMeasuredHeight()} values must be set, along with those for all of @@ -332,7 +337,7 @@ import java.util.Arrays; * measure() on them again with actual numbers if the sum of all the children's * unconstrained sizes is too big or too small. *

      - * + * *

      * The measure pass uses two classes to communicate dimensions. The * {@link MeasureSpec} class is used by views to tell their parents how they @@ -350,7 +355,7 @@ import java.util.Arrays; * For example, AbsoluteLayout has its own subclass of LayoutParams which adds * an X and Y value. *

      - * + * *

      * MeasureSpecs are used to push requirements down the tree from parent to * child. A MeasureSpec can be in one of three modes: @@ -367,13 +372,13 @@ import java.util.Arrays; * within this size. * *

      - * + * *

      * To intiate a layout, call {@link #requestLayout}. This method is typically * called by a view on itself when it believes that is can no longer fit within * its current bounds. *

      - * + * * *

      Drawing

      *

      @@ -381,17 +386,18 @@ import java.util.Arrays; * intersects the the invalid region. Because the tree is traversed in-order, * this means that parents will draw before (i.e., behind) their children, with * siblings drawn in the order they appear in the tree. + * If you set a background drawable for a View, then the View will draw it for you + * before calling back to its onDraw() method. *

      - * + * *

      - * The framework will not draw views that are not in the invalid region, and also - * will take care of drawing the views background for you. + * Note that the framework will not draw views that are not in the invalid region. *

      - * + * *

      * To force a view to draw, call {@link #invalidate()}. *

      - * + * * *

      Event Handling and Threading

      *

      @@ -408,13 +414,13 @@ import java.util.Arrays; * as appropriate.

    4. *
    *

    - * + * *

    Note: The entire view tree is single threaded. You must always be on * the UI thread when calling any method on any view. * If you are doing work on other threads and want to update the state of a view * from that thread, you should use a {@link Handler}. *

    - * + * * *

    Focus Handling

    *

    @@ -479,7 +485,7 @@ import java.util.Arrays; * offset as well as mechanisms for drawing scrollbars. See * {@link #scrollBy(int, int)}, {@link #scrollTo(int, int)} for more details. *

    - * + * * *

    Tags

    *

    @@ -488,7 +494,7 @@ import java.util.Arrays; * often used as a convenience to store data related to views in the views * themselves rather than by putting them in a separate structure. *

    - * + * * *

    Animation

    *

    @@ -543,7 +549,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback { * setFlags. */ private static final int FOCUSABLE = 0x00000001; - + /** * Mask for use with setFlags indicating bits used for focus. */ @@ -599,7 +605,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback { * {@hide} */ static final int ENABLED_MASK = 0x00000020; - + /** * This view won't draw. {@link #onDraw} won't be called and further * optimizations @@ -615,7 +621,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback { * {@hide} */ static final int DRAW_MASK = 0x00000080; - + /** *

    This view doesn't show scrollbars.

    * {@hide} @@ -752,22 +758,22 @@ public class View implements Drawable.Callback, KeyEvent.Callback { /** * The scrollbar style to display the scrollbars inside the content area, - * without increasing the padding. The scrollbars will be overlaid with + * without increasing the padding. The scrollbars will be overlaid with * translucency on the view's content. */ public static final int SCROLLBARS_INSIDE_OVERLAY = 0; - + /** * The scrollbar style to display the scrollbars inside the padded area, - * increasing the padding of the view. The scrollbars will not overlap the + * increasing the padding of the view. The scrollbars will not overlap the * content area of the view. */ public static final int SCROLLBARS_INSIDE_INSET = 0x01000000; /** * The scrollbar style to display the scrollbars at the edge of the view, - * without increasing the padding. The scrollbars will be overlaid with - * translucency. + * without increasing the padding. The scrollbars will be overlaid with + * translucency. */ public static final int SCROLLBARS_OUTSIDE_OVERLAY = 0x02000000; @@ -789,7 +795,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback { * {@hide} */ static final int SCROLLBARS_OUTSIDE_MASK = 0x02000000; - + /** * Mask for scrollbar style. * {@hide} @@ -841,7 +847,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback { * Use with {@link #focusSearch}. Move focus down. */ public static final int FOCUS_DOWN = 0x00000082; - + /** * Base View state sets */ @@ -850,7 +856,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback { * Indicates the view has no states set. States are used with * {@link android.graphics.drawable.Drawable} to change the drawing of the * view depending on its state. - * + * * @see android.graphics.drawable.Drawable * @see #getDrawableState() */ @@ -1003,7 +1009,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback { /** * Indicates the view is pressed and its window has the focus. - * + * * @see #PRESSED_STATE_SET * @see #WINDOW_FOCUSED_STATE_SET */ @@ -1021,7 +1027,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback { /** * Indicates the view is pressed, selected and its window has the focus. - * + * * @see #PRESSED_STATE_SET * @see #SELECTED_STATE_SET * @see #WINDOW_FOCUSED_STATE_SET @@ -1040,7 +1046,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback { /** * Indicates the view is pressed, focused and its window has the focus. - * + * * @see #PRESSED_STATE_SET * @see #FOCUSED_STATE_SET * @see #WINDOW_FOCUSED_STATE_SET @@ -1050,7 +1056,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback { /** * Indicates the view is pressed, focused and selected. - * + * * @see #PRESSED_STATE_SET * @see #SELECTED_STATE_SET * @see #FOCUSED_STATE_SET @@ -1060,7 +1066,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback { /** * Indicates the view is pressed, focused, selected and its window has the focus. - * + * * @see #PRESSED_STATE_SET * @see #FOCUSED_STATE_SET * @see #SELECTED_STATE_SET @@ -1071,7 +1077,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback { /** * Indicates the view is pressed and enabled. - * + * * @see #PRESSED_STATE_SET * @see #ENABLED_STATE_SET */ @@ -1080,7 +1086,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback { /** * Indicates the view is pressed, enabled and its window has the focus. - * + * * @see #PRESSED_STATE_SET * @see #ENABLED_STATE_SET * @see #WINDOW_FOCUSED_STATE_SET @@ -1090,7 +1096,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback { /** * Indicates the view is pressed, enabled and selected. - * + * * @see #PRESSED_STATE_SET * @see #ENABLED_STATE_SET * @see #SELECTED_STATE_SET @@ -1101,7 +1107,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback { /** * Indicates the view is pressed, enabled, selected and its window has the * focus. - * + * * @see #PRESSED_STATE_SET * @see #ENABLED_STATE_SET * @see #SELECTED_STATE_SET @@ -1112,18 +1118,18 @@ public class View implements Drawable.Callback, KeyEvent.Callback { /** * Indicates the view is pressed, enabled and focused. - * + * * @see #PRESSED_STATE_SET * @see #ENABLED_STATE_SET * @see #FOCUSED_STATE_SET */ protected static final int[] PRESSED_ENABLED_FOCUSED_STATE_SET = stateSetUnion(PRESSED_ENABLED_STATE_SET, FOCUSED_STATE_SET); - + /** * Indicates the view is pressed, enabled, focused and its window has the * focus. - * + * * @see #PRESSED_STATE_SET * @see #ENABLED_STATE_SET * @see #FOCUSED_STATE_SET @@ -1134,7 +1140,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback { /** * Indicates the view is pressed, enabled, focused and selected. - * + * * @see #PRESSED_STATE_SET * @see #ENABLED_STATE_SET * @see #SELECTED_STATE_SET @@ -1146,7 +1152,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback { /** * Indicates the view is pressed, enabled, focused, selected and its window * has the focus. - * + * * @see #PRESSED_STATE_SET * @see #ENABLED_STATE_SET * @see #SELECTED_STATE_SET @@ -1242,6 +1248,13 @@ public class View implements Drawable.Callback, KeyEvent.Callback { * @hide */ protected static final int[] PRESSED_SINGLE_STATE_SET = {R.attr.state_single, R.attr.state_pressed}; + + /** + * Temporary Rect currently for use in setBackground(). This will probably + * be extended in the future to hold our own class with more than just + * a Rect. :) + */ + static final ThreadLocal sThreadLocal = new ThreadLocal(); /** * The animation currently associated with this view. @@ -1263,21 +1276,12 @@ public class View implements Drawable.Callback, KeyEvent.Callback { @ViewDebug.ExportedProperty protected int mMeasuredHeight; - /** - * Used to store a pair of coordinates, for instance returned values - * returned by {@link #getLocationInWindow(int[])}. - * - * This field should be made private, so it is hidden from the SDK. - * {@hide} - */ - protected final int[] mLocation = new int[2]; - /** * The view's identifier. * {@hide} * * @see #setId(int) - * @see #getId() + * @see #getId() */ @ViewDebug.ExportedProperty(resolveId = true) int mID = NO_ID; @@ -1287,7 +1291,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback { * {@hide} * * @see #setTag(Object) - * @see #getTag() + * @see #getTag() */ protected Object mTag; @@ -1320,7 +1324,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback { private static final int LAYOUT_REQUIRED = 0x00002000; private static final int PRESSED = 0x00004000; - + /** {@hide} */ static final int DRAWING_CACHE_VALID = 0x00008000; /** @@ -1329,7 +1333,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback { * {@hide} */ static final int ANIMATION_STARTED = 0x00010000; - + private static final int SAVE_STATE_CALLED = 0x00020000; /** @@ -1339,8 +1343,18 @@ public class View implements Drawable.Callback, KeyEvent.Callback { */ static final int ALPHA_SET = 0x00040000; + /** + * Set by {@link #setScrollContainer(boolean)}. + */ + static final int SCROLL_CONTAINER = 0x00080000; + + /** + * Set by {@link #setScrollContainer(boolean)}. + */ + static final int SCROLL_CONTAINER_ADDED = 0x00100000; + // Note: flag 0x00000040 is available - + /** * The parent this view is attached to. * {@hide} @@ -1357,10 +1371,11 @@ public class View implements Drawable.Callback, KeyEvent.Callback { /** * {@hide} */ + @ViewDebug.ExportedProperty int mPrivateFlags; - + /** - * Count of how many windows this view has been attached to. + * Count of how many windows this view has been attached to. */ int mWindowAttachCount; @@ -1376,6 +1391,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback { * The view flags hold various views states. * {@hide} */ + @ViewDebug.ExportedProperty int mViewFlags; /** @@ -1450,7 +1466,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback { */ @ViewDebug.ExportedProperty protected int mPaddingBottom; - + /** * Cache the paddingRight set by the user to append to the scrollbar's size. */ @@ -1462,7 +1478,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback { */ @ViewDebug.ExportedProperty int mUserPaddingBottom; - + private int mOldWidthMeasureSpec = Integer.MIN_VALUE; private int mOldHeightMeasureSpec = Integer.MIN_VALUE; @@ -1479,28 +1495,28 @@ public class View implements Drawable.Callback, KeyEvent.Callback { * {@hide} */ protected OnFocusChangeListener mOnFocusChangeListener; - + /** * Listener used to dispatch click events. * This field should be made private, so it is hidden from the SDK. * {@hide} */ protected OnClickListener mOnClickListener; - + /** * Listener used to dispatch long click events. * This field should be made private, so it is hidden from the SDK. * {@hide} */ protected OnLongClickListener mOnLongClickListener; - + /** * Listener used to build the context menu. * This field should be made private, so it is hidden from the SDK. * {@hide} */ protected OnCreateContextMenuListener mOnCreateContextMenuListener; - + private OnKeyListener mOnKeyListener; private OnTouchListener mOnTouchListener; @@ -1518,11 +1534,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback { private Bitmap mDrawingCache; - /** - * Used for local (within a stackframe) calls that need a rect temporarily - */ - private final Rect mTempRect = new Rect(); - /** * When this view has focus and the next focus is {@link #FOCUS_LEFT}, * the user may specify which view to go to next. @@ -1542,13 +1553,13 @@ public class View implements Drawable.Callback, KeyEvent.Callback { private int mNextFocusUpId = View.NO_ID; /** - * When this view has focus and the next focus is {@link #FOCUS_DOWN}, + * When this view has focus and the next focus is {@link #FOCUS_DOWN}, * the user may specify which view to go to next. */ private int mNextFocusDownId = View.NO_ID; private CheckForLongPress mPendingCheckForLongPress; - + /** * Whether the long press's action has been invoked. The tap's action is invoked on the * up event while a long press is invoked as soon as the long press duration is reached, so @@ -1561,12 +1572,14 @@ public class View implements Drawable.Callback, KeyEvent.Callback { * The minimum height of the view. We'll try our best to have the height * of this view to at least this amount. */ + @ViewDebug.ExportedProperty private int mMinHeight; - + /** * The minimum width of the view. We'll try our best to have the width * of this view to at least this amount. */ + @ViewDebug.ExportedProperty private int mMinWidth; /** @@ -1574,7 +1587,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback { * but should be handled by another view. */ private TouchDelegate mTouchDelegate = null; - + /** * Solid color to use as a background when creating the drawing cache. Enables * the cache to use 16 bit bitmaps instead of 32 bit. @@ -1591,7 +1604,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback { /** * Simple constructor to use when creating a view from code. - * + * * @param context The Context the view is running in, through which it can * access the current theme, resources, etc. */ @@ -1607,11 +1620,11 @@ public class View implements Drawable.Callback, KeyEvent.Callback { * that were specified in the XML file. This version uses a default style of * 0, so the only attribute values applied are those in the Context's Theme * and the given AttributeSet. - * + * *

    * The method onFinishInflate() will be called after all children have been * added. - * + * * @param context The Context the view is running in, through which it can * access the current theme, resources, etc. * @param attrs The attributes of the XML tag that is inflating the view. @@ -1629,7 +1642,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback { * R.attr.buttonStyle for defStyle; this allows * the theme's button style to modify all of the base view attributes (in * particular its background) as well as the Button class's attributes. - * + * * @param context The Context the view is running in, through which it can * access the current theme, resources, etc. * @param attrs The attributes of the XML tag that is inflating the view. @@ -1663,7 +1676,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback { int scrollbarStyle = SCROLLBARS_INSIDE_OVERLAY; viewFlagValues |= SOUND_EFFECTS_ENABLED; - viewFlagMasks |= SOUND_EFFECTS_ENABLED; + viewFlagMasks |= SOUND_EFFECTS_ENABLED; final int N = a.getIndexCount(); for (int i = 0; i < N; i++) { @@ -1833,7 +1846,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback { if (viewFlagMasks != 0) { setFlags(viewFlagValues, viewFlagMasks); } - + // Needs to be called after mViewFlags is set if (scrollbarStyle != SCROLLBARS_INSIDE_OVERLAY) { recomputePadding(); @@ -1866,7 +1879,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback { * being inflated from XML. This method is automatically called when the XML * is inflated. *

    - * + * * @param a the styled attributes set to initialize the fading edges from */ protected void initializeFadingEdge(TypedArray a) { @@ -1875,7 +1888,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback { mScrollCache.fadingEdgeLength = a.getDimensionPixelSize( R.styleable.View_fadingEdgeLength, ViewConfiguration.getFadingEdgeLength()); } - + /** * Returns the size of the vertical faded edges used to indicate that more * content in this view is visible. @@ -1907,7 +1920,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback { initScrollCache(); mScrollCache.fadingEdgeLength = length; } - + /** * Returns the size of the horizontal faded edges used to indicate that more * content in this view is visible. @@ -1978,7 +1991,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback { * being inflated from XML. This method is automatically called when the XML * is inflated. *

    - * + * * @param a the styled attributes set to initialize the scrollbars from */ protected void initializeScrollbars(TypedArray a) { @@ -1999,8 +2012,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback { if (thumb != null) { mScrollCache.scrollBar.setHorizontalThumbDrawable(thumb); } - - boolean alwaysDraw = a.getBoolean(R.styleable.View_scrollbarAlwaysDrawHorizontalTrack, + + boolean alwaysDraw = a.getBoolean(R.styleable.View_scrollbarAlwaysDrawHorizontalTrack, false); if (alwaysDraw) { mScrollCache.scrollBar.setAlwaysDrawHorizontalTrack(true); @@ -2013,13 +2026,13 @@ public class View implements Drawable.Callback, KeyEvent.Callback { if (thumb != null) { mScrollCache.scrollBar.setVerticalThumbDrawable(thumb); } - - alwaysDraw = a.getBoolean(R.styleable.View_scrollbarAlwaysDrawVerticalTrack, + + alwaysDraw = a.getBoolean(R.styleable.View_scrollbarAlwaysDrawVerticalTrack, false); if (alwaysDraw) { mScrollCache.scrollBar.setAlwaysDrawVerticalTrack(true); } - + // Re-apply user/background padding so that scrollbar(s) get added recomputePadding(); } @@ -2037,16 +2050,16 @@ public class View implements Drawable.Callback, KeyEvent.Callback { /** * Register a callback to be invoked when focus of this view changed. - * + * * @param l The callback that will run. */ public void setOnFocusChangeListener(OnFocusChangeListener l) { mOnFocusChangeListener = l; } - + /** * Returns the focus-change callback registered for this view. - * + * * @return The callback, or null if one is not registered. */ public OnFocusChangeListener getOnFocusChangeListener() { @@ -2056,7 +2069,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback { /** * Register a callback to be invoked when this view is clicked. If this view is not * clickable, it becomes clickable. - * + * * @param l The callback that will run * * @see #setClickable(boolean) @@ -2067,11 +2080,11 @@ public class View implements Drawable.Callback, KeyEvent.Callback { } mOnClickListener = l; } - + /** * Register a callback to be invoked when this view is clicked and held. If this view is not * long clickable, it becomes long clickable. - * + * * @param l The callback that will run * * @see #setLongClickable(boolean) @@ -2084,9 +2097,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback { } /** - * Register a callback to be invoked when the context menu for this view is + * Register a callback to be invoked when the context menu for this view is * being built. If this view is not long clickable, it becomes long clickable. - * + * * @param l The callback that will run * */ @@ -2096,10 +2109,10 @@ public class View implements Drawable.Callback, KeyEvent.Callback { } mOnCreateContextMenuListener = l; } - + /** * Call this view's OnClickListener, if it is defined. - * + * * @return True there was an assigned OnClickListener that was called, false * otherwise is returned. */ @@ -2112,11 +2125,11 @@ public class View implements Drawable.Callback, KeyEvent.Callback { return false; } - + /** * Call this view's OnLongClickListener, if it is defined. Invokes the context menu * if the OnLongClickListener did not consume the event. - * + * * @return True there was an assigned OnLongClickListener that was called, false * otherwise is returned. */ @@ -2130,10 +2143,10 @@ public class View implements Drawable.Callback, KeyEvent.Callback { } return handled; } - + /** * Bring up the context menu for this view. - * + * * @return Whether a context menu was displayed. */ public boolean showContextMenu() { @@ -2155,7 +2168,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback { public void setOnTouchListener(OnTouchListener l) { mOnTouchListener = l; } - + /** * Give this view focus. This will cause {@link #onFocusChanged} to be called. * @@ -2191,7 +2204,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback { * Request that a rectangle of this view be visible on the screen, * scrolling if necessary just enough. * - * A View should call this if it maintains some notion of which part + *

    A View should call this if it maintains some notion of which part * of its content is interesting. For example, a text editing view * should call this when its cursor moves. * @@ -2206,11 +2219,11 @@ public class View implements Drawable.Callback, KeyEvent.Callback { * Request that a rectangle of this view be visible on the screen, * scrolling if necessary just enough. * - * A View should call this if it maintains some notion of which part + *

    A View should call this if it maintains some notion of which part * of its content is interesting. For example, a text editing view * should call this when its cursor moves. * - * When immediate is set to true, scrolling will not be + *

    When immediate is set to true, scrolling will not be * animated. * * @param rectangle The rectangle. @@ -2221,9 +2234,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback { View child = this; ViewParent parent = mParent; boolean scrolled = false; - while (parent instanceof ViewGroup) { - ViewGroup vgParent = (ViewGroup) parent; - scrolled |= vgParent.requestChildRectangleOnScreen(child, + while (parent != null) { + scrolled |= parent.requestChildRectangleOnScreen(child, rectangle, immediate); // offset rect so next call has the rectangle in the @@ -2231,12 +2243,16 @@ public class View implements Drawable.Callback, KeyEvent.Callback { rectangle.offset(child.getLeft(), child.getTop()); rectangle.offset(-child.getScrollX(), -child.getScrollY()); + if (!(parent instanceof View)) { + break; + } + child = (View) parent; parent = child.getParent(); } return scrolled; } - + /** * Called when this view wants to give up focus. This will cause * {@link #onFocusChanged} to be called. @@ -2257,7 +2273,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback { refreshDrawableState(); } } - + /** * Called to clear the focus of a view that is about to be removed. * Doesn't call clearChildFocus, which prevents this view from taking @@ -2271,7 +2287,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback { refreshDrawableState(); } } - + /** * Called internally by the view system when a new view is getting focus. * This is what clears the old focus. @@ -2292,7 +2308,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback { /** * Returns true if this view has focus iteself, or is the ancestor of the * view that has focus. - * + * * @return True if this view has or contains focus, false otherwise. */ @ViewDebug.ExportedProperty @@ -2315,17 +2331,19 @@ public class View implements Drawable.Callback, KeyEvent.Callback { public boolean hasFocusable() { return (mViewFlags & VISIBILITY_MASK) == VISIBLE && isFocusable(); } - + /** * Called by the view system when the focus state of this view changes. * When the focus change event is caused by directional navigation, direction * and previouslyFocusedRect provide insight into where the focus is coming from. + * When overriding, be sure to call up through to the super class so that + * the standard focus handling will occur. * * @param gainFocus True if the View has focus; false otherwise. - * @param direction The direction focus has moved when requestFocus() - * is called to give this view focus. Values are - * View.FOCUS_UP, View.FOCUS_DOWN, View.FOCUS_LEFT or - * View.FOCUS_RIGHT. It may not always apply, in which + * @param direction The direction focus has moved when requestFocus() + * is called to give this view focus. Values are + * View.FOCUS_UP, View.FOCUS_DOWN, View.FOCUS_LEFT or + * View.FOCUS_RIGHT. It may not always apply, in which * case use the default. * @param previouslyFocusedRect The rectangle, in this view's coordinate * system, of the previously focused view. If applicable, this will be @@ -2333,20 +2351,29 @@ public class View implements Drawable.Callback, KeyEvent.Callback { * from (in addition to direction). Will be null otherwise. */ protected void onFocusChanged(boolean gainFocus, int direction, Rect previouslyFocusedRect) { + InputMethodManager imm = InputMethodManager.peekInstance(); if (!gainFocus) { if (isPressed()) { setPressed(false); } + if (imm != null && mAttachInfo != null + && mAttachInfo.mHasWindowFocus) { + imm.focusOut(this); + } + } else if (imm != null && mAttachInfo != null + && mAttachInfo.mHasWindowFocus) { + imm.focusIn(this); } + invalidate(); if (mOnFocusChangeListener != null) { mOnFocusChangeListener.onFocusChange(this, gainFocus); } } - + /** * Returns true if this view has focus - * + * * @return True if this view has focus, false otherwise. */ @ViewDebug.ExportedProperty @@ -2357,7 +2384,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback { /** * Find the view in the hierarchy rooted at this view that currently has * focus. - * + * * @return The view that currently has focus, or null if no focused view can * be found. */ @@ -2365,6 +2392,28 @@ public class View implements Drawable.Callback, KeyEvent.Callback { return (mPrivateFlags & FOCUSED) != 0 ? this : null; } + /** + * Change whether this view is one of the set of scrollable containers in + * its window. This will be used to determine whether the window can + * resize or must pan when a soft input area is open -- scrollable + * containers allow the window to use resize mode since the container + * will appropriately shrink. + */ + public void setScrollContainer(boolean isScrollContainer) { + if (isScrollContainer) { + if (mAttachInfo != null && (mPrivateFlags&SCROLL_CONTAINER_ADDED) == 0) { + mAttachInfo.mScrollContainers.add(this); + mPrivateFlags |= SCROLL_CONTAINER_ADDED; + } + mPrivateFlags |= SCROLL_CONTAINER; + } else { + if ((mPrivateFlags&SCROLL_CONTAINER_ADDED) != 0) { + mAttachInfo.mScrollContainers.remove(this); + } + mPrivateFlags &= ~(SCROLL_CONTAINER|SCROLL_CONTAINER_ADDED); + } + } + /** * Returns the quality of the drawing cache. * @@ -2388,7 +2437,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback { * @param quality One of {@link #DRAWING_CACHE_QUALITY_AUTO}, * {@link #DRAWING_CACHE_QUALITY_LOW}, or {@link #DRAWING_CACHE_QUALITY_HIGH} * - * @see #getDrawingCacheQuality() + * @see #getDrawingCacheQuality() * @see #setDrawingCacheEnabled(boolean) * @see #isDrawingCacheEnabled() * @@ -2418,7 +2467,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback { * * @param keepScreenOn Supply true to set {@link #KEEP_SCREEN_ON}. * - * @see #getKeepScreenOn() + * @see #getKeepScreenOn() * * @attr ref android.R.styleable#View_keepScreenOn */ @@ -2508,10 +2557,10 @@ public class View implements Drawable.Callback, KeyEvent.Callback { /** * Returns the visibility of this view and all of its ancestors - * + * * @return True if this view and all of its ancestors are {@link #VISIBLE} */ - public boolean isShown() { + public boolean isShown() { View current = this; //noinspection ConstantConditions do { @@ -2522,7 +2571,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback { if (parent == null) { return false; // We are not attached to the view root } - if (parent instanceof ViewRoot) { + if (!(parent instanceof View)) { return true; } current = (View) parent; @@ -2534,7 +2583,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback { /** * Apply the insets for system windows to this view, if the FITS_SYSTEM_WINDOWS flag * is set - * + * * @param insets Insets for system windows * * @return True if this view applied the insets, false otherwise @@ -2545,14 +2594,15 @@ public class View implements Drawable.Callback, KeyEvent.Callback { mPaddingTop = insets.top; mPaddingRight = insets.right; mPaddingBottom = insets.bottom; + requestLayout(); return true; } return false; } - + /** * Returns the visibility status for this view. - * + * * @return One of {@link #VISIBLE}, {@link #INVISIBLE}, or {@link #GONE}. * @attr ref android.R.styleable#View_visibility */ @@ -2567,7 +2617,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback { /** * Set the enabled state of this view. - * + * * @param visibility One of {@link #VISIBLE}, {@link #INVISIBLE}, or {@link #GONE}. * @attr ref android.R.styleable#View_visibility */ @@ -2578,40 +2628,40 @@ public class View implements Drawable.Callback, KeyEvent.Callback { /** * Returns the enabled status for this view. The interpretation of the * enabled state varies by subclass. - * + * * @return True if this view is enabled, false otherwise. */ @ViewDebug.ExportedProperty public boolean isEnabled() { return (mViewFlags & ENABLED_MASK) == ENABLED; } - + /** * Set the enabled state of this view. The interpretation of the enabled * state varies by subclass. - * + * * @param enabled True if this view is enabled, false otherwise. */ public void setEnabled(boolean enabled) { setFlags(enabled ? ENABLED : DISABLED, ENABLED_MASK); - + /* * The View most likely has to change its appearance, so refresh * the drawable state. */ refreshDrawableState(); - + // Invalidate too, since the default behavior for views is to be // be drawn at 50% alpha rather than to change the drawable. invalidate(); } - + /** * Set whether this view can receive the focus. * * Setting this to false will also ensure that this view is not focusable * in touch mode. - * + * * @param focusable If true, this view can receive the focus. * * @see #setFocusableInTouchMode(boolean) @@ -2631,7 +2681,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback { * * @param focusableInTouchMode If true, this view can receive the focus while * in touch mode. - * + * * @see #setFocusable(boolean) * @attr ref android.R.styleable#View_focusableInTouchMode */ @@ -2676,18 +2726,18 @@ public class View implements Drawable.Callback, KeyEvent.Callback { } /** - * If this view doesn't do any drawing on its own, set this flag to + * If this view doesn't do any drawing on its own, set this flag to * allow further optimizations. By default, this flag is not set on * View, but could be set on some View subclasses such as ViewGroup. - * + * * Typically, if you override {@link #onDraw} you should clear this flag. - * + * * @param willNotDraw whether or not this View draw on its own */ public void setWillNotDraw(boolean willNotDraw) { setFlags(willNotDraw ? WILL_NOT_DRAW : 0, DRAW_MASK); } - + /** * Returns whether or not this View draws on its own. * @@ -2739,7 +2789,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback { * is clickable it will change its state to "pressed" on every click. * Subclasses should set the view clickable to visually react to * user's clicks. - * + * * @param clickable true to make the view clickable, false otherwise * * @see #isClickable() @@ -2766,7 +2816,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback { * clickable it reacts to the user holding down the button for a longer * duration than a tap. This event can either launch the listener or a * context menu. - * + * * @param longClickable true to make the view long clickable, false otherwise * @see #isLongClickable() * @attr ref android.R.styleable#View_longClickable @@ -2777,10 +2827,10 @@ public class View implements Drawable.Callback, KeyEvent.Callback { /** * Sets the pressed that for this view. - * + * * @see #isClickable() * @see #setClickable(boolean) - * + * * @param pressed Pass true to set the View's internal state to "pressed", or false to reverts * the View's internal state from a previously set "pressed" state. */ @@ -2793,12 +2843,12 @@ public class View implements Drawable.Callback, KeyEvent.Callback { refreshDrawableState(); dispatchSetPressed(pressed); } - + /** * Dispatch setPressed to all of this View's children. - * + * * @see #setPressed(boolean) - * + * * @param pressed The new pressed state */ protected void dispatchSetPressed(boolean pressed) { @@ -2818,7 +2868,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback { public boolean isPressed() { return (mPrivateFlags & PRESSED) == PRESSED; } - + /** * Indicates whether this view will save its state (that is, * whether its {@link #onSaveInstanceState} method will be called). @@ -2839,12 +2889,12 @@ public class View implements Drawable.Callback, KeyEvent.Callback { * view still must have an id assigned to it (via {@link #setId setId()}) * for its state to be saved. This flag can only disable the * saving of this view; any child views may still have their state saved. - * + * * @param enabled Set to false to disable state saving, or true * (the default) to allow it. * * @see #isSaveEnabled() - * @see #setId(int) + * @see #setId(int) * @see #onSaveInstanceState() * @attr ref android.R.styleable#View_saveEnabled */ @@ -2855,7 +2905,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback { /** * Returns whether this View is able to take focus. - * + * * @return True if this view can take focus, or false otherwise. * @attr ref android.R.styleable#View_focusable */ @@ -2880,9 +2930,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback { /** * Find the nearest view in the specified direction that can take focus. * This does not actually give focus to that view. - * + * * @param direction One of FOCUS_UP, FOCUS_DOWN, FOCUS_LEFT, and FOCUS_RIGHT - * + * * @return The nearest focusable in the specified direction, or null if none * can be found. */ @@ -2893,7 +2943,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback { return null; } } - + /** * This method is the last chance for the focused view and its ancestors to * respond to an arrow key. This is called when the focused view did not @@ -2943,7 +2993,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback { } return result; } - + /** * Find and return all focusable views that are descendants of this view, * possibly including this view if it is focusable itself. @@ -2961,7 +3011,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback { * Add any focusable views that are descendants of this view (possibly * including this view if it is focusable itself) to views. If we are in touch mode, * only add views that are also focusable in touch mode. - * + * * @param views Focusable views found so far * @param direction The direction of the focus */ @@ -2972,11 +3022,11 @@ public class View implements Drawable.Callback, KeyEvent.Callback { views.add(this); } - + /** * Find and return all touchable views that are descendants of this view, * possibly including this view if it is touchable itself. - * + * * @return A list of touchable views */ public ArrayList getTouchables() { @@ -2987,13 +3037,13 @@ public class View implements Drawable.Callback, KeyEvent.Callback { /** * Add any touchable views that are descendants of this view (possibly - * including this view if it is touchable itself) to views. - * + * including this view if it is touchable itself) to views. + * * @param views Touchable views found so far */ public void addTouchables(ArrayList views) { final int viewFlags = mViewFlags; - + if (((viewFlags & CLICKABLE) == CLICKABLE || (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE) && (viewFlags & ENABLED_MASK) == ENABLED) { views.add(this); @@ -3024,14 +3074,14 @@ public class View implements Drawable.Callback, KeyEvent.Callback { /** * Call this to try to give focus to a specific view or to one of its * descendants and give it a hint about what direction focus is heading. - * + * * A view will not actually take focus if it is not focusable ({@link #isFocusable} returns false), * or if it is focusable and it is not focusable in touch mode ({@link #isFocusableInTouchMode}) * while the device is in touch mode. * * See also {@link #focusSearch}, which is what you call to say that you * have focus, and you want your parent to look for the next one. - * + * * This is equivalent to calling {@link #requestFocus(int, Rect)} with * null set for the previously focused rectangle. * @@ -3096,11 +3146,11 @@ public class View implements Drawable.Callback, KeyEvent.Callback { * Call this to try to give focus to a specific view or to one of its descendants. This is a * special variant of {@link #requestFocus() } that will allow views that are not focuable in * touch mode to request focus when they are touched. - * + * * @return Whether this view or one of its descendants actually took focus. - * + * * @see #isInTouchMode() - * + * */ public final boolean requestFocusFromTouch() { // Leave touch mode if we need to @@ -3115,7 +3165,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback { } return requestFocus(View.FOCUS_DOWN); } - + /** * @return Whether any ancestor of this view blocks descendant focus. */ @@ -3131,42 +3181,74 @@ public class View implements Drawable.Callback, KeyEvent.Callback { } return false; } - + + /** + * capture information of this view for later analysis: developement only + * check dynamic switch to make sure we only dump view + * when ViewDebug.SYSTEM_PROPERTY_CAPTURE_VIEW) is set + */ + private static void captureViewInfo(String subTag, View v) { + if (v == null || + SystemProperties.getInt(ViewDebug.SYSTEM_PROPERTY_CAPTURE_VIEW, 0) == 0) { + return; + } + ViewDebug.dumpCapturedView(subTag, v); + } + + /** + * Dispatch a key event before it is processed by any input method + * associated with the view hierarchy. This can be used to intercept + * key events in special situations before the IME consumes them; a + * typical example would be handling the BACK key to update the application's + * UI instead of allowing the IME to see it and close itself. + * + * @param event The key event to be dispatched. + * @return True if the event was handled, false otherwise. + */ + public boolean dispatchKeyEventPreIme(KeyEvent event) { + return onKeyPreIme(event.getKeyCode(), event); + } + /** * Dispatch a key event to the next view on the focus path. This path runs * from the top of the view tree down to the currently focused view. If this * view has focus, it will dispatch to itself. Otherwise it will dispatch * the next node down the focus path. This method also fires any key * listeners. - * + * * @param event The key event to be dispatched. * @return True if the event was handled, false otherwise. */ public boolean dispatchKeyEvent(KeyEvent event) { // If any attached key listener a first crack at the event. //noinspection SimplifiableIfStatement + + if (android.util.Config.LOGV) { + captureViewInfo("captureViewKeyEvent", this); + } + if (mOnKeyListener != null && (mViewFlags & ENABLED_MASK) == ENABLED && mOnKeyListener.onKey(this, event.getKeyCode(), event)) { return true; } - + return event.dispatch(this); } /** * Dispatches a key shortcut event. - * + * * @param event The key event to be dispatched. * @return True if the event was handled by the view, false otherwise. */ public boolean dispatchKeyShortcutEvent(KeyEvent event) { return onKeyShortcut(event.getKeyCode(), event); } - + /** * Pass the touch screen motion event down to the target view, or this * view if it is the target. - * + * * @param event The motion event to be dispatched. * @return True if the event was handled by the view, false otherwise. */ @@ -3180,7 +3262,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback { /** * Pass a trackball motion event down to the focused view. - * + * * @param event The motion event to be dispatched. * @return True if the event was handled by the view, false otherwise. */ @@ -3192,7 +3274,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback { /** * Called when the window containing this view gains or loses window focus. * ViewGroups should override to route to their children. - * + * * @param hasFocus True if the window containing this view now has focus, * false otherwise. */ @@ -3206,23 +3288,29 @@ public class View implements Drawable.Callback, KeyEvent.Callback { * your view and its window must have focus. If a window is displayed * on top of yours that takes input focus, then your own window will lose * focus but the view focus will remain unchanged. - * + * * @param hasWindowFocus True if the window containing this view now has * focus, false otherwise. */ public void onWindowFocusChanged(boolean hasWindowFocus) { + InputMethodManager imm = InputMethodManager.peekInstance(); if (!hasWindowFocus) { if (isPressed()) { setPressed(false); } + if (imm != null && (mPrivateFlags & FOCUSED) != 0) { + imm.focusOut(this); + } + } else if (imm != null && (mPrivateFlags & FOCUSED) != 0) { + imm.focusIn(this); } refreshDrawableState(); } - + /** * Returns true if this view is in a window that currently has window focus. * Note that this is not the same as the view itself having focus. - * + * * @return True if this view is in a window that currently has window focus. */ public boolean hasWindowFocus() { @@ -3232,9 +3320,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback { /** * Dispatch a window visibility change down the view hierarchy. * ViewGroups should override to route to their children. - * + * * @param visibility The new visibility of the window. - * + * * @see #onWindowVisibilityChanged */ public void dispatchWindowVisibilityChanged(int visibility) { @@ -3248,22 +3336,59 @@ public class View implements Drawable.Callback, KeyEvent.Callback { * to the window manager; this does not tell you whether or not * your window is obscured by other windows on the screen, even if it * is itself visible. - * + * * @param visibility The new visibility of the window. */ protected void onWindowVisibilityChanged(int visibility) { } - + /** * Returns the current visibility of the window this view is attached to * (either {@link #GONE}, {@link #INVISIBLE}, or {@link #VISIBLE}). - * + * * @return Returns the current visibility of the view's window. */ public int getWindowVisibility() { return mAttachInfo != null ? mAttachInfo.mWindowVisibility : GONE; } - + + /** + * Retrieve the overall visible display size in which the window this view is + * attached to has been positioned in. This takes into account screen + * decorations above the window, for both cases where the window itself + * is being position inside of them or the window is being placed under + * then and covered insets are used for the window to position its content + * inside. In effect, this tells you the available area where content can + * be placed and remain visible to users. + * + *

    This function requires an IPC back to the window manager to retrieve + * the requested information, so should not be used in performance critical + * code like drawing. + * + * @param outRect Filled in with the visible display frame. If the view + * is not attached to a window, this is simply the raw display size. + */ + public void getWindowVisibleDisplayFrame(Rect outRect) { + if (mAttachInfo != null) { + try { + mAttachInfo.mSession.getDisplayFrame(mAttachInfo.mWindow, outRect); + } catch (RemoteException e) { + return; + } + // XXX This is really broken, and probably all needs to be done + // in the window manager, and we need to know more about whether + // we want the area behind or in front of the IME. + final Rect insets = mAttachInfo.mVisibleInsets; + outRect.left += insets.left; + outRect.top += insets.top; + outRect.right -= insets.right; + outRect.bottom -= insets.bottom; + return; + } + Display d = WindowManagerImpl.getDefault().getDefaultDisplay(); + outRect.set(0, 0, d.getWidth(), d.getHeight()); + } + /** * Private function to aggregate all per-view attributes in to the view * root. @@ -3278,7 +3403,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback { mAttachInfo.mKeepScreenOn = true; } } - + void needGlobalAttributesUpdate(boolean force) { AttachInfo ai = mAttachInfo; if (ai != null) { @@ -3287,7 +3412,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback { } } } - + /** * Returns whether the device is currently in touch mode. Touch mode is entered * once the user begins interacting with the device by touch, and affects various @@ -3306,21 +3431,38 @@ public class View implements Drawable.Callback, KeyEvent.Callback { /** * Returns the context the view is running in, through which it can - * access the current theme, resources, etc. - * + * access the current theme, resources, etc. + * * @return The view's Context. */ + @ViewDebug.CapturedViewProperty public final Context getContext() { return mContext; } + /** + * Handle a key event before it is processed by any input method + * associated with the view hierarchy. This can be used to intercept + * key events in special situations before the IME consumes them; a + * typical example would be handling the BACK key to update the application's + * UI instead of allowing the IME to see it and close itself. + * + * @param keyCode The value in event.getKeyCode(). + * @param event Description of the key event. + * @return If you handled the event, return true. If you want to allow the + * event to be handled by the next receiver, return false. + */ + public boolean onKeyPreIme(int keyCode, KeyEvent event) { + return false; + } + /** * Default implementation of {@link KeyEvent.Callback#onKeyMultiple(int, int, KeyEvent) * KeyEvent.Callback.onKeyMultiple()}: perform press of the view * when {@link KeyEvent#KEYCODE_DPAD_CENTER} or {@link KeyEvent#KEYCODE_ENTER} * is released, if the view is enabled and clickable. - * - * @param keyCode A key code that represents the button pressed, from + * + * @param keyCode A key code that represents the button pressed, from * {@link android.view.KeyEvent}. * @param event The KeyEvent object that defines the button action. */ @@ -3354,8 +3496,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback { * KeyEvent.Callback.onKeyMultiple()}: perform clicking of the view * when {@link KeyEvent#KEYCODE_DPAD_CENTER} or * {@link KeyEvent#KEYCODE_ENTER} is released. - * - * @param keyCode A key code that represents the button pressed, from + * + * @param keyCode A key code that represents the button pressed, from * {@link android.view.KeyEvent}. * @param event The KeyEvent object that defines the button action. */ @@ -3390,8 +3532,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback { * Default implementation of {@link KeyEvent.Callback#onKeyMultiple(int, int, KeyEvent) * KeyEvent.Callback.onKeyMultiple()}: always returns false (doesn't handle * the event). - * - * @param keyCode A key code that represents the button pressed, from + * + * @param keyCode A key code that represents the button pressed, from * {@link android.view.KeyEvent}. * @param repeatCount The number of times the action was made. * @param event The KeyEvent object that defines the button action. @@ -3402,7 +3544,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback { /** * Called when an unhandled key shortcut event occurs. - * + * * @param keyCode The value in event.getKeyCode(). * @param event Description of the key event. * @return If you handled the event, return true. If you want to allow the @@ -3411,11 +3553,23 @@ public class View implements Drawable.Callback, KeyEvent.Callback { public boolean onKeyShortcut(int keyCode, KeyEvent event) { return false; } - + + /** + * Create a new InputConnection for an InputMethod to interact + * with the view. The default implementation returns null, since it doesn't + * support input methods. You can override this to implement such support. + * This is only needed for views that take focus and text input. + * + * @param outAttrs Fill in with attribute information about the connection. + */ + public InputConnection createInputConnection(EditorInfo outAttrs) { + return null; + } + /** * Show the context menu for this view. It is not safe to hold on to the * menu after returning from this method. - * + * * @param menu The context menu to populate */ public void createContextMenu(ContextMenu menu) { @@ -3517,7 +3671,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback { if (mPendingCheckForLongPress != null) { removeCallbacks(mPendingCheckForLongPress); } - + // Only perform take click actions if we were in the pressed state if (!focusTaken) { performClick(); @@ -3548,10 +3702,10 @@ public class View implements Drawable.Callback, KeyEvent.Callback { case MotionEvent.ACTION_MOVE: final int x = (int) event.getX(); final int y = (int) event.getY(); - + // Be lenient about moving outside of buttons int slop = ViewConfiguration.getTouchSlop(); - if ((x < 0 - slop) || (x >= getWidth() + slop) || + if ((x < 0 - slop) || (x >= getWidth() + slop) || (y < 0 - slop) || (y >= getHeight() + slop)) { // Outside button if ((mPrivateFlags & PRESSED) != 0) { @@ -3598,7 +3752,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback { public void setTouchDelegate(TouchDelegate delegate) { mTouchDelegate = delegate; } - + /** * Gets the TouchDelegate for this View. */ @@ -3608,7 +3762,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback { /** * Set flags controlling behavior of this view. - * + * * @param flags Constant indicating the value which should be set * @param mask Constant indicating the bit range that should be changed */ @@ -3648,7 +3802,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback { mPrivateFlags |= DRAWN; needGlobalAttributesUpdate(true); - + // a view becoming visible is worth notifying the parent // about in case nothing has focus. even if this specific view // isn't focusable, it may contain something that is, so let @@ -3668,6 +3822,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback { if (((mViewFlags & VISIBILITY_MASK) == GONE) && hasFocus()) { clearFocus(); } + if (mAttachInfo != null) { + mAttachInfo.mViewVisibilityChanged = true; + } } /* Check if the VISIBLE bit has changed */ @@ -3681,6 +3838,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback { clearFocus(); } } + if (mAttachInfo != null) { + mAttachInfo.mViewVisibilityChanged = true; + } } if ((changed & WILL_NOT_CACHE_DRAWING) != 0) { @@ -3712,7 +3872,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback { mPrivateFlags &= ~SKIP_DRAW; mPrivateFlags |= ONLY_DRAWS_BACKGROUND; } else { - mPrivateFlags |= SKIP_DRAW; + mPrivateFlags |= SKIP_DRAW; } } else { mPrivateFlags &= ~SKIP_DRAW; @@ -3720,7 +3880,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback { requestLayout(); invalidate(); } - + if ((changed & KEEP_SCREEN_ON) != 0) { if (mParent != null) { mParent.recomputeViewAttributes(this); @@ -3740,10 +3900,10 @@ public class View implements Drawable.Callback, KeyEvent.Callback { /** * This is called in response to an internal scroll in this view (i.e., the - * view scrolled its own contents). This is typically as a result of + * view scrolled its own contents). This is typically as a result of * {@link #scrollBy(int, int)} or {@link #scrollTo(int, int)} having been * called. - * + * * @param l Current horizontal scroll origin. * @param t Current vertical scroll origin. * @param oldl Previous horizontal scroll origin. @@ -3757,7 +3917,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback { * This is called during layout when the size of this view has changed. If * you were just added to the view hierarchy, you're called with the old * values of 0. - * + * * @param w Current width of this view. * @param h Current height of this view. * @param oldw Old width of this view. @@ -3765,7 +3925,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback { */ protected void onSizeChanged(int w, int h, int oldw, int oldh) { } - + /** * Called by draw to draw the child views. This may be overridden * by derived classes to gain control just before its children are drawn @@ -3778,7 +3938,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback { /** * Gets the parent of this view. Note that the parent is a * ViewParent and not necessarily a View. - * + * * @return Parent of this view. */ public final ViewParent getParent() { @@ -3790,7 +3950,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback { * the displayed part of your view. You do not need to draw any pixels * farther left, since those are outside of the frame of your view on * screen. - * + * * @return The left edge of the displayed part of your view, in pixels. */ public final int getScrollX() { @@ -3801,7 +3961,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback { * Return the scrolled top position of this view. This is the top edge of * the displayed part of your view. You do not need to draw any pixels above * it, since those are outside of the frame of your view on screen. - * + * * @return The top edge of the displayed part of your view, in pixels. */ public final int getScrollY() { @@ -3810,7 +3970,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback { /** * Return the width of the your view. - * + * * @return The width of your view, in pixels. */ @ViewDebug.ExportedProperty @@ -3820,7 +3980,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback { /** * Return the height of your view. - * + * * @return The height of your view, in pixels. */ @ViewDebug.ExportedProperty @@ -3832,7 +3992,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback { * Return the visible drawing bounds of your view. Fills in the output * rectangle with the values from getScrollX(), getScrollY(), * getWidth(), and getHeight(). - * + * * @param outRect The (scrolled) drawing bounds of the view. */ public void getDrawingRect(Rect outRect) { @@ -3846,69 +4006,73 @@ public class View implements Drawable.Callback, KeyEvent.Callback { * The width of this view as measured in the most recent call to measure(). * This should be used during measurement and layout calculations only. Use * {@link #getWidth()} to see how wide a view is after layout. - * + * * @return The measured width of this view. */ public final int getMeasuredWidth() { return mMeasuredWidth; } - + /** * The height of this view as measured in the most recent call to measure(). * This should be used during measurement and layout calculations only. Use * {@link #getHeight()} to see how tall a view is after layout. - * + * * @return The measured height of this view. */ public final int getMeasuredHeight() { return mMeasuredHeight; } - + /** * Top position of this view relative to its parent. - * + * * @return The top of this view, in pixels. */ + @ViewDebug.CapturedViewProperty public final int getTop() { return mTop; } - + /** * Bottom position of this view relative to its parent. - * + * * @return The bottom of this view, in pixels. */ + @ViewDebug.CapturedViewProperty public final int getBottom() { return mBottom; } - + /** * Left position of this view relative to its parent. - * + * * @return The left edge of this view, in pixels. */ + @ViewDebug.CapturedViewProperty public final int getLeft() { return mLeft; } - + /** * Right position of this view relative to its parent. - * + * * @return The right edge of this view, in pixels. */ + @ViewDebug.CapturedViewProperty public final int getRight() { return mRight; } /** * Hit rectangle in parent's coordinates - * + * * @param outRect The hit rectangle of the view. */ public void getHitRect(Rect outRect) { outRect.set(mLeft, mTop, mRight, mBottom); } - + /** * When a view has focus and the user navigates away from it, the next view is searched for * starting from the rectangle filled in by this method. @@ -3929,7 +4093,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback { * coordinates, offset it by -globalOffset (e.g. r.offset(-globalOffset.x, * -globalOffset.y)) If the view is completely clipped or translated out, * return false. - * + * * @param r If true is returned, r holds the global coordinates of the * visible portion of this view. * @param globalOffset If true is returned, globalOffset holds the dx,dy @@ -3962,7 +4126,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback { } return false; } - + /** * Offset this view's vertical location by the specified number of pixels. * @@ -3975,18 +4139,18 @@ public class View implements Drawable.Callback, KeyEvent.Callback { /** * Offset this view's horizontal location by the specified amount of pixels. - * + * * @param offset the numer of pixels to offset the view by */ public void offsetLeftAndRight(int offset) { mLeft += offset; mRight += offset; } - + /** * Get the LayoutParams associated with this view. All views should have - * layout parameters. These supply parameters to the parent of this - * view specifying how it should be arranged. There are many subclasses of + * layout parameters. These supply parameters to the parent of this + * view specifying how it should be arranged. There are many subclasses of * ViewGroup.LayoutParams, and these correspond to the different subclasses * of ViewGroup that are responsible for arranging their children. * @return The LayoutParams associated with this view @@ -4012,7 +4176,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback { mLayoutParams = params; requestLayout(); } - + /** * Set the scrolled position of your view. This will cause a call to * {@link #onScrollChanged(int, int, int, int)} and the view will be @@ -4047,7 +4211,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback { * visible, {@link #onDraw} will be called at some point in the future. * This must be called from a UI thread. To call from a non-UI thread, call * {@link #postInvalidate()}. - * + * * WARNING: This method is destructive to dirty. * @param dirty the rectangle representing the bounds of the dirty region */ @@ -4058,13 +4222,15 @@ public class View implements Drawable.Callback, KeyEvent.Callback { if ((mPrivateFlags & (DRAWN | HAS_BOUNDS)) == (DRAWN | HAS_BOUNDS)) { mPrivateFlags &= ~DRAWING_CACHE_VALID; - ViewParent p = mParent; - if (p != null) { + final ViewParent p = mParent; + final AttachInfo ai = mAttachInfo; + if (p != null && ai != null) { final int scrollX = mScrollX; final int scrollY = mScrollY; - mTempRect.set(dirty.left - scrollX, dirty.top - scrollY, - dirty.right - scrollX, dirty.bottom - scrollY); - p.invalidateChild(this, mTempRect); + final Rect r = ai.mTmpInvalRect; + r.set(dirty.left - scrollX, dirty.top - scrollY, + dirty.right - scrollX, dirty.bottom - scrollY); + mParent.invalidateChild(this, r); } } } @@ -4087,12 +4253,14 @@ public class View implements Drawable.Callback, KeyEvent.Callback { if ((mPrivateFlags & (DRAWN | HAS_BOUNDS)) == (DRAWN | HAS_BOUNDS)) { mPrivateFlags &= ~DRAWING_CACHE_VALID; - ViewParent p = mParent; - if (p != null && l < r && t < b) { + final ViewParent p = mParent; + final AttachInfo ai = mAttachInfo; + if (p != null && ai != null && l < r && t < b) { final int scrollX = mScrollX; final int scrollY = mScrollY; - mTempRect.set(l - scrollX, t - scrollY, r - scrollX, b - scrollY); - p.invalidateChild(this, mTempRect); + final Rect tmpr = ai.mTmpInvalRect; + tmpr.set(l - scrollX, t - scrollY, r - scrollX, b - scrollY); + p.invalidateChild(this, tmpr); } } } @@ -4109,25 +4277,27 @@ public class View implements Drawable.Callback, KeyEvent.Callback { if ((mPrivateFlags & (DRAWN | HAS_BOUNDS)) == (DRAWN | HAS_BOUNDS)) { mPrivateFlags &= ~DRAWN & ~DRAWING_CACHE_VALID; - ViewParent p = mParent; - if (p != null) { - mTempRect.set(0, 0, mRight - mLeft, mBottom - mTop); + final ViewParent p = mParent; + final AttachInfo ai = mAttachInfo; + if (p != null && ai != null) { + final Rect r = ai.mTmpInvalRect; + r.set(0, 0, mRight - mLeft, mBottom - mTop); // Don't call invalidate -- we don't want to internally scroll // our own bounds - p.invalidateChild(this, mTempRect); + p.invalidateChild(this, r); } } } - + /** * @return A handler associated with the thread running the View. This * handler can be used to pump events in the UI events queue. */ - protected Handler getHandler() { + public Handler getHandler() { if (mAttachInfo != null) { return mAttachInfo.mHandler; } - return null; + return null; } /** @@ -4260,7 +4430,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback { /** * Cause an invalidate to happen on a subsequent cycle through the event * loop. Waits for the specified amount of time. - * + * * @param delayMilliseconds the duration in milliseconds to delay the * invalidation by */ @@ -4304,7 +4474,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback { * Called by a parent to request that a child update its values for mScrollX * and mScrollY if necessary. This will typically be done if the child is * animating a scroll using a {@link android.widget.Scroller Scroller} - * object. + * object. */ public void computeScroll() { } @@ -4337,7 +4507,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback { public void setHorizontalFadingEdgeEnabled(boolean horizontalFadingEdgeEnabled) { if (isHorizontalFadingEdgeEnabled() != horizontalFadingEdgeEnabled) { if (horizontalFadingEdgeEnabled) { - initScrollCache(); + initScrollCache(); } mViewFlags ^= FADING_EDGE_HORIZONTAL; @@ -4504,12 +4674,12 @@ public class View implements Drawable.Callback, KeyEvent.Callback { * inset. When inset, they add to the padding of the view. And the scrollbars * can be drawn inside the padding area or on the edge of the view. For example, * if a view has a background drawable and you want to draw the scrollbars - * inside the padding specified by the drawable, you can use + * inside the padding specified by the drawable, you can use * SCROLLBARS_INSIDE_OVERLAY or SCROLLBARS_INSIDE_INSET. If you want them to * appear at the edge of the view, ignoring the padding, then you can use - * SCROLLBARS_OUTSIDE_OVERLAY or SCROLLBARS_OUTSIDE_INSET.

    - * @param style the style of the scrollbars. Should be one of - * SCROLLBARS_INSIDE_OVERLAY, SCROLLBARS_INSIDE_INSET, + * SCROLLBARS_OUTSIDE_OVERLAY or SCROLLBARS_OUTSIDE_INSET.

    + * @param style the style of the scrollbars. Should be one of + * SCROLLBARS_INSIDE_OVERLAY, SCROLLBARS_INSIDE_INSET, * SCROLLBARS_OUTSIDE_OVERLAY or SCROLLBARS_OUTSIDE_INSET. * @see #SCROLLBARS_INSIDE_OVERLAY * @see #SCROLLBARS_INSIDE_INSET @@ -4517,12 +4687,12 @@ public class View implements Drawable.Callback, KeyEvent.Callback { * @see #SCROLLBARS_OUTSIDE_INSET */ public void setScrollBarStyle(int style) { - if (style != (mViewFlags & SCROLLBARS_STYLE_MASK)) { + if (style != (mViewFlags & SCROLLBARS_STYLE_MASK)) { mViewFlags = (mViewFlags & ~SCROLLBARS_STYLE_MASK) | (style & SCROLLBARS_STYLE_MASK); recomputePadding(); } } - + /** *

    Returns the current scrollbar style.

    * @return the current scrollbar style @@ -4534,7 +4704,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback { public int getScrollBarStyle() { return mViewFlags & SCROLLBARS_STYLE_MASK; } - + /** *

    Compute the horizontal range that the horizontal scrollbar * represents.

    @@ -4670,10 +4840,10 @@ public class View implements Drawable.Callback, KeyEvent.Callback { final ScrollabilityCache cache = mScrollCache; if (cache != null) { final int viewFlags = mViewFlags; - - final boolean drawHorizontalScrollBar = + + final boolean drawHorizontalScrollBar = (viewFlags & SCROLLBARS_HORIZONTAL) == SCROLLBARS_HORIZONTAL; - final boolean drawVerticalScrollBar = + final boolean drawVerticalScrollBar = (viewFlags & SCROLLBARS_VERTICAL) == SCROLLBARS_VERTICAL; if (drawVerticalScrollBar || drawHorizontalScrollBar) { @@ -4728,12 +4898,12 @@ public class View implements Drawable.Callback, KeyEvent.Callback { final int scrollY = mScrollY; final int inside = (viewFlags & SCROLLBARS_OUTSIDE_MASK) == 0 ? ~0 : 0; final int top = scrollY + height - size - (mUserPaddingBottom & inside); - - final int verticalScrollBarGap = + + final int verticalScrollBarGap = (viewFlags & SCROLLBARS_VERTICAL) == SCROLLBARS_VERTICAL ? getVerticalScrollbarWidth() : 0; - - scrollBar.setBounds(scrollX + (mPaddingLeft & inside) + getScrollBarPaddingLeft(), top, + + scrollBar.setBounds(scrollX + (mPaddingLeft & inside) + getScrollBarPaddingLeft(), top, scrollX + width - (mUserPaddingRight & inside) - verticalScrollBarGap, top + size); scrollBar.setParameters( computeHorizontalScrollRange(), @@ -4773,8 +4943,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback { final int inside = (mViewFlags & SCROLLBARS_OUTSIDE_MASK) == 0 ? ~0 : 0; // TODO: Deal with RTL languages to position scrollbar on left final int left = scrollX + width - size - (mUserPaddingRight & inside); - - scrollBar.setBounds(left, scrollY + (mPaddingTop & inside), + + scrollBar.setBounds(left, scrollY + (mPaddingTop & inside), left + size, scrollY + height - (mUserPaddingBottom & inside)); scrollBar.setParameters( computeVerticalScrollRange(), @@ -4832,7 +5002,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback { removeCallbacks(mPendingCheckForLongPress); } } - + /** * @return The number of times this view has been attached to a window */ @@ -4855,7 +5025,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback { * {@link #getWindowToken}, except if the window this view in is a panel * window (attached to another containing window), then the token of * the containing window is returned instead. - * + * * @return Returns the associated window token, either * {@link #getWindowToken()} or the containing window's token. */ @@ -4892,6 +5062,10 @@ public class View implements Drawable.Callback, KeyEvent.Callback { info.mTreeObserver.merge(mFloatingTreeObserver); mFloatingTreeObserver = null; } + if ((mPrivateFlags&SCROLL_CONTAINER) != 0) { + mAttachInfo.mScrollContainers.add(this); + mPrivateFlags |= SCROLL_CONTAINER_ADDED; + } performCollectViewAttributes(visibility); onAttachedToWindow(); int vis = info.mWindowVisibility; @@ -4909,16 +5083,20 @@ public class View implements Drawable.Callback, KeyEvent.Callback { onWindowVisibilityChanged(GONE); } } - + onDetachedFromWindow(); + if ((mPrivateFlags&SCROLL_CONTAINER_ADDED) != 0) { + mAttachInfo.mScrollContainers.remove(this); + mPrivateFlags &= ~SCROLL_CONTAINER_ADDED; + } mAttachInfo = null; } /** * Store this view hierarchy's frozen state into the given container. - * + * * @param container The SparseArray in which to save the view's state. - * + * * @see #restoreHierarchyState * @see #dispatchSaveInstanceState * @see #onSaveInstanceState @@ -4931,9 +5109,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback { * Called by {@link #saveHierarchyState} to store the state for this view and its children. * May be overridden to modify how freezing happens to a view's children; for example, some * views may want to not store state for their children. - * + * * @param container The SparseArray in which to save the view's state. - * + * * @see #dispatchRestoreInstanceState * @see #saveHierarchyState * @see #onSaveInstanceState @@ -4966,7 +5144,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback { * in a text view (but usually not the text itself since that is stored in a * content provider or other persistent storage), the currently selected * item in a list view. - * + * * @return Returns a Parcelable object containing the view's current dynamic * state, or null if there is nothing interesting to save. The * default implementation returns null. @@ -4982,9 +5160,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback { /** * Restore this view hierarchy's frozen state from the given container. - * + * * @param container The SparseArray which holds previously frozen states. - * + * * @see #saveHierarchyState * @see #dispatchRestoreInstanceState * @see #onRestoreInstanceState @@ -4997,9 +5175,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback { * Called by {@link #restoreHierarchyState} to retrieve the state for this view and its * children. May be overridden to modify how restoreing happens to a view's children; for * example, some views may want to not store state for their children. - * + * * @param container The SparseArray which holds previously saved state. - * + * * @see #dispatchSaveInstanceState * @see #restoreHierarchyState * @see #onRestoreInstanceState @@ -5024,10 +5202,10 @@ public class View implements Drawable.Callback, KeyEvent.Callback { * Hook allowing a view to re-apply a representation of its internal state that had previously * been generated by {@link #onSaveInstanceState}. This function will never be called with a * null state. - * + * * @param state The frozen state that had previously been returned by * {@link #onSaveInstanceState}. - * + * * @see #onSaveInstanceState * @see #restoreHierarchyState * @see #dispatchRestoreInstanceState @@ -5038,7 +5216,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback { throw new IllegalArgumentException("Wrong state class -- expecting View State"); } } - + /** *

    Return the time at which the drawing of the view hierarchy started.

    * @@ -5095,7 +5273,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback { * * @see #isDrawingCacheEnabled() * @see #getDrawingCache() - * @see #buildDrawingCache() + * @see #buildDrawingCache() */ public void setDrawingCacheEnabled(boolean enabled) { setFlags(enabled ? DRAWING_CACHE_ENABLED : 0, DRAWING_CACHE_ENABLED); @@ -5126,7 +5304,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback { * * @see #setDrawingCacheEnabled(boolean) * @see #isDrawingCacheEnabled() - * @see #buildDrawingCache() + * @see #buildDrawingCache() * @see #destroyDrawingCache() */ public Bitmap getDrawingCache() { @@ -5148,7 +5326,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback { * * @see #setDrawingCacheEnabled(boolean) * @see #buildDrawingCache() - * @see #getDrawingCache() + * @see #getDrawingCache() */ public void destroyDrawingCache() { if (mDrawingCache != null) { @@ -5156,31 +5334,31 @@ public class View implements Drawable.Callback, KeyEvent.Callback { mDrawingCache = null; } } - + /** * Setting a solid background color for the drawing cache's bitmaps will improve * perfromance and memory usage. Note, though that this should only be used if this * view will always be drawn on top of a solid color. - * + * * @param color The background color to use for the drawing cache's bitmap - * + * * @see #setDrawingCacheEnabled(boolean) * @see #buildDrawingCache() - * @see #getDrawingCache() + * @see #getDrawingCache() */ public void setDrawingCacheBackgroundColor(int color) { mDrawingCacheBackgroundColor = color; } - + /** * @see #setDrawingCacheBackgroundColor(int) - * + * * @return The background color to used for the drawing cache's bitmap */ public int getDrawingCacheBackgroundColor() { return mDrawingCacheBackgroundColor; } - + /** *

    Forces the drawing cache to be built if the drawing cache is invalid.

    * @@ -5204,7 +5382,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback { final int height = mBottom - mTop; final int drawingCacheBackgroundColor = mDrawingCacheBackgroundColor; - final boolean opaque = drawingCacheBackgroundColor != 0 || + final boolean opaque = drawingCacheBackgroundColor != 0 || (mBGDrawable != null && mBGDrawable.getOpacity() == PixelFormat.OPAQUE); if (width <= 0 || height <= 0 || @@ -5242,9 +5420,22 @@ public class View implements Drawable.Callback, KeyEvent.Callback { quality = Bitmap.Config.RGB_565; } - mDrawingCache = bitmap = Bitmap.createBitmap(width, height, quality); + // Try to cleanup memory + if (mDrawingCache != null) { + mDrawingCache.recycle(); + } - clear = drawingCacheBackgroundColor != 0; + try { + mDrawingCache = bitmap = Bitmap.createBitmap(width, height, quality); + } catch (OutOfMemoryError e) { + // If there is not enough memory to create the bitmap cache, just + // ignore the issue as bitmap caches are not required to draw the + // view hierarchy + mDrawingCache = null; + return; + } + + clear = drawingCacheBackgroundColor != 0; } Canvas canvas; @@ -5293,7 +5484,103 @@ public class View implements Drawable.Callback, KeyEvent.Callback { mPrivateFlags |= DRAWING_CACHE_VALID; } } - + + /** + * Indicates whether this View is currently in edit mode. A View is usually + * in edit mode when displayed within a developer tool. For instance, if + * this View is being drawn by a visual user interface builder, this method + * should return true. + * + * Subclasses should check the return value of this method to provide + * different behaviors if their normal behavior might interfere with the + * host environment. For instance: the class spawns a thread in its + * constructor, the drawing code relies on device-specific features, etc. + * + * This method is usually checked in the drawing code of custom widgets. + * + * @return True if this View is in edit mode, false otherwise. + */ + public boolean isInEditMode() { + return false; + } + + /** + * If the View draws content inside its padding and enables fading edges, + * it needs to support padding offsets. Padding offsets are added to the + * fading edges to extend the length of the fade so that it covers pixels + * drawn inside the padding. + * + * Subclasses of this class should override this method if they need + * to draw content inside the padding. + * + * @return True if padding offset must be applied, false otherwise. + * + * @see #getLeftPaddingOffset() + * @see #getRightPaddingOffset() + * @see #getTopPaddingOffset() + * @see #getBottomPaddingOffset() + * + * @since CURRENT + */ + protected boolean isPaddingOffsetRequired() { + return false; + } + + /** + * Amount by which to extend the left fading region. Called only when + * {@link #isPaddingOffsetRequired()} returns true. + * + * @return The left padding offset in pixels. + * + * @see #isPaddingOffsetRequired() + * + * @since CURRENT + */ + protected int getLeftPaddingOffset() { + return 0; + } + + /** + * Amount by which to extend the right fading region. Called only when + * {@link #isPaddingOffsetRequired()} returns true. + * + * @return The right padding offset in pixels. + * + * @see #isPaddingOffsetRequired() + * + * @since CURRENT + */ + protected int getRightPaddingOffset() { + return 0; + } + + /** + * Amount by which to extend the top fading region. Called only when + * {@link #isPaddingOffsetRequired()} returns true. + * + * @return The top padding offset in pixels. + * + * @see #isPaddingOffsetRequired() + * + * @since CURRENT + */ + protected int getTopPaddingOffset() { + return 0; + } + + /** + * Amount by which to extend the bottom fading region. Called only when + * {@link #isPaddingOffsetRequired()} returns true. + * + * @return The bottom padding offset in pixels. + * + * @see #isPaddingOffsetRequired() + * + * @since CURRENT + */ + protected int getBottomPaddingOffset() { + return 0; + } /** * Manually render this view (and all of its children) to the given Canvas. @@ -5379,13 +5666,24 @@ public class View implements Drawable.Callback, KeyEvent.Callback { float rightFadeStrength = 0.0f; // Step 2, save the canvas' layers - final int paddingLeft = mPaddingLeft; - final int paddingTop = mPaddingTop; + int paddingLeft = mPaddingLeft; + int paddingTop = mPaddingTop; + + final boolean offsetRequired = isPaddingOffsetRequired(); + if (offsetRequired) { + paddingLeft += getLeftPaddingOffset(); + paddingTop += getTopPaddingOffset(); + } - final int left = mScrollX + paddingLeft; - final int right = left + mRight - mLeft - mPaddingRight - paddingLeft; - final int top = mScrollY + paddingTop; - final int bottom = top + mBottom - mTop - mPaddingBottom - paddingTop; + int left = mScrollX + paddingLeft; + int right = left + mRight - mLeft - mPaddingRight - paddingLeft; + int top = mScrollY + paddingTop; + int bottom = top + mBottom - mTop - mPaddingBottom - paddingTop; + + if (offsetRequired) { + right += getRightPaddingOffset(); + bottom += getBottomPaddingOffset(); + } final ScrollabilityCache scrollabilityCache = mScrollCache; int length = scrollabilityCache.fadingEdgeLength; @@ -5416,23 +5714,23 @@ public class View implements Drawable.Callback, KeyEvent.Callback { } saveCount = canvas.getSaveCount(); - + int solidColor = getSolidColor(); if (solidColor == 0) { final int flags = Canvas.HAS_ALPHA_LAYER_SAVE_FLAG; - + if (drawTop) { canvas.saveLayer(left, top, right, top + length, null, flags); } - + if (drawBottom) { canvas.saveLayer(left, bottom - length, right, bottom, null, flags); } - + if (drawLeft) { canvas.saveLayer(left, top, left + length, bottom, null, flags); } - + if (drawRight) { canvas.saveLayer(right - length, top, right, bottom, null, flags); } @@ -5495,10 +5793,10 @@ public class View implements Drawable.Callback, KeyEvent.Callback { * and needs to draw fading edges. Returning a non-zero color enables the view system to * optimize the drawing of the fading edges. If you do return a non-zero color, the alpha * should be set to 0xFF. - * + * * @see #setVerticalFadingEdgeEnabled * @see #setHorizontalFadingEdgeEnabled - * + * * @return The known solid color background for this view, or 0 if the color may vary */ public int getSolidColor() { @@ -5550,12 +5848,12 @@ public class View implements Drawable.Callback, KeyEvent.Callback { private static String printPrivateFlags(int privateFlags) { String output = ""; int numFlags = 0; - + if ((privateFlags & WANTS_FOCUS) == WANTS_FOCUS) { output += "WANTS_FOCUS"; numFlags++; } - + if ((privateFlags & FOCUSED) == FOCUSED) { if (numFlags > 0) { output += " "; @@ -5563,7 +5861,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback { output += "FOCUSED"; numFlags++; } - + if ((privateFlags & SELECTED) == SELECTED) { if (numFlags > 0) { output += " "; @@ -5571,15 +5869,15 @@ public class View implements Drawable.Callback, KeyEvent.Callback { output += "SELECTED"; numFlags++; } - + if ((privateFlags & IS_ROOT_NAMESPACE) == IS_ROOT_NAMESPACE) { if (numFlags > 0) { output += " "; } output += "IS_ROOT_NAMESPACE"; numFlags++; - } - + } + if ((privateFlags & HAS_BOUNDS) == HAS_BOUNDS) { if (numFlags > 0) { output += " "; @@ -5587,7 +5885,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback { output += "HAS_BOUNDS"; numFlags++; } - + if ((privateFlags & DRAWN) == DRAWN) { if (numFlags > 0) { output += " "; @@ -5611,17 +5909,17 @@ public class View implements Drawable.Callback, KeyEvent.Callback { /** * Assign a size and position to a view and all of its * descendants - * - *

    This is the second phase of the layout mechanism. + * + *

    This is the second phase of the layout mechanism. * (The first is measuring). In this phase, each parent calls * layout on all of its children to position them. * This is typically done using the child measurements * that were stored in the measure pass(). - * + * * Derived classes with children should override * onLayout. In that method, they should * call layout on each of their their children. - * + * * @param l Left position, relative to parent * @param t Top position, relative to parent * @param r Right position, relative to parent @@ -5639,11 +5937,11 @@ public class View implements Drawable.Callback, KeyEvent.Callback { } mPrivateFlags &= ~FORCE_LAYOUT; } - + /** * Called from layout when this view should * assign a size and position to each of its children. - * + * * Derived classes with children should override * this method and call layout on each of * their their children. @@ -5655,12 +5953,12 @@ public class View implements Drawable.Callback, KeyEvent.Callback { */ protected void onLayout(boolean changed, int left, int top, int right, int bottom) { } - + /** * Assign a size and position to this view. - * + * * This is called from layout. - * + * * @param left Left position, relative to parent * @param top Top position, relative to parent * @param right Right position, relative to parent @@ -5699,7 +5997,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback { int newWidth = right - left; int newHeight = bottom - top; - + if (newWidth != oldWidth || newHeight != oldHeight) { onSizeChanged(newWidth, newHeight, oldWidth, oldHeight); } @@ -5725,7 +6023,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback { /** * Finalize inflating a view from XML. This is called as the last phase * of inflation, after all child views have been added. - * + * *

    Even if the subclass overrides onFinishInflate, they should always be * sure to call the super method, so that we get called. */ @@ -5734,7 +6032,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback { /** * Returns the resources associated with this view. - * + * * @return Resources object. */ public Resources getResources() { @@ -5787,9 +6085,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback { * Unschedule any events associated with the given Drawable. This can be * used when selecting a new Drawable into a view, so that the previous * one is completely unscheduled. - * + * * @param who The Drawable to unschedule. - * + * * @see #drawableStateChanged */ public void unscheduleDrawable(Drawable who) { @@ -5803,17 +6101,17 @@ public class View implements Drawable.Callback, KeyEvent.Callback { * override this function and return true for any Drawable it is * displaying. This allows animations for those drawables to be * scheduled. - * + * *

    Be sure to call through to the super class when overriding this * function. - * + * * @param who The Drawable to verify. Return true if it is one you are * displaying, else return the result of calling through to the * super class. - * + * * @return boolean If true than the Drawable is being displayed in the * view; else false and it is not allowed to animate. - * + * * @see #unscheduleDrawable * @see #drawableStateChanged */ @@ -5824,7 +6122,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback { /** * This function is called whenever the state of the view changes in such * a way that it impacts the state of drawables being shown. - * + * *

    Be sure to call through to the superclass when overriding this * function. * @@ -5836,12 +6134,12 @@ public class View implements Drawable.Callback, KeyEvent.Callback { d.setState(getDrawableState()); } } - + /** * Call this to force a view to update its drawable state. This will cause * drawableStateChanged to be called on this view. Views that are interested * in the new state should call getDrawableState. - * + * * @see #drawableStateChanged * @see #getDrawableState */ @@ -5858,9 +6156,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback { /** * Return an array of resource IDs of the drawable states representing the * current state of the view. - * + * * @return The current drawable state - * + * * @see Drawable#setState * @see #drawableStateChanged * @see #onCreateDrawableState @@ -5880,14 +6178,14 @@ public class View implements Drawable.Callback, KeyEvent.Callback { * this view. This is called by the view * system when the cached Drawable state is determined to be invalid. To * retrieve the current state, you should use {@link #getDrawableState}. - * + * * @param extraSpace if non-zero, this is the number of extra entries you * would like in the returned array in which you can place your own * states. - * + * * @return Returns an array holding the current {@link Drawable} state of * the view. - * + * * @see #mergeDrawableStates */ protected int[] onCreateDrawableState(int extraSpace) { @@ -5897,22 +6195,20 @@ public class View implements Drawable.Callback, KeyEvent.Callback { } int[] drawableState; - + int privateFlags = mPrivateFlags; - boolean isPressed = (privateFlags & PRESSED) != 0; - int viewStateIndex = (isPressed ? 1 : 0); + int viewStateIndex = (((privateFlags & PRESSED) != 0) ? 1 : 0); - boolean isEnabled = (mViewFlags & ENABLED_MASK) == ENABLED; - viewStateIndex = (viewStateIndex << 1) + (isEnabled ? 1 : 0); + viewStateIndex = (viewStateIndex << 1) + + (((mViewFlags & ENABLED_MASK) == ENABLED) ? 1 : 0); - boolean isFocused = isFocused(); - viewStateIndex = (viewStateIndex << 1) + (isFocused ? 1 : 0); - - boolean isSelected = (privateFlags & SELECTED) != 0; - viewStateIndex = (viewStateIndex << 1) + (isSelected ? 1 : 0); - - boolean hasWindowFocus = hasWindowFocus(); + viewStateIndex = (viewStateIndex << 1) + (isFocused() ? 1 : 0); + + viewStateIndex = (viewStateIndex << 1) + + (((privateFlags & SELECTED) != 0) ? 1 : 0); + + final boolean hasWindowFocus = hasWindowFocus(); viewStateIndex = (viewStateIndex << 1) + (hasWindowFocus ? 1 : 0); drawableState = VIEW_STATE_SETS[viewStateIndex]; @@ -5920,9 +6216,12 @@ public class View implements Drawable.Callback, KeyEvent.Callback { //noinspection ConstantIfStatement if (false) { Log.i("View", "drawableStateIndex=" + viewStateIndex); - Log.i("View", toString() + " pressed=" + isPressed - + " en=" + isEnabled + " fo=" + isFocused - + " sl=" + isSelected + " wf=" + hasWindowFocus + Log.i("View", toString() + + " pressed=" + ((privateFlags & PRESSED) != 0) + + " en=" + ((mViewFlags & ENABLED_MASK) == ENABLED) + + " fo=" + hasFocus() + + " sl=" + ((privateFlags & SELECTED) != 0) + + " wf=" + hasWindowFocus + ": " + Arrays.toString(drawableState)); } @@ -5940,22 +6239,22 @@ public class View implements Drawable.Callback, KeyEvent.Callback { return fullState; } - + /** * Merge your own state values in additionalState into the base * state values baseState that were returned by * {@link #onCreateDrawableState}. - * + * * @param baseState The base state values returned by * {@link #onCreateDrawableState}, which will be modified to also hold your * own additional state values. - * + * * @param additionalState The additional state values you would like * added to baseState; this array is not modified. - * + * * @return As a convenience, the baseState array you originally * passed into the function is returned. - * + * * @see #onCreateDrawableState */ protected static int[] mergeDrawableStates(int[] baseState, int[] additionalState) { @@ -5967,7 +6266,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback { System.arraycopy(additionalState, 0, baseState, i + 1, additionalState.length); return baseState; } - + /** * Sets the background color for this view. * @param color the color of the background @@ -5975,7 +6274,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback { public void setBackgroundColor(int color) { setBackgroundDrawable(new ColorDrawable(color)); } - + /** * Set the background to a given resource. The resource should refer to * a Drawable object. @@ -6002,13 +6301,13 @@ public class View implements Drawable.Callback, KeyEvent.Callback { * padding. However, when a background is removed, this View's padding isn't * touched. If setting the padding is desired, please use * {@link #setPadding(int, int, int, int)}. - * + * * @param d The Drawable to use as the background, or null to remove the * background */ public void setBackgroundDrawable(Drawable d) { boolean requestLayout = false; - + mBackgroundResource = 0; /* @@ -6021,11 +6320,15 @@ public class View implements Drawable.Callback, KeyEvent.Callback { } if (d != null) { - final Rect padding = mTempRect; + Rect padding = sThreadLocal.get(); + if (padding == null) { + padding = new Rect(); + sThreadLocal.set(padding); + } if (d.getPadding(padding)) { setPadding(padding.left, padding.top, padding.right, padding.bottom); } - + // Compare the minimum sizes of the old Drawable and the new. If there isn't an old or // if it has a different minimum size, we should layout again if (mBGDrawable == null || mBGDrawable.getMinimumHeight() != d.getMinimumHeight() || @@ -6048,7 +6351,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback { } else { /* Remove the background */ mBGDrawable = null; - + if ((mPrivateFlags & ONLY_DRAWS_BACKGROUND) != 0) { /* * This view ONLY drew the background before and we're removing @@ -6065,7 +6368,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback { * padding. This is noted in the Javadocs. Hence, we don't need to * requestLayout(), the invalidate() below is sufficient. */ - + // The old background's minimum size could have affected this // View's layout, so let's requestLayout requestLayout = true; @@ -6091,7 +6394,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback { // TODO: Deal with RTL languages return 0; } - + /* * Returns the pixels occupied by the vertical scrollbar, if not overlaid */ @@ -6114,7 +6417,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback { } /** - * Sets the padding. The view may add on the space required to display + * Sets the padding. The view may add on the space required to display * the scrollbars, depending on the style and visibility of the scrollbars. * So the values returned from {@link #getPaddingLeft}, {@link #getPaddingTop}, * {@link #getPaddingRight} and {@link #getPaddingBottom} may be different @@ -6132,10 +6435,10 @@ public class View implements Drawable.Callback, KeyEvent.Callback { */ public void setPadding(int left, int top, int right, int bottom) { boolean changed = false; - + mUserPaddingRight = right; mUserPaddingBottom = bottom; - + if (mPaddingLeft != left + getScrollBarPaddingLeft()) { changed = true; mPaddingLeft = left; @@ -6216,17 +6519,17 @@ public class View implements Drawable.Callback, KeyEvent.Callback { dispatchSetSelected(selected); } } - + /** * Dispatch setSelected to all of this View's children. - * + * * @see #setSelected(boolean) - * + * * @param selected The new selected state */ protected void dispatchSetSelected(boolean selected) { } - + /** * Indicates the selection state of this view. * @@ -6265,6 +6568,13 @@ public class View implements Drawable.Callback, KeyEvent.Callback { * @return the topmost view containing this view */ public View getRootView() { + if (mAttachInfo != null) { + final View v = mAttachInfo.mRootView; + if (v != null) { + return v; + } + } + View parent = this; while (parent.mParent != null && parent.mParent instanceof View) { @@ -6305,22 +6615,18 @@ public class View implements Drawable.Callback, KeyEvent.Callback { location[0] = mLeft; location[1] = mTop; - if (!(mParent instanceof View)) { - return; + ViewParent viewParent = mParent; + while (viewParent instanceof View) { + final View view = (View)viewParent; + location[0] += view.mLeft - view.mScrollX; + location[1] += view.mTop - view.mScrollY; + viewParent = view.mParent; } - - View parent = (View) mParent; - - while (parent != null) { - location[0] += parent.mLeft - parent.mScrollX; - location[1] += parent.mTop - parent.mScrollY; - - final ViewParent viewParent = parent.mParent; - if (viewParent != null && viewParent instanceof View) { - parent = (View) viewParent; - } else { - parent = null; - } + + if (viewParent instanceof ViewRoot) { + // *cough* + final ViewRoot vr = (ViewRoot)viewParent; + location[1] -= vr.mCurScrollY; } } @@ -6380,13 +6686,13 @@ public class View implements Drawable.Callback, KeyEvent.Callback { * Sets the identifier for this view. The identifier does not have to be * unique in this view's hierarchy. The identifier should be a positive * number. - * + * * @see #NO_ID * @see #getId * @see #findViewById * * @param id a number used to identify the view - * + * * @attr ref android.R.styleable#View_id */ public void setId(int id) { @@ -6421,11 +6727,12 @@ public class View implements Drawable.Callback, KeyEvent.Callback { * * @return a positive integer used to identify the view or {@link #NO_ID} * if the view has no ID - * + * * @see #setId * @see #findViewById * @attr ref android.R.styleable#View_id */ + @ViewDebug.CapturedViewProperty public int getId() { return mID; } @@ -6433,7 +6740,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback { /** * Returns this view's tag. * - * @return the Object stored in this view as a tag + * @return the Object stored in this view as a tag */ @ViewDebug.ExportedProperty public Object getTag() { @@ -6473,7 +6780,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback { */ protected void debug(int depth) { String output = debugIndent(depth - 1); - + output += "+ " + this; int id = getId(); if (id != -1) { @@ -6484,18 +6791,18 @@ public class View implements Drawable.Callback, KeyEvent.Callback { output += " (tag=" + tag + ")"; } Log.d(VIEW_LOG_TAG, output); - + if ((mPrivateFlags & FOCUSED) != 0) { - output = debugIndent(depth) + " FOCUSED"; + output = debugIndent(depth) + " FOCUSED"; Log.d(VIEW_LOG_TAG, output); } - + output = debugIndent(depth); output += "frame={" + mLeft + ", " + mTop + ", " + mRight + ", " + mBottom + "} scroll={" + mScrollX + ", " + mScrollY + "} "; Log.d(VIEW_LOG_TAG, output); - + if (mPaddingLeft != 0 || mPaddingTop != 0 || mPaddingRight != 0 || mPaddingBottom != 0) { output = debugIndent(depth); @@ -6503,12 +6810,12 @@ public class View implements Drawable.Callback, KeyEvent.Callback { + ", " + mPaddingRight + ", " + mPaddingBottom + "}"; Log.d(VIEW_LOG_TAG, output); } - + output = debugIndent(depth); output += "mMeasureWidth=" + mMeasuredWidth + " mMeasureHeight=" + mMeasuredHeight; Log.d(VIEW_LOG_TAG, output); - + output = debugIndent(depth); if (mLayoutParams == null) { output += "BAD! no layout params"; @@ -6516,7 +6823,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback { output = mLayoutParams.debug(output); } Log.d(VIEW_LOG_TAG, output); - + output = debugIndent(depth); output += "flags={"; output += View.printFlags(mViewFlags); @@ -6583,8 +6890,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback { */ public void forceLayout() { mPrivateFlags |= FORCE_LAYOUT; - } - + } + /** *

    * This is called to find out how big a view should be. The parent @@ -6596,14 +6903,14 @@ public class View implements Drawable.Callback, KeyEvent.Callback { * {@link #onMeasure(int, int)}, called by this method. Therefore, only * {@link #onMeasure(int, int)} can and must be overriden by subclasses. *

    - * - * + * + * * @param widthMeasureSpec Horizontal space requirements as imposed by the * parent * @param heightMeasureSpec Vertical space requirements as imposed by the * parent * - * @see #onMeasure(int, int) + * @see #onMeasure(int, int) */ public final void measure(int widthMeasureSpec, int heightMeasureSpec) { if ((mPrivateFlags & FORCE_LAYOUT) == FORCE_LAYOUT || @@ -6642,7 +6949,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback { * should be overriden by subclasses to provide accurate and efficient * measurement of their contents. *

    - * + * *

    * CONTRACT: When overriding this method, you * must call {@link #setMeasuredDimension(int, int)} to store the @@ -6651,35 +6958,35 @@ public class View implements Drawable.Callback, KeyEvent.Callback { * {@link #measure(int, int)}. Calling the superclass' * {@link #onMeasure(int, int)} is a valid use. *

    - * + * *

    * The base class implementation of measure defaults to the background size, * unless a larger size is allowed by the MeasureSpec. Subclasses should * override {@link #onMeasure(int, int)} to provide better measurements of * their content. *

    - * + * *

    * If this method is overridden, it is the subclass's responsibility to make * sure the measured height and width are at least the view's minimum height * and width ({@link #getSuggestedMinimumHeight()} and * {@link #getSuggestedMinimumWidth()}). *

    - * + * * @param widthMeasureSpec horizontal space requirements as imposed by the parent. * The requirements are encoded with * {@link android.view.View.MeasureSpec}. * @param heightMeasureSpec vertical space requirements as imposed by the parent. * The requirements are encoded with * {@link android.view.View.MeasureSpec}. - * + * * @see #getMeasuredWidth() * @see #getMeasuredHeight() * @see #setMeasuredDimension(int, int) * @see #getSuggestedMinimumHeight() * @see #getSuggestedMinimumWidth() * @see android.view.View.MeasureSpec#getMode(int) - * @see android.view.View.MeasureSpec#getSize(int) + * @see android.view.View.MeasureSpec#getSize(int) */ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec), @@ -6704,7 +7011,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback { /** * Utility to reconcile a desired size with constraints imposed by a MeasureSpec. * Will take the desired size, unless a different size is imposed by the constraints. - * + * * @param size How big the view wants to be * @param measureSpec Constraints imposed by the parent * @return The size this view should be. @@ -6726,12 +7033,12 @@ public class View implements Drawable.Callback, KeyEvent.Callback { } return result; } - + /** * Utility to return a default size. Uses the supplied size if the * MeasureSpec imposed no contraints. Will get larger if allowed * by the MeasureSpec. - * + * * @param size Default size for this view * @param measureSpec Constraints imposed by the parent * @return The size this view should be. @@ -6740,7 +7047,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback { int result = size; int specMode = MeasureSpec.getMode(measureSpec); int specSize = MeasureSpec.getSize(measureSpec); - + switch (specMode) { case MeasureSpec.UNSPECIFIED: result = size; @@ -6761,19 +7068,19 @@ public class View implements Drawable.Callback, KeyEvent.Callback { *

    * When being used in {@link #onMeasure(int, int)}, the caller should still * ensure the returned height is within the requirements of the parent. - * + * * @return The suggested minimum height of the view. */ protected int getSuggestedMinimumHeight() { int suggestedMinHeight = mMinHeight; - + if (mBGDrawable != null) { final int bgMinHeight = mBGDrawable.getMinimumHeight(); if (suggestedMinHeight < bgMinHeight) { suggestedMinHeight = bgMinHeight; } } - + return suggestedMinHeight; } @@ -6785,19 +7092,19 @@ public class View implements Drawable.Callback, KeyEvent.Callback { *

    * When being used in {@link #onMeasure(int, int)}, the caller should still * ensure the returned width is within the requirements of the parent. - * + * * @return The suggested minimum width of the view. */ protected int getSuggestedMinimumWidth() { int suggestedMinWidth = mMinWidth; - + if (mBGDrawable != null) { final int bgMinWidth = mBGDrawable.getMinimumWidth(); if (suggestedMinWidth < bgMinWidth) { suggestedMinWidth = bgMinWidth; } } - + return suggestedMinWidth; } @@ -6805,7 +7112,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback { * Sets the minimum height of the view. It is not guaranteed the view will * be able to achieve this minimum height (for example, if its parent layout * constrains it with less available height). - * + * * @param minHeight The minimum height the view will try to be. */ public void setMinimumHeight(int minHeight) { @@ -6816,7 +7123,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback { * Sets the minimum width of the view. It is not guaranteed the view will * be able to achieve this minimum width (for example, if its parent layout * constrains it with less available width). - * + * * @param minWidth The minimum width the view will try to be. */ public void setMinimumWidth(int minWidth) { @@ -6832,10 +7139,10 @@ public class View implements Drawable.Callback, KeyEvent.Callback { public Animation getAnimation() { return mCurrentAnimation; } - + /** * Start the specified animation now. - * + * * @param animation the animation to start now */ public void startAnimation(Animation animation) { @@ -6843,23 +7150,23 @@ public class View implements Drawable.Callback, KeyEvent.Callback { setAnimation(animation); invalidate(); } - + /** * Cancels any animations for this view. */ public void clearAnimation() { mCurrentAnimation = null; } - + /** * Sets the next animation to play for this view. * If you want the animation to play immediately, use * startAnimation. This method provides allows fine-grained * control over the start time and invalidation, but you * must make sure that 1) the animation has a start time set, and - * 2) the view will be invalidated when the animation is supposed to + * 2) the view will be invalidated when the animation is supposed to * start. - * + * * @param animation The next animation, or null. */ public void setAnimation(Animation animation) { @@ -6914,25 +7221,26 @@ public class View implements Drawable.Callback, KeyEvent.Callback { * SurfaceView is always considered transparent, but its children are not, * therefore all View objects remove themselves from the global transparent * region (passed as a parameter to this function). - * + * * @param region The transparent region for this ViewRoot (window). - * + * * @return Returns true if the effective visibility of the view at this * point is opaque, regardless of the transparent region; returns false * if it is possible for underlying windows to be seen behind the view. - * + * * {@hide} */ public boolean gatherTransparentRegion(Region region) { - if (region != null) { + final AttachInfo attachInfo = mAttachInfo; + if (region != null && attachInfo != null) { final int pflags = mPrivateFlags; if ((pflags & SKIP_DRAW) == 0) { // The SKIP_DRAW flag IS NOT set, so this view draws. We need to // remove it from the transparent region. - getLocationInWindow(mLocation); - region.op(mLocation[0], mLocation[1], - mLocation[0] + mRight - mLeft, mLocation[1] + mBottom - mTop, - Region.Op.DIFFERENCE); + final int[] location = attachInfo.mTransparentLocation; + getLocationInWindow(location); + region.op(location[0], location[1], location[0] + mRight - mLeft, + location[1] + mBottom - mTop, Region.Op.DIFFERENCE); } else if ((pflags & ONLY_DRAWS_BACKGROUND) != 0 && mBGDrawable != null) { // The ONLY_DRAWS_BACKGROUND flag IS set and the background drawable // exists, so we remove the background drawable's non-transparent @@ -6952,7 +7260,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback { * * The sound effect will only be played if sound effects are enabled by the user, and * {@link #isSoundEffectsEnabled()} is true. - * + * * @param soundConstant One of the constants defined in {@link SoundEffectConstants} */ protected void playSoundEffect(int soundConstant) { @@ -6967,7 +7275,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback { * update a Region being computed for {@link #gatherTransparentRegion} so * that any non-transparent parts of the Drawable are removed from the * given transparent region. - * + * * @param dr The Drawable whose transparency is to be applied to the region. * @param region A Region holding the current transparency information, * where any parts of the region that are set are considered to be @@ -6982,7 +7290,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback { } final Region r = dr.getTransparentRegion(); final Rect db = dr.getBounds(); - if (r != null) { + final AttachInfo attachInfo = mAttachInfo; + if (r != null && attachInfo != null) { final int w = getRight()-getLeft(); final int h = getBottom()-getTop(); if (db.left > 0) { @@ -7001,8 +7310,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback { //Log.i("VIEW", "Drawable bottom " + db.bottom + " < view " + h); r.op(0, db.bottom, w, h, Region.Op.UNION); } - getLocationInWindow(mLocation); - r.translate(mLocation[0], mLocation[1]); + final int[] location = attachInfo.mTransparentLocation; + getLocationInWindow(location); + r.translate(location[0], location[1]); region.op(r, Region.Op.INTERSECT); } else { region.op(db, Region.Op.DIFFERENCE); @@ -7177,10 +7487,10 @@ public class View implements Drawable.Callback, KeyEvent.Callback { } class CheckForLongPress implements Runnable { - + private int mOriginalWindowAttachCount; - - public void run() { + + public void run() { if (isPressed() && (mParent != null) && hasWindowFocus() && mOriginalWindowAttachCount == mWindowAttachCount) { if (performLongClick()) { @@ -7188,7 +7498,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback { } } } - + public void rememberWindowAttachCount() { mOriginalWindowAttachCount = mWindowAttachCount; } @@ -7279,7 +7589,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback { /** * Called when the context menu for this view is being built. It is not * safe to hold onto the menu after this method returns. - * + * * @param menu The context menu that is being built * @param v The view for which the context menu is being built * @param menuInfo Extra information about the item for which the @@ -7297,12 +7607,12 @@ public class View implements Drawable.Callback, KeyEvent.Callback { /** * Base class for derived classes that want to save and restore their own - * state in {@link #onSaveInstanceState}. + * state in {@link android.view.View#onSaveInstanceState()}. */ public static class BaseSavedState extends AbsSavedState { /** * Constructor used when reading from a parcel. Reads the state of the superclass. - * + * * @param source */ public BaseSavedState(Parcel source) { @@ -7311,7 +7621,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback { /** * Constructor called by derived classes when creating their SavedState objects - * + * * @param superState The state of the superclass of this view */ public BaseSavedState(Parcelable superState) { @@ -7340,11 +7650,21 @@ public class View implements Drawable.Callback, KeyEvent.Callback { void playSoundEffect(int effectId); } - IBinder mWindowToken; + final IWindowSession mSession; + + final IWindow mWindow; + + final IBinder mWindowToken; + + final SoundEffectPlayer mSoundEffectPlayer; + + /** + * The top view of the hierarchy. + */ + View mRootView; + IBinder mPanelParentWindowToken; Surface mSurface; - IWindowSession mSession; - SoundEffectPlayer mSoundEffectPlayer; /** * Left position of this view's window @@ -7356,6 +7676,37 @@ public class View implements Drawable.Callback, KeyEvent.Callback { */ int mWindowTop; + /** + * For windows that are full-screen but using insets to layout inside + * of the screen decorations, these are the current insets for the + * content of the window. + */ + final Rect mContentInsets = new Rect(); + + /** + * For windows that are full-screen but using insets to layout inside + * of the screen decorations, these are the current insets for the + * actual visible parts of the window. + */ + final Rect mVisibleInsets = new Rect(); + + /** + * The internal insets given by this window. This value is + * supplied by the client (through + * {@link ViewTreeObserver.OnComputeInternalInsetsListener}) and will + * be given to the window manager when changed to be used in laying + * out windows behind it. + */ + final ViewTreeObserver.InternalInsetsInfo mGivenInternalInsets + = new ViewTreeObserver.InternalInsetsInfo(); + + /** + * All views in the window's hierarchy that serve as scroll containers, + * used to determine if the window can be resized or must be panned + * to adjust for a soft input area. + */ + final ArrayList mScrollContainers = new ArrayList(); + /** * Indicates whether the view's window currently has the focus. */ @@ -7365,7 +7716,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback { * The current visibility of the window. */ int mWindowVisibility; - + /** * Indicates the time at which drawing started to occur. */ @@ -7375,7 +7726,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback { * Indicates whether the view's window is currently in touch mode. */ boolean mInTouchMode; - + /** * Indicates that ViewRoot should trigger a global layout change * the next time it performs a traversal @@ -7387,12 +7738,29 @@ public class View implements Drawable.Callback, KeyEvent.Callback { * recomputed. */ boolean mAttributesChanged; - + /** * Set during a traveral if any views want to keep the screen on. */ boolean mKeepScreenOn; - + + /** + * Set if the visibility of any views has changed. + */ + boolean mViewVisibilityChanged; + + /** + * Global to the view hierarchy used as a temporary for dealing with + * x/y points in the transparent region computations. + */ + final int[] mTransparentLocation = new int[2]; + + /** + * Global to the view hierarchy used as a temporary for dealing with + * x/y points in the ViewGroup.invalidateChild implementation. + */ + final int[] mInvalidateChildLocation = new int[2]; + /** * The view tree observer used to dispatch global events like * layout, pre-draw, touch mode change, etc. @@ -7422,17 +7790,23 @@ public class View implements Drawable.Callback, KeyEvent.Callback { */ static final int INVALIDATE_RECT_MSG = 0x2; - AttachInfo(Handler handler) { - this(handler, null); - } - + /** + * Temporary for use in computing invalidate rectangles while + * calling up the hierarchy. + */ + final Rect mTmpInvalRect = new Rect(); + /** * Creates a new set of attachment information with the specified * events handler and thread. * * @param handler the events handler the view must use */ - AttachInfo(Handler handler, SoundEffectPlayer effectPlayer) { + AttachInfo(IWindowSession session, IWindow window, + Handler handler, SoundEffectPlayer effectPlayer) { + mSession = session; + mWindow = window; + mWindowToken = window.asBinder(); mHandler = handler; mSoundEffectPlayer = effectPlayer; } diff --git a/core/java/android/view/ViewConfiguration.java b/core/java/android/view/ViewConfiguration.java index 38be806e2043414be6ea1dc6b9241db18d968996..b7110ce101ab709fe4cebd175b03a34b5f6a2d79 100644 --- a/core/java/android/view/ViewConfiguration.java +++ b/core/java/android/view/ViewConfiguration.java @@ -45,6 +45,13 @@ public class ViewConfiguration { */ private static final int LONG_PRESS_TIMEOUT = 500; + /** + * Defines the duration in milliseconds a user needs to hold down the + * appropriate button to bring up the global actions dialog (power off, + * lock screen, etc). + */ + private static final int GLOBAL_ACTIONS_KEY_TIMEOUT = 500; + /** * Defines the duration in milliseconds we will wait to see if a touch event * is a top or a scroll. If the user does not move within this interval, it is @@ -65,14 +72,6 @@ public class ViewConfiguration { */ private static final int ZOOM_CONTROLS_TIMEOUT = 3000; - /** - * Defines the duration in milliseconds a user needs to hold down the - * appropriate button to bring up the global actions dialog (power off, - * lock screen, etc). - */ - private static final int GLOBAL_ACTIONS_KEY_TIMEOUT = 1000; - - /** * Inset in pixels to look for touchable content when the user touches the edge of the screen */ diff --git a/core/java/android/view/ViewDebug.java b/core/java/android/view/ViewDebug.java index 1bf46b48cd412f3abc3141961e2dbf97a91776d9..883c7bd2e5d26ce1b28e43d9f30aa69158e23aae 100644 --- a/core/java/android/view/ViewDebug.java +++ b/core/java/android/view/ViewDebug.java @@ -19,6 +19,7 @@ package android.view; import android.util.Log; import android.content.res.Resources; import android.graphics.Bitmap; +import android.os.Environment; import java.io.File; import java.io.BufferedWriter; @@ -60,7 +61,19 @@ public class ViewDebug { * check that this value is set to true as not to affect performance. */ public static final boolean TRACE_RECYCLER = false; - + + /** + * The system property of dynamic switch for capturing view information + * when it is set, we dump interested fields and methods for the view on focus + */ + static final String SYSTEM_PROPERTY_CAPTURE_VIEW = "debug.captureview"; + + /** + * The system property of dynamic switch for capturing event information + * when it is set, we log key events, touch/motion and trackball events + */ + static final String SYSTEM_PROPERTY_CAPTURE_EVENT = "debug.captureevent"; + /** * This annotation can be used to mark fields and methods to be dumped by * the view server. Only non-void methods with no arguments can be annotated @@ -143,6 +156,29 @@ public class ViewDebug { */ String to(); } + + /** + * This annotation can be used to mark fields and methods to be dumped when + * the view is captured. Methods with this annotation must have no arguments + * and must return . + * + * @hide pending API Council approval + */ + @Target({ ElementType.FIELD, ElementType.METHOD }) + @Retention(RetentionPolicy.RUNTIME) + public @interface CapturedViewProperty { + /** + * When retrieveReturn is true, we need to retrieve second level methods + * e.g., we need myView.getFirstLevelMethod().getSecondLevelMethod() + * we will set retrieveReturn = true on the annotation of + * myView.getFirstLevelMethod() + * @return true if we need the second level methods + */ + boolean retrieveReturn() default false; + } + + private static HashMap, Method[]> mCapturedViewMethodsForClasses = null; + private static HashMap, Field[]> mCapturedViewFieldsForClasses = null; // Maximum delay in ms after which we stop trying to capture a View's drawing private static final int CAPTURE_TIMEOUT = 4000; @@ -154,7 +190,7 @@ public class ViewDebug { private static HashMap, Field[]> sFieldsForClasses; private static HashMap, Method[]> sMethodsForClasses; - + /** * Defines the type of hierarhcy trace to output to the hierarchy traces file. */ @@ -250,8 +286,8 @@ public class ViewDebug { /** * Starts tracing the view recycler of the specified view. The trace is identified by a prefix, - * used to build the traces files names: /tmp/view-recycler/PREFIX.traces and - * /tmp/view-recycler/PREFIX.recycler. + * used to build the traces files names: /EXTERNAL/view-recycler/PREFIX.traces and + * /EXTERNAL/view-recycler/PREFIX.recycler. * * Only one view recycler can be traced at the same time. After calling this method, any * other invocation will result in a IllegalStateException unless @@ -287,10 +323,10 @@ public class ViewDebug { /** * Stops the current view recycer tracing. * - * Calling this method creates the file /tmp/view-recycler/PREFIX.traces + * Calling this method creates the file /EXTERNAL/view-recycler/PREFIX.traces * containing all the traces (or method calls) relative to the specified view's recycler. * - * Calling this method creates the file /tmp/view-recycler/PREFIX.recycler + * Calling this method creates the file /EXTERNAL/view-recycler/PREFIX.recycler * containing all of the views used by the recycler of the view supplied to * {@link #startRecyclerTracing(String, View)}. * @@ -310,7 +346,7 @@ public class ViewDebug { " stopRecyclerTracing()!"); } - File recyclerDump = new File("/tmp/view-recycler/"); + File recyclerDump = new File(Environment.getExternalStorageDirectory(), "view-recycler/"); recyclerDump.mkdirs(); recyclerDump = new File(recyclerDump, sRecyclerTracePrefix + ".recycler"); @@ -329,7 +365,7 @@ public class ViewDebug { return; } - recyclerDump = new File("/tmp/view-recycler/"); + recyclerDump = new File(Environment.getExternalStorageDirectory(), "view-recycler/"); recyclerDump = new File(recyclerDump, sRecyclerTracePrefix + ".traces"); try { final FileOutputStream file = new FileOutputStream(recyclerDump); @@ -384,14 +420,14 @@ public class ViewDebug { /** * Starts tracing the view hierarchy of the specified view. The trace is identified by a prefix, - * used to build the traces files names: /tmp/view-hierarchy/PREFIX.traces and - * /tmp/view-hierarchy/PREFIX.tree. + * used to build the traces files names: /EXTERNAL/view-hierarchy/PREFIX.traces and + * /EXTERNAL/view-hierarchy/PREFIX.tree. * * Only one view hierarchy can be traced at the same time. After calling this method, any * other invocation will result in a IllegalStateException unless * {@link #stopHierarchyTracing()} is invoked before. * - * Calling this method creates the file /tmp/view-hierarchy/PREFIX.traces + * Calling this method creates the file /EXTERNAL/view-hierarchy/PREFIX.traces * containing all the traces (or method calls) relative to the specified view's hierarchy. * * This method will return immediately if TRACE_HIERARCHY is false. @@ -413,7 +449,7 @@ public class ViewDebug { " a new trace!"); } - File hierarchyDump = new File("/tmp/view-hierarchy/"); + File hierarchyDump = new File(Environment.getExternalStorageDirectory(), "view-hierarchy/"); hierarchyDump.mkdirs(); hierarchyDump = new File(hierarchyDump, prefix + ".traces"); @@ -431,10 +467,11 @@ public class ViewDebug { /** * Stops the current view hierarchy tracing. This method closes the file - * /tmp/view-hierarchy/PREFIX.traces. + * /EXTERNAL/view-hierarchy/PREFIX.traces. * - * Calling this method creates the file /tmp/view-hierarchy/PREFIX.tree containing - * the view hierarchy of the view supplied to {@link #startHierarchyTracing(String, View)}. + * Calling this method creates the file /EXTERNAL/view-hierarchy/PREFIX.tree + * containing the view hierarchy of the view supplied to + * {@link #startHierarchyTracing(String, View)}. * * This method will return immediately if TRACE_HIERARCHY is false. * @@ -459,7 +496,7 @@ public class ViewDebug { } sHierarchyTraces = null; - File hierarchyDump = new File("/tmp/view-hierarchy/"); + File hierarchyDump = new File(Environment.getExternalStorageDirectory(), "view-hierarchy/"); hierarchyDump.mkdirs(); hierarchyDump = new File(hierarchyDump, sHierarchyTracePrefix + ".tree"); @@ -484,7 +521,7 @@ public class ViewDebug { sHierarhcyRoot = null; } - + static void dispatchCommand(View view, String command, String parameters, OutputStream clientStream) throws IOException { @@ -714,10 +751,10 @@ public class ViewDebug { final ArrayList foundMethods = new ArrayList(); methods = klass.getDeclaredMethods(); - + int count = methods.length; for (int i = 0; i < count; i++) { - final Method method = methods[i]; + final Method method = methods[i]; if (method.getParameterTypes().length == 0 && method.isAnnotationPresent(ExportedProperty.class) && method.getReturnType() != Void.class) { @@ -746,7 +783,7 @@ public class ViewDebug { klass = klass.getSuperclass(); } while (klass != Object.class); } - + private static void exportMethods(Object view, BufferedWriter out, Class klass, String prefix) throws IOException { @@ -767,8 +804,12 @@ public class ViewDebug { final Resources resources = ((View) view).getContext().getResources(); final int id = (Integer) methodValue; if (id >= 0) { - methodValue = resources.getResourceTypeName(id) + '/' + - resources.getResourceEntryName(id); + try { + methodValue = resources.getResourceTypeName(id) + '/' + + resources.getResourceEntryName(id); + } catch (Resources.NotFoundException e) { + methodValue = "UNKNOWN"; + } } else { methodValue = "NO_ID"; } @@ -839,8 +880,12 @@ public class ViewDebug { final Resources resources = ((View) view).getContext().getResources(); final int id = field.getInt(view); if (id >= 0) { - fieldValue = resources.getResourceTypeName(id) + '/' + - resources.getResourceEntryName(id); + try { + fieldValue = resources.getResourceTypeName(id) + '/' + + resources.getResourceEntryName(id); + } catch (Resources.NotFoundException e) { + fieldValue = "UNKNOWN"; + } } else { fieldValue = "NO_ID"; } @@ -924,4 +969,160 @@ public class ViewDebug { } return true; } + + private static Field[] capturedViewGetPropertyFields(Class klass) { + if (mCapturedViewFieldsForClasses == null) { + mCapturedViewFieldsForClasses = new HashMap, Field[]>(); + } + final HashMap, Field[]> map = mCapturedViewFieldsForClasses; + + Field[] fields = map.get(klass); + if (fields != null) { + return fields; + } + + final ArrayList foundFields = new ArrayList(); + fields = klass.getFields(); + + int count = fields.length; + for (int i = 0; i < count; i++) { + final Field field = fields[i]; + if (field.isAnnotationPresent(CapturedViewProperty.class)) { + field.setAccessible(true); + foundFields.add(field); + } + } + + fields = foundFields.toArray(new Field[foundFields.size()]); + map.put(klass, fields); + + return fields; + } + + private static Method[] capturedViewGetPropertyMethods(Class klass) { + if (mCapturedViewMethodsForClasses == null) { + mCapturedViewMethodsForClasses = new HashMap, Method[]>(); + } + final HashMap, Method[]> map = mCapturedViewMethodsForClasses; + + Method[] methods = map.get(klass); + if (methods != null) { + return methods; + } + + final ArrayList foundMethods = new ArrayList(); + methods = klass.getMethods(); + + int count = methods.length; + for (int i = 0; i < count; i++) { + final Method method = methods[i]; + if (method.getParameterTypes().length == 0 && + method.isAnnotationPresent(CapturedViewProperty.class) && + method.getReturnType() != Void.class) { + method.setAccessible(true); + foundMethods.add(method); + } + } + + methods = foundMethods.toArray(new Method[foundMethods.size()]); + map.put(klass, methods); + + return methods; + } + + private static String capturedViewExportMethods(Object obj, Class klass, + String prefix) { + + if (obj == null) { + return "null"; + } + + StringBuilder sb = new StringBuilder(); + final Method[] methods = capturedViewGetPropertyMethods(klass); + + int count = methods.length; + for (int i = 0; i < count; i++) { + final Method method = methods[i]; + try { + Object methodValue = method.invoke(obj, (Object[]) null); + final Class returnType = method.getReturnType(); + + CapturedViewProperty property = method.getAnnotation(CapturedViewProperty.class); + if (property.retrieveReturn()) { + //we are interested in the second level data only + sb.append(capturedViewExportMethods(methodValue, returnType, method.getName() + "#")); + } else { + sb.append(prefix); + sb.append(method.getName()); + sb.append("()="); + + if (methodValue != null) { + final String value = methodValue.toString().replace("\n", "\\n"); + sb.append(value); + } else { + sb.append("null"); + } + sb.append("; "); + } + } catch (IllegalAccessException e) { + //Exception IllegalAccess, it is OK here + //we simply ignore this method + } catch (InvocationTargetException e) { + //Exception InvocationTarget, it is OK here + //we simply ignore this method + } + } + return sb.toString(); + } + + private static String capturedViewExportFields(Object obj, Class klass, String prefix) { + + if (obj == null) { + return "null"; + } + + StringBuilder sb = new StringBuilder(); + final Field[] fields = capturedViewGetPropertyFields(klass); + + int count = fields.length; + for (int i = 0; i < count; i++) { + final Field field = fields[i]; + try { + Object fieldValue = field.get(obj); + + sb.append(prefix); + sb.append(field.getName()); + sb.append("="); + + if (fieldValue != null) { + final String value = fieldValue.toString().replace("\n", "\\n"); + sb.append(value); + } else { + sb.append("null"); + } + sb.append(' '); + } catch (IllegalAccessException e) { + //Exception IllegalAccess, it is OK here + //we simply ignore this field + } + } + return sb.toString(); + } + + /** + * dump view info for id based instrument test generation + * (and possibly further data analysis). The results are dumped + * to the log. + * @param tag for log + * @param view for dump + * + * @hide pending API Council approval + */ + public static void dumpCapturedView(String tag, Object view) { + Class klass = view.getClass(); + StringBuilder sb = new StringBuilder(klass.getName() + ": "); + sb.append(capturedViewExportFields(view, klass, "")); + sb.append(capturedViewExportMethods(view, klass, "")); + Log.d(tag, sb.toString()); + } } diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java index 9063821c2dc09a7acfa4f74b42c8912abe08d25b..e26a19e54e5e48a426e0d9ba8a27b211e1d9565e 100644 --- a/core/java/android/view/ViewGroup.java +++ b/core/java/android/view/ViewGroup.java @@ -73,7 +73,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager private View mFocused; // The current transformation to apply on the child being drawn - private final Transformation mChildTransformation = new Transformation(); + private Transformation mChildTransformation; // Target of Motion events private View mMotionTarget; @@ -148,9 +148,6 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager * {@link #getChildStaticTransformation(View, android.view.animation.Transformation)} should * set this flags in {@link #mGroupFlags}. * - * This flag needs to be removed until we can add a setter for it. People - * can't be directly stuffing values in to mGroupFlags!!! - * * {@hide} */ protected static final int FLAG_SUPPORT_STATIC_TRANSFORMATIONS = 0x800; @@ -466,27 +463,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager } /** - * Called when a child of this group wants a particular rectangle to be - * positioned onto the screen. {@link ViewGroup}s overriding this can trust - * that: - *

      - *
    • child will be a direct child of this group
    • - *
    • rectangle will be in the child's coordinates
    • - *
    - * - *

    {@link ViewGroup}s overriding this should uphold the contract:

    - *
      - *
    • nothing will change if the rectangle is already visible
    • - *
    • the view port will be scrolled only just enough to make the - * rectangle visible
    • - *
        - * - * @param child The direct child making the request. - * @param rectangle The rectangle in the child's coordinates the child - * wishes to be on the screen. - * @param immediate True to forbid animated or delayed scrolling, - * false otherwise - * @return Whether the group scrolled to handle the operation + * {@inheritDoc} */ public boolean requestChildRectangleOnScreen(View child, Rect rectangle, boolean immediate) { return false; @@ -723,6 +700,19 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager } } + /** + * {@inheritDoc} + */ + @Override + public boolean dispatchKeyEventPreIme(KeyEvent event) { + if ((mPrivateFlags & (FOCUSED | HAS_BOUNDS)) == (FOCUSED | HAS_BOUNDS)) { + return super.dispatchKeyEventPreIme(event); + } else if (mFocused != null && (mFocused.mPrivateFlags & HAS_BOUNDS) == HAS_BOUNDS) { + return mFocused.dispatchKeyEventPreIme(event); + } + return false; + } + /** * {@inheritDoc} */ @@ -736,6 +726,19 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager return false; } + /** + * {@inheritDoc} + */ + @Override + public boolean dispatchKeyShortcutEvent(KeyEvent event) { + if ((mPrivateFlags & (FOCUSED | HAS_BOUNDS)) == (FOCUSED | HAS_BOUNDS)) { + return super.dispatchKeyShortcutEvent(event); + } else if (mFocused != null && (mFocused.mPrivateFlags & HAS_BOUNDS) == HAS_BOUNDS) { + return mFocused.dispatchKeyShortcutEvent(event); + } + return false; + } + /** * {@inheritDoc} */ @@ -1314,7 +1317,9 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager final int flags = mGroupFlags; if ((flags & FLAG_CLEAR_TRANSFORMATION) == FLAG_CLEAR_TRANSFORMATION) { - mChildTransformation.clear(); + if (mChildTransformation != null) { + mChildTransformation.clear(); + } mGroupFlags &= ~FLAG_CLEAR_TRANSFORMATION; } @@ -1328,6 +1333,9 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager child.onAnimationStart(); } + if (mChildTransformation == null) { + mChildTransformation = new Transformation(); + } more = a.getTransformation(drawingTime, mChildTransformation); transformToApply = mChildTransformation; @@ -1347,6 +1355,9 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager } } else if ((flags & FLAG_SUPPORT_STATIC_TRANSFORMATIONS) == FLAG_SUPPORT_STATIC_TRANSFORMATIONS) { + if (mChildTransformation == null) { + mChildTransformation = new Transformation(); + } final boolean hasTransform = getChildStaticTransformation(child, mChildTransformation); if (hasTransform) { final int transformType = mChildTransformation.getTransformationType(); @@ -1506,8 +1517,28 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager } } + /** + * When this property is set to true, this ViewGroup supports static transformations on + * children; this causes + * {@link #getChildStaticTransformation(View, android.view.animation.Transformation)} to be + * invoked when a child is drawn. + * + * Any subclass overriding + * {@link #getChildStaticTransformation(View, android.view.animation.Transformation)} should + * set this property to true. + * + * @param enabled True to enable static transformations on children, false otherwise. + * + * @see #FLAG_SUPPORT_STATIC_TRANSFORMATIONS + */ + protected void setStaticTransformationsEnabled(boolean enabled) { + setBooleanFlag(FLAG_SUPPORT_STATIC_TRANSFORMATIONS, enabled); + } + /** * {@inheritDoc} + * + * @see #setStaticTransformationsEnabled(boolean) */ protected boolean getChildStaticTransformation(View child, Transformation t) { return false; @@ -1969,7 +2000,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager if (view.getAnimation() != null) { addDisappearingView(view); - } else if (mAttachInfo != null) { + } else if (view.mAttachInfo != null) { view.dispatchDetachedFromWindow(); } @@ -2107,7 +2138,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager if (animate && child.getAnimation() != null) { addDisappearingView(child); - } else if (mAttachInfo != null) { + } else if (child.mAttachInfo != null) { child.dispatchDetachedFromWindow(); } @@ -2205,7 +2236,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager } /** - * Detaches all views from theparent. Detaching a view should be temporary and followed + * Detaches all views from the parent. Detaching a view should be temporary and followed * either by a call to {@link #attachViewToParent(View, int, android.view.ViewGroup.LayoutParams)} * or a call to {@link #removeDetachedView(View, boolean)}. When a view is detached, * its parent is null and cannot be retrieved by a call to {@link #getChildAt(int)}. @@ -2242,13 +2273,16 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager ViewParent parent = this; - final int[] location = mLocation; - location[CHILD_LEFT_INDEX] = child.mLeft; - location[CHILD_TOP_INDEX] = child.mTop; - - do { - parent = parent.invalidateChildInParent(location, dirty); - } while (parent != null); + final AttachInfo attachInfo = mAttachInfo; + if (attachInfo != null) { + final int[] location = attachInfo.mInvalidateChildLocation; + location[CHILD_LEFT_INDEX] = child.mLeft; + location[CHILD_TOP_INDEX] = child.mTop; + + do { + parent = parent.invalidateChildInParent(location, dirty); + } while (parent != null); + } } /** @@ -2917,7 +2951,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager if (disappearingChildren.contains(view)) { disappearingChildren.remove(view); - if (mAttachInfo != null) { + if (view.mAttachInfo != null) { view.dispatchDetachedFromWindow(); } diff --git a/core/java/android/view/ViewParent.java b/core/java/android/view/ViewParent.java index 1a5d495d0ee4b724e3e8a37c436fe4112da1269d..b456c5d108d41930b338e8bd439d2aff3344322e 100644 --- a/core/java/android/view/ViewParent.java +++ b/core/java/android/view/ViewParent.java @@ -182,4 +182,30 @@ public interface ViewParent { * intercept touch events. */ public void requestDisallowInterceptTouchEvent(boolean disallowIntercept); + + /** + * Called when a child of this group wants a particular rectangle to be + * positioned onto the screen. {@link ViewGroup}s overriding this can trust + * that: + *
          + *
        • child will be a direct child of this group
        • + *
        • rectangle will be in the child's coordinates
        • + *
        + * + *

        {@link ViewGroup}s overriding this should uphold the contract:

        + *
          + *
        • nothing will change if the rectangle is already visible
        • + *
        • the view port will be scrolled only just enough to make the + * rectangle visible
        • + *
            + * + * @param child The direct child making the request. + * @param rectangle The rectangle in the child's coordinates the child + * wishes to be on the screen. + * @param immediate True to forbid animated or delayed scrolling, + * false otherwise + * @return Whether the group scrolled to handle the operation + */ + public boolean requestChildRectangleOnScreen(View child, Rect rectangle, + boolean immediate); } diff --git a/core/java/android/view/ViewRoot.java b/core/java/android/view/ViewRoot.java index ca674045e49c6ac8d5efbc5a91a147b7f2dd1b34..db0b368ebcf71595e0f9f07114649dab79170726 100644 --- a/core/java/android/view/ViewRoot.java +++ b/core/java/android/view/ViewRoot.java @@ -16,18 +16,26 @@ package android.view; +import com.android.internal.view.IInputMethodCallback; +import com.android.internal.view.IInputMethodSession; + import android.graphics.Canvas; import android.graphics.PixelFormat; +import android.graphics.Point; import android.graphics.PorterDuff; import android.graphics.Rect; import android.graphics.Region; import android.os.*; import android.os.Process; +import android.os.SystemProperties; import android.util.AndroidRuntimeException; import android.util.Config; import android.util.Log; import android.util.EventLog; +import android.util.SparseArray; import android.view.View.MeasureSpec; +import android.view.inputmethod.InputMethodManager; +import android.widget.Scroller; import android.content.pm.PackageManager; import android.content.Context; import android.app.ActivityManagerNative; @@ -51,15 +59,19 @@ import static javax.microedition.khronos.opengles.GL10.*; * {@hide} */ @SuppressWarnings({"EmptyCatchBlock"}) -final class ViewRoot extends Handler implements ViewParent, View.AttachInfo.SoundEffectPlayer { +public final class ViewRoot extends Handler implements ViewParent, + View.AttachInfo.SoundEffectPlayer { private static final String TAG = "ViewRoot"; private static final boolean DBG = false; @SuppressWarnings({"ConstantConditionalExpression"}) private static final boolean LOCAL_LOGV = false ? Config.LOGD : Config.LOGV; /** @noinspection PointlessBooleanExpression*/ private static final boolean DEBUG_DRAW = false || LOCAL_LOGV; + private static final boolean DEBUG_LAYOUT = false || LOCAL_LOGV; + private static final boolean DEBUG_INPUT_RESIZE = false || LOCAL_LOGV; private static final boolean DEBUG_ORIENTATION = false || LOCAL_LOGV; - private static final boolean DEBUG_TRACKBALL = LOCAL_LOGV; + private static final boolean DEBUG_TRACKBALL = false || LOCAL_LOGV; + private static final boolean DEBUG_IMF = false || LOCAL_LOGV; private static final boolean WATCH_POINTER = false; static final boolean PROFILE_DRAWING = false; @@ -75,85 +87,103 @@ final class ViewRoot extends Handler implements ViewParent, View.AttachInfo.Soun */ static final int MAX_TRACKBALL_DELAY = 250; - private static long sInstanceCount = 0; + static long sInstanceCount = 0; - private static IWindowSession sWindowSession; + static IWindowSession sWindowSession; - private static final Object mStaticInit = new Object(); - private static boolean mInitialized = false; + static final Object mStaticInit = new Object(); + static boolean mInitialized = false; static final ThreadLocal sUiThreads = new ThreadLocal(); static final RunQueue sRunQueue = new RunQueue(); - private long mLastTrackballTime = 0; - private final TrackballAxis mTrackballAxisX = new TrackballAxis(); - private final TrackballAxis mTrackballAxisY = new TrackballAxis(); + long mLastTrackballTime = 0; + final TrackballAxis mTrackballAxisX = new TrackballAxis(); + final TrackballAxis mTrackballAxisY = new TrackballAxis(); - private final Thread mThread; + final int[] mTmpLocation = new int[2]; + + final InputMethodCallback mInputMethodCallback; + final SparseArray mPendingEvents = new SparseArray(); + int mPendingEventSeq = 0; + + final Thread mThread; - private final WindowLeaked mLocation; + final WindowLeaked mLocation; - private final WindowManager.LayoutParams mWindowAttributes = new WindowManager.LayoutParams(); + final WindowManager.LayoutParams mWindowAttributes = new WindowManager.LayoutParams(); final W mWindow; - private View mView; - private View mFocusedView; - private int mViewVisibility; - private boolean mAppVisible = true; + View mView; + View mFocusedView; + int mViewVisibility; + boolean mAppVisible = true; - private final Region mTransparentRegion; - private final Region mPreviousTransparentRegion; + final Region mTransparentRegion; + final Region mPreviousTransparentRegion; - private int mWidth; - private int mHeight; - private Rect mDirty; // will be a graphics.Region soon + int mWidth; + int mHeight; + Rect mDirty; // will be a graphics.Region soon - private final View.AttachInfo mAttachInfo; + final View.AttachInfo mAttachInfo; - private final Rect mTempRect; // used in the transaction to not thrash the heap. + final Rect mTempRect; // used in the transaction to not thrash the heap. + final Rect mVisRect; // used to retrieve visible rect of focused view. + final Point mVisPoint; // used to retrieve global offset of focused view. - private boolean mTraversalScheduled; - private boolean mWillDrawSoon; - private boolean mLayoutRequested; - private boolean mFirst; - private boolean mReportNextDraw; - private boolean mFullRedrawNeeded; - private boolean mNewSurfaceNeeded; + boolean mTraversalScheduled; + boolean mWillDrawSoon; + boolean mLayoutRequested; + boolean mFirst; + boolean mReportNextDraw; + boolean mFullRedrawNeeded; + boolean mNewSurfaceNeeded; + boolean mHasHadWindowFocus; - private boolean mWindowAttributesChanged = false; + boolean mWindowAttributesChanged = false; // These can be accessed by any thread, must be protected with a lock. - private Surface mSurface; + Surface mSurface; - private boolean mAdded; - private boolean mAddedTouchMode; + boolean mAdded; + boolean mAddedTouchMode; /*package*/ int mAddNesting; // These are accessed by multiple threads. - private final Rect mWinFrame; // frame given by window manager. - - private final Rect mCoveredInsets = new Rect(); - private final Rect mNewCoveredInsets = new Rect(); - - private EGL10 mEgl; - private EGLDisplay mEglDisplay; - private EGLContext mEglContext; - private EGLSurface mEglSurface; - private GL11 mGL; - private Canvas mGlCanvas; - private boolean mUseGL; - private boolean mGlWanted; + final Rect mWinFrame; // frame given by window manager. + + final Rect mPendingVisibleInsets = new Rect(); + final Rect mPendingContentInsets = new Rect(); + final ViewTreeObserver.InternalInsetsInfo mLastGivenInsets + = new ViewTreeObserver.InternalInsetsInfo(); + + boolean mScrollMayChange; + int mSoftInputMode; + View mLastScrolledFocus; + int mScrollY; + int mCurScrollY; + Scroller mScroller; + + EGL10 mEgl; + EGLDisplay mEglDisplay; + EGLContext mEglContext; + EGLSurface mEglSurface; + GL11 mGL; + Canvas mGlCanvas; + boolean mUseGL; + boolean mGlWanted; /** * see {@link #playSoundEffect(int)} */ - private AudioManager mAudioManager; + AudioManager mAudioManager; - public ViewRoot() { + public ViewRoot(Context context) { super(); ++sInstanceCount; @@ -164,9 +194,10 @@ final class ViewRoot extends Handler implements ViewParent, View.AttachInfo.Soun synchronized (mStaticInit) { if (!mInitialized) { try { + InputMethodManager imm = InputMethodManager.getInstance(context); sWindowSession = IWindowManager.Stub.asInterface( ServiceManager.getService("window")) - .openSession(new Binder()); + .openSession(imm.getClient(), imm.getInputContext()); mInitialized = true; } catch (RemoteException e) { } @@ -180,8 +211,11 @@ final class ViewRoot extends Handler implements ViewParent, View.AttachInfo.Soun mHeight = -1; mDirty = new Rect(); mTempRect = new Rect(); + mVisRect = new Rect(); + mVisPoint = new Point(); mWinFrame = new Rect(); mWindow = new W(this); + mInputMethodCallback = new InputMethodCallback(this); mViewVisibility = View.GONE; mTransparentRegion = new Region(); mPreviousTransparentRegion = new Region(); @@ -194,7 +228,7 @@ final class ViewRoot extends Handler implements ViewParent, View.AttachInfo.Soun handler = new RootHandler(); sUiThreads.set(handler); } - mAttachInfo = new View.AttachInfo(handler, this); + mAttachInfo = new View.AttachInfo(sWindowSession, mWindow, handler, this); } @Override @@ -350,8 +384,10 @@ final class ViewRoot extends Handler implements ViewParent, View.AttachInfo.Soun synchronized (this) { if (mView == null) { mWindowAttributes.copyFrom(attrs); + mSoftInputMode = attrs.softInputMode; mWindowAttributesChanged = true; mView = view; + mAttachInfo.mRootView = view; if (panelParentView != null) { mAttachInfo.mPanelParentWindowToken = panelParentView.getApplicationWindowToken(); @@ -366,16 +402,20 @@ final class ViewRoot extends Handler implements ViewParent, View.AttachInfo.Soun try { res = sWindowSession.add(mWindow, attrs, - getHostVisibility(), mCoveredInsets); + getHostVisibility(), mAttachInfo.mContentInsets); } catch (RemoteException e) { mAdded = false; mView = null; + mAttachInfo.mRootView = null; unscheduleTraversals(); throw new RuntimeException("Adding window failed", e); } + mPendingContentInsets.set(mAttachInfo.mContentInsets); + mPendingVisibleInsets.set(0, 0, 0, 0); if (Config.LOGV) Log.v("ViewRoot", "Added window " + mWindow); if (res < WindowManagerImpl.ADD_OKAY) { mView = null; + mAttachInfo.mRootView = null; mAdded = false; unscheduleTraversals(); switch (res) { @@ -427,9 +467,13 @@ final class ViewRoot extends Handler implements ViewParent, View.AttachInfo.Soun return mLocation; } - public void setLayoutParams(WindowManager.LayoutParams attrs) { + void setLayoutParams(WindowManager.LayoutParams attrs, boolean newView) { synchronized (this) { mWindowAttributes.copyFrom(attrs); + if (newView) { + mSoftInputMode = attrs.softInputMode; + requestLayout(); + } mWindowAttributesChanged = true; scheduleTraversals(); } @@ -467,6 +511,11 @@ final class ViewRoot extends Handler implements ViewParent, View.AttachInfo.Soun public void invalidateChild(View child, Rect dirty) { checkThread(); if (LOCAL_LOGV) Log.v(TAG, "Invalidate child: " + dirty); + if (mCurScrollY != 0) { + mTempRect.set(dirty); + mTempRect.offset(0, -mCurScrollY); + dirty = mTempRect; + } mDirty.union(dirty); if (!mWillDrawSoon) { scheduleTraversals(); @@ -486,6 +535,8 @@ final class ViewRoot extends Handler implements ViewParent, View.AttachInfo.Soun if (child != mView) { throw new RuntimeException("child is not mine, honest!"); } + // Note: don't apply scroll offset, because we want to know its + // visibility in the virtual canvas being given to the view hierarchy. return r.intersect(0, 0, mWidth, mHeight); } @@ -528,7 +579,7 @@ final class ViewRoot extends Handler implements ViewParent, View.AttachInfo.Soun boolean windowResizesToFitContent = false; boolean fullRedrawNeeded = mFullRedrawNeeded; boolean newSurface = false; - WindowManager.LayoutParams lp = (WindowManager.LayoutParams) host.getLayoutParams(); + WindowManager.LayoutParams lp = mWindowAttributes; int desiredWindowWidth; int desiredWindowHeight; @@ -544,7 +595,7 @@ final class ViewRoot extends Handler implements ViewParent, View.AttachInfo.Soun WindowManager.LayoutParams params = null; if (mWindowAttributesChanged) { mWindowAttributesChanged = false; - params = mWindowAttributes; + params = lp; } if (mFirst) { @@ -559,9 +610,7 @@ final class ViewRoot extends Handler implements ViewParent, View.AttachInfo.Soun // is attached to the window. Note that at this point the surface // object is not initialized to its backing store, but soon it // will be (assuming the window is visible). - attachInfo.mWindowToken = mWindow.asBinder(); attachInfo.mSurface = mSurface; - attachInfo.mSession = sWindowSession; attachInfo.mHasWindowFocus = false; attachInfo.mWindowVisibility = viewVisibility; attachInfo.mRecomputeGlobalAttributes = false; @@ -590,16 +639,35 @@ final class ViewRoot extends Handler implements ViewParent, View.AttachInfo.Soun destroyGL(); } } + if (viewVisibility == View.GONE) { + // After making a window gone, we will count it as being + // shown for the first time the next time it gets focus. + mHasHadWindowFocus = false; + } } + boolean insetsChanged = false; + if (mLayoutRequested) { if (mFirst) { - host.fitSystemWindows(mCoveredInsets); + host.fitSystemWindows(mAttachInfo.mContentInsets); // make sure touch mode code executes by setting cached value // to opposite of the added touch mode. mAttachInfo.mInTouchMode = !mAddedTouchMode; ensureTouchModeLocally(mAddedTouchMode); } else { + if (!mAttachInfo.mContentInsets.equals(mPendingContentInsets)) { + mAttachInfo.mContentInsets.set(mPendingContentInsets); + host.fitSystemWindows(mAttachInfo.mContentInsets); + insetsChanged = true; + if (DEBUG_LAYOUT) Log.v(TAG, "Content insets changing to: " + + mAttachInfo.mContentInsets); + } + if (!mAttachInfo.mVisibleInsets.equals(mPendingVisibleInsets)) { + mAttachInfo.mVisibleInsets.set(mPendingVisibleInsets); + if (DEBUG_LAYOUT) Log.v(TAG, "Visible insets changing to: " + + mAttachInfo.mVisibleInsets); + } if (lp.width == ViewGroup.LayoutParams.WRAP_CONTENT || lp.height == ViewGroup.LayoutParams.WRAP_CONTENT) { windowResizesToFitContent = true; @@ -614,7 +682,7 @@ final class ViewRoot extends Handler implements ViewParent, View.AttachInfo.Soun childHeightMeasureSpec = getRootMeasureSpec(desiredWindowHeight, lp.height); // Ask host how big it wants to be - if (DEBUG_ORIENTATION) Log.v("ViewRoot", + if (DEBUG_ORIENTATION || DEBUG_LAYOUT) Log.v("ViewRoot", "Measuring " + host + " in display " + desiredWindowWidth + "x" + desiredWindowHeight + "..."); host.measure(childWidthMeasureSpec, childHeightMeasureSpec); @@ -633,11 +701,37 @@ final class ViewRoot extends Handler implements ViewParent, View.AttachInfo.Soun attachInfo.mKeepScreenOn = false; host.dispatchCollectViewAttributes(0); if (attachInfo.mKeepScreenOn != oldVal) { - params = mWindowAttributes; + params = lp; //Log.i(TAG, "Keep screen on changed: " + attachInfo.mKeepScreenOn); } } + if (mFirst || attachInfo.mViewVisibilityChanged) { + attachInfo.mViewVisibilityChanged = false; + int resizeMode = mSoftInputMode & + WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST; + // If we are in auto resize mode, then we need to determine + // what mode to use now. + if (resizeMode == WindowManager.LayoutParams.SOFT_INPUT_ADJUST_UNSPECIFIED) { + final int N = attachInfo.mScrollContainers.size(); + for (int i=0; i ci.left || vi.top > ci.top + || vi.right > ci.right || vi.bottom > ci.bottom) { + // We'll assume that we aren't going to change the scroll + // offset, since we want to avoid that unless it is actually + // going to make the focus visible... otherwise we scroll + // all over the place. + scrollY = mScrollY; + // We can be called for two different situations: during a draw, + // to update the scroll position if the focus has changed (in which + // case 'rectangle' is null), or in response to a + // requestChildRectangleOnScreen() call (in which case 'rectangle' + // is non-null and we just want to scroll to whatever that + // rectangle is). + View focus = mFocusedView; + if (focus != mLastScrolledFocus) { + // If the focus has changed, then ignore any requests to scroll + // to a rectangle; first we want to make sure the entire focus + // view is visible. + rectangle = null; + } + if (focus == mLastScrolledFocus && !mScrollMayChange + && rectangle == null) { + // Optimization: if the focus hasn't changed since last + // time, and no layout has happened, then just leave things + // as they are. + if (DEBUG_INPUT_RESIZE) Log.v(TAG, "Keeping scroll y=" + + mScrollY + " vi=" + vi.toShortString()); + } else if (focus != null) { + // We need to determine if the currently focused view is + // within the visible part of the window and, if not, apply + // a pan so it can be seen. + mLastScrolledFocus = focus; + mScrollMayChange = false; + // Try to find the rectangle from the focus view. + if (focus.getGlobalVisibleRect(mVisRect, null)) { + if (DEBUG_INPUT_RESIZE) Log.v(TAG, "Root w=" + + mView.getWidth() + " h=" + mView.getHeight() + + " ci=" + ci.toShortString() + + " vi=" + vi.toShortString()); + if (rectangle == null) { + focus.getFocusedRect(mTempRect); + if (DEBUG_INPUT_RESIZE) Log.v(TAG, "Focus " + focus + + ": focusRect=" + mTempRect.toShortString()); + ((ViewGroup) mView).offsetDescendantRectToMyCoords( + focus, mTempRect); + if (DEBUG_INPUT_RESIZE) Log.v(TAG, + "Focus in window: focusRect=" + + mTempRect.toShortString() + + " visRect=" + mVisRect.toShortString()); + } else { + mTempRect.set(rectangle); + if (DEBUG_INPUT_RESIZE) Log.v(TAG, + "Request scroll to rect: " + + mTempRect.toShortString() + + " visRect=" + mVisRect.toShortString()); + } + if (mTempRect.intersect(mVisRect)) { + if (DEBUG_INPUT_RESIZE) Log.v(TAG, + "Focus window visible rect: " + + mTempRect.toShortString()); + if (mTempRect.height() > + (mView.getHeight()-vi.top-vi.bottom)) { + // If the focus simply is not going to fit, then + // best is probably just to leave things as-is. + if (DEBUG_INPUT_RESIZE) Log.v(TAG, + "Too tall; leaving scrollY=" + scrollY); + } else if ((mTempRect.top-scrollY) < vi.top) { + scrollY -= vi.top - (mTempRect.top-scrollY); + if (DEBUG_INPUT_RESIZE) Log.v(TAG, + "Top covered; scrollY=" + scrollY); + } else if ((mTempRect.bottom-scrollY) + > (mView.getHeight()-vi.bottom)) { + scrollY += (mTempRect.bottom-scrollY) + - (mView.getHeight()-vi.bottom); + if (DEBUG_INPUT_RESIZE) Log.v(TAG, + "Bottom covered; scrollY=" + scrollY); + } + handled = true; + } + } + } + } + + if (scrollY != mScrollY) { + if (DEBUG_INPUT_RESIZE) Log.v(TAG, "Pan scroll changed: old=" + + mScrollY + " , new=" + scrollY); + if (!immediate) { + if (mScroller == null) { + mScroller = new Scroller(mView.getContext()); + } + mScroller.startScroll(0, mScrollY, 0, scrollY-mScrollY); + } else if (mScroller != null) { + mScroller.abortAnimation(); + } + mScrollY = scrollY; + } + + return handled; + } + public void requestChildFocus(View child, View focused) { checkThread(); if (mFocusedView != focused) { mAttachInfo.mTreeObserver.dispatchOnGlobalFocusChange(mFocusedView, focused); + scheduleTraversals(); } mFocusedView = focused; } @@ -1063,6 +1370,7 @@ final class ViewRoot extends Handler implements ViewParent, View.AttachInfo.Soun mView.dispatchDetachedFromWindow(); } mView = null; + mAttachInfo.mRootView = null; if (mUseGL) { destroyGL(); } @@ -1081,16 +1389,17 @@ final class ViewRoot extends Handler implements ViewParent, View.AttachInfo.Soun } - private final static int DO_TRAVERSAL = 1000; - private final static int DIE = 1001; - private final static int RESIZED = 1002; - private final static int RESIZED_REPORT = 1003; - private final static int WINDOW_FOCUS_CHANGED = 1004; - private final static int DISPATCH_KEY = 1005; - private final static int DISPATCH_POINTER = 1006; - private final static int DISPATCH_TRACKBALL = 1007; - private final static int DISPATCH_APP_VISIBILITY = 1008; - private final static int DISPATCH_GET_NEW_SURFACE = 1009; + public final static int DO_TRAVERSAL = 1000; + public final static int DIE = 1001; + public final static int RESIZED = 1002; + public final static int RESIZED_REPORT = 1003; + public final static int WINDOW_FOCUS_CHANGED = 1004; + public final static int DISPATCH_KEY = 1005; + public final static int DISPATCH_POINTER = 1006; + public final static int DISPATCH_TRACKBALL = 1007; + public final static int DISPATCH_APP_VISIBILITY = 1008; + public final static int DISPATCH_GET_NEW_SURFACE = 1009; + public final static int FINISHED_EVENT = 1010; @Override public void handleMessage(Message msg) { @@ -1107,6 +1416,9 @@ final class ViewRoot extends Handler implements ViewParent, View.AttachInfo.Soun mProfile = false; } break; + case FINISHED_EVENT: + handleFinishedEvent(msg.arg1, msg.arg2 != 0); + break; case DISPATCH_KEY: if (LOCAL_LOGV) Log.v( "ViewRoot", "Dispatching key " @@ -1124,7 +1436,7 @@ final class ViewRoot extends Handler implements ViewParent, View.AttachInfo.Soun } didFinish = true; } else { - didFinish = false; + didFinish = event.getAction() == MotionEvent.ACTION_OUTSIDE; } try { @@ -1136,7 +1448,10 @@ final class ViewRoot extends Handler implements ViewParent, View.AttachInfo.Soun if (isDown) { ensureTouchMode(true); } - + if(Config.LOGV) { + captureMotionLog("captureDispatchPointer", event); + } + event.offsetLocation(0, mCurScrollY); handled = mView.dispatchTouchEvent(event); if (!handled && isDown) { int edgeSlop = ViewConfiguration.getEdgeSlop(); @@ -1207,7 +1522,11 @@ final class ViewRoot extends Handler implements ViewParent, View.AttachInfo.Soun handleGetNewSurface(); break; case RESIZED: - if (mWinFrame.width() == msg.arg1 && mWinFrame.height() == msg.arg2) { + Rect coveredInsets = ((Rect[])msg.obj)[0]; + Rect visibleInsets = ((Rect[])msg.obj)[1]; + if (mWinFrame.width() == msg.arg1 && mWinFrame.height() == msg.arg2 + && mPendingContentInsets.equals(coveredInsets) + && mPendingVisibleInsets.equals(visibleInsets)) { break; } // fall through... @@ -1217,6 +1536,8 @@ final class ViewRoot extends Handler implements ViewParent, View.AttachInfo.Soun mWinFrame.right = msg.arg1; mWinFrame.top = 0; mWinFrame.bottom = msg.arg2; + mPendingContentInsets.set(((Rect[])msg.obj)[0]); + mPendingVisibleInsets.set(((Rect[])msg.obj)[1]); if (msg.what == RESIZED_REPORT) { mReportNextDraw = true; } @@ -1245,6 +1566,18 @@ final class ViewRoot extends Handler implements ViewParent, View.AttachInfo.Soun if (mView != null) { mView.dispatchWindowFocusChanged(hasWindowFocus); } + + // Note: must be done after the focus change callbacks, + // so all of the view state is set up correctly. + if (hasWindowFocus) { + InputMethodManager imm = InputMethodManager.peekInstance(); + if (imm != null) { + imm.onWindowFocus(mView.findFocus(), + mWindowAttributes.softInputMode, !mHasHadWindowFocus, + mWindowAttributes.flags); + } + mHasHadWindowFocus = true; + } } } break; case DIE: @@ -1387,7 +1720,7 @@ final class ViewRoot extends Handler implements ViewParent, View.AttachInfo.Soun didFinish = false; } - //Log.i("foo", "Motion event:" + event); + if (DEBUG_TRACKBALL) Log.v(TAG, "Motion event:" + event); boolean handled = false; try { @@ -1397,7 +1730,7 @@ final class ViewRoot extends Handler implements ViewParent, View.AttachInfo.Soun handled = mView.dispatchTrackballEvent(event); if (!handled) { // we could do something here, like changing the focus - // or someting? + // or something? } } } finally { @@ -1456,8 +1789,8 @@ final class ViewRoot extends Handler implements ViewParent, View.AttachInfo.Soun + " / Y=" + y.position + " step=" + y.step + " dir=" + y.dir + " acc=" + y.acceleration + " move=" + event.getY()); - final float xOff = x.collect(event.getX(), "X"); - final float yOff = y.collect(event.getY(), "Y"); + final float xOff = x.collect(event.getX(), event.getEventTime(), "X"); + final float yOff = y.collect(event.getY(), event.getEventTime(), "Y"); // Generate DPAD events based on the trackball movement. // We pick the axis that has moved the most as the direction of @@ -1489,9 +1822,9 @@ final class ViewRoot extends Handler implements ViewParent, View.AttachInfo.Soun if (keycode != 0) { if (movement < 0) movement = -movement; int accelMovement = (int)(movement * accel); - //Log.i(TAG, "Move: movement=" + movement - // + " accelMovement=" + accelMovement - // + " accel=" + accel); + if (DEBUG_TRACKBALL) Log.v(TAG, "Move: movement=" + movement + + " accelMovement=" + accelMovement + + " accel=" + accel); if (accelMovement > movement) { if (DEBUG_TRACKBALL) Log.v("foo", "Delivering fake DPAD: " + keycode); @@ -1602,8 +1935,116 @@ final class ViewRoot extends Handler implements ViewParent, View.AttachInfo.Soun return false; } - + /** + * log motion events + */ + private static void captureMotionLog(String subTag, MotionEvent ev) { + //check dynamic switch + if (ev == null || + SystemProperties.getInt(ViewDebug.SYSTEM_PROPERTY_CAPTURE_EVENT, 0) == 0) { + return; + } + + StringBuilder sb = new StringBuilder(subTag + ": "); + sb.append(ev.getDownTime()).append(','); + sb.append(ev.getEventTime()).append(','); + sb.append(ev.getAction()).append(','); + sb.append(ev.getX()).append(','); + sb.append(ev.getY()).append(','); + sb.append(ev.getPressure()).append(','); + sb.append(ev.getSize()).append(','); + sb.append(ev.getMetaState()).append(','); + sb.append(ev.getXPrecision()).append(','); + sb.append(ev.getYPrecision()).append(','); + sb.append(ev.getDeviceId()).append(','); + sb.append(ev.getEdgeFlags()); + Log.d(TAG, sb.toString()); + } + /** + * log motion events + */ + private static void captureKeyLog(String subTag, KeyEvent ev) { + //check dynamic switch + if (ev == null || + SystemProperties.getInt(ViewDebug.SYSTEM_PROPERTY_CAPTURE_EVENT, 0) == 0) { + return; + } + StringBuilder sb = new StringBuilder(subTag + ": "); + sb.append(ev.getDownTime()).append(','); + sb.append(ev.getEventTime()).append(','); + sb.append(ev.getAction()).append(','); + sb.append(ev.getKeyCode()).append(','); + sb.append(ev.getRepeatCount()).append(','); + sb.append(ev.getMetaState()).append(','); + sb.append(ev.getDeviceId()).append(','); + sb.append(ev.getScanCode()); + Log.d(TAG, sb.toString()); + } + + int enqueuePendingEvent(Object event, boolean sendDone) { + int seq = mPendingEventSeq+1; + if (seq < 0) seq = 0; + mPendingEventSeq = seq; + mPendingEvents.put(seq, event); + return sendDone ? seq : -seq; + } + + Object retrievePendingEvent(int seq) { + if (seq < 0) seq = -seq; + Object event = mPendingEvents.get(seq); + if (event != null) { + mPendingEvents.remove(seq); + } + return event; + } + private void deliverKeyEvent(KeyEvent event, boolean sendDone) { + boolean handled = false; + handled = mView.dispatchKeyEventPreIme(event); + if (handled) { + if (sendDone) { + if (LOCAL_LOGV) Log.v( + "ViewRoot", "Telling window manager key is finished"); + try { + sWindowSession.finishKey(mWindow); + } catch (RemoteException e) { + } + } + return; + } + InputMethodManager imm = InputMethodManager.peekInstance(); + if (imm != null && mView != null && imm.isActive()) { + int seq = enqueuePendingEvent(event, sendDone); + if (DEBUG_IMF) Log.v(TAG, "Sending key event to IME: seq=" + + seq + " event=" + event); + imm.dispatchKeyEvent(mView.getContext(), seq, event, + mInputMethodCallback); + return; + } + deliverKeyEventToViewHierarchy(event, sendDone); + } + + void handleFinishedEvent(int seq, boolean handled) { + final KeyEvent event = (KeyEvent)retrievePendingEvent(seq); + if (DEBUG_IMF) Log.v(TAG, "IME finished event: seq=" + seq + + " handled=" + handled + " event=" + event); + if (event != null) { + final boolean sendDone = seq >= 0; + if (!handled) { + deliverKeyEventToViewHierarchy(event, sendDone); + return; + } else if (sendDone) { + if (LOCAL_LOGV) Log.v( + "ViewRoot", "Telling window manager key is finished"); + try { + sWindowSession.finishKey(mWindow); + } catch (RemoteException e) { + } + } + } + } + + private void deliverKeyEventToViewHierarchy(KeyEvent event, boolean sendDone) { try { if (mView != null && mAdded) { final int action = event.getAction(); @@ -1611,8 +2052,11 @@ final class ViewRoot extends Handler implements ViewParent, View.AttachInfo.Soun if (checkForLeavingTouchModeAndConsume(event)) { return; + } + + if (Config.LOGV) { + captureKeyLog("captureDispatchKeyEvent", event); } - boolean keyHandled = mView.dispatchKeyEvent(event); if ((!keyHandled && isDown) || (action == KeyEvent.ACTION_MULTIPLE)) { @@ -1740,10 +2184,11 @@ final class ViewRoot extends Handler implements ViewParent, View.AttachInfo.Soun // animation info. try { if ((sWindowSession.relayout( - mWindow, mWindowAttributes, - mView.mMeasuredWidth, mView.mMeasuredHeight, - viewVisibility, mWinFrame, mCoveredInsets, mSurface) - &WindowManagerImpl.RELAYOUT_FIRST_TIME) != 0) { + mWindow, mWindowAttributes, + mView.mMeasuredWidth, mView.mMeasuredHeight, + viewVisibility, false, mWinFrame, mPendingContentInsets, + mPendingVisibleInsets, mSurface) + &WindowManagerImpl.RELAYOUT_FIRST_TIME) != 0) { sWindowSession.finishDrawing(mWindow); } } catch (RemoteException e) { @@ -1767,12 +2212,23 @@ final class ViewRoot extends Handler implements ViewParent, View.AttachInfo.Soun } } - public void dispatchResized(int w, int h, boolean reportDraw) { - if (DEBUG_DRAW) Log.v(TAG, "Resized " + this + ": w=" + w - + " h=" + h + " reportDraw=" + reportDraw); - Message msg = obtainMessage(reportDraw ? RESIZED_REPORT : RESIZED); + public void dispatchFinishedEvent(int seq, boolean handled) { + Message msg = obtainMessage(FINISHED_EVENT); + msg.arg1 = seq; + msg.arg2 = handled ? 1 : 0; + sendMessage(msg); + } + + public void dispatchResized(int w, int h, Rect coveredInsets, + Rect visibleInsets, boolean reportDraw) { + if (DEBUG_LAYOUT) Log.v(TAG, "Resizing " + this + ": w=" + w + + " h=" + h + " coveredInsets=" + coveredInsets.toShortString() + + " visibleInsets=" + visibleInsets.toShortString() + + " reportDraw=" + reportDraw); + Message msg = obtainMessage(reportDraw ? RESIZED_REPORT :RESIZED); msg.arg1 = w; msg.arg2 = h; + msg.obj = new Rect[] { new Rect(coveredInsets), new Rect(visibleInsets) }; sendMessage(msg); } @@ -1855,6 +2311,30 @@ final class ViewRoot extends Handler implements ViewParent, View.AttachInfo.Soun // ViewRoot never intercepts touch event, so this can be a no-op } + public boolean requestChildRectangleOnScreen(View child, Rect rectangle, + boolean immediate) { + return scrollToRectOrFocus(rectangle, immediate); + } + + static class InputMethodCallback extends IInputMethodCallback.Stub { + private WeakReference mViewRoot; + + public InputMethodCallback(ViewRoot viewRoot) { + mViewRoot = new WeakReference(viewRoot); + } + + public void finishedEvent(int seq, boolean handled) { + final ViewRoot viewRoot = mViewRoot.get(); + if (viewRoot != null) { + viewRoot.dispatchFinishedEvent(seq, handled); + } + } + + public void sessionCreated(IInputMethodSession session) throws RemoteException { + // Stub -- not for use in the client. + } + } + static class W extends IWindow.Stub { private WeakReference mViewRoot; @@ -1862,10 +2342,12 @@ final class ViewRoot extends Handler implements ViewParent, View.AttachInfo.Soun mViewRoot = new WeakReference(viewRoot); } - public void resized(int w, int h, boolean reportDraw) { + public void resized(int w, int h, Rect coveredInsets, + Rect visibleInsets, boolean reportDraw) { final ViewRoot viewRoot = mViewRoot.get(); if (viewRoot != null) { - viewRoot.dispatchResized(w, h, reportDraw); + viewRoot.dispatchResized(w, h, coveredInsets, + visibleInsets, reportDraw); } } @@ -1961,9 +2443,30 @@ final class ViewRoot extends Handler implements ViewParent, View.AttachInfo.Soun * discrete (DPAD) movements based on raw trackball motion. */ static final class TrackballAxis { + /** + * The maximum amount of acceleration we will apply. + */ + static final float MAX_ACCELERATION = 20; + + /** + * The maximum amount of time (in milliseconds) between events in order + * for us to consider the user to be doing fast trackball movements, + * and thus apply an acceleration. + */ + static final long FAST_MOVE_TIME = 100; + + /** + * Scaling factor to the time (in milliseconds) between events to how + * much to multiple/divide the current acceleration. When movement + * is < FAST_MOVE_TIME this multiplies the acceleration; when > + * FAST_MOVE_TIME it divides it. + */ + static final float ACCEL_MOVE_SCALING_FACTOR = (1.0f/50); + float position; float absPosition; float acceleration = 1; + long lastMoveTime = 0; int step; int dir; int nonAccelMovement; @@ -1971,6 +2474,7 @@ final class ViewRoot extends Handler implements ViewParent, View.AttachInfo.Soun void reset(int _step) { position = 0; acceleration = 1; + lastMoveTime = 0; step = _step; dir = 0; } @@ -1985,23 +2489,56 @@ final class ViewRoot extends Handler implements ViewParent, View.AttachInfo.Soun * @return Returns the absolute value of the amount of movement * collected so far. */ - float collect(float off, String axis) { + float collect(float off, long time, String axis) { + long normTime; if (off > 0) { + normTime = (long)(off * FAST_MOVE_TIME); if (dir < 0) { if (DEBUG_TRACKBALL) Log.v(TAG, axis + " reversed to positive!"); position = 0; step = 0; acceleration = 1; + lastMoveTime = 0; } dir = 1; } else if (off < 0) { + normTime = (long)((-off) * FAST_MOVE_TIME); if (dir > 0) { if (DEBUG_TRACKBALL) Log.v(TAG, axis + " reversed to negative!"); position = 0; step = 0; acceleration = 1; + lastMoveTime = 0; } dir = -1; + } else { + normTime = 0; + } + + // The number of milliseconds between each movement that is + // considered "normal" and will not result in any acceleration + // or deceleration, scaled by the offset we have here. + if (normTime > 0) { + long delta = time - lastMoveTime; + lastMoveTime = time; + float acc = acceleration; + if (delta < normTime) { + // The user is scrolling rapidly, so increase acceleration. + float scale = (normTime-delta) * ACCEL_MOVE_SCALING_FACTOR; + if (scale > 1) acc *= scale; + if (DEBUG_TRACKBALL) Log.v(TAG, axis + " accelerate: off=" + + off + " normTime=" + normTime + " delta=" + delta + + " scale=" + scale + " acc=" + acc); + acceleration = acc < MAX_ACCELERATION ? acc : MAX_ACCELERATION; + } else { + // The user is scrolling slowly, so decrease acceleration. + float scale = (delta-normTime) * ACCEL_MOVE_SCALING_FACTOR; + if (scale > 1) acc /= scale; + if (DEBUG_TRACKBALL) Log.v(TAG, axis + " deccelerate: off=" + + off + " normTime=" + normTime + " delta=" + delta + + " scale=" + scale + " acc=" + acc); + acceleration = acc > 1 ? acc : 1; + } } position += off; return (absPosition = Math.abs(position)); @@ -2050,12 +2587,11 @@ final class ViewRoot extends Handler implements ViewParent, View.AttachInfo.Soun break; // After the first two, we generate discrete movements // consistently with the trackball, applying an acceleration - // if the trackball is moving quickly. The acceleration is - // currently very simple, just reducing the amount of - // trackball motion required as more discrete movements are - // generated. This should probably be changed to take time - // more into account, so that quick trackball movements will - // have increased acceleration. + // if the trackball is moving quickly. This is a simple + // acceleration on top of what we already compute based + // on how quickly the wheel is being turned, to apply + // a longer increasing acceleration to continuous movement + // in one direction. default: if (absPosition < 1) { return movement; @@ -2065,7 +2601,7 @@ final class ViewRoot extends Handler implements ViewParent, View.AttachInfo.Soun absPosition = Math.abs(position); float acc = acceleration; acc *= 1.1f; - acceleration = acc < 20 ? acc : acceleration; + acceleration = acc < MAX_ACCELERATION ? acc : acceleration; break; } } while (true); diff --git a/core/java/android/view/ViewTreeObserver.java b/core/java/android/view/ViewTreeObserver.java index 2e1e01a6fd360ba1bcd0edc398adb8b80b8619f4..05f5fa2a153251f4ed2aa7f911538267aa0c85d3 100644 --- a/core/java/android/view/ViewTreeObserver.java +++ b/core/java/android/view/ViewTreeObserver.java @@ -16,6 +16,8 @@ package android.view; +import android.graphics.Rect; + import java.util.ArrayList; /** @@ -32,6 +34,7 @@ public final class ViewTreeObserver { private ArrayList mOnGlobalLayoutListeners; private ArrayList mOnPreDrawListeners; private ArrayList mOnTouchModeChangeListeners; + private ArrayList mOnComputeInternalInsetsListeners; private boolean mAlive = true; @@ -95,6 +98,108 @@ public final class ViewTreeObserver { public void onTouchModeChanged(boolean isInTouchMode); } + /** + * Parameters used with OnComputeInternalInsetsListener. + * {@hide pending API Council approval} + */ + public final static class InternalInsetsInfo { + /** + * Offsets from the frame of the window at which the content of + * windows behind it should be placed. + */ + public final Rect contentInsets = new Rect(); + + /** + * Offsets from the fram of the window at which windows behind it + * are visible. + */ + public final Rect visibleInsets = new Rect(); + + /** + * Option for {@link #setTouchableInsets(int)}: the entire window frame + * can be touched. + */ + public static final int TOUCHABLE_INSETS_FRAME = 0; + + /** + * Option for {@link #setTouchableInsets(int)}: the area inside of + * the content insets can be touched. + */ + public static final int TOUCHABLE_INSETS_CONTENT = 1; + + /** + * Option for {@link #setTouchableInsets(int)}: the area inside of + * the visible insets can be touched. + */ + public static final int TOUCHABLE_INSETS_VISIBLE = 2; + + /** + * Set which parts of the window can be touched: either + * {@link #TOUCHABLE_INSETS_FRAME}, {@link #TOUCHABLE_INSETS_CONTENT}, + * or {@link #TOUCHABLE_INSETS_VISIBLE}. + */ + public void setTouchableInsets(int val) { + mTouchableInsets = val; + } + + public int getTouchableInsets() { + return mTouchableInsets; + } + + int mTouchableInsets; + + void reset() { + final Rect givenContent = contentInsets; + final Rect givenVisible = visibleInsets; + givenContent.left = givenContent.top = givenContent.right + = givenContent.bottom = givenVisible.left = givenVisible.top + = givenVisible.right = givenVisible.bottom = 0; + mTouchableInsets = TOUCHABLE_INSETS_FRAME; + } + + @Override public boolean equals(Object o) { + try { + if (o == null) { + return false; + } + InternalInsetsInfo other = (InternalInsetsInfo)o; + if (!contentInsets.equals(other.contentInsets)) { + return false; + } + if (!visibleInsets.equals(other.visibleInsets)) { + return false; + } + return mTouchableInsets == other.mTouchableInsets; + } catch (ClassCastException e) { + return false; + } + } + + void set(InternalInsetsInfo other) { + contentInsets.set(other.contentInsets); + visibleInsets.set(other.visibleInsets); + mTouchableInsets = other.mTouchableInsets; + } + } + + /** + * Interface definition for a callback to be invoked when layout has + * completed and the client can compute its interior insets. + * {@hide pending API Council approval} + */ + public interface OnComputeInternalInsetsListener { + /** + * Callback method to be invoked when layout has completed and the + * client can compute its interior insets. + * + * @param inoutInfo Should be filled in by the implementation with + * the information about the insets of the window. This is called + * with whatever values the previous OnComputeInternalInsetsListener + * returned, if there are multiple such listeners in the window. + */ + public void onComputeInternalInsets(InternalInsetsInfo inoutInfo); + } + /** * Creates a new ViewTreeObserver. This constructor should not be called */ @@ -141,6 +246,14 @@ public final class ViewTreeObserver { } } + if (observer.mOnComputeInternalInsetsListeners != null) { + if (mOnComputeInternalInsetsListeners != null) { + mOnComputeInternalInsetsListeners.addAll(observer.mOnComputeInternalInsetsListeners); + } else { + mOnComputeInternalInsetsListeners = observer.mOnComputeInternalInsetsListeners; + } + } + observer.kill(); } @@ -281,6 +394,43 @@ public final class ViewTreeObserver { mOnTouchModeChangeListeners.remove(victim); } + /** + * Register a callback to be invoked when the invoked when it is time to + * compute the window's internal insets. + * + * @param listener The callback to add + * + * @throws IllegalStateException If {@link #isAlive()} returns false + * {@hide pending API Council approval} + */ + public void addOnComputeInternalInsetsListener(OnComputeInternalInsetsListener listener) { + checkIsAlive(); + + if (mOnComputeInternalInsetsListeners == null) { + mOnComputeInternalInsetsListeners = new ArrayList(); + } + + mOnComputeInternalInsetsListeners.add(listener); + } + + /** + * Remove a previously installed internal insets computation callback + * + * @param victim The callback to remove + * + * @throws IllegalStateException If {@link #isAlive()} returns false + * + * @see #addOnComputeInternalInsetsListener(OnComputeInternalInsetsListener) + * {@hide pending API Council approval} + */ + public void removeOnComputeInternalInsetsListener(OnComputeInternalInsetsListener victim) { + checkIsAlive(); + if (mOnComputeInternalInsetsListeners == null) { + return; + } + mOnComputeInternalInsetsListeners.remove(victim); + } + private void checkIsAlive() { if (!mAlive) { throw new IllegalStateException("This ViewTreeObserver is not alive, call " @@ -373,4 +523,25 @@ public final class ViewTreeObserver { } } } + + /** + * Returns whether there are listeners for computing internal insets. + */ + final boolean hasComputeInternalInsetsListeners() { + final ArrayList listeners = mOnComputeInternalInsetsListeners; + return (listeners != null && listeners.size() > 0); + } + + /** + * Calls all listeners to compute the current insets. + */ + final void dispatchOnComputeInternalInsets(InternalInsetsInfo inoutInfo) { + final ArrayList listeners = mOnComputeInternalInsetsListeners; + if (listeners != null) { + final int count = listeners.size(); + for (int i = count - 1; i >= 0; i--) { + listeners.get(i).onComputeInternalInsets(inoutInfo); + } + } + } } diff --git a/core/java/android/view/VolumePanel.java b/core/java/android/view/VolumePanel.java index 24f485367c599fb9c3711c51df4af04cd0eae3de..f4d0fdeda8057503edf4a5dce06c4b0c6b60a909 100644 --- a/core/java/android/view/VolumePanel.java +++ b/core/java/android/view/VolumePanel.java @@ -19,10 +19,15 @@ package android.view; import android.media.ToneGenerator; import android.media.AudioManager; import android.media.AudioService; +import android.media.AudioSystem; import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.res.Resources; import android.os.Handler; import android.os.Message; import android.os.Vibrator; +import android.text.TextUtils; import android.util.Config; import android.util.Log; import android.widget.ImageView; @@ -69,46 +74,47 @@ public class VolumePanel extends Handler private static final int MSG_STOP_SOUNDS = 3; private static final int MSG_VIBRATE = 4; - private final String RINGTONE_VOLUME_TEXT; - private final String MUSIC_VOLUME_TEXT; - private final String INCALL_VOLUME_TEXT; - private final String ALARM_VOLUME_TEXT; - private final String UNKNOWN_VOLUME_TEXT; + private static final int RINGTONE_VOLUME_TEXT = com.android.internal.R.string.volume_ringtone; + private static final int MUSIC_VOLUME_TEXT = com.android.internal.R.string.volume_music; + private static final int INCALL_VOLUME_TEXT = com.android.internal.R.string.volume_call; + private static final int ALARM_VOLUME_TEXT = com.android.internal.R.string.volume_alarm; + private static final int UNKNOWN_VOLUME_TEXT = com.android.internal.R.string.volume_unknown; + private static final int NOTIFICATION_VOLUME_TEXT = + com.android.internal.R.string.volume_notification; protected Context mContext; + private AudioManager mAudioManager; protected AudioService mAudioService; - private Toast mToast; - private View mView; - private TextView mMessage; - private ImageView mOtherStreamIcon; - private ImageView mRingerStreamIcon; - private ProgressBar mLevel; + private final Toast mToast; + private final View mView; + private final TextView mMessage; + private final TextView mAdditionalMessage; + private final ImageView mSmallStreamIcon; + private final ImageView mLargeStreamIcon; + private final ProgressBar mLevel; // Synchronize when accessing this private ToneGenerator mToneGenerators[]; private Vibrator mVibrator; - + public VolumePanel(Context context, AudioService volumeService) { mContext = context; + mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE); mAudioService = volumeService; mToast = new Toast(context); - - RINGTONE_VOLUME_TEXT = context.getString(com.android.internal.R.string.volume_ringtone); - MUSIC_VOLUME_TEXT = context.getString(com.android.internal.R.string.volume_music); - INCALL_VOLUME_TEXT = context.getString(com.android.internal.R.string.volume_call); - ALARM_VOLUME_TEXT = context.getString(com.android.internal.R.string.volume_alarm); - UNKNOWN_VOLUME_TEXT = context.getString(com.android.internal.R.string.volume_unknown); - + LayoutInflater inflater = (LayoutInflater) context .getSystemService(Context.LAYOUT_INFLATER_SERVICE); View view = mView = inflater.inflate(com.android.internal.R.layout.volume_adjust, null); mMessage = (TextView) view.findViewById(com.android.internal.R.id.message); - mOtherStreamIcon = (ImageView) view.findViewById(com.android.internal.R.id.other_stream_icon); - mRingerStreamIcon = (ImageView) view.findViewById(com.android.internal.R.id.ringer_stream_icon); + mAdditionalMessage = + (TextView) view.findViewById(com.android.internal.R.id.additional_message); + mSmallStreamIcon = (ImageView) view.findViewById(com.android.internal.R.id.other_stream_icon); + mLargeStreamIcon = (ImageView) view.findViewById(com.android.internal.R.id.ringer_stream_icon); mLevel = (ProgressBar) view.findViewById(com.android.internal.R.id.level); - mToneGenerators = new ToneGenerator[AudioManager.NUM_STREAMS]; + mToneGenerators = new ToneGenerator[AudioSystem.getNumStreamTypes()]; mVibrator = new Vibrator(); } @@ -148,13 +154,17 @@ public class VolumePanel extends Handler protected void onShowVolumeChanged(int streamType, int flags) { int index = mAudioService.getStreamVolume(streamType); - String message = UNKNOWN_VOLUME_TEXT; + int message = UNKNOWN_VOLUME_TEXT; + int additionalMessage = 0; if (LOGD) { Log.d(TAG, "onShowVolumeChanged(streamType: " + streamType + ", flags: " + flags + "), index: " + index); } + // get max volume for progress bar + int max = mAudioService.getStreamMaxVolume(streamType); + switch (streamType) { case AudioManager.STREAM_RING: { @@ -165,32 +175,60 @@ public class VolumePanel extends Handler case AudioManager.STREAM_MUSIC: { message = MUSIC_VOLUME_TEXT; - setOtherIcon(index); + if (mAudioManager.isBluetoothA2dpOn()) { + additionalMessage = + com.android.internal.R.string.volume_music_hint_playing_through_bluetooth; + setLargeIcon(com.android.internal.R.drawable.ic_volume_bluetooth_ad2p); + } else { + setSmallIcon(index); + } break; } case AudioManager.STREAM_VOICE_CALL: { - message = INCALL_VOLUME_TEXT; /* - * For in-call voice call volume, there is no inaudible volume - * level, so never show the mute icon + * For in-call voice call volume, there is no inaudible volume. + * Rescale the UI control so the progress bar doesn't go all + * the way to zero and don't show the mute icon. */ - setOtherIcon(index == 0 ? 1 : index); + index++; + max++; + message = INCALL_VOLUME_TEXT; + if (mAudioManager.isBluetoothScoOn()) { + additionalMessage = + com.android.internal.R.string.volume_call_hint_playing_through_bluetooth; + setLargeIcon(com.android.internal.R.drawable.ic_volume_bluetooth_in_call); + } else { + setSmallIcon(index); + } break; } case AudioManager.STREAM_ALARM: { message = ALARM_VOLUME_TEXT; - setOtherIcon(index); + setSmallIcon(index); + break; + } + + case AudioManager.STREAM_NOTIFICATION: { + message = NOTIFICATION_VOLUME_TEXT; + setSmallIcon(index); break; } } - if (!mMessage.getText().equals(message)) { - mMessage.setText(message); + String messageString = Resources.getSystem().getString(message); + if (!mMessage.getText().equals(messageString)) { + mMessage.setText(messageString); } - int max = mAudioService.getStreamMaxVolume(streamType); + if (additionalMessage == 0) { + mAdditionalMessage.setVisibility(View.GONE); + } else { + mAdditionalMessage.setVisibility(View.VISIBLE); + mAdditionalMessage.setText(Resources.getSystem().getString(additionalMessage)); + } + if (max != mLevel.getMax()) { mLevel.setMax(max); } @@ -230,7 +268,8 @@ public class VolumePanel extends Handler protected void onStopSounds() { synchronized (this) { - for (int i = AudioManager.NUM_STREAMS - 1; i >= 0; i--) { + int numStreamTypes = AudioSystem.getNumStreamTypes(); + for (int i = numStreamTypes - 1; i >= 0; i--) { ToneGenerator toneGen = mToneGenerators[i]; if (toneGen != null) { toneGen.stopTone(); @@ -261,19 +300,41 @@ public class VolumePanel extends Handler } } } - - private void setOtherIcon(int index) { - mRingerStreamIcon.setVisibility(View.GONE); - mOtherStreamIcon.setVisibility(View.VISIBLE); + + /** + * Makes the small icon visible, and hides the large icon. + * + * @param index The volume index, where 0 means muted. + */ + private void setSmallIcon(int index) { + mLargeStreamIcon.setVisibility(View.GONE); + mSmallStreamIcon.setVisibility(View.VISIBLE); - mOtherStreamIcon.setImageResource(index == 0 + mSmallStreamIcon.setImageResource(index == 0 ? com.android.internal.R.drawable.ic_volume_off_small : com.android.internal.R.drawable.ic_volume_small); } + /** + * Makes the large image view visible with the given icon. + * + * @param resId The icon to display. + */ + private void setLargeIcon(int resId) { + mSmallStreamIcon.setVisibility(View.GONE); + mLargeStreamIcon.setVisibility(View.VISIBLE); + mLargeStreamIcon.setImageResource(resId); + } + + /** + * Makes the ringer icon visible with an icon that is chosen + * based on the current ringer mode. + * + * @param index + */ private void setRingerIcon(int index) { - mOtherStreamIcon.setVisibility(View.GONE); - mRingerStreamIcon.setVisibility(View.VISIBLE); + mSmallStreamIcon.setVisibility(View.GONE); + mLargeStreamIcon.setVisibility(View.VISIBLE); int ringerMode = mAudioService.getRingerMode(); int icon; @@ -287,14 +348,14 @@ public class VolumePanel extends Handler } else { icon = com.android.internal.R.drawable.ic_volume; } - mRingerStreamIcon.setImageResource(icon); + mLargeStreamIcon.setImageResource(icon); } protected void onFreeResources() { // We'll keep the views, just ditch the cached drawable and hence // bitmaps - mOtherStreamIcon.setImageDrawable(null); - mRingerStreamIcon.setImageDrawable(null); + mSmallStreamIcon.setImageDrawable(null); + mLargeStreamIcon.setImageDrawable(null); synchronized (this) { for (int i = mToneGenerators.length - 1; i >= 0; i--) { diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java index 4aeab2d3cc6fcfe0b6354e3551b02c48e21c2d6b..a68436b0cc15ccbdd00997bd583d6c851fe6d457 100644 --- a/core/java/android/view/Window.java +++ b/core/java/android/view/Window.java @@ -24,6 +24,7 @@ import android.graphics.drawable.Drawable; import android.net.Uri; import android.os.Bundle; import android.os.IBinder; +import android.util.Log; /** * Abstract base class for a top-level window look and behavior policy. An @@ -106,6 +107,8 @@ public abstract class Window { private boolean mHaveWindowFormat = false; private int mDefaultWindowFormat = PixelFormat.OPAQUE; + private boolean mHasSoftInputMode = false; + // The current window attributes. private final WindowManager.LayoutParams mWindowAttributes = new WindowManager.LayoutParams(); @@ -382,11 +385,7 @@ public abstract class Window { && mAppName != null) { wp.setTitle(mAppName); } - if (wp.windowAnimations == 0) { - wp.windowAnimations = getWindowStyle().getResourceId( - com.android.internal.R.styleable.Window_windowAnimationStyle, 0); - } - } + } if (wp.packageName == null) { wp.packageName = mContext.getPackageName(); } @@ -525,6 +524,26 @@ public abstract class Window { } } + /** + * Specify an explicit soft input mode to use for the window, as per + * {@link WindowManager.LayoutParams#softInputMode + * WindowManager.LayoutParams.softInputMode}. Providing anything besides + * "unspecified" here will override the input mode the window would + * normally retrieve from its theme. + */ + public void setSoftInputMode(int mode) { + final WindowManager.LayoutParams attrs = getAttributes(); + if (mode != WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED) { + attrs.softInputMode = mode; + mHasSoftInputMode = true; + } else { + mHasSoftInputMode = false; + } + if (mCallback != null) { + mCallback.onWindowAttributesChanged(attrs); + } + } + /** * Convenience function to set the flag bits as specified in flags, as * per {@link #setFlags}. @@ -572,14 +591,17 @@ public abstract class Window { } /** - * Specify custom window attributes. + * Specify custom window attributes. PLEASE NOTE: the + * layout params you give here should generally be from values previously + * retrieved with {@link #getAttributes()}; you probably do not want to + * blindly create and apply your own, since this will blow away any values + * set by the framework that you are not interested in. * * @param a The new window attributes, which will completely override any * current values. */ public void setAttributes(WindowManager.LayoutParams a) { mWindowAttributes.copyFrom(a); - mForcedWindowFlags = 0xffffffff; if (mCallback != null) { mCallback.onWindowAttributesChanged(mWindowAttributes); } @@ -603,6 +625,13 @@ public abstract class Window { return mForcedWindowFlags; } + /** + * Has the app specified their own soft input mode? + */ + protected final boolean hasSoftInputMode() { + return mHasSoftInputMode; + } + /** * Enable extended screen features. This must be called before * setContentView(). May be called as many times as desired as long as it @@ -926,8 +955,7 @@ public abstract class Window { * @see #setFormat * @see PixelFormat */ - protected void setDefaultWindowFormat(int format) - { + protected void setDefaultWindowFormat(int format) { mDefaultWindowFormat = format; if (!mHaveWindowFormat) { final WindowManager.LayoutParams attrs = getAttributes(); diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java index 4c1dec5050adc6a48e145e2a48cb634a30f04f8d..7d202aac7e6f71b93321105c042fdfe8497a5980 100644 --- a/core/java/android/view/WindowManager.java +++ b/core/java/android/view/WindowManager.java @@ -125,6 +125,9 @@ public interface WindowManager extends ViewManager { * @see #TYPE_APPLICATION_PANEL * @see #TYPE_APPLICATION_MEDIA * @see #TYPE_APPLICATION_SUB_PANEL + * @see #TYPE_APPLICATION_ATTACHED_DIALOG + * @see #TYPE_INPUT_METHOD + * @see #TYPE_INPUT_METHOD_DIALOG * @see #TYPE_STATUS_BAR * @see #TYPE_SEARCH_BAR * @see #TYPE_PHONE @@ -133,6 +136,12 @@ public interface WindowManager extends ViewManager { * @see #TYPE_TOAST * @see #TYPE_SYSTEM_OVERLAY * @see #TYPE_PRIORITY_PHONE + * @see #TYPE_STATUS_BAR_PANEL + * @see #TYPE_SYSTEM_DIALOG + * @see #TYPE_KEYGUARD_DIALOG + * @see #TYPE_SYSTEM_ERROR + * @see #TYPE_INPUT_METHOD + * @see #TYPE_INPUT_METHOD_DIALOG */ public int type; @@ -193,12 +202,18 @@ public interface WindowManager extends ViewManager { * {@link #TYPE_APPLICATION_PANEL} panels. */ public static final int TYPE_APPLICATION_SUB_PANEL = FIRST_SUB_WINDOW+2; - + + /** Window type: like {@link #TYPE_APPLICATION_PANEL}, but layout + * of the window happens as that of a top-level window, not + * as a child of its container. + */ + public static final int TYPE_APPLICATION_ATTACHED_DIALOG = FIRST_SUB_WINDOW+3; + /** * End of types of sub-windows. */ public static final int LAST_SUB_WINDOW = 1999; - + /** * Start of system-specific window types. These are not normally * created by applications. @@ -277,11 +292,24 @@ public interface WindowManager extends ViewManager { */ public static final int TYPE_SYSTEM_ERROR = FIRST_SYSTEM_WINDOW+10; + /** + * Window type: internal input methods windows, which appear above + * the normal UI. Application windows may be resized or panned to keep + * the input focus visible while this window is displayed. + */ + public static final int TYPE_INPUT_METHOD = FIRST_SYSTEM_WINDOW+11; + + /** + * Window type: internal input methods dialog windows, which appear above + * the current input method window. + */ + public static final int TYPE_INPUT_METHOD_DIALOG= FIRST_SYSTEM_WINDOW+12; + /** * End of types of system windows. */ public static final int LAST_SYSTEM_WINDOW = 2999; - + /** * Specifies what type of memory buffers should be used by this window. * Default is normal. @@ -330,7 +358,19 @@ public interface WindowManager extends ViewManager { /** Window flag: blur everything behind this window. */ public static final int FLAG_BLUR_BEHIND = 0x00000004; - /** Window flag: this window won't ever get focus. */ + /** Window flag: this window won't ever get key input focus, so the + * user can not send key or other button events to it. Those will + * instead go to whatever focusable window is behind it. This flag + * will also enable {@link #FLAG_NOT_TOUCH_MODAL} whether or not that + * is explicitly set. + * + *

            Setting this flag also implies that the window will not need to + * interact with + * a soft input method, so it will be Z-ordered and positioned + * independently of any active input method (typically this means it + * gets Z-ordered on top of the input method, so it can use the full + * screen for its content and cover the input method if needed. You + * can use {@link #FLAG_ALT_FOCUSABLE_IM} to modify this behavior. */ public static final int FLAG_NOT_FOCUSABLE = 0x00000008; /** Window flag: this window can never receive touch events. */ @@ -405,12 +445,123 @@ public interface WindowManager extends ViewManager { * set for you by Window as described in {@link Window#setFlags}.*/ public static final int FLAG_LAYOUT_INSET_DECOR = 0x00010000; + /** Window flag: invert the state of {@link #FLAG_NOT_FOCUSABLE} with + * respect to how this window interacts with the current method. That + * is, if FLAG_NOT_FOCUSABLE is set and this flag is set, then the + * window will behave as if it needs to interact with the input method + * and thus be placed behind/away from it; if FLAG_NOT_FOCUSABLE is + * not set and this flag is set, then the window will behave as if it + * doesn't need to interact with the input method and can be placed + * to use more space and cover the input method. + */ + public static final int FLAG_ALT_FOCUSABLE_IM = 0x00020000; + + /** Window flag: if you have set {@link #FLAG_NOT_TOUCH_MODAL}, you + * can set this flag to receive a single special MotionEvent with + * the action + * {@link MotionEvent#ACTION_OUTSIDE MotionEvent.ACTION_OUTSIDE} for + * touches that occur outside of your window. Note that you will not + * receive the full down/move/up gesture, only the location of the + * first down as an ACTION_OUTSIDE. + */ + public static final int FLAG_WATCH_OUTSIDE_TOUCH = 0x00040000; + + /** Window flag: set when this window was created from the restored + * state of a previous window, indicating this is not the first time + * the user has navigated to it. + */ + public static final int FLAG_RESTORED_STATE = 0x00080000; + /** Window flag: a special option intended for system dialogs. When * this flag is set, the window will demand focus unconditionally when * it is created. * {@hide} */ public static final int FLAG_SYSTEM_ERROR = 0x40000000; + /** + * Mask for {@link #softInputMode} of the bits that determine the + * desired visibility state of the soft input area for this window. + */ + public static final int SOFT_INPUT_MASK_STATE = 0x0f; + + /** + * Visibility state for {@link #softInputMode}: no state has been specified. + */ + public static final int SOFT_INPUT_STATE_UNSPECIFIED = 0; + + /** + * Visibility state for {@link #softInputMode}: please don't change the state of + * the soft input area. + */ + public static final int SOFT_INPUT_STATE_UNCHANGED = 1; + + /** + * Visibility state for {@link #softInputMode}: please hide any soft input + * area. + */ + public static final int SOFT_INPUT_STATE_HIDDEN = 2; + + /** + * Visibility state for {@link #softInputMode}: please show the soft input area + * the first time the window is shown. + */ + public static final int SOFT_INPUT_STATE_FIRST_VISIBLE = 3; + + /** + * Visibility state for {@link #softInputMode}: please always show the soft + * input area. + */ + public static final int SOFT_INPUT_STATE_VISIBLE = 4; + + /** + * Mask for {@link #softInputMode} of the bits that determine the + * way that the window should be adjusted to accomodate the soft + * input window. + */ + public static final int SOFT_INPUT_MASK_ADJUST = 0xf0; + + /** Adjustment option for {@link #softInputMode}: nothing specified. + * The system will try to pick one or + * the other depending on the contents of the window. + */ + public static final int SOFT_INPUT_ADJUST_UNSPECIFIED = 0x00; + + /** Adjustment option for {@link #softInputMode}: set to allow the + * window to be resized when an input + * method is shown, so that its contents are not covered by the input + * method. This can not be combined with + * {@link #SOFT_INPUT_ADJUST_PAN}; if + * neither of these are set, then the system will try to pick one or + * the other depending on the contents of the window. + */ + public static final int SOFT_INPUT_ADJUST_RESIZE = 0x10; + + /** Adjustment option for {@link #softInputMode}: set to have a window + * pan when an input method is + * shown, so it doesn't need to deal with resizing but just panned + * by the framework to ensure the current input focus is visible. This + * can not be combined with {@link #SOFT_INPUT_ADJUST_RESIZE}; if + * neither of these are set, then the system will try to pick one or + * the other depending on the contents of the window. + */ + public static final int SOFT_INPUT_ADJUST_PAN = 0x20; + + /** + * Desired operating mode for any soft input area. May any combination + * of: + * + *

              + *
            • One of the visibility states + * {@link #SOFT_INPUT_STATE_UNSPECIFIED}, {@link #SOFT_INPUT_STATE_UNCHANGED}, + * {@link #SOFT_INPUT_STATE_HIDDEN}, {@link #SOFT_INPUT_STATE_FIRST_VISIBLE}, or + * {@link #SOFT_INPUT_STATE_VISIBLE}. + *
            • One of the adjustment options + * {@link #SOFT_INPUT_ADJUST_UNSPECIFIED}, + * {@link #SOFT_INPUT_ADJUST_RESIZE}, or + * {@link #SOFT_INPUT_ADJUST_PAN}. + */ + public int softInputMode; + /** * Placement of window within the screen as per {@link Gravity} * @@ -533,6 +684,7 @@ public interface WindowManager extends ViewManager { out.writeInt(type); out.writeInt(memoryType); out.writeInt(flags); + out.writeInt(softInputMode); out.writeInt(gravity); out.writeFloat(horizontalMargin); out.writeFloat(verticalMargin); @@ -565,6 +717,7 @@ public interface WindowManager extends ViewManager { type = in.readInt(); memoryType = in.readInt(); flags = in.readInt(); + softInputMode = in.readInt(); gravity = in.readInt(); horizontalMargin = in.readFloat(); verticalMargin = in.readFloat(); @@ -586,6 +739,7 @@ public interface WindowManager extends ViewManager { public static final int TITLE_CHANGED = 1<<6; public static final int ALPHA_CHANGED = 1<<7; public static final int MEMORY_TYPE_CHANGED = 1<<8; + public static final int SOFT_INPUT_MODE_CHANGED = 1<<9; public final int copyFrom(LayoutParams o) { int changes = 0; @@ -606,6 +760,22 @@ public interface WindowManager extends ViewManager { y = o.y; changes |= LAYOUT_CHANGED; } + if (horizontalWeight != o.horizontalWeight) { + horizontalWeight = o.horizontalWeight; + changes |= LAYOUT_CHANGED; + } + if (verticalWeight != o.verticalWeight) { + verticalWeight = o.verticalWeight; + changes |= LAYOUT_CHANGED; + } + if (horizontalMargin != o.horizontalMargin) { + horizontalMargin = o.horizontalMargin; + changes |= LAYOUT_CHANGED; + } + if (verticalMargin != o.verticalMargin) { + verticalMargin = o.verticalMargin; + changes |= LAYOUT_CHANGED; + } if (type != o.type) { type = o.type; changes |= TYPE_CHANGED; @@ -618,6 +788,10 @@ public interface WindowManager extends ViewManager { flags = o.flags; changes |= FLAGS_CHANGED; } + if (softInputMode != o.softInputMode) { + softInputMode = o.softInputMode; + changes |= SOFT_INPUT_MODE_CHANGED; + } if (gravity != o.gravity) { gravity = o.gravity; changes |= LAYOUT_CHANGED; @@ -677,15 +851,37 @@ public interface WindowManager extends ViewManager { @Override public String toString() { - return "WM.LayoutParams{" - + Integer.toHexString(System.identityHashCode(this)) - + " (" + x + "," + y + ")(" - + (width==FILL_PARENT?"fill_parent":(width==WRAP_CONTENT?"wrap_content":width)) - + "x" - + (height==FILL_PARENT?"fill_parent":(height==WRAP_CONTENT?"wrap_content":height)) - + ") gr=#" + Integer.toHexString(gravity) - + " ty=" + type + " fl=#" + Integer.toHexString(flags) - + " fmt=" + format + "}"; + StringBuilder sb = new StringBuilder(256); + sb.append("WM.LayoutParams{"); + sb.append("("); + sb.append(x); + sb.append(','); + sb.append(y); + sb.append(")("); + sb.append((width==FILL_PARENT?"fill":(width==WRAP_CONTENT?"wrap":width))); + sb.append('x'); + sb.append((height==FILL_PARENT?"fill":(height==WRAP_CONTENT?"wrap":height))); + sb.append(")"); + if (softInputMode != 0) { + sb.append(" sim=#"); + sb.append(Integer.toHexString(softInputMode)); + } + if (gravity != 0) { + sb.append(" gr=#"); + sb.append(Integer.toHexString(gravity)); + } + sb.append(" ty="); + sb.append(type); + sb.append(" fl=#"); + sb.append(Integer.toHexString(flags)); + sb.append(" fmt="); + sb.append(format); + if (windowAnimations != 0) { + sb.append(" wanim=0x"); + sb.append(Integer.toHexString(windowAnimations)); + } + sb.append('}'); + return sb.toString(); } private CharSequence mTitle = ""; diff --git a/core/java/android/view/WindowManagerImpl.java b/core/java/android/view/WindowManagerImpl.java index fbecf4668ca2d1725769fa1d3addf1c27e2797fd..755d7b8cf289254a521ceb99a92cae3f2e694c51 100644 --- a/core/java/android/view/WindowManagerImpl.java +++ b/core/java/android/view/WindowManagerImpl.java @@ -22,6 +22,7 @@ import android.util.AndroidRuntimeException; import android.util.Config; import android.util.Log; import android.view.WindowManager; +import android.view.inputmethod.InputMethodManager; final class WindowLeaked extends AndroidRuntimeException { public WindowLeaked(String msg) { @@ -128,7 +129,7 @@ public class WindowManagerImpl implements WindowManager { root.mAddNesting++; // Update layout parameters. view.setLayoutParams(wparams); - root.setLayoutParams(wparams); + root.setLayoutParams(wparams, true); return; } @@ -144,7 +145,7 @@ public class WindowManagerImpl implements WindowManager { } } - root = new ViewRoot(); + root = new ViewRoot(view.getContext()); root.mAddNesting = 1; view.setLayoutParams(wparams); @@ -191,7 +192,7 @@ public class WindowManagerImpl implements WindowManager { int index = findViewLocked(view, true); ViewRoot root = mRoots[index]; mParams[index] = wparams; - root.setLayoutParams(wparams); + root.setLayoutParams(wparams, false); } } @@ -236,6 +237,10 @@ public class WindowManagerImpl implements WindowManager { return view; } + InputMethodManager imm = InputMethodManager.getInstance(view.getContext()); + if (imm != null) { + imm.windowDismissed(mViews[index].getWindowToken()); + } root.die(false); finishRemoveViewLocked(view, index); return view; @@ -294,6 +299,26 @@ public class WindowManagerImpl implements WindowManager { } } + public WindowManager.LayoutParams getRootViewLayoutParameter(View view) { + ViewParent vp = view.getParent(); + while (vp != null && !(vp instanceof ViewRoot)) { + vp = vp.getParent(); + } + + if (vp == null) return null; + + ViewRoot vr = (ViewRoot)vp; + + int N = mRoots.length; + for (int i = 0; i < N; ++i) { + if (mRoots[i] == vr) { + return mParams[i]; + } + } + + return null; + } + public void closeAll() { closeAll(null, null, null); } diff --git a/core/java/android/view/WindowManagerPolicy.java b/core/java/android/view/WindowManagerPolicy.java index 93e1a0bed9d7ed4b5edcacb8126a11b52387cc3b..a6def51784c596c6091ffcb097b1184933a99988 100644 --- a/core/java/android/view/WindowManagerPolicy.java +++ b/core/java/android/view/WindowManagerPolicy.java @@ -109,45 +109,91 @@ public interface WindowManagerPolicy { * getFrame() if so desired. Must be called with the window manager * lock held. * - * @param parentLeft The left edge of the parent container this window - * is in, used for computing its position. - * @param parentTop The top edge of the parent container this window - * is in, used for computing its position. - * @param parentRight The right edge of the parent container this window - * is in, used for computing its position. - * @param parentBottom The bottom edge of the parent container this window - * is in, used for computing its position. - * @param displayLeft The left edge of the available display, used - * for constraining the overall dimensions of the window. - * @param displayTop The left edge of the available display, used - * for constraining the overall dimensions of the window. - * @param displayRight The right edge of the available display, used - * for constraining the overall dimensions of the window. - * @param displayBottom The bottom edge of the available display, used - * for constraining the overall dimensions of the window. + * @param parentFrame The frame of the parent container this window + * is in, used for computing its basic position. + * @param displayFrame The frame of the overall display in which this + * window can appear, used for constraining the overall dimensions + * of the window. + * @param contentFrame The frame within the display in which we would + * like active content to appear. This will cause windows behind to + * be resized to match the given content frame. + * @param visibleFrame The frame within the display that the window + * is actually visible, used for computing its visible insets to be + * given to windows behind. + * This can be used as a hint for scrolling (avoiding resizing) + * the window to make certain that parts of its content + * are visible. */ - public void computeFrameLw(int parentLeft, int parentRight, int parentBottom, - int parentHeight, int displayLeft, int displayTop, - int displayRight, int displayBottom); + public void computeFrameLw(Rect parentFrame, Rect displayFrame, + Rect contentFrame, Rect visibleFrame); /** - * Set the window's frame to an exact value. Must be called with the + * Retrieve the current frame of the window. Must be called with the * window manager lock held. * - * @param left Left edge of the window. - * @param top Top edge of the window. - * @param right Right edge (exclusive) of the window. - * @param bottom Bottom edge (exclusive) of the window. + * @return Rect The rectangle holding the window frame. */ - public void setFrameLw(int left, int top, int right, int bottom); + public Rect getFrameLw(); /** - * Retrieve the current frame of the window. Must be called with the + * Retrieve the frame of the display that this window was last + * laid out in. Must be called with the * window manager lock held. * - * @return Rect The rectangle holding the window frame. + * @return Rect The rectangle holding the display frame. */ - public Rect getFrameLw(); + public Rect getDisplayFrameLw(); + + /** + * Retrieve the frame of the content area that this window was last + * laid out in. This is the area in which the content of the window + * should be placed. It will be smaller than the display frame to + * account for screen decorations such as a status bar or soft + * keyboard. Must be called with the + * window manager lock held. + * + * @return Rect The rectangle holding the content frame. + */ + public Rect getContentFrameLw(); + + /** + * Retrieve the frame of the visible area that this window was last + * laid out in. This is the area of the screen in which the window + * will actually be fully visible. It will be smaller than the + * content frame to account for transient UI elements blocking it + * such as an input method's candidates UI. Must be called with the + * window manager lock held. + * + * @return Rect The rectangle holding the visible frame. + */ + public Rect getVisibleFrameLw(); + + /** + * Returns true if this window is waiting to receive its given + * internal insets from the client app, and so should not impact the + * layout of other windows. + */ + public boolean getGivenInsetsPendingLw(); + + /** + * Retrieve the insets given by this window's client for the content + * area of windows behind it. Must be called with the + * window manager lock held. + * + * @return Rect The left, top, right, and bottom insets, relative + * to the window's frame, of the actual contents. + */ + public Rect getGivenContentInsetsLw(); + + /** + * Retrieve the insets given by this window's client for the visible + * area of windows behind it. Must be called with the + * window manager lock held. + * + * @return Rect The left, top, right, and bottom insets, relative + * to the window's frame, of the actual visible area. + */ + public Rect getGivenVisibleInsetsLw(); /** * Retrieve the current LayoutParams of the window. @@ -157,6 +203,11 @@ public interface WindowManagerPolicy { */ public WindowManager.LayoutParams getAttrs(); + /** + * Get the layer at which this window's surface will be Z-ordered. + */ + public int getSurfaceLayer(); + /** * Return the token for the application (actually activity) that owns * this window. May return null for system windows. @@ -240,18 +291,6 @@ public interface WindowManagerPolicy { * lock held. */ public void showLw(); - - /** - * Sets insets on the window that represent the area within the window that is covered - * by system windows (e.g. status bar). Must be called with the window - * manager lock held. - * - * @param l - * @param t - * @param r - * @param b - */ - public void setCoveredInsetsLw(int l, int t, int r, int b); } /** No transition happening. */ @@ -506,14 +545,15 @@ public interface WindowManagerPolicy { /** - * Return the insets for the areas covered by system windows. These values are computed on the - * mose recent layout, so they are not guaranteed to be correct. + * Return the insets for the areas covered by system windows. These values + * are computed on the most recent layout, so they are not guaranteed to + * be correct. * * @param attrs The LayoutParams of the window. - * @param coveredInset The areas covered by system windows, expressed as positive insets + * @param contentInset The areas covered by system windows, expressed as positive insets * */ - public void getCoveredInsetHintLw(WindowManager.LayoutParams attrs, Rect coveredInset); + public void getContentInsetHintLw(WindowManager.LayoutParams attrs, Rect contentInset); /** * Called when layout of the windows is finished. After this function has diff --git a/core/java/android/view/animation/Animation.java b/core/java/android/view/animation/Animation.java index 39fe561fe9953177f0f457f1c79fc77440a7bc84..9f3650b3ce5c84691bffabe61bbf5fb99be5369b 100644 --- a/core/java/android/view/animation/Animation.java +++ b/core/java/android/view/animation/Animation.java @@ -581,6 +581,16 @@ public abstract class Animation { } } + /** + * Compute a hint at how long the entire animation may last, in milliseconds. + * Animations can be written to cause themselves to run for a different + * duration than what is computed here, but generally this should be + * accurate. + */ + public long computeDurationHint() { + return (getStartOffset() + getDuration()) * (getRepeatCount() + 1); + } + /** * Gets the transformation to apply at a specified point in time. Implementations of this * method should always replace the specified Transformation or document they are doing diff --git a/core/java/android/view/animation/AnimationSet.java b/core/java/android/view/animation/AnimationSet.java index 3c5920fb3cf9a698a0ab599170cf060f7d456cbb..688da70edcc1a5c876350cdb52fd65a3e4218e6e 100644 --- a/core/java/android/view/animation/AnimationSet.java +++ b/core/java/android/view/animation/AnimationSet.java @@ -223,6 +223,23 @@ public class AnimationSet extends Animation { return duration; } + /** + * The duration hint of an animation set is the maximum of the duration + * hints of all of its component animations. + * + * @see android.view.animation.Animation#computeDurationHint + */ + public long computeDurationHint() { + long duration = 0; + final int count = mAnimations.size(); + final ArrayList animations = mAnimations; + for (int i = count - 1; i >= 0; --i) { + final long d = animations.get(i).computeDurationHint(); + if (d > duration) duration = d; + } + return duration; + } + /** * The transformation of an animation set is the concatenation of all of its * component animations. diff --git a/core/java/android/view/animation/Transformation.java b/core/java/android/view/animation/Transformation.java index c7a0cc803d9775661f1b664a69636e2c0fbc85b6..f9e85bf4e46380a3523abb7a074b49e5ac9dcb39 100644 --- a/core/java/android/view/animation/Transformation.java +++ b/core/java/android/view/animation/Transformation.java @@ -134,6 +134,14 @@ public class Transformation { @Override public String toString() { - return "Transformation{alpha=" + mAlpha + " matrix=" + mMatrix + "}"; + return "Transformation{alpha=" + mAlpha + " matrix=" + + mMatrix.toShortString() + "}"; + } + + /** + * Return a string representation of the transformation in a compact form. + */ + public String toShortString() { + return "{alpha=" + mAlpha + " matrix=" + mMatrix.toShortString() + "}"; } } diff --git a/core/java/android/view/inputmethod/BaseInputConnection.java b/core/java/android/view/inputmethod/BaseInputConnection.java new file mode 100644 index 0000000000000000000000000000000000000000..4416ee5ee7af4bfe89e17ef9ee103c9eb63211bd --- /dev/null +++ b/core/java/android/view/inputmethod/BaseInputConnection.java @@ -0,0 +1,98 @@ +/* + * 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 android.view.inputmethod; + +import android.content.Context; +import android.os.Handler; +import android.os.Message; +import android.view.KeyEvent; +import android.view.View; +import android.view.ViewRoot; + +/** + * Base class for implementors of the InputConnection interface, taking care + * of implementing common system-oriented parts of the functionality. + */ +public abstract class BaseInputConnection implements InputConnection { + final InputMethodManager mIMM; + final Handler mH; + final View mTargetView; + + BaseInputConnection(InputMethodManager mgr) { + mIMM = mgr; + mTargetView = null; + mH = null; + } + + public BaseInputConnection(View targetView) { + mIMM = (InputMethodManager)targetView.getContext().getSystemService( + Context.INPUT_METHOD_SERVICE); + mH = targetView.getHandler(); + mTargetView = targetView; + } + + /** + * Provides standard implementation for sending a key event to the window + * attached to the input connection's view. + */ + public boolean sendKeyEvent(KeyEvent event) { + synchronized (mIMM.mH) { + Handler h = mH; + if (h == null) { + if (mIMM.mServedView != null) { + h = mIMM.mServedView.getHandler(); + } + } + if (h != null && mTargetView != null) { + h.post(new DispatchKey(event, mTargetView.getRootView())); + } + } + return false; + } + + /** + * Provides standard implementation for hiding the status icon associated + * with the current input method. + */ + public boolean hideStatusIcon() { + mIMM.updateStatusIcon(0, null); + return true; + } + + /** + * Provides standard implementation for showing the status icon associated + * with the current input method. + */ + public boolean showStatusIcon(String packageName, int resId) { + mIMM.updateStatusIcon(resId, packageName); + return true; + } + + static class DispatchKey implements Runnable { + KeyEvent mEvent; + View mView; + + DispatchKey(KeyEvent event, View v) { + mEvent = event; + mView = v; + } + + public void run() { + mView.dispatchKeyEvent(mEvent); + } + } +} \ No newline at end of file diff --git a/core/java/android/view/inputmethod/CompletionInfo.aidl b/core/java/android/view/inputmethod/CompletionInfo.aidl new file mode 100644 index 0000000000000000000000000000000000000000..e601054409f1ea5179231882b8767336152dd3ff --- /dev/null +++ b/core/java/android/view/inputmethod/CompletionInfo.aidl @@ -0,0 +1,19 @@ +/* + * 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 android.view.inputmethod; + +parcelable CompletionInfo; diff --git a/core/java/android/view/inputmethod/CompletionInfo.java b/core/java/android/view/inputmethod/CompletionInfo.java new file mode 100644 index 0000000000000000000000000000000000000000..3a8fe7246a3fb7847edab18942e40fde998fed98 --- /dev/null +++ b/core/java/android/view/inputmethod/CompletionInfo.java @@ -0,0 +1,131 @@ +/* + * Copyright (C) 2007-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 android.view.inputmethod; + +import android.os.Parcel; +import android.os.Parcelable; +import android.text.TextUtils; + +/** + * Information about a single text completion that an editor has reported to + * an input method. + */ +public final class CompletionInfo implements Parcelable { + static final String TAG = "CompletionInfo"; + + final long mId; + final int mPosition; + final CharSequence mText; + final CharSequence mLabel; + + /** + * Create a simple completion with just text, no label. + */ + public CompletionInfo(long id, int index, CharSequence text) { + mId = id; + mPosition = index; + mText = text; + mLabel = null; + } + + /** + * Create a full completion with both text and label. + */ + public CompletionInfo(long id, int index, CharSequence text, CharSequence label) { + mId = id; + mPosition = index; + mText = text; + mLabel = label; + } + + CompletionInfo(Parcel source) { + mId = source.readLong(); + mPosition = source.readInt(); + mText = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(source); + mLabel = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(source); + } + + /** + * Return the abstract identifier for this completion, typically + * corresponding to the id associated with it in the original adapter. + */ + public long getId() { + return mId; + } + + /** + * Return the original position of this completion, typically + * corresponding to its position in the original adapter. + */ + public int getPosition() { + return mPosition; + } + + /** + * Return the actual text associated with this completion. This is the + * real text that will be inserted into the editor if the user selects it. + */ + public CharSequence getText() { + return mText; + } + + /** + * Return the user-visible label for the completion, or null if the plain + * text should be shown. If non-null, this will be what the user sees as + * the completion option instead of the actual text. + */ + public CharSequence getLabel() { + return mLabel; + } + + @Override + public String toString() { + return "CompletionInfo{#" + mPosition + " \"" + mText + + "\" id=" + mId + " label=" + mLabel + "}"; + } + + /** + * Used to package this object into a {@link Parcel}. + * + * @param dest The {@link Parcel} to be written. + * @param flags The flags used for parceling. + */ + public void writeToParcel(Parcel dest, int flags) { + dest.writeLong(mId); + dest.writeInt(mPosition); + TextUtils.writeToParcel(mText, dest, flags); + TextUtils.writeToParcel(mLabel, dest, flags); + } + + /** + * Used to make this class parcelable. + */ + public static final Parcelable.Creator CREATOR + = new Parcelable.Creator() { + public CompletionInfo createFromParcel(Parcel source) { + return new CompletionInfo(source); + } + + public CompletionInfo[] newArray(int size) { + return new CompletionInfo[size]; + } + }; + + public int describeContents() { + return 0; + } +} diff --git a/core/java/android/view/inputmethod/DefaultInputMethod.java b/core/java/android/view/inputmethod/DefaultInputMethod.java new file mode 100644 index 0000000000000000000000000000000000000000..da5cab55ada390542332d0a82f99a3540c3a141b --- /dev/null +++ b/core/java/android/view/inputmethod/DefaultInputMethod.java @@ -0,0 +1,239 @@ +package android.view.inputmethod; + +import android.graphics.Rect; +import android.os.Bundle; +import android.os.IBinder; +import android.os.RemoteException; +import android.util.Log; +import android.view.KeyEvent; +import android.view.MotionEvent; + +import com.android.internal.view.IInputContext; +import com.android.internal.view.IInputMethod; +import com.android.internal.view.IInputMethodCallback; +import com.android.internal.view.IInputMethodSession; +import com.android.internal.view.InputConnectionWrapper; + +/** + * This is the default input method that runs in the same context of the + * application that requests text input. It does nothing but returns false for + * any key events, so that all key events will be processed by the key listener + * of the focused text box. + * {@hide} + */ +public class DefaultInputMethod implements InputMethod, InputMethodSession { + private static IInputMethod sInstance = new SimpleInputMethod( + new DefaultInputMethod()); + + private static InputMethodInfo sProperty = new InputMethodInfo( + "android.text.inputmethod", DefaultInputMethod.class.getName(), + "Default", "android.text.inputmethod.defaultImeSettings"); + + private InputConnection mInputConnection; + + public static IInputMethod getInstance() { + return sInstance; + } + + public static InputMethodInfo getMetaInfo() { + return sProperty; + } + + public void bindInput(InputBinding binding) { + mInputConnection = binding.getConnection(); + } + + public void unbindInput() { + } + + public void createSession(SessionCallback callback) { + callback.sessionCreated(this); + } + + public void setSessionEnabled(InputMethodSession session, boolean enabled) { + } + + public void revokeSession(InputMethodSession session) { + } + + public void finishInput() { + mInputConnection.hideStatusIcon(); + } + + public void displayCompletions(CompletionInfo[] completions) { + } + + public void updateExtractedText(int token, ExtractedText text) { + } + + public void updateSelection(int oldSelStart, int oldSelEnd, + int newSelStart, int newSelEnd) { + } + + public void updateCursor(Rect newCursor) { + } + + public void dispatchKeyEvent(int seq, KeyEvent event, EventCallback callback) { + callback.finishedEvent(seq, false); + } + + public void dispatchTrackballEvent(int seq, MotionEvent event, EventCallback callback) { + callback.finishedEvent(seq, false); + } + + public void restartInput(EditorInfo attribute) { + } + + public void attachToken(IBinder token) { + } + + public void startInput(EditorInfo attribute) { + mInputConnection + .showStatusIcon("android", com.android.internal.R.drawable.ime_qwerty); + } + + public void appPrivateCommand(String action, Bundle data) { + } + + public void hideSoftInput() { + } + + public void showSoftInput() { + } +} + +// ---------------------------------------------------------------------- + +class SimpleInputMethod extends IInputMethod.Stub { + final InputMethod mInputMethod; + + static class Session extends IInputMethodSession.Stub { + final InputMethodSession mSession; + + Session(InputMethodSession session) { + mSession = session; + } + + public void finishInput() { + mSession.finishInput(); + } + + public void updateSelection(int oldSelStart, int oldSelEnd, + int newSelStart, int newSelEnd) { + mSession.updateSelection(oldSelStart, oldSelEnd, + newSelStart, newSelEnd); + } + + public void updateCursor(Rect newCursor) { + mSession.updateCursor(newCursor); + } + + static class InputMethodEventCallbackWrapper implements InputMethodSession.EventCallback { + final IInputMethodCallback mCb; + InputMethodEventCallbackWrapper(IInputMethodCallback cb) { + mCb = cb; + } + public void finishedEvent(int seq, boolean handled) { + try { + mCb.finishedEvent(seq, handled); + } catch (RemoteException e) { + } + } + } + + public void dispatchKeyEvent(int seq, KeyEvent event, IInputMethodCallback callback) { + mSession.dispatchKeyEvent(seq, event, + new InputMethodEventCallbackWrapper(callback)); + } + + public void dispatchTrackballEvent(int seq, MotionEvent event, IInputMethodCallback callback) { + mSession.dispatchTrackballEvent(seq, event, + new InputMethodEventCallbackWrapper(callback)); + } + + public void displayCompletions(CompletionInfo[] completions) { + mSession.displayCompletions(completions); + } + + public void updateExtractedText(int token, ExtractedText text) { + mSession.updateExtractedText(token, text); + } + + public void appPrivateCommand(String action, Bundle data) { + mSession.appPrivateCommand(action, data); + } + } + + public SimpleInputMethod(InputMethod inputMethod) { + mInputMethod = inputMethod; + } + + public InputMethod getInternalInputMethod() { + return mInputMethod; + } + + public void attachToken(IBinder token) { + mInputMethod.attachToken(token); + } + + public void bindInput(InputBinding binding) { + InputConnectionWrapper ic = new InputConnectionWrapper( + IInputContext.Stub.asInterface(binding.getConnectionToken())); + InputBinding nu = new InputBinding(ic, binding); + mInputMethod.bindInput(nu); + } + + public void unbindInput() { + mInputMethod.unbindInput(); + } + + public void restartInput(EditorInfo attribute) { + mInputMethod.restartInput(attribute); + } + + public void startInput(EditorInfo attribute) { + mInputMethod.startInput(attribute); + } + + static class InputMethodSessionCallbackWrapper implements InputMethod.SessionCallback { + final IInputMethodCallback mCb; + InputMethodSessionCallbackWrapper(IInputMethodCallback cb) { + mCb = cb; + } + + public void sessionCreated(InputMethodSession session) { + try { + mCb.sessionCreated(new Session(session)); + } catch (RemoteException e) { + } + } + } + + public void createSession(IInputMethodCallback callback) throws RemoteException { + mInputMethod.createSession(new InputMethodSessionCallbackWrapper(callback)); + } + + public void setSessionEnabled(IInputMethodSession session, boolean enabled) throws RemoteException { + try { + InputMethodSession ls = ((Session)session).mSession; + mInputMethod.setSessionEnabled(ls, enabled); + } catch (ClassCastException e) { + Log.w("SimpleInputMethod", "Incoming session not of correct type: " + session, e); + } + } + + public void revokeSession(IInputMethodSession session) throws RemoteException { + try { + InputMethodSession ls = ((Session)session).mSession; + mInputMethod.revokeSession(ls); + } catch (ClassCastException e) { + Log.w("SimpleInputMethod", "Incoming session not of correct type: " + session, e); + } + } + + public void showSoftInput() { + } + + public void hideSoftInput() { + } +} diff --git a/core/java/android/view/inputmethod/EditorInfo.aidl b/core/java/android/view/inputmethod/EditorInfo.aidl new file mode 100644 index 0000000000000000000000000000000000000000..48068f000ceeea309ae81ca0a4302e3b210dfa7b --- /dev/null +++ b/core/java/android/view/inputmethod/EditorInfo.aidl @@ -0,0 +1,19 @@ +/* + * 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 android.view.inputmethod; + +parcelable EditorInfo; diff --git a/core/java/android/view/inputmethod/EditorInfo.java b/core/java/android/view/inputmethod/EditorInfo.java new file mode 100644 index 0000000000000000000000000000000000000000..c0506913e3731609787e6841c73536502f52b009 --- /dev/null +++ b/core/java/android/view/inputmethod/EditorInfo.java @@ -0,0 +1,126 @@ +package android.view.inputmethod; + +import android.os.Bundle; +import android.os.Parcel; +import android.os.Parcelable; +import android.text.InputType; +import android.text.TextUtils; + +/** + * An EditorInfo describes several attributes of a text editing object + * that an input method is communicating with (typically an EditText), most + * importantly the type of text content it contains. + */ +public class EditorInfo implements InputType, Parcelable { + /** + * The content type of the text box, whose bits are defined by + * {@link InputType}. + * + * @see InputType + * @see #TYPE_MASK_CLASS + * @see #TYPE_MASK_VARIATION + * @see #TYPE_MASK_FLAGS + */ + public int inputType = TYPE_CLASS_TEXT; + + /** + * A string supplying additional information about the content type that + * is private to a particular IME implementation. The string must be + * scoped to a package owned by the implementation, to ensure there are + * no conflicts between implementations, but other than that you can put + * whatever you want in it to communicate with the IME. For example, + * you could have a string that supplies an argument like + * "com.example.myapp.SpecialMode=3". This field is can be + * filled in from the {@link android.R.attr#editorPrivateContentType} + * attribute of a TextView. + */ + public String privateContentType = null; + + /** + * The text offset of the start of the selection at the time editing + * began; -1 if not known. + */ + public int initialSelStart = -1; + + /** + * The text offset of the end of the selection at the time editing + * began; -1 if not known. + */ + public int initialSelEnd = -1; + + /** + * The capitalization mode of the first character being edited in the + * text. Values may be any combination of + * {@link TextUtils#CAP_MODE_CHARACTERS TextUtils.CAP_MODE_CHARACTERS}, + * {@link TextUtils#CAP_MODE_WORDS TextUtils.CAP_MODE_WORDS}, and + * {@link TextUtils#CAP_MODE_SENTENCES TextUtils.CAP_MODE_SENTENCES}, though + * you should generally just take a non-zero value to mean start out in + * caps mode. + */ + public int initialCapsMode = 0; + + /** + * The "hint" text of the text view, typically shown in-line when the + * text is empty to tell the user what to enter. + */ + public CharSequence hintText; + + /** + * A label to show to the user describing the text they are writing. + */ + public CharSequence label; + + /** + * Any extra data to supply to the input method. This is for extended + * communication with specific input methods; the name fields in the + * bundle should be scoped (such as "com.mydomain.im.SOME_FIELD") so + * that they don't conflict with others. This field is can be + * filled in from the {@link android.R.attr#editorExtras} + * attribute of a TextView. + */ + public Bundle extras; + + /** + * Used to package this object into a {@link Parcel}. + * + * @param dest The {@link Parcel} to be written. + * @param flags The flags used for parceling. + */ + public void writeToParcel(Parcel dest, int flags) { + dest.writeInt(inputType); + dest.writeString(privateContentType); + dest.writeInt(initialSelStart); + dest.writeInt(initialSelEnd); + dest.writeInt(initialCapsMode); + TextUtils.writeToParcel(hintText, dest, flags); + TextUtils.writeToParcel(label, dest, flags); + dest.writeBundle(extras); + } + + /** + * Used to make this class parcelable. + */ + public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { + public EditorInfo createFromParcel(Parcel source) { + EditorInfo res = new EditorInfo(); + res.inputType = source.readInt(); + res.privateContentType = source.readString(); + res.initialSelStart = source.readInt(); + res.initialSelEnd = source.readInt(); + res.initialCapsMode = source.readInt(); + res.hintText = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(source); + res.label = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(source); + res.extras = source.readBundle(); + return res; + } + + public EditorInfo[] newArray(int size) { + return new EditorInfo[size]; + } + }; + + public int describeContents() { + return 0; + } + +} diff --git a/core/java/android/view/inputmethod/ExtractedText.aidl b/core/java/android/view/inputmethod/ExtractedText.aidl new file mode 100644 index 0000000000000000000000000000000000000000..95e56d7d8640ee66937d679b8a60272bc0071b81 --- /dev/null +++ b/core/java/android/view/inputmethod/ExtractedText.aidl @@ -0,0 +1,19 @@ +/* + * 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 android.view.inputmethod; + +parcelable ExtractedText; diff --git a/core/java/android/view/inputmethod/ExtractedText.java b/core/java/android/view/inputmethod/ExtractedText.java new file mode 100644 index 0000000000000000000000000000000000000000..0ca3c79349d752be955b88470598a8d636af0186 --- /dev/null +++ b/core/java/android/view/inputmethod/ExtractedText.java @@ -0,0 +1,82 @@ +package android.view.inputmethod; + +import android.os.Parcel; +import android.os.Parcelable; +import android.text.TextUtils; + +/** + * Information about text that has been extracted for use by an input method. + */ +public class ExtractedText implements Parcelable { + /** + * The text that has been extracted. + */ + public CharSequence text; + + /** + * The offset in the overall text at which the extracted text starts. + */ + public int startOffset; + + /** + * The offset where the selection currently starts within the extracted + * text. The real selection start position is at + * startOffset+selectionStart. + */ + public int selectionStart; + + /** + * The offset where the selection currently ends within the extracted + * text. The real selection end position is at + * startOffset+selectionEnd. + */ + public int selectionEnd; + + /** + * Bit for {@link #flags}: set if the text being edited can only be on + * a single line. + */ + public static final int FLAG_SINGLE_LINE = 0x0001; + + /** + * Additional bit flags of information about the edited text. + */ + public int flags; + + /** + * Used to package this object into a {@link Parcel}. + * + * @param dest The {@link Parcel} to be written. + * @param flags The flags used for parceling. + */ + public void writeToParcel(Parcel dest, int flags) { + TextUtils.writeToParcel(text, dest, flags); + dest.writeInt(startOffset); + dest.writeInt(selectionStart); + dest.writeInt(selectionEnd); + dest.writeInt(flags); + } + + /** + * Used to make this class parcelable. + */ + public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { + public ExtractedText createFromParcel(Parcel source) { + ExtractedText res = new ExtractedText(); + res.text = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(source); + res.startOffset = source.readInt(); + res.selectionStart = source.readInt(); + res.selectionEnd = source.readInt(); + res.flags = source.readInt(); + return res; + } + + public ExtractedText[] newArray(int size) { + return new ExtractedText[size]; + } + }; + + public int describeContents() { + return 0; + } +} diff --git a/core/java/android/view/inputmethod/ExtractedTextRequest.aidl b/core/java/android/view/inputmethod/ExtractedTextRequest.aidl new file mode 100644 index 0000000000000000000000000000000000000000..c69acc7b47bbf3c52fd88aff86a4d0def652ad78 --- /dev/null +++ b/core/java/android/view/inputmethod/ExtractedTextRequest.aidl @@ -0,0 +1,19 @@ +/* + * 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 android.view.inputmethod; + +parcelable ExtractedTextRequest; diff --git a/core/java/android/view/inputmethod/ExtractedTextRequest.java b/core/java/android/view/inputmethod/ExtractedTextRequest.java new file mode 100644 index 0000000000000000000000000000000000000000..d9623290ea7ad5cb5e45a5fa9227b04fe37240ac --- /dev/null +++ b/core/java/android/view/inputmethod/ExtractedTextRequest.java @@ -0,0 +1,61 @@ +package android.view.inputmethod; + +import android.os.Parcel; +import android.os.Parcelable; +import android.text.TextUtils; + +/** + * Description of what an input method would like from an application when + * extract text from its input editor. + */ +public class ExtractedTextRequest implements Parcelable { + /** + * Arbitrary integer that can be supplied in the request, which will be + * delivered back when reporting updates. + */ + public int token; + + /** + * Hint for the maximum number of lines to return. + */ + public int hintMaxLines; + + /** + * Hint for the maximum number of characters to return. + */ + public int hintMaxChars; + + /** + * Used to package this object into a {@link Parcel}. + * + * @param dest The {@link Parcel} to be written. + * @param flags The flags used for parceling. + */ + public void writeToParcel(Parcel dest, int flags) { + dest.writeInt(token); + dest.writeInt(hintMaxLines); + dest.writeInt(hintMaxChars); + } + + /** + * Used to make this class parcelable. + */ + public static final Parcelable.Creator CREATOR + = new Parcelable.Creator() { + public ExtractedTextRequest createFromParcel(Parcel source) { + ExtractedTextRequest res = new ExtractedTextRequest(); + res.token = source.readInt(); + res.hintMaxLines = source.readInt(); + res.hintMaxChars = source.readInt(); + return res; + } + + public ExtractedTextRequest[] newArray(int size) { + return new ExtractedTextRequest[size]; + } + }; + + public int describeContents() { + return 0; + } +} diff --git a/core/java/android/view/inputmethod/InputBinding.aidl b/core/java/android/view/inputmethod/InputBinding.aidl new file mode 100644 index 0000000000000000000000000000000000000000..ea09d8b4aa7fcd13f846f3d465f489dc843f5f21 --- /dev/null +++ b/core/java/android/view/inputmethod/InputBinding.aidl @@ -0,0 +1,19 @@ +/* + * 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 android.view.inputmethod; + +parcelable InputBinding; diff --git a/core/java/android/view/inputmethod/InputBinding.java b/core/java/android/view/inputmethod/InputBinding.java new file mode 100644 index 0000000000000000000000000000000000000000..f4209efcdcc4553d250e65174a770a7c0f9ac016 --- /dev/null +++ b/core/java/android/view/inputmethod/InputBinding.java @@ -0,0 +1,152 @@ +/* + * Copyright (C) 2007-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 android.view.inputmethod; + +import android.os.IBinder; +import android.os.Parcel; +import android.os.Parcelable; +import android.text.TextUtils; + +/** + * Information given to an {@link InputMethod} about a client connecting + * to it. + */ +public final class InputBinding implements Parcelable { + static final String TAG = "InputBinding"; + + /** + * The connection back to the client. + */ + final InputConnection mConnection; + + /** + * A remotable token for the connection back to the client. + */ + final IBinder mConnectionToken; + + /** + * The UID where this binding came from. + */ + final int mUid; + + /** + * The PID where this binding came from. + */ + final int mPid; + + /** + * Constructor. + * + * @param conn The interface for communicating back with the application. + * @param connToken A remoteable token for communicating across processes. + * @param uid The user id of the client of this binding. + * @param pid The process id of where the binding came from. + */ + public InputBinding(InputConnection conn, IBinder connToken, + int uid, int pid) { + mConnection = conn; + mConnectionToken = connToken; + mUid = uid; + mPid = pid; + } + + /** + * Constructor from an existing InputBinding taking a new local input + * connection interface. + * + * @param conn The new connection interface. + * @param binding Existing binding to copy. + */ + public InputBinding(InputConnection conn, InputBinding binding) { + mConnection = conn; + mConnectionToken = binding.getConnectionToken(); + mUid = binding.getUid(); + mPid = binding.getPid(); + } + + InputBinding(Parcel source) { + mConnection = null; + mConnectionToken = source.readStrongBinder(); + mUid = source.readInt(); + mPid = source.readInt(); + } + + /** + * Return the connection for interacting back with the application. + */ + public InputConnection getConnection() { + return mConnection; + } + + /** + * Return the token for the connection back to the application. You can + * not use this directly, it must be converted to a {@link InputConnection} + * for you. + */ + public IBinder getConnectionToken() { + return mConnectionToken; + } + + /** + * Return the user id of the client associated with this binding. + */ + public int getUid() { + return mUid; + } + + /** + * Return the process id where this binding came from. + */ + public int getPid() { + return mPid; + } + + @Override + public String toString() { + return "InputBinding{" + mConnectionToken + + " / uid " + mUid + " / pid " + mPid + "}"; + } + + /** + * Used to package this object into a {@link Parcel}. + * + * @param dest The {@link Parcel} to be written. + * @param flags The flags used for parceling. + */ + public void writeToParcel(Parcel dest, int flags) { + dest.writeStrongBinder(mConnectionToken); + dest.writeInt(mUid); + dest.writeInt(mPid); + } + + /** + * Used to make this class parcelable. + */ + public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { + public InputBinding createFromParcel(Parcel source) { + return new InputBinding(source); + } + + public InputBinding[] newArray(int size) { + return new InputBinding[size]; + } + }; + + public int describeContents() { + return 0; + } +} diff --git a/core/java/android/view/inputmethod/InputConnection.java b/core/java/android/view/inputmethod/InputConnection.java new file mode 100644 index 0000000000000000000000000000000000000000..5f8ba1fb6639450af5b48c7014e67c0ae527e262 --- /dev/null +++ b/core/java/android/view/inputmethod/InputConnection.java @@ -0,0 +1,249 @@ +/* + * Copyright (C) 2007-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 android.view.inputmethod; + +import android.os.Bundle; +import android.text.Spanned; +import android.view.KeyCharacterMap; +import android.view.KeyEvent; + +/** + * The InputConnection interface is the communication channel from an + * {@link InputMethod} back to the application that is receiving its input. It + * is used to perform such things as reading text around the cursor, + * committing text to the text box, and sending raw key events to the application. + */ +public interface InputConnection { + /** + * Get n characters of text before the current cursor position. + * + *

              This method may fail either if the input connection has become invalid + * (such as its process crashing) or the client is taking too long to + * respond with the text (it is given a couple seconds to return). + * In either case, a null is returned. + * + * @param n The expected length of the text. + * + * @return Returns the text before the cursor position; the length of the + * returned text might be less than n. + */ + public CharSequence getTextBeforeCursor(int n); + + /** + * Get n characters of text after the current cursor position. + * + *

              This method may fail either if the input connection has become invalid + * (such as its process crashing) or the client is taking too long to + * respond with the text (it is given a couple seconds to return). + * In either case, a null is returned. + * + * @param n The expected length of the text. + * + * @return Returns the text after the cursor position; the length of the + * returned text might be less than n. + */ + public CharSequence getTextAfterCursor(int n); + + /** + * Retrieve the current capitalization mode in effect at the current + * cursor position in the text. See + * {@link android.text.TextUtils#getCapsMode TextUtils.getCapsMode} for + * more information. + * + *

              This method may fail either if the input connection has become invalid + * (such as its process crashing) or the client is taking too long to + * respond with the text (it is given a couple seconds to return). + * In either case, a 0 is returned. + * + * @param reqModes The desired modes to retrieve, as defined by + * {@link android.text.TextUtils#getCapsMode TextUtils.getCapsMode}. These + * constants are defined so that you can simply pass the current + * {@link EditorInfo#inputType TextBoxAttribute.contentType} value + * directly in to here. + * + * @return Returns the caps mode flags that are in effect. + */ + public int getCursorCapsMode(int reqModes); + + public static final int EXTRACTED_TEXT_MONITOR = 0x0001; + + /** + * Retrieve the current text in the input connection's editor, and monitor + * for any changes to it. This function returns with the current text, + * and optionally the input connection can send updates to the + * input method when its text changes. + * + *

              This method may fail either if the input connection has become invalid + * (such as its process crashing) or the client is taking too long to + * respond with the text (it is given a couple seconds to return). + * In either case, a null is returned. + * + * @param request Description of how the text should be returned. + * @param flags Additional options to control the client, either 0 or + * {@link #EXTRACTED_TEXT_MONITOR}. + * + * @return Returns an ExtractedText object describing the state of the + * text view and containing the extracted text itself. + */ + public ExtractedText getExtractedText(ExtractedTextRequest request, + int flags); + + /** + * Delete leftLength characters of text before the current cursor + * position, and delete rightLength characters of text after the + * current cursor position, excluding composing text. + * + * @param leftLength The number of characters to be deleted before the + * current cursor position. + * @param rightLength The number of characters to be deleted after the + * current cursor position. + * + * @return Returns true on success, false if the input connection is no longer + * valid. + */ + boolean deleteSurroundingText(int leftLength, int rightLength); + + /** + * Set composing text around the current cursor position with the given text, + * and set the new cursor position. Any composing text set previously will + * be removed automatically. + * + * @param text The composing text with styles if necessary. If no style + * object attached to the text, the default style for composing text + * is used. See {#link android.text.Spanned} for how to attach style + * object to the text. {#link android.text.SpannableString} and + * {#link android.text.SpannableStringBuilder} are two + * implementations of the interface {#link android.text.Spanned}. + * @param newCursorPosition The new cursor position within the + * text. + * + * @return Returns true on success, false if the input connection is no longer + * valid. + */ + public boolean setComposingText(CharSequence text, int newCursorPosition); + + /** + * Commit text to the text box and set the new cursor position. + * Any composing text set previously will be removed + * automatically. + * + * @param text The committed text. + * @param newCursorPosition The new cursor position within the + * text. + * + * + * @return Returns true on success, false if the input connection is no longer + * valid. + */ + public boolean commitText(CharSequence text, int newCursorPosition); + + /** + * Commit a completion the user has selected from the possible ones + * previously reported to {@link InputMethodSession#displayCompletions + * InputMethodSession.displayCompletions()}. This will result in the + * same behavior as if the user had selected the completion from the + * actual UI. + * + * @param text The committed completion. + * + * @return Returns true on success, false if the input connection is no longer + * valid. + */ + public boolean commitCompletion(CompletionInfo text); + + /** + * Send a key event to the process that is currently attached through + * this input connection. The event will be dispatched like a normal + * key event, to the currently focused; this generally is the view that + * is providing this InputConnection, but due to the asynchronous nature + * of this protocol that can not be guaranteed and the focus may have + * changed by the time the event is received. + * + *

              + * This method can be used to send key events to the application. For + * example, an on-screen keyboard may use this method to simulate a hardware + * keyboard. There are three types of standard keyboards, numeric (12-key), + * predictive (20-key) and ALPHA (QWERTY). You can specify the keyboard type + * by specify the device id of the key event. + * + *

              + * You will usually want to set the flag + * {@link KeyEvent#FLAG_SOFT_KEYBOARD KeyEvent.FLAG_SOFT_KEYBOARD} on all + * key event objects you give to this API; the flag will not be set + * for you. + * + * @param event The key event. + * + * @return Returns true on success, false if the input connection is no longer + * valid. + * + * @see KeyEvent + * @see KeyCharacterMap#NUMERIC + * @see KeyCharacterMap#PREDICTIVE + * @see KeyCharacterMap#ALPHA + */ + public boolean sendKeyEvent(KeyEvent event); + + /** + * Clear the given meta key pressed states in the given input connection. + * + * @param states The states to be cleared, may be one or more bits as + * per {@link KeyEvent#getMetaState() KeyEvent.getMetaState()}. + * + * @return Returns true on success, false if the input connection is no longer + * valid. + */ + public boolean clearMetaKeyStates(int states); + + /** + * API to send private commands from an input method to its connected + * editor. This can be used to provide domain-specific features that are + * only known between certain input methods and their clients. Note that + * because the InputConnection protocol is asynchronous, you have no way + * to get a result back or know if the client understood the command; you + * can use the information in {@link EditorInfo} to determine if + * a client supports a particular command. + * + * @param action Name of the command to be performed. This must + * be a scoped name, i.e. prefixed with a package name you own, so that + * different developers will not create conflicting commands. + * @param data Any data to include with the command. + * @return Returns true if the command was sent (whether or not the + * associated editor understood it), false if the input connection is no longer + * valid. + */ + public boolean performPrivateCommand(String action, Bundle data); + + /** + * Show an icon in the status bar. + * + * @param packageName The package holding the icon resource to be shown. + * @param resId The resource id of the icon to show. + * + * @return Returns true on success, false if the input connection is no longer + * valid. + */ + public boolean showStatusIcon(String packageName, int resId); + + /** + * Hide the icon shown in the status bar. + * + * @return Returns true on success, false if the input connection is no longer + * valid. + */ + public boolean hideStatusIcon(); +} diff --git a/core/java/android/view/inputmethod/InputConnectionWrapper.java b/core/java/android/view/inputmethod/InputConnectionWrapper.java new file mode 100644 index 0000000000000000000000000000000000000000..f150ad61b7edd1c0041d561b9e26fa1bd7bbbd03 --- /dev/null +++ b/core/java/android/view/inputmethod/InputConnectionWrapper.java @@ -0,0 +1,95 @@ +/* + * Copyright (C) 2007-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 android.view.inputmethod; + +import android.os.Bundle; +import android.view.KeyEvent; + +/** + * Wrapper around InputConnection interface, calling through to another + * implementation of it. + */ +public class InputConnectionWrapper implements InputConnection { + InputConnection mBase; + + /** + * Create a new wrapper around an existing InputConnection implementation. + */ + public InputConnectionWrapper(InputConnection base) { + mBase = base; + } + + /** + * Return the base InputConnection that this class is wrapping. + */ + InputConnection getBase() { + return mBase; + } + + public CharSequence getTextBeforeCursor(int n) { + return mBase.getTextBeforeCursor(n); + } + + public CharSequence getTextAfterCursor(int n) { + return mBase.getTextAfterCursor(n); + } + + public int getCursorCapsMode(int reqModes) { + return mBase.getCursorCapsMode(reqModes); + } + + public ExtractedText getExtractedText(ExtractedTextRequest request, + int flags) { + return mBase.getExtractedText(request, flags); + } + + public boolean deleteSurroundingText(int leftLength, int rightLength) { + return mBase.deleteSurroundingText(leftLength, rightLength); + } + + public boolean setComposingText(CharSequence text, int newCursorPosition) { + return mBase.setComposingText(text, newCursorPosition); + } + + public boolean commitText(CharSequence text, int newCursorPosition) { + return mBase.commitText(text, newCursorPosition); + } + + public boolean commitCompletion(CompletionInfo text) { + return mBase.commitCompletion(text); + } + + public boolean sendKeyEvent(KeyEvent event) { + return mBase.sendKeyEvent(event); + } + + public boolean clearMetaKeyStates(int states) { + return mBase.clearMetaKeyStates(states); + } + + public boolean performPrivateCommand(String action, Bundle data) { + return mBase.performPrivateCommand(action, data); + } + + public boolean showStatusIcon(String packageName, int resId) { + return mBase.showStatusIcon(packageName, resId); + } + + public boolean hideStatusIcon() { + return mBase.hideStatusIcon(); + } +} diff --git a/core/java/android/view/inputmethod/InputMethod.java b/core/java/android/view/inputmethod/InputMethod.java new file mode 100644 index 0000000000000000000000000000000000000000..259e759d97fc6b8f9775ca8b7daca2e117a7068f --- /dev/null +++ b/core/java/android/view/inputmethod/InputMethod.java @@ -0,0 +1,170 @@ +/* + * Copyright (C) 2007-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 android.view.inputmethod; + +import android.graphics.Rect; +import android.inputmethodservice.InputMethodService; +import android.os.Bundle; +import android.os.IBinder; +import android.view.KeyEvent; +import android.view.MotionEvent; + +/** + * The InputMethod interface represents an input method which can generate key + * events and text, such as digital, email addresses, CJK characters, other + * language characters, and etc., while handling various input events, and send + * the text back to the application that requests text input. + * + *

              Applications will not normally use this interface themselves, instead + * relying on the standard interaction provided by + * {@link android.widget.TextView} and {@link android.widget.EditText}. + * + *

              Those implementing input methods should normally do so by deriving from + * {@link InputMethodService} or one of its subclasses. When implementing + * an input method, the service component containing it must also supply + * a {@link #SERVICE_META_DATA} meta-data field, referencing an XML resource + * providing details about the input method. All input methods also must + * require that clients hold the + * {@link android.Manifest.permission#BIND_INPUT_METHOD} in order to interact + * with the service; if this is not required, the system will not use that + * input method, because it can not trust that it is not compromised. + */ +public interface InputMethod { + /** + * This is the interface name that a service implementing an input + * method should say that it supports -- that is, this is the action it + * uses for its intent filter. (Note: this name is used because this + * interface should be moved to the view package.) + */ + public static final String SERVICE_INTERFACE = "android.view.InputMethod"; + + /** + * Name under which an InputMethod service component publishes information + * about itself. This meta-data must reference an XML resource containing + * an + * <{@link android.R.styleable#InputMethod input-method}> + * tag. + */ + public static final String SERVICE_META_DATA = "android.view.im"; + + public interface SessionCallback { + public void sessionCreated(InputMethodSession session); + } + + /** + * Called first thing after an input method is created, this supplies a + * unique token for the session it has with the system service. It is + * needed to identify itself with the service to validate its operations. + * This token must not be passed to applications, since + * it grants special priviledges that should not be given to applications. + * + *

              Note: to protect yourself from malicious clients, you should only + * accept the first token given to you. Any after that may come from the + * client. + */ + public void attachToken(IBinder token); + + /** + * Bind a new application environment in to the input method, so that it + * can later start and stop input processing. + * Typically this method is called when this input method is enabled in an + * application for the first time. + * + * @param binding Information about the application window that is binding + * to the input method. + * + * @see InputBinding + * @see #unbindInput() + */ + public void bindInput(InputBinding binding); + + /** + * Unbind an application environment, called when the information previously + * set by {@link #bindInput} is no longer valid for this input method. + * + *

              + * Typically this method is called when the application changes to be + * non-foreground. + */ + public void unbindInput(); + + /** + * This method is called when the application starts to receive text and it + * is ready for this input method to process received events and send result + * text back to the application. + * + * @param attribute The attribute of the text box (typically, a EditText) + * that requests input. + * + * @see EditorInfo + */ + public void startInput(EditorInfo attribute); + + /** + * This method is called when the state of this input method needs to be + * reset. + * + *

              + * Typically, this method is called when the input focus is moved from one + * text box to another. + * + * @param attribute The attribute of the text box (typically, a EditText) + * that requests input. + * + * @see EditorInfo + */ + public void restartInput(EditorInfo attribute); + + /** + * Create a new {@link InputMethodSession} that can be handed to client + * applications for interacting with the input method. You can later + * use {@link #revokeSession(InputMethodSession)} to destroy the session + * so that it can no longer be used by any clients. + * + * @param callback Interface that is called with the newly created session. + */ + public void createSession(SessionCallback callback); + + /** + * Control whether a particular input method session is active. + * + * @param session The {@link InputMethodSession} previously provided through + * SessionCallback.sessionCreated() that is to be changed. + */ + public void setSessionEnabled(InputMethodSession session, boolean enabled); + + /** + * Disable and destroy a session that was previously created with + * {@link #createSession(android.view.inputmethod.InputMethod.SessionCallback)}. + * After this call, the given session interface is no longer active and + * calls on it will fail. + * + * @param session The {@link InputMethodSession} previously provided through + * SessionCallback.sessionCreated() that is to be revoked. + */ + public void revokeSession(InputMethodSession session); + + /** + * Request that any soft input part of the input method be shown to the user. + */ + public void showSoftInput(); + + /** + * Request that any soft input part of the input method be hidden from the user. + */ + public void hideSoftInput(); +} diff --git a/core/java/android/view/inputmethod/InputMethodInfo.aidl b/core/java/android/view/inputmethod/InputMethodInfo.aidl new file mode 100644 index 0000000000000000000000000000000000000000..5f4d6b65a787823ab67066e4294a2e1e1291ba6f --- /dev/null +++ b/core/java/android/view/inputmethod/InputMethodInfo.aidl @@ -0,0 +1,19 @@ +/* + * 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 android.view.inputmethod; + +parcelable InputMethodInfo; diff --git a/core/java/android/view/inputmethod/InputMethodInfo.java b/core/java/android/view/inputmethod/InputMethodInfo.java new file mode 100644 index 0000000000000000000000000000000000000000..e8f4b54cbd34b6b89aa66a4fdf21365c45a244b9 --- /dev/null +++ b/core/java/android/view/inputmethod/InputMethodInfo.java @@ -0,0 +1,300 @@ +/* + * Copyright (C) 2007-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 android.view.inputmethod; + +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; + +import android.content.ComponentName; +import android.content.Context; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageManager; +import android.content.pm.ResolveInfo; +import android.content.pm.ServiceInfo; +import android.content.res.TypedArray; +import android.content.res.XmlResourceParser; +import android.graphics.drawable.Drawable; +import android.os.Parcel; +import android.os.Parcelable; +import android.util.AttributeSet; +import android.util.Printer; +import android.util.Xml; + +import java.io.IOException; + +/** + * This class is used to specify meta information of an input method. + */ +public final class InputMethodInfo implements Parcelable { + static final String TAG = "InputMethodMetaInfo"; + + /** + * The Service that implements this input method component. + */ + final ResolveInfo mService; + + /** + * The unique string Id to identify the input method. This is generated + * from the input method component. + */ + final String mId; + + /** + * The input method setting activity's name, used by the system settings to + * launch the setting activity of this input method. + */ + final String mSettingsActivityName; + + /** + * The resource in the input method's .apk that holds a boolean indicating + * whether it should be considered the default input method for this + * system. This is a resource ID instead of the final value so that it + * can change based on the configuration (in particular locale). + */ + final int mIsDefaultResId; + + /** + * Constructor. + * + * @param context The Context in which we are parsing the input method. + * @param service The ResolveInfo returned from the package manager about + * this input method's component. + */ + public InputMethodInfo(Context context, ResolveInfo service) + throws XmlPullParserException, IOException { + mService = service; + ServiceInfo si = service.serviceInfo; + mId = new ComponentName(si.packageName, si.name).flattenToShortString(); + + PackageManager pm = context.getPackageManager(); + String settingsActivityComponent = null; + int isDefaultResId = 0; + + XmlResourceParser parser = null; + try { + parser = si.loadXmlMetaData(pm, InputMethod.SERVICE_META_DATA); + if (parser == null) { + throw new XmlPullParserException("No " + + InputMethod.SERVICE_META_DATA + " meta-data"); + } + + AttributeSet attrs = Xml.asAttributeSet(parser); + + int type; + while ((type=parser.next()) != XmlPullParser.END_DOCUMENT + && type != XmlPullParser.START_TAG) { + } + + String nodeName = parser.getName(); + if (!"input-method".equals(nodeName)) { + throw new XmlPullParserException( + "Meta-data does not start with input-method tag"); + } + + TypedArray sa = context.getResources().obtainAttributes(attrs, + com.android.internal.R.styleable.InputMethod); + settingsActivityComponent = sa.getString( + com.android.internal.R.styleable.InputMethod_settingsActivity); + isDefaultResId = sa.getResourceId( + com.android.internal.R.styleable.InputMethod_isDefault, 0); + sa.recycle(); + } finally { + if (parser != null) parser.close(); + } + + mSettingsActivityName = settingsActivityComponent; + mIsDefaultResId = isDefaultResId; + } + + InputMethodInfo(Parcel source) { + mId = source.readString(); + mSettingsActivityName = source.readString(); + mIsDefaultResId = source.readInt(); + mService = ResolveInfo.CREATOR.createFromParcel(source); + } + + /** + * Temporary API for creating a built-in input method. + */ + public InputMethodInfo(String packageName, String className, + CharSequence label, String settingsActivity) { + ResolveInfo ri = new ResolveInfo(); + ServiceInfo si = new ServiceInfo(); + ApplicationInfo ai = new ApplicationInfo(); + ai.packageName = packageName; + ai.enabled = true; + si.applicationInfo = ai; + si.enabled = true; + si.packageName = packageName; + si.name = className; + si.exported = true; + si.nonLocalizedLabel = label; + ri.serviceInfo = si; + mService = ri; + mId = new ComponentName(si.packageName, si.name).flattenToShortString(); + mSettingsActivityName = settingsActivity; + mIsDefaultResId = 0; + } + + /** + * Return a unique ID for this input method. The ID is generated from + * the package and class name implementing the method. + */ + public String getId() { + return mId; + } + + /** + * Return the .apk package that implements this input method. + */ + public String getPackageName() { + return mService.serviceInfo.packageName; + } + + /** + * Return the class name of the service component that implements + * this input method. + */ + public String getServiceName() { + return mService.serviceInfo.name; + } + + /** + * Return the component of the service that implements this input + * method. + */ + public ComponentName getComponent() { + return new ComponentName(mService.serviceInfo.packageName, + mService.serviceInfo.name); + } + + /** + * Load the user-displayed label for this input method. + * + * @param pm Supply a PackageManager used to load the input method's + * resources. + */ + public CharSequence loadLabel(PackageManager pm) { + return mService.loadLabel(pm); + } + + /** + * Load the user-displayed icon for this input method. + * + * @param pm Supply a PackageManager used to load the input method's + * resources. + */ + public Drawable loadIcon(PackageManager pm) { + return mService.loadIcon(pm); + } + + /** + * Return the class name of an activity that provides a settings UI for + * the input method. You can launch this activity be starting it with + * an {@link android.content.Intent} whose action is MAIN and with an + * explicit {@link android.content.ComponentName} + * composed of {@link #getPackageName} and the class name returned here. + * + *

              A null will be returned if there is no settings activity associated + * with the input method. + */ + public String getSettingsActivity() { + return mSettingsActivityName; + } + + /** + * Return the resource identifier of a resource inside of this input + * method's .apk that determines whether it should be considered a + * default input method for the system. + */ + public int getIsDefaultResourceId() { + return mIsDefaultResId; + } + + /** + * Returns true if this input method is one of the components that is + * built in to the system. + */ + public boolean isBuiltin() { + return mService.serviceInfo.packageName.equals( + InputMethodManager.BUILDIN_INPUTMETHOD_PACKAGE); + } + + public void dump(Printer pw, String prefix) { + pw.println(prefix + "mId=" + mId + + " mSettingsActivityName=" + mSettingsActivityName); + pw.println(prefix + "mIsDefaultResId=0x" + + Integer.toHexString(mIsDefaultResId)); + pw.println(prefix + "Service:"); + mService.dump(pw, prefix + " "); + } + + @Override + public String toString() { + return "InputMethodMetaInfo{" + mId + + ", settings: " + + mSettingsActivityName + "}"; + } + + /** + * Used to test whether the given parameter object is an + * {@link InputMethodInfo} and its Id is the same to this one. + * + * @return true if the given parameter object is an + * {@link InputMethodInfo} and its Id is the same to this one. + */ + @Override + public boolean equals(Object o) { + if (o == this) return true; + if (o == null) return false; + + if (!(o instanceof InputMethodInfo)) return false; + + InputMethodInfo obj = (InputMethodInfo) o; + return mId.equals(obj.mId); + } + + /** + * Used to package this object into a {@link Parcel}. + * + * @param dest The {@link Parcel} to be written. + * @param flags The flags used for parceling. + */ + public void writeToParcel(Parcel dest, int flags) { + dest.writeString(mId); + dest.writeString(mSettingsActivityName); + dest.writeInt(mIsDefaultResId); + mService.writeToParcel(dest, flags); + } + + /** + * Used to make this class parcelable. + */ + public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { + public InputMethodInfo createFromParcel(Parcel source) { + return new InputMethodInfo(source); + } + + public InputMethodInfo[] newArray(int size) { + return new InputMethodInfo[size]; + } + }; + + public int describeContents() { + return 0; + } +} diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java new file mode 100644 index 0000000000000000000000000000000000000000..da825933753893c4ed0c876f8f36266384bc5c13 --- /dev/null +++ b/core/java/android/view/inputmethod/InputMethodManager.java @@ -0,0 +1,900 @@ +/* + * Copyright (C) 2007-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 android.view.inputmethod; + +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.graphics.Rect; +import android.os.Bundle; +import android.os.Handler; +import android.os.IBinder; +import android.os.Looper; +import android.os.Message; +import android.os.RemoteException; +import android.os.ServiceManager; +import android.util.Log; +import android.view.KeyEvent; +import android.view.MotionEvent; +import android.view.View; + +import com.android.internal.view.IInputConnectionWrapper; +import com.android.internal.view.IInputContext; +import com.android.internal.view.IInputMethodCallback; +import com.android.internal.view.IInputMethodClient; +import com.android.internal.view.IInputMethodManager; +import com.android.internal.view.IInputMethodSession; +import com.android.internal.view.InputBindResult; + +import java.util.List; + +/** + * Public interface to the global input method manager. You can retrieve + * an instance of this interface with + * {@link Context#getSystemService(String) Context.getSystemService()}. + */ +public final class InputMethodManager { + static final boolean DEBUG = false; + static final String TAG = "InputMethodManager"; + + /** + * The package name of the build-in input method. + * {@hide} + */ + public static final String BUILDIN_INPUTMETHOD_PACKAGE = "android.text.inputmethod"; + + static final Object mInstanceSync = new Object(); + static InputMethodManager mInstance; + + final IInputMethodManager mService; + final Looper mMainLooper; + + // For scheduling work on the main thread. This also serves as our + // global lock. + final H mH; + + // The currently active input connection. + final MutableInputConnectionWrapper mInputConnectionWrapper; + final IInputContext mIInputContext; + + /** + * True if this input method client is active, initially false. + */ + boolean mActive = false; + + /** + * The current base input connection, used when mActive is true. + */ + InputConnection mCurrentInputConnection; + + // ----------------------------------------------------------- + + /** + * This is the view that should currently be served by an input method, + * regardless of the state of setting that up. + */ + View mServedView; + /** + * For evaluating the state after a focus change, this is the view that + * had focus. + */ + View mLastServedView; + /** + * This is set when we are in the process of connecting, to determine + * when we have actually finished. + */ + boolean mServedConnecting; + /** + * This is non-null when we have connected the served view; it holds + * the attributes that were last retrieved from the served view and given + * to the input connection. + */ + EditorInfo mCurrentTextBoxAttribute; + /** + * The InputConnection that was last retrieved from the served view. + */ + InputConnection mServedInputConnection; + /** + * The completions that were last provided by the served view. + */ + CompletionInfo[] mCompletions; + + // Cursor position on the screen. + Rect mTmpCursorRect = new Rect(); + Rect mCursorRect = new Rect(); + int mCursorSelStart; + int mCursorSelEnd; + + // ----------------------------------------------------------- + + /** + * Sequence number of this binding, as returned by the server. + */ + int mBindSequence = -1; + /** + * ID of the method we are bound to. + */ + String mCurId; + /** + * The actual instance of the method to make calls on it. + */ + IInputMethodSession mCurMethod; + + // ----------------------------------------------------------- + + static final int MSG_CHECK_FOCUS = 1; + + class H extends Handler { + H(Looper looper) { + super(looper); + } + + @Override + public void handleMessage(Message msg) { + switch (msg.what) { + case MSG_CHECK_FOCUS: + checkFocus(); + return; + } + } + } + + static class NoOpInputConnection implements InputConnection { + + public boolean clearMetaKeyStates(int states) { + return false; + } + + public boolean commitCompletion(CompletionInfo text) { + return false; + } + + public boolean commitText(CharSequence text, int newCursorPosition) { + return false; + } + + public boolean deleteSurroundingText(int leftLength, int rightLength) { + return false; + } + + public int getCursorCapsMode(int reqModes) { + return 0; + } + + public ExtractedText getExtractedText(ExtractedTextRequest request, int flags) { + return null; + } + + public CharSequence getTextAfterCursor(int n) { + return null; + } + + public CharSequence getTextBeforeCursor(int n) { + return null; + } + + public boolean hideStatusIcon() { + return false; + } + + public boolean performPrivateCommand(String action, Bundle data) { + return false; + } + + public boolean sendKeyEvent(KeyEvent event) { + return false; + } + + public boolean setComposingText(CharSequence text, int newCursorPosition) { + return false; + } + + public boolean showStatusIcon(String packageName, int resId) { + return false; + } + } + + final NoOpInputConnection mNoOpInputConnection = new NoOpInputConnection(); + + final IInputMethodClient.Stub mClient = new IInputMethodClient.Stub() { + public void setUsingInputMethod(boolean state) { + + } + + public void onBindMethod(InputBindResult res) { + synchronized (mH) { + if (mBindSequence < 0 || mBindSequence != res.sequence) { + Log.w(TAG, "Ignoring onBind: cur seq=" + mBindSequence + + ", given seq=" + res.sequence); + return; + } + + mCurMethod = res.method; + mCurId = res.id; + mBindSequence = res.sequence; + } + startInputInner(); + } + + public void onUnbindMethod(int sequence) { + synchronized (mH) { + if (mBindSequence == sequence) { + if (false) { + // XXX the server has already unbound! + if (mCurMethod != null && mCurrentTextBoxAttribute != null) { + try { + mCurMethod.finishInput(); + } catch (RemoteException e) { + Log.w(TAG, "IME died: " + mCurId, e); + } + } + } + clearBindingLocked(); + + // If we were actively using the last input method, then + // we would like to re-connect to the next input method. + if (mServedView != null && mServedView.isFocused()) { + mServedConnecting = true; + } + } + startInputInner(); + } + } + + public void setActive(boolean active) { + mActive = active; + mInputConnectionWrapper.setBaseInputConnection(active + ? mCurrentInputConnection : mNoOpInputConnection); + } + }; + + final InputConnection mDummyInputConnection = new BaseInputConnection(this) { + public boolean commitText(CharSequence text, int newCursorPosition) { + return false; + } + public boolean commitCompletion(CompletionInfo text) { + return false; + } + public boolean deleteSurroundingText(int leftLength, int rightLength) { + return false; + } + public ExtractedText getExtractedText(ExtractedTextRequest request, + int flags) { + return null; + } + public CharSequence getTextAfterCursor(int n) { + return null; + } + public CharSequence getTextBeforeCursor(int n) { + return null; + } + public int getCursorCapsMode(int reqModes) { + return 0; + } + public boolean clearMetaKeyStates(int states) { + return false; + } + public boolean performPrivateCommand(String action, Bundle data) { + return false; + } + public boolean setComposingText(CharSequence text, int newCursorPosition) { + return false; + } + }; + + InputMethodManager(IInputMethodManager service, Looper looper) { + mService = service; + mMainLooper = looper; + mH = new H(looper); + mInputConnectionWrapper = new MutableInputConnectionWrapper(mNoOpInputConnection); + mIInputContext = new IInputConnectionWrapper(looper, + mInputConnectionWrapper); + setCurrentInputConnection(mDummyInputConnection); + + if (mInstance == null) { + mInstance = this; + } + } + + /** + * Retrieve the global InputMethodManager instance, creating it if it + * doesn't already exist. + * @hide + */ + static public InputMethodManager getInstance(Context context) { + synchronized (mInstanceSync) { + if (mInstance != null) { + return mInstance; + } + IBinder b = ServiceManager.getService(Context.INPUT_METHOD_SERVICE); + IInputMethodManager service = IInputMethodManager.Stub.asInterface(b); + mInstance = new InputMethodManager(service, context.getMainLooper()); + } + return mInstance; + } + + /** + * Private optimization: retrieve the global InputMethodManager instance, + * if it exists. + * @hide + */ + static public InputMethodManager peekInstance() { + return mInstance; + } + + /** @hide */ + public IInputMethodClient getClient() { + return mClient; + } + + /** @hide */ + public IInputContext getInputContext() { + return mIInputContext; + } + + public List getInputMethodList() { + try { + return mService.getInputMethodList(); + } catch (RemoteException e) { + throw new RuntimeException(e); + } + } + + public List getEnabledInputMethodList() { + try { + return mService.getEnabledInputMethodList(); + } catch (RemoteException e) { + throw new RuntimeException(e); + } + } + + public void updateStatusIcon(int iconId, String iconPackage) { + try { + mService.updateStatusIcon(iconId, iconPackage); + } catch (RemoteException e) { + throw new RuntimeException(e); + } + } + + /** + * Return true if the given view is the currently active view for the + * input method. + */ + public boolean isActive(View view) { + synchronized (mH) { + return mServedView == view && mCurrentTextBoxAttribute != null; + } + } + + /** + * Return true if any view is currently active in the input method. + */ + public boolean isActive() { + synchronized (mH) { + return mServedView != null && mCurrentTextBoxAttribute != null; + } + } + + /** + * Return true if the currently served view is accepting full text edits. + * If false, it has no input connection, so can only handle raw key events. + */ + public boolean isAcceptingText() { + return mServedInputConnection != null; + } + + /** + * Reset all of the state associated with being bound to an input method. + */ + void clearBindingLocked() { + clearConnectionLocked(); + mBindSequence = -1; + mCurId = null; + mCurMethod = null; + } + + /** + * Record the desired input connection, but only set it if mActive is true. + */ + void setCurrentInputConnection(InputConnection connection) { + mCurrentInputConnection = connection; + mInputConnectionWrapper.setBaseInputConnection(mActive + ? connection : mNoOpInputConnection); + } + + /** + * Reset all of the state associated with a served view being connected + * to an input method + */ + void clearConnectionLocked() { + mCurrentTextBoxAttribute = null; + mServedInputConnection = null; + setCurrentInputConnection(mDummyInputConnection); + } + + /** + * Disconnect any existing input connection, clearing the served view. + */ + void finishInputLocked() { + synchronized (mH) { + if (mServedView != null) { + if (DEBUG) Log.v(TAG, "FINISH INPUT: " + mServedView); + updateStatusIcon(0, null); + + if (mCurrentTextBoxAttribute != null) { + try { + mService.finishInput(mClient); + } catch (RemoteException e) { + } + } + + mServedView = null; + mCompletions = null; + mServedConnecting = false; + clearConnectionLocked(); + } + } + } + + public void displayCompletions(View view, CompletionInfo[] completions) { + synchronized (mH) { + if (mServedView != view) { + return; + } + + mCompletions = completions; + if (mCurMethod != null) { + try { + mCurMethod.displayCompletions(mCompletions); + } catch (RemoteException e) { + } + } + } + } + + public void updateExtractedText(View view, int token, ExtractedText text) { + synchronized (mH) { + if (mServedView != view) { + return; + } + + if (mCurMethod != null) { + try { + mCurMethod.updateExtractedText(token, text); + } catch (RemoteException e) { + } + } + } + } + + /** + * Explicitly request that the current input method's soft input area be + * shown to the user, if needed. Call this if the user interacts with + * your view in such a way that they have expressed they would like to + * start performing input into it. + * + * @param view The currently focused view, which would like to receive + * soft keyboard input. + */ + public void showSoftInput(View view) { + synchronized (mH) { + if (mServedView != view) { + return; + } + + try { + mService.showSoftInput(mClient); + } catch (RemoteException e) { + } + } + } + + /** + * Request to hide the soft input window from the context of the window + * that is currently accepting input. This should be called as a result + * of the user doing some actually than fairly explicitly requests to + * have the input window hidden. + * + * @param windowToken The token of the window that is making the request, + * as returned by {@link View#getWindowToken() View.getWindowToken()}. + */ + public void hideSoftInputFromWindow(IBinder windowToken) { + synchronized (mH) { + if (mServedView == null || mServedView.getWindowToken() != windowToken) { + return; + } + + try { + mService.hideSoftInput(mClient); + } catch (RemoteException e) { + } + } + } + + /** + * If the input method is currently connected to the given view, + * restart it with its new contents. You should call this when the text + * within your view changes outside of the normal input method or key + * input flow, such as when an application calls TextView.setText(). + * + * @param view The view whose text has changed. + */ + public void restartInput(View view) { + synchronized (mH) { + if (mServedView != view) { + return; + } + + mServedConnecting = true; + } + + startInputInner(); + } + + void startInputInner() { + final View view; + synchronized (mH) { + view = mServedView; + + // Make sure we have a window token for the served view. + if (DEBUG) Log.v(TAG, "Starting input: view=" + view); + if (view == null) { + if (DEBUG) Log.v(TAG, "ABORT input: no served view!"); + return; + } + } + + // Now we need to get an input connection from the served view. + // This is complicated in a couple ways: we can't be holding our lock + // when calling out to the view, and we need to make sure we call into + // the view on the same thread that is driving its view hierarchy. + Handler vh = view.getHandler(); + if (vh == null) { + // If the view doesn't have a handler, something has changed out + // from under us, so just bail. + if (DEBUG) Log.v(TAG, "ABORT input: no handler for view!"); + return; + } + if (vh.getLooper() != Looper.myLooper()) { + // The view is running on a different thread than our own, so + // we need to reschedule our work for over there. + if (DEBUG) Log.v(TAG, "Starting input: reschedule to view thread"); + vh.post(new Runnable() { + public void run() { + startInputInner(); + } + }); + } + + // Okay we are now ready to call into the served view and have it + // do its stuff. + // Life is good: let's hook everything up! + EditorInfo tba = new EditorInfo(); + InputConnection ic = view.createInputConnection(tba); + if (DEBUG) Log.v(TAG, "Starting input: tba=" + tba + " ic=" + ic); + + synchronized (mH) { + // Now that we are locked again, validate that our state hasn't + // changed. + if (mServedView != view || !mServedConnecting) { + // Something else happened, so abort. + if (DEBUG) Log.v(TAG, + "Starting input: finished by someone else (view=" + + mServedView + " conn=" + mServedConnecting + ")"); + return; + } + + // If we already have a text box, then this view is already + // connected so we want to restart it. + final boolean initial = mCurrentTextBoxAttribute == null; + + // Hook 'em up and let 'er rip. + mCurrentTextBoxAttribute = tba; + mServedConnecting = false; + mServedInputConnection = ic; + if (ic != null) { + mCursorSelStart = tba.initialSelStart; + mCursorSelEnd = tba.initialSelEnd; + mCursorRect.setEmpty(); + setCurrentInputConnection(ic); + } else { + setCurrentInputConnection(mDummyInputConnection); + } + + try { + if (DEBUG) Log.v(TAG, "START INPUT: " + view + " ic=" + + ic + " tba=" + tba); + InputBindResult res = mService.startInput(mClient, tba, initial, + mCurMethod == null); + if (DEBUG) Log.v(TAG, "Starting input: Bind result=" + res); + if (res != null) { + if (res.id != null) { + mBindSequence = res.sequence; + mCurMethod = res.method; + } else { + // This means there is no input method available. + if (DEBUG) Log.v(TAG, "ABORT input: no input method!"); + return; + } + } + if (mCurMethod != null && mCompletions != null) { + try { + mCurMethod.displayCompletions(mCompletions); + } catch (RemoteException e) { + } + } + } catch (RemoteException e) { + Log.w(TAG, "IME died: " + mCurId, e); + } + } + } + + /** + * When the focused window is dismissed, this method is called to finish the + * input method started before. + * @hide + */ + public void windowDismissed(IBinder appWindowToken) { + synchronized (mH) { + if (mServedView != null && + mServedView.getWindowToken() == appWindowToken) { + finishInputLocked(); + } + } + } + + /** + * Call this when a view receives focus. + * @hide + */ + public void focusIn(View view) { + synchronized (mH) { + if (DEBUG) Log.v(TAG, "focusIn: " + view); + // Okay we have a new view that is being served. + mServedView = view; + mCompletions = null; + mServedConnecting = true; + } + + startInputInner(); + } + + /** + * Call this when a view loses focus. + * @hide + */ + public void focusOut(View view) { + synchronized (mH) { + if (DEBUG) Log.v(TAG, "focusOut: " + view + + " mServedView=" + mServedView + + " winFocus=" + view.hasWindowFocus()); + if (mServedView == view && view.hasWindowFocus()) { + mLastServedView = view; + mH.removeMessages(MSG_CHECK_FOCUS); + mH.sendEmptyMessage(MSG_CHECK_FOCUS); + } + } + } + + void checkFocus() { + synchronized (mH) { + if (DEBUG) Log.v(TAG, "checkFocus: view=" + mServedView + + " last=" + mLastServedView); + if (mServedView == mLastServedView) { + finishInputLocked(); + // In this case, we used to have a focused view on the window, + // but no longer do. We should make sure the input method is + // no longer shown, since it serves no purpose. + closeCurrentInput(); + } + mLastServedView = null; + } + } + + void closeCurrentInput() { + try { + mService.hideSoftInput(mClient); + } catch (RemoteException e) { + } + } + + /** + * Called by ViewRoot the first time it gets window focus. + */ + public void onWindowFocus(View focusedView, int softInputMode, + boolean first, int windowFlags) { + synchronized (mH) { + if (DEBUG) Log.v(TAG, "onWindowFocus: " + focusedView + + " softInputMode=" + softInputMode + + " first=" + first + " flags=#" + + Integer.toHexString(windowFlags)); + try { + mService.windowGainedFocus(mClient, focusedView != null, + softInputMode, first, windowFlags); + } catch (RemoteException e) { + } + } + } + + /** + * Report the current selection range. + */ + public void updateSelection(View view, int selStart, int selEnd) { + synchronized (mH) { + if (mServedView != view || mCurrentTextBoxAttribute == null + || mCurMethod == null) { + return; + } + + if (mCursorSelStart != selStart || mCursorSelEnd != selEnd) { + if (DEBUG) Log.d(TAG, "updateSelection"); + + try { + if (DEBUG) Log.v(TAG, "SELECTION CHANGE: " + mCurMethod); + mCurMethod.updateSelection(mCursorSelStart, mCursorSelEnd, + selStart, selEnd); + mCursorSelStart = selStart; + mCursorSelEnd = selEnd; + } catch (RemoteException e) { + Log.w(TAG, "IME died: " + mCurId, e); + } + } + } + } + + /** + * Returns true if the current input method wants to watch the location + * of the input editor's cursor in its window. + */ + public boolean isWatchingCursor(View view) { + return false; + } + + /** + * Report the current cursor location in its window. + */ + public void updateCursor(View view, int left, int top, int right, int bottom) { + synchronized (mH) { + if (mServedView != view || mCurrentTextBoxAttribute == null + || mCurMethod == null) { + return; + } + + mTmpCursorRect.set(left, top, right, bottom); + if (!mCursorRect.equals(mTmpCursorRect)) { + if (DEBUG) Log.d(TAG, "updateCursor"); + + try { + if (DEBUG) Log.v(TAG, "CURSOR CHANGE: " + mCurMethod); + mCurMethod.updateCursor(mTmpCursorRect); + mCursorRect.set(mTmpCursorRect); + } catch (RemoteException e) { + Log.w(TAG, "IME died: " + mCurId, e); + } + } + } + } + + /** + * Force switch to a new input method component. This can only be called + * from the currently active input method, as validated by the given token. + * @param token Supplies the identifying token given to an input method + * when it was started, which allows it to perform this operation on + * itself. + * @param id The unique identifier for the new input method to be switched to. + */ + public void setInputMethod(IBinder token, String id) { + try { + mService.setInputMethod(token, id); + } catch (RemoteException e) { + throw new RuntimeException(e); + } + } + + /** + * Close/hide the input method's soft input area, so the user no longer + * sees it or can interact with it. This can only be called + * from the currently active input method, as validated by the given token. + * @param token Supplies the identifying token given to an input method + * when it was started, which allows it to perform this operation on + * itself. + */ + public void hideSoftInputFromInputMethod(IBinder token) { + try { + mService.hideMySoftInput(token); + } catch (RemoteException e) { + throw new RuntimeException(e); + } + } + + /** + * @hide + */ + public void dispatchKeyEvent(Context context, int seq, KeyEvent key, + IInputMethodCallback callback) { + synchronized (mH) { + if (DEBUG) Log.d(TAG, "dispatchKeyEvent"); + + if (mCurMethod == null || mCurrentTextBoxAttribute == null) { + try { + callback.finishedEvent(seq, false); + } catch (RemoteException e) { + } + return; + } + + if (key.getAction() == KeyEvent.ACTION_DOWN + && key.getKeyCode() == KeyEvent.KEYCODE_SYM) { + showInputMethodPicker(); + try { + callback.finishedEvent(seq, true); + } catch (RemoteException e) { + } + return; + } + try { + if (DEBUG) Log.v(TAG, "DISPATCH KEY: " + mCurMethod); + mCurMethod.dispatchKeyEvent(seq, key, callback); + } catch (RemoteException e) { + Log.w(TAG, "IME died: " + mCurId + " dropping: " + key, e); + try { + callback.finishedEvent(seq, false); + } catch (RemoteException ex) { + } + } + } + } + + /** + * @hide + */ + void dispatchTrackballEvent(Context context, int seq, MotionEvent motion, + IInputMethodCallback callback) { + synchronized (mH) { + if (DEBUG) Log.d(TAG, "dispatchTrackballEvent"); + + if (mCurMethod == null || mCurrentTextBoxAttribute == null) { + try { + callback.finishedEvent(seq, false); + } catch (RemoteException e) { + } + return; + } + + try { + if (DEBUG) Log.v(TAG, "DISPATCH TRACKBALL: " + mCurMethod); + mCurMethod.dispatchTrackballEvent(seq, motion, callback); + } catch (RemoteException e) { + Log.w(TAG, "IME died: " + mCurId + " dropping trackball: " + motion, e); + try { + callback.finishedEvent(seq, false); + } catch (RemoteException ex) { + } + } + } + } + + public void showInputMethodPicker() { + synchronized (mH) { + try { + mService.showInputMethodPickerFromClient(mClient); + } catch (RemoteException e) { + Log.w(TAG, "IME died: " + mCurId, e); + } + } + } +} diff --git a/core/java/android/view/inputmethod/InputMethodSession.java b/core/java/android/view/inputmethod/InputMethodSession.java new file mode 100644 index 0000000000000000000000000000000000000000..603da13902f9d7b31476f6a56b99994a76da260d --- /dev/null +++ b/core/java/android/view/inputmethod/InputMethodSession.java @@ -0,0 +1,137 @@ +/* + * Copyright (C) 2007-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 android.view.inputmethod; + +import android.graphics.Rect; +import android.os.Bundle; +import android.view.KeyEvent; +import android.view.MotionEvent; + +/** + * The InputMethodSession interface provides the per-client functionality + * of {@link InputMethod} that is safe to expose to applications. + * + *

              Applications will not normally use this interface themselves, instead + * relying on the standard interaction provided by + * {@link android.widget.TextView} and {@link android.widget.EditText}. + */ +public interface InputMethodSession { + + public interface EventCallback { + void finishedEvent(int seq, boolean handled); + } + + /** + * This method is called when the application would like to stop + * receiving text input. + */ + public void finishInput(); + + /** + * This method is called when the selection or cursor in the current + * target input field has changed. + * + * @param oldSelStart The previous text offset of the cursor selection + * start position. + * @param oldSelEnd The previous text offset of the cursor selection + * end position. + * @param newSelStart The new text offset of the cursor selection + * start position. + * @param newSelEnd The new text offset of the cursor selection + * end position. + */ + public void updateSelection(int oldSelStart, int oldSelEnd, + int newSelStart, int newSelEnd); + + /** + * This method is called when cursor location of the target input field + * has changed within its window. This is not normally called, but will + * only be reported if requested by the input method. + * + * @param newCursor The rectangle of the cursor currently being shown in + * the input field's window coordinates. + */ + public void updateCursor(Rect newCursor); + + /** + * Called by a text editor that performs auto completion, to tell the + * input method about the completions it has available. This can be used + * by the input method to display them to the user to select the text to + * be inserted. + * + * @param completions Array of text completions that are available, starting with + * the best. If this array is null, any existing completions will be + * removed. + */ + public void displayCompletions(CompletionInfo[] completions); + + /** + * Called by a text editor to report its new extracted text when its + * contents change. This will only be called if the input method + * calls {@link InputConnection#getExtractedText(ExtractedTextRequest, int) + * InputConnection.getExtractedText()} with the option to report updates. + * + * @param token The input method supplied token for identifying its request. + * @param text The new extracted text. + */ + public void updateExtractedText(int token, ExtractedText text); + + /** + * This method is called when a key is pressed. When done with the event, + * the implementation must call back on callback with its + * result. + * + *

              + * If the input method wants to handle this event, return true, otherwise + * return false and the caller (i.e. the application) will handle the event. + * + * @param event The key event. + * + * @return Whether the input method wants to handle this event. + * + * @see #dispatchKeyUp + * @see android.view.KeyEvent + */ + public void dispatchKeyEvent(int seq, KeyEvent event, EventCallback callback); + + /** + * This method is called when there is a track ball event. + * + *

              + * If the input method wants to handle this event, return true, otherwise + * return false and the caller (i.e. the application) will handle the event. + * + * @param event The motion event. + * + * @return Whether the input method wants to handle this event. + * + * @see android.view.MotionEvent + */ + public void dispatchTrackballEvent(int seq, MotionEvent event, EventCallback callback); + + /** + * Process a private command sent from the application to the input method. + * This can be used to provide domain-specific features that are + * only known between certain input methods and their clients. + * + * @param action Name of the command to be performed. This must + * be a scoped name, i.e. prefixed with a package name you own, so that + * different developers will not create conflicting commands. + * @param data Any data to include with the command. + */ + public void appPrivateCommand(String action, Bundle data); +} diff --git a/core/java/android/view/inputmethod/MutableInputConnectionWrapper.java b/core/java/android/view/inputmethod/MutableInputConnectionWrapper.java new file mode 100644 index 0000000000000000000000000000000000000000..025a0599aab0bc9352f90cf5d809d641f1f19771 --- /dev/null +++ b/core/java/android/view/inputmethod/MutableInputConnectionWrapper.java @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2007-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 android.view.inputmethod; + + +/** + * Special version of {@link InputConnectionWrapper} that allows the base + * input connection to be modified after it is initially set. + */ +public class MutableInputConnectionWrapper extends InputConnectionWrapper { + public MutableInputConnectionWrapper(InputConnection base) { + super(base); + } + + /** + * Change the base InputConnection for this wrapper. All calls will then be + * delegated to the base input connection. + * + * @param base The new base InputConnection for this wrapper. + */ + public void setBaseInputConnection(InputConnection base) { + mBase = base; + } +} diff --git a/core/java/android/view/inputmethod/package.html b/core/java/android/view/inputmethod/package.html new file mode 100644 index 0000000000000000000000000000000000000000..348aba68204ada9d3c608540a24b03043829f838 --- /dev/null +++ b/core/java/android/view/inputmethod/package.html @@ -0,0 +1,11 @@ + + +Framework classes for interaction between views and input methods (such +as soft keyboards). In most cases the main classes here are not needed for +most applications, since they are dealt with for you by +{@link android.widget.TextView}. When implementing a custom text editor, +however, you will need to implement the +{@link android.view.inputmethod.InputConnection} class to allow the current +input method to interact with your view. + + diff --git a/core/java/android/webkit/BrowserFrame.java b/core/java/android/webkit/BrowserFrame.java index e99c4449393ffddf22f45f3c7c9af358d58c6d88..1dd37be06493ffe5be2c8bb7c85b81cca9ec5bd1 100644 --- a/core/java/android/webkit/BrowserFrame.java +++ b/core/java/android/webkit/BrowserFrame.java @@ -26,10 +26,10 @@ import android.os.Handler; import android.os.Message; import android.util.Config; import android.util.Log; +import android.util.TypedValue; import junit.framework.Assert; -import java.net.URLDecoder; import java.net.URLEncoder; import java.util.HashMap; import java.util.Iterator; @@ -52,9 +52,7 @@ class BrowserFrame extends Handler { private final WebViewDatabase mDatabase; private final WebViewCore mWebViewCore; private boolean mLoadInitFromJava; - private String mCurrentUrl; private int mLoadType; - private String mCompletedUrl; private boolean mFirstLayoutDone = true; private boolean mCommitted = true; @@ -114,9 +112,7 @@ class BrowserFrame extends Handler { CookieSyncManager.createInstance(context); } AssetManager am = context.getAssets(); - nativeCreateFrame(am, proxy.getBackForwardList()); - // Create a native FrameView and attach it to the native frame. - nativeCreateView(w); + nativeCreateFrame(w, am, proxy.getBackForwardList()); mSettings = settings; mContext = context; @@ -142,11 +138,7 @@ class BrowserFrame extends Handler { stringByEvaluatingJavaScriptFromString( url.substring("javascript:".length())); } else { - if (!nativeLoadUrl(url)) { - reportError(android.net.http.EventHandler.ERROR_BAD_URL, - mContext.getString(com.android.internal.R.string.httpErrorBadUrl), - url); - } + nativeLoadUrl(url); } mLoadInitFromJava = false; } @@ -185,6 +177,17 @@ class BrowserFrame extends Handler { mLoadInitFromJava = false; } + /** + * Go back or forward the number of steps given. + * @param steps A negative or positive number indicating the direction + * and number of steps to move. + */ + public void goBackOrForward(int steps) { + mLoadInitFromJava = true; + nativeGoBackOrForward(steps); + mLoadInitFromJava = false; + } + /** * native callback * Report an error to an activity. @@ -216,34 +219,12 @@ class BrowserFrame extends Handler { return mLoadType; } - /* package */String currentUrl() { - return mCurrentUrl; - } - - /* package */void didFirstLayout(String url) { - // this is common case - if (url.equals(mCurrentUrl)) { - if (!mFirstLayoutDone) { - mFirstLayoutDone = true; - // ensure {@link WebViewCore#webkitDraw} is called as we were - // blocking the update in {@link #loadStarted} - mWebViewCore.contentInvalidate(); - } - } else if (url.equals(mCompletedUrl)) { - /* - * FIXME: when loading http://www.google.com/m, - * mCurrentUrl will be http://www.google.com/m, - * mCompletedUrl will be http://www.google.com/m#search - * and url will be http://www.google.com/m#search. - * This is probably a bug in WebKit. If url matches mCompletedUrl, - * also set mFirstLayoutDone to be true and update. - */ - if (!mFirstLayoutDone) { - mFirstLayoutDone = true; - // ensure {@link WebViewCore#webkitDraw} is called as we were - // blocking the update in {@link #loadStarted} - mWebViewCore.contentInvalidate(); - } + /* package */void didFirstLayout() { + if (!mFirstLayoutDone) { + mFirstLayoutDone = true; + // ensure {@link WebViewCore#webkitDraw} is called as we were + // blocking the update in {@link #loadStarted} + mWebViewCore.contentDraw(); } mWebViewCore.mEndScaleZoom = true; } @@ -258,8 +239,6 @@ class BrowserFrame extends Handler { mIsMainFrame = isMainFrame; if (isMainFrame || loadType == FRAME_LOADTYPE_STANDARD) { - mCurrentUrl = url; - mCompletedUrl = null; mLoadType = loadType; if (isMainFrame) { @@ -310,7 +289,6 @@ class BrowserFrame extends Handler { // mIsMainFrame and isMainFrame are better be equal!!! if (isMainFrame || loadType == FRAME_LOADTYPE_STANDARD) { - mCompletedUrl = url; if (isMainFrame) { mCallbackProxy.switchOutDrawHistory(); mCallbackProxy.onPageFinished(url); @@ -355,8 +333,8 @@ class BrowserFrame extends Handler { WebAddress uri = new WebAddress( mCallbackProxy.getBackForwardList().getCurrentItem() .getUrl()); - String host = uri.mHost; - String[] up = mDatabase.getUsernamePassword(host); + String schemePlusHost = uri.mScheme + uri.mHost; + String[] up = mDatabase.getUsernamePassword(schemePlusHost); if (up != null && up[0] != null) { setUsernamePassword(up[0], up[1]); } @@ -441,7 +419,13 @@ class BrowserFrame extends Handler { if (mLoadInitFromJava == true) { return false; } - return mCallbackProxy.shouldOverrideUrlLoading(url); + if (mCallbackProxy.shouldOverrideUrlLoading(url)) { + // if the url is hijacked, reset the state of the BrowserFrame + didFirstLayout(); + return true; + } else { + return false; + } } public void addJavascriptInterface(Object obj, String interfaceName) { @@ -462,7 +446,7 @@ class BrowserFrame extends Handler { * @param method The http method. * @param headers The http headers. * @param postData If the method is "POST" postData is sent as the request - * body. + * body. Is null when empty. * @param cacheMode The cache mode to use when loading this resource. * @param isHighPriority True if this resource needs to be put at the front * of the network queue. @@ -473,7 +457,7 @@ class BrowserFrame extends Handler { String url, String method, HashMap headers, - String postData, + byte[] postData, int cacheMode, boolean isHighPriority, boolean synchronous) { @@ -497,41 +481,47 @@ class BrowserFrame extends Handler { } WebAddress uri = new WebAddress(mCallbackProxy .getBackForwardList().getCurrentItem().getUrl()); - String host = uri.mHost; + String schemePlusHost = uri.mScheme + uri.mHost; String[] ret = getUsernamePassword(); - if (ret != null && postData != null && ret[0].length() > 0 - && ret[1].length() > 0 - && postData.contains(URLEncoder.encode(ret[0])) - && postData.contains(URLEncoder.encode(ret[1]))) { - String[] saved = mDatabase.getUsernamePassword(host); - if (saved != null) { - // null username implies that user has chosen not to - // save password - if (saved[0] != null) { - // non-null username implies that user has - // chosen to save password, so update the - // recorded password - mDatabase.setUsernamePassword(host, ret[0], - ret[1]); + // Has the user entered a username/password pair and is + // there some POST data + if (ret != null && postData != null && + ret[0].length() > 0 && ret[1].length() > 0) { + // Check to see if the username & password appear in + // the post data (there could be another form on the + // page and that was posted instead. + String postString = new String(postData); + if (postString.contains(URLEncoder.encode(ret[0])) && + postString.contains(URLEncoder.encode(ret[1]))) { + String[] saved = mDatabase.getUsernamePassword( + schemePlusHost); + if (saved != null) { + // null username implies that user has chosen not to + // save password + if (saved[0] != null) { + // non-null username implies that user has + // chosen to save password, so update the + // recorded password + mDatabase.setUsernamePassword( + schemePlusHost, ret[0], ret[1]); + } + } else { + // CallbackProxy will handle creating the resume + // message + mCallbackProxy.onSavePassword(schemePlusHost, ret[0], + ret[1], null); } - } else { - // CallbackProxy will handle creating the resume - // message - mCallbackProxy.onSavePassword(host, ret[0], ret[1], - null); } } } catch (ParseException ex) { // if it is bad uri, don't save its password } - } - if (postData == null) { - postData = ""; + } } // is this resource the main-frame top-level page? - boolean isMainFramePage = mIsMainFrame && url.equals(mCurrentUrl); + boolean isMainFramePage = mIsMainFrame; if (Config.LOGV) { Log.v(LOGTAG, "startLoadingResource: url=" + url + ", method=" @@ -561,8 +551,8 @@ class BrowserFrame extends Handler { CacheManager.endCacheTransaction(); } - FrameLoader loader = new FrameLoader(loadListener, - mSettings.getUserAgentString(), method, isHighPriority); + FrameLoader loader = new FrameLoader(loadListener, mSettings, + method, isHighPriority); loader.setHeaders(headers); loader.setPostData(postData); loader.setCacheMode(cacheMode); // Set the load mode to the mode used @@ -666,36 +656,51 @@ class BrowserFrame extends Handler { return mSettings.getUserAgentString(); } + // these ids need to be in sync with enum RAW_RES_ID in WebFrame + private static final int NODOMAIN = 1; + private static final int LOADERROR = 2; + + String getRawResFilename(int id) { + int resid; + switch (id) { + case NODOMAIN: + resid = com.android.internal.R.raw.nodomain; + break; + + case LOADERROR: + resid = com.android.internal.R.raw.loaderror; + break; + + default: + Log.e(LOGTAG, "getRawResFilename got incompatible resource ID"); + return new String(); + } + TypedValue value = new TypedValue(); + mContext.getResources().getValue(resid, value, true); + return value.string.toString(); + } + //========================================================================== // native functions //========================================================================== /** - * Create a new native frame. + * Create a new native frame for a given WebView + * @param w A WebView that the frame draws into. * @param am AssetManager to use to get assets. * @param list The native side will add and remove items from this list as * the native list changes. */ - private native void nativeCreateFrame(AssetManager am, + private native void nativeCreateFrame(WebViewCore w, AssetManager am, WebBackForwardList list); - /** - * Create a native view attached to a WebView. - * @param w A WebView that the frame draws into. - */ - private native void nativeCreateView(WebViewCore w); - - private native void nativeCallPolicyFunction(int policyFunction, - int decision); /** * Destroy the native frame. */ public native void nativeDestroyFrame(); - /** - * Detach the view from the frame. - */ - private native void nativeDetachView(); + private native void nativeCallPolicyFunction(int policyFunction, + int decision); /** * Reload the current main frame. @@ -707,7 +712,7 @@ class BrowserFrame extends Handler { * @param steps A negative or positive number indicating the direction * and number of steps to move. */ - public native void goBackOrForward(int steps); + private native void nativeGoBackOrForward(int steps); /** * stringByEvaluatingJavaScriptFromString will execute the @@ -738,7 +743,7 @@ class BrowserFrame extends Handler { /** * Returns false if the url is bad. */ - private native boolean nativeLoadUrl(String url); + private native void nativeLoadUrl(String url); private native void nativeLoadData(String baseUrl, String data, String mimeType, String encoding, String failUrl); diff --git a/core/java/android/webkit/CacheManager.java b/core/java/android/webkit/CacheManager.java index f5a09b83b724a86a825e3328542a178388b71ae5..d12940d04f41e3f4450da79738714a6a8c7739e6 100644 --- a/core/java/android/webkit/CacheManager.java +++ b/core/java/android/webkit/CacheManager.java @@ -62,8 +62,18 @@ public final class CacheManager { // Reference count the enable/disable transaction private static int mRefCount; + // trimCacheIfNeeded() is called when a page is fully loaded. But JavaScript + // can load the content, e.g. in a slideshow, continuously, so we need to + // trim the cache on a timer base too. endCacheTransaction() is called on a + // timer base. We share the same timer with less frequent update. + private static int mTrimCacheCount = 0; + private static final int TRIM_CACHE_INTERVAL = 5; + private static WebViewDatabase mDataBase; private static File mBaseDir; + + // Flag to clear the cache when the CacheManager is initialized + private static boolean mClearCacheOnInit = false; public static class CacheResult { // these fields are saved to the database @@ -145,16 +155,37 @@ public final class CacheManager { static void init(Context context) { mDataBase = WebViewDatabase.getInstance(context); mBaseDir = new File(context.getCacheDir(), "webviewCache"); + if (createCacheDirectory() && mClearCacheOnInit) { + removeAllCacheFiles(); + mClearCacheOnInit = false; + } + } + + /** + * Create the cache directory if it does not already exist. + * + * @return true if the cache directory didn't exist and was created. + */ + static private boolean createCacheDirectory() { if (!mBaseDir.exists()) { if(!mBaseDir.mkdirs()) { Log.w(LOGTAG, "Unable to create webviewCache directory"); - return; + return false; } FileUtils.setPermissions( mBaseDir.toString(), FileUtils.S_IRWXU|FileUtils.S_IRWXG|FileUtils.S_IXOTH, -1, -1); + // If we did create the directory, we need to flush + // the cache database. The directory could be recreated + // because the system flushed all the data/cache directories + // to free up disk space. + WebViewCore.endCacheTransaction(); + mDataBase.clearCache(); + WebViewCore.startCacheTransaction(); + return true; } + return false; } /** @@ -224,7 +255,12 @@ public final class CacheManager { // only called from WebCore thread // make sure to call startCacheTransaction/endCacheTransaction in pair public static boolean endCacheTransaction() { - return mDataBase.endCacheTransaction(); + boolean ret = mDataBase.endCacheTransaction(); + if (++mTrimCacheCount >= TRIM_CACHE_INTERVAL) { + mTrimCacheCount = 0; + trimCacheIfNeeded(); + } + return ret; } /** @@ -319,7 +355,20 @@ public final class CacheManager { try { ret.outStream = new FileOutputStream(ret.outFile); } catch (FileNotFoundException e) { - return null; + // This can happen with the system did a purge and our + // subdirectory has gone, so lets try to create it again + if (createCacheDirectory()) { + try { + ret.outStream = new FileOutputStream(ret.outFile); + } catch (FileNotFoundException e2) { + // We failed to create the file again, so there + // is something else wrong. Return null. + return null; + } + } else { + // Failed to create cache directory + return null; + } } ret.mimeType = mimeType; } @@ -371,14 +420,25 @@ public final class CacheManager { */ // only called from WebCore thread static boolean removeAllCacheFiles() { + // Note, this is called before init() when the database is + // created or upgraded. + if (mBaseDir == null) { + // Init() has not been called yet, so just flag that + // we need to clear the cache when init() is called. + mClearCacheOnInit = true; + return true; + } // delete cache in a separate thread to not block UI. final Runnable clearCache = new Runnable() { public void run() { // delete all cache files try { String[] files = mBaseDir.list(); - for (int i = 0; i < files.length; i++) { - new File(mBaseDir, files[i]).delete(); + // if mBaseDir doesn't exist, files can be null. + if (files != null) { + for (int i = 0; i < files.length; i++) { + new File(mBaseDir, files[i]).delete(); + } } } catch (SecurityException e) { // Ignore SecurityExceptions. diff --git a/core/java/android/webkit/CallbackProxy.java b/core/java/android/webkit/CallbackProxy.java index 7c296cc377678a3f83e85be9aa6dc66db2b250fe..cae94c9366bb857e509f2c0027d050c4fc81c1dd 100644 --- a/core/java/android/webkit/CallbackProxy.java +++ b/core/java/android/webkit/CallbackProxy.java @@ -354,12 +354,12 @@ class CallbackProxy extends Handler { case SAVE_PASSWORD: Bundle bundle = msg.getData(); - String host = bundle.getString("host"); + String schemePlusHost = bundle.getString("host"); String username = bundle.getString("username"); String password = bundle.getString("password"); // If the client returned false it means that the notify message // will not be sent and we should notify WebCore ourselves. - if (!mWebView.onSavePassword(host, username, password, + if (!mWebView.onSavePassword(schemePlusHost, username, password, (Message) msg.obj)) { synchronized (this) { notify(); @@ -700,8 +700,8 @@ class CallbackProxy extends Handler { // functions just need to operate within the UI thread. //-------------------------------------------------------------------------- - public boolean onSavePassword(String host, String username, String password, - Message resumeMsg) { + public boolean onSavePassword(String schemePlusHost, String username, + String password, Message resumeMsg) { // resumeMsg should be null at this point because we want to create it // within the CallbackProxy. if (Config.DEBUG) { @@ -711,7 +711,7 @@ class CallbackProxy extends Handler { Message msg = obtainMessage(SAVE_PASSWORD, resumeMsg); Bundle bundle = msg.getData(); - bundle.putString("host", host); + bundle.putString("host", schemePlusHost); bundle.putString("username", username); bundle.putString("password", password); synchronized (this) { diff --git a/core/java/android/webkit/CookieManager.java b/core/java/android/webkit/CookieManager.java index 176471f2931b50405f0d8ca981fdcdf74a09616e..00b17d21f1f3ae14aaf06934ae77226520571d66 100644 --- a/core/java/android/webkit/CookieManager.java +++ b/core/java/android/webkit/CookieManager.java @@ -151,13 +151,34 @@ public final class CookieManager { } boolean domainMatch(String urlHost) { - return urlHost.equals(domain) || - (domain.startsWith(".") && - urlHost.endsWith(domain.substring(1))); + if (domain.startsWith(".")) { + if (urlHost.endsWith(domain.substring(1))) { + int len = domain.length(); + int urlLen = urlHost.length(); + if (urlLen > len - 1) { + // make sure bar.com doesn't match .ar.com + return urlHost.charAt(urlLen - len) == PERIOD; + } + return true; + } + return false; + } else { + // exact match if domain is not leading w/ dot + return urlHost.equals(domain); + } } boolean pathMatch(String urlPath) { - return urlPath.startsWith (path); + if (urlPath.startsWith(path)) { + int len = path.length(); + int urlLen = urlPath.length(); + if (urlLen > len) { + // make sure /wee doesn't match /we + return urlPath.charAt(len) == PATH_DELIM; + } + return true; + } + return false; } public String toString() { @@ -232,7 +253,7 @@ public final class CookieManager { * a system private class. */ public synchronized void setCookie(WebAddress uri, String value) { - if (value != null && value.length() > 4096) { + if (value != null && value.length() > MAX_COOKIE_LENGTH) { return; } if (!mAcceptCookie || uri == null) { @@ -246,25 +267,19 @@ public final class CookieManager { if (hostAndPath == null) { return; } + + // For default path, when setting a cookie, the spec says: + //Path: Defaults to the path of the request URL that generated the + // Set-Cookie response, up to, but not including, the + // right-most /. + if (hostAndPath[1].length() > 1) { + int index = hostAndPath[1].lastIndexOf(PATH_DELIM); + hostAndPath[1] = hostAndPath[1].substring(0, + index > 0 ? index : index + 1); + } ArrayList cookies = null; try { - /* Google is setting cookies like the following to detect whether - * a browser supports cookie. We need to skip the leading "www" for - * the default host. Otherwise the second cookie will make the first - * cookie expired. - * - * url: https://www.google.com/accounts/ServiceLoginAuth - * value: LSID=xxxxxxxxxxxxx;Path=/accounts; - * Expires=Tue, 13-Mar-2018 01:41:39 GMT - * - * url: https://www.google.com/accounts/ServiceLoginAuth - * value:LSID=EXPIRED;Domain=www.google.com;Path=/accounts; - * Expires=Mon, 01-Jan-1990 00:00:00 GMT - */ - if (hostAndPath[0].startsWith("www.")) { - hostAndPath[0] = hostAndPath[0].substring(3); - } cookies = parseCookie(hostAndPath[0], hostAndPath[1], value); } catch (RuntimeException ex) { Log.e(LOGTAG, "parse cookie failed for: " + value); @@ -622,26 +637,17 @@ public final class CookieManager { /* * find cookie path, e.g. for http://www.google.com, the path is "/" - * for http://www.google.com/lab/, the path is "/lab/" - * for http://www.google.com/lab/foo, the path is "/lab/" - * for http://www.google.com/lab?hl=en, the path is "/lab/" - * for http://www.google.com/lab.asp?hl=en, the path is "/" + * for http://www.google.com/lab/, the path is "/lab" + * for http://www.google.com/lab/foo, the path is "/lab/foo" + * for http://www.google.com/lab?hl=en, the path is "/lab" + * for http://www.google.com/lab.asp?hl=en, the path is "/lab.asp" * Note: the path from URI has at least one "/" + * See: + * http://www.unix.com.ua/rfc/rfc2109.html */ index = ret[1].indexOf(QUESTION_MARK); if (index != -1) { ret[1] = ret[1].substring(0, index); - if (ret[1].charAt(ret[1].length() - 1) != PATH_DELIM) { - index = ret[1].lastIndexOf(PATH_DELIM); - if (ret[1].lastIndexOf('.') > index) { - ret[1] = ret[1].substring(0, index + 1); - } else { - ret[1] += PATH_DELIM; - } - } - } else if (ret[1].charAt(ret[1].length() - 1) != PATH_DELIM) { - ret[1] = ret[1].substring(0, - ret[1].lastIndexOf(PATH_DELIM) + 1); } return ret; } else @@ -687,10 +693,6 @@ public final class CookieManager { String cookieString) { ArrayList ret = new ArrayList(); - // domain needs at least two PERIOD, - if (host.indexOf(PERIOD) == host.lastIndexOf(PERIOD)) { - host = PERIOD + host; - } int index = 0; int length = cookieString.length(); while (true) { @@ -841,15 +843,14 @@ public final class CookieManager { "illegal format for max-age: " + value); } } else if (name.equals(PATH)) { - // make sure path ends with PATH_DELIM - if (value.length() > 1 && - value.charAt(value.length() - 1) != PATH_DELIM) { - cookie.path = value + PATH_DELIM; - } else { - cookie.path = value; - } + cookie.path = value; } else if (name.equals(DOMAIN)) { int lastPeriod = value.lastIndexOf(PERIOD); + if (lastPeriod == 0) { + // disallow cookies set for TLDs like [.com] + cookie.domain = null; + continue; + } try { Integer.parseInt(value.substring(lastPeriod + 1)); // no wildcard for ip address match @@ -862,15 +863,22 @@ public final class CookieManager { // ignore the exception, value is a host name } value = value.toLowerCase(); - if (value.endsWith(host) || host.endsWith(value)) { - // domain needs at least two PERIOD - if (value.indexOf(PERIOD) == lastPeriod) { - value = PERIOD + value; + if (value.charAt(0) != PERIOD) { + // pre-pended dot to make it as a domain cookie + value = PERIOD + value; + lastPeriod++; + } + if (host.endsWith(value.substring(1))) { + int len = value.length(); + int hostLen = host.length(); + if (hostLen > (len - 1) + && host.charAt(hostLen - len) != PERIOD) { + // make sure the bar.com doesn't match .ar.com + cookie.domain = null; + continue; } // disallow cookies set on ccTLDs like [.co.uk] - int len = value.length(); - if ((value.charAt(0) == PERIOD) - && (len == lastPeriod + 3) + if ((len == lastPeriod + 3) && (len >= 6 && len <= 8)) { String s = value.substring(1, lastPeriod); if (Arrays.binarySearch(BAD_COUNTRY_2LDS, s) >= 0) { @@ -880,7 +888,7 @@ public final class CookieManager { } cookie.domain = value; } else { - // no cross-site cookie + // no cross-site or more specific sub-domain cookie cookie.domain = null; } } diff --git a/core/java/android/webkit/DateSorter.java b/core/java/android/webkit/DateSorter.java index 3dc15c15f90b08fc70a3a1ddd2a15f49162d8320..750403b49817304a0ea76bf214e52f2e9692707c 100644 --- a/core/java/android/webkit/DateSorter.java +++ b/core/java/android/webkit/DateSorter.java @@ -17,7 +17,7 @@ package android.webkit; import android.content.Context; -import android.util.Log; +import android.content.res.Resources; import java.util.Calendar; import java.util.Date; @@ -40,6 +40,8 @@ public class DateSorter { private long [] mBins = new long[DAY_COUNT]; private String [] mLabels = new String[DAY_COUNT]; + + private static final int NUM_DAYS_AGO = 5; Date mDate = new Date(); Calendar mCal = Calendar.getInstance(); @@ -48,6 +50,7 @@ public class DateSorter { * @param context Application context */ public DateSorter(Context context) { + Resources resources = context.getResources(); Calendar c = Calendar.getInstance(); beginningOfDay(c); @@ -56,9 +59,9 @@ public class DateSorter { mBins[0] = c.getTimeInMillis(); // Today c.roll(Calendar.DAY_OF_YEAR, -1); mBins[1] = c.getTimeInMillis(); // Yesterday - c.roll(Calendar.DAY_OF_YEAR, -4); + c.roll(Calendar.DAY_OF_YEAR, -(NUM_DAYS_AGO - 1)); mBins[2] = c.getTimeInMillis(); // Five days ago - c.roll(Calendar.DAY_OF_YEAR, 5); // move back to today + c.roll(Calendar.DAY_OF_YEAR, NUM_DAYS_AGO); // move back to today c.roll(Calendar.MONTH, -1); mBins[3] = c.getTimeInMillis(); // One month ago c.roll(Calendar.MONTH, -1); @@ -67,14 +70,14 @@ public class DateSorter { // build labels mLabels[0] = context.getText(com.android.internal.R.string.today).toString(); mLabels[1] = context.getText(com.android.internal.R.string.yesterday).toString(); - mLabels[2] = context.getString(com.android.internal.R.string.daysDurationPastPlural, 5); - mLabels[3] = context.getText(com.android.internal.R.string.oneMonthDurationPast).toString(); - StringBuilder sb = new StringBuilder(); - sb.append(context.getText(com.android.internal.R.string.before)).append(" "); - sb.append(context.getText(com.android.internal.R.string.oneMonthDurationPast)); - mLabels[4] = sb.toString(); - + int resId = com.android.internal.R.plurals.num_days_ago; + String format = resources.getQuantityString(resId, NUM_DAYS_AGO); + mLabels[2] = String.format(format, NUM_DAYS_AGO); + + mLabels[3] = context.getText(com.android.internal.R.string.oneMonthDurationPast).toString(); + mLabels[4] = context.getText(com.android.internal.R.string.beforeOneMonthDurationPast) + .toString(); } /** diff --git a/core/java/android/webkit/FileLoader.java b/core/java/android/webkit/FileLoader.java index 6696bae967db7fbf6cc2513bfe5aaa405672a28a..10343b2c0e24157a8c4eda9cc911a4c4d0638536 100644 --- a/core/java/android/webkit/FileLoader.java +++ b/core/java/android/webkit/FileLoader.java @@ -16,6 +16,8 @@ package android.webkit; +import com.android.internal.R; + import android.content.Context; import android.content.res.AssetManager; import android.net.http.EventHandler; @@ -35,6 +37,7 @@ class FileLoader extends StreamLoader { private String mPath; // Full path to the file to load private Context mContext; // Application context, used for asset loads private boolean mIsAsset; // Indicates if the load is an asset or not + private boolean mAllowFileAccess; // Allow/block file system access /** * Construct a FileLoader with the file URL specified as the content @@ -44,12 +47,15 @@ class FileLoader extends StreamLoader { * @param loadListener LoadListener to pass the content to * @param context Context to use to access the asset. * @param asset true if url points to an asset. + * @param allowFileAccess true if this WebView is allowed to access files + * on the file system. */ FileLoader(String url, LoadListener loadListener, Context context, - boolean asset) { + boolean asset, boolean allowFileAccess) { super(loadListener); mIsAsset = asset; mContext = context; + mAllowFileAccess = allowFileAccess; // clean the Url int index = url.indexOf('?'); @@ -73,35 +79,27 @@ class FileLoader extends StreamLoader { mDataStream = mContext.getAssets().open(mPath, AssetManager.ACCESS_STREAMING); } else { - mHandler.error(EventHandler.FILE_ERROR, - mContext.getString( - com.android.internal.R.string.httpErrorFileNotFound)); - return false; -/* - if (!mPath.startsWith( - Environment.getExternalStorageDirectory().getPath())) { + if (!mAllowFileAccess) { mHandler.error(EventHandler.FILE_ERROR, - mContext.getString( - com.android.internal.R.string.httpErrorFileNotFound)); + mContext.getString(R.string.httpErrorFileNotFound)); return false; } + mDataStream = new FileInputStream(mPath); mContentLength = (new File(mPath)).length(); -*/ } mHandler.status(1, 1, 0, "OK"); } catch (java.io.FileNotFoundException ex) { mHandler.error( EventHandler.FILE_NOT_FOUND_ERROR, - mContext.getString(com.android.internal.R.string.httpErrorFileNotFound) + + mContext.getString(R.string.httpErrorFileNotFound) + " " + ex.getMessage()); return false; } catch (java.io.IOException ex) { mHandler.error(EventHandler.FILE_ERROR, - mContext.getString( - com.android.internal.R.string.httpErrorFileNotFound) + + mContext.getString(R.string.httpErrorFileNotFound) + " " + ex.getMessage()); return false; } @@ -121,10 +119,13 @@ class FileLoader extends StreamLoader { * @param loadListener LoadListener to pass the content to * @param context Context to use to access the asset. * @param asset true if url points to an asset. + * @param allowFileAccess true if this FileLoader can load files from the + * file system. */ public static void requestUrl(String url, LoadListener loadListener, - Context context, boolean asset) { - FileLoader loader = new FileLoader(url, loadListener, context, asset); + Context context, boolean asset, boolean allowFileAccess) { + FileLoader loader = new FileLoader(url, loadListener, context, asset, + allowFileAccess); loader.load(); } diff --git a/core/java/android/webkit/FrameLoader.java b/core/java/android/webkit/FrameLoader.java index ebfebd07df87b573257f8c67a1c33b999dd4ad02..7a3bbe6ca32ba2afb0ae12441b394b1c7307d319 100644 --- a/core/java/android/webkit/FrameLoader.java +++ b/core/java/android/webkit/FrameLoader.java @@ -28,16 +28,16 @@ import java.util.Map; class FrameLoader { - protected LoadListener mListener; - protected Map mHeaders; - protected String mMethod; - protected String mPostData; - protected boolean mIsHighPriority; - protected Network mNetwork; - protected int mCacheMode; - protected String mReferrer; - protected String mUserAgent; - protected String mContentType; + private final LoadListener mListener; + private final String mMethod; + private final boolean mIsHighPriority; + private final WebSettings mSettings; + private Map mHeaders; + private byte[] mPostData; + private Network mNetwork; + private int mCacheMode; + private String mReferrer; + private String mContentType; private static final int URI_PROTOCOL = 0x100; @@ -53,43 +53,14 @@ class FrameLoader { private static final String LOGTAG = "webkit"; - /* - * Construct the Accept_Language once. If the user changes language, then - * the phone will be rebooted. - */ - private static String ACCEPT_LANGUAGE; - static { - // Set the accept-language to the current locale plus US if we are in a - // different locale than US. - java.util.Locale l = java.util.Locale.getDefault(); - ACCEPT_LANGUAGE = ""; - if (l.getLanguage() != null) { - ACCEPT_LANGUAGE += l.getLanguage(); - if (l.getCountry() != null) { - ACCEPT_LANGUAGE += "-" + l.getCountry(); - } - } - if (!l.equals(java.util.Locale.US)) { - ACCEPT_LANGUAGE += ", "; - java.util.Locale us = java.util.Locale.US; - if (us.getLanguage() != null) { - ACCEPT_LANGUAGE += us.getLanguage(); - if (us.getCountry() != null) { - ACCEPT_LANGUAGE += "-" + us.getCountry(); - } - } - } - } - - - FrameLoader(LoadListener listener, String userAgent, + FrameLoader(LoadListener listener, WebSettings settings, String method, boolean highPriority) { mListener = listener; mHeaders = null; mMethod = method; mIsHighPriority = highPriority; mCacheMode = WebSettings.LOAD_NORMAL; - mUserAgent = userAgent; + mSettings = settings; } public void setReferrer(String ref) { @@ -97,7 +68,7 @@ class FrameLoader { if (URLUtil.isNetworkUrl(ref)) mReferrer = ref; } - public void setPostData(String postData) { + public void setPostData(byte[] postData) { mPostData = postData; } @@ -140,12 +111,15 @@ class FrameLoader { } if (URLUtil.isNetworkUrl(url)){ + if (mSettings.getBlockNetworkLoads()) { + mListener.error(EventHandler.ERROR_BAD_URL, + mListener.getContext().getString( + com.android.internal.R.string.httpErrorBadUrl)); + return false; + } mNetwork = Network.getInstance(mListener.getContext()); - return handleHTTPLoad(false); - } else if (URLUtil.isCookielessProxyUrl(url)) { - mNetwork = Network.getInstance(mListener.getContext()); - return handleHTTPLoad(true); - } else if (handleLocalFile(url, mListener)) { + return handleHTTPLoad(); + } else if (handleLocalFile(url, mListener, mSettings)) { return true; } if (Config.LOGV) { @@ -160,14 +134,15 @@ class FrameLoader { } /* package */ - static boolean handleLocalFile(String url, LoadListener loadListener) { + static boolean handleLocalFile(String url, LoadListener loadListener, + WebSettings settings) { if (URLUtil.isAssetUrl(url)) { FileLoader.requestUrl(url, loadListener, loadListener.getContext(), - true); + true, settings.getAllowFileAccess()); return true; } else if (URLUtil.isFileUrl(url)) { FileLoader.requestUrl(url, loadListener, loadListener.getContext(), - false); + false, settings.getAllowFileAccess()); return true; } else if (URLUtil.isContentUrl(url)) { // Send the raw url to the ContentLoader because it will do a @@ -186,21 +161,12 @@ class FrameLoader { return false; } - protected boolean handleHTTPLoad(boolean proxyUrl) { + private boolean handleHTTPLoad() { if (mHeaders == null) { mHeaders = new HashMap(); } populateStaticHeaders(); - - if (!proxyUrl) { - // Don't add private information if this is a proxy load, ie don't - // add cookies and authentication - populateHeaders(); - } else { - // If this is a proxy URL, fix it to be a network load - mListener.setUrl("http://" - + mListener.url().substring(URLUtil.PROXY_BASE.length())); - } + populateHeaders(); // response was handled by UrlIntercept, don't issue HTTP request if (handleUrlIntercept()) return true; @@ -246,7 +212,7 @@ class FrameLoader { * This function is used by handleUrlInterecpt and handleCache to * setup a load from the byte stream in a CacheResult. */ - protected void startCacheLoad(CacheResult result) { + private void startCacheLoad(CacheResult result) { if (Config.LOGV) { Log.v(LOGTAG, "FrameLoader: loading from cache: " + mListener.url()); @@ -264,7 +230,7 @@ class FrameLoader { * * Returns true if the response was handled by UrlIntercept. */ - protected boolean handleUrlIntercept() { + private boolean handleUrlIntercept() { // Check if the URL can be served from UrlIntercept. If // successful, return the data just like a cache hit. CacheResult result = UrlInterceptRegistry.getSurrogate( @@ -284,7 +250,7 @@ class FrameLoader { * correctly. * Returns true if the response was handled from the cache */ - protected boolean handleCache() { + private boolean handleCache() { switch (mCacheMode) { // This mode is normally used for a reload, it instructs the http // loader to not use the cached content. @@ -357,11 +323,12 @@ class FrameLoader { } mHeaders.put("Accept-Charset", "utf-8, iso-8859-1, utf-16, *;q=0.7"); - if (ACCEPT_LANGUAGE.length() > 0) { - mHeaders.put("Accept-Language", ACCEPT_LANGUAGE); + String acceptLanguage = mSettings.getAcceptLanguage(); + if (acceptLanguage.length() > 0) { + mHeaders.put("Accept-Language", acceptLanguage); } - - mHeaders.put("User-Agent", mUserAgent); + + mHeaders.put("User-Agent", mSettings.getUserAgentString()); } /** diff --git a/core/java/android/webkit/HttpDateTime.java b/core/java/android/webkit/HttpDateTime.java index b22f2ba294a06d62c137f62d9570b380e73ab1ea..c6ec2d27cfee4ed3520915d262ccbfef44ad0991 100644 --- a/core/java/android/webkit/HttpDateTime.java +++ b/core/java/android/webkit/HttpDateTime.java @@ -16,7 +16,7 @@ package android.webkit; -import android.pim.Time; +import android.text.format.Time; import java.util.Calendar; import java.util.regex.Matcher; diff --git a/core/java/android/webkit/JWebCoreJavaBridge.java b/core/java/android/webkit/JWebCoreJavaBridge.java index 1cfea99d0443285c09989443f49909cc44b95386..a0049ac982e2576c3aa465f06b3b97d9f708c913 100644 --- a/core/java/android/webkit/JWebCoreJavaBridge.java +++ b/core/java/android/webkit/JWebCoreJavaBridge.java @@ -191,4 +191,5 @@ final class JWebCoreJavaBridge extends Handler { private native void nativeFinalize(); private native void sharedTimerFired(); private native void setDeferringTimers(boolean defer); + public native void setNetworkOnLine(boolean online); } diff --git a/core/java/android/webkit/LoadListener.java b/core/java/android/webkit/LoadListener.java index 86947a250366cad38db2d3b8fc789f19c5d6002b..c45ab29fa8c4a5f5066cd17253682218714b91ee 100644 --- a/core/java/android/webkit/LoadListener.java +++ b/core/java/android/webkit/LoadListener.java @@ -99,7 +99,7 @@ class LoadListener extends Handler implements EventHandler { // cache. It is needed if the cache returns a redirect private String mMethod; private Map mRequestHeaders; - private String mPostData; + private byte[] mPostData; private boolean mIsHighPriority; // Flag to indicate that this load is synchronous. private boolean mSynchronous; @@ -220,7 +220,8 @@ class LoadListener extends Handler implements EventHandler { */ Message contMsg = obtainMessage(MSG_LOCATION_CHANGED); Message stopMsg = obtainMessage(MSG_CONTENT_FINISHED); - //TODO, need to call mCallbackProxy and request UI. + mBrowserFrame.getCallbackProxy().onFormResubmission( + stopMsg, contMsg); break; } @@ -286,15 +287,16 @@ class LoadListener extends Handler implements EventHandler { if (newMimeType != null) { mMimeType = newMimeType; } - } else if (mMimeType.equalsIgnoreCase("text/vnd.wap.wml") || - mMimeType. - equalsIgnoreCase("application/vnd.wap.xhtml+xml")) { + } else if (mMimeType.equalsIgnoreCase("text/vnd.wap.wml")) { // As we don't support wml, render it as plain text mMimeType = "text/plain"; } else { // XXX: Until the servers send us either correct xhtml or // text/html, treat application/xhtml+xml as text/html. - if (mMimeType.equalsIgnoreCase("application/xhtml+xml")) { + // It seems that xhtml+xml and vnd.wap.xhtml+xml mime + // subtypes are used interchangeably. So treat them the same. + if (mMimeType.equalsIgnoreCase("application/xhtml+xml") || + mMimeType.equals("application/vnd.wap.xhtml+xml")) { mMimeType = "text/html"; } } @@ -527,23 +529,21 @@ class LoadListener extends Handler implements EventHandler { } else { sendMessageInternal(obtainMessage(MSG_LOCATION_CHANGED)); } - - break; + return; case HTTP_AUTH: case HTTP_PROXY_AUTH: + // According to rfc2616, the response for HTTP_AUTH must include + // WWW-Authenticate header field and the response for + // HTTP_PROXY_AUTH must include Proxy-Authenticate header field. if (mAuthHeader != null && (Network.getInstance(mContext).isValidProxySet() || !mAuthHeader.isProxy())) { Network.getInstance(mContext).handleAuthRequest(this); - } else { - final int stringId = - com.android.internal.R.string.httpErrorUnsupportedAuthScheme; - error(EventHandler.ERROR_UNSUPPORTED_AUTH_SCHEME, - getContext().getText(stringId).toString()); + return; } - break; - + break; // use default + case HTTP_NOT_MODIFIED: // Server could send back NOT_MODIFIED even if we didn't // ask for it, so make sure we have a valid CacheLoader @@ -554,16 +554,18 @@ class LoadListener extends Handler implements EventHandler { if (Config.LOGV) { Log.v(LOGTAG, "LoadListener cache load url=" + url()); } - break; - } // Fall through to default if there is no CacheLoader + return; + } + break; // use default case HTTP_NOT_FOUND: // Not an error, the server can send back content. default: - sendMessageInternal(obtainMessage(MSG_CONTENT_FINISHED)); - detachRequestHandle(); break; } + + sendMessageInternal(obtainMessage(MSG_CONTENT_FINISHED)); + detachRequestHandle(); } /** @@ -725,7 +727,7 @@ class LoadListener extends Handler implements EventHandler { * @param isHighPriority */ void setRequestData(String method, Map headers, - String postData, boolean isHighPriority) { + byte[] postData, boolean isHighPriority) { mMethod = method; mRequestHeaders = headers; mPostData = postData; @@ -878,37 +880,16 @@ class LoadListener extends Handler implements EventHandler { int statusCode = mStatusCode == HTTP_NOT_MODIFIED ? HTTP_OK : mStatusCode; // pass content-type content-length and content-encoding - int nativeResponse = nativeCreateResponse(mUrl, statusCode, mStatusText, + final int nativeResponse = nativeCreateResponse( + mUrl, statusCode, mStatusText, mMimeType, mContentLength, mEncoding, mCacheResult == null ? 0 : mCacheResult.expires / 1000); if (mHeaders != null) { - // "content-disposition", - String value = mHeaders.getContentDisposition(); - if (value != null) { - nativeSetResponseHeader(nativeResponse, - Headers.CONTENT_DISPOSITION, value); - } - - // location - value = mHeaders.getLocation(); - if (value != null) { - nativeSetResponseHeader(nativeResponse, - Headers.LOCATION, value); - } - - // refresh (paypal.com are using this) - value = mHeaders.getRefresh(); - if (value != null) { - nativeSetResponseHeader(nativeResponse, - Headers.REFRESH, value); - } - - // Content-Type - value = mHeaders.getContentType(); - if (value != null) { - nativeSetResponseHeader(nativeResponse, - Headers.CONTENT_TYPE, value); - } + mHeaders.getHeaders(new Headers.HeaderCallback() { + public void header(String name, String value) { + nativeSetResponseHeader(nativeResponse, name, value); + } + }); } return nativeResponse; } @@ -1048,7 +1029,6 @@ class LoadListener extends Handler implements EventHandler { cancel(); return; } else if (!URLUtil.isNetworkUrl(redirectTo)) { - cancel(); final String text = mContext .getString(com.android.internal.R.string.open_permission_deny) + "\n" + redirectTo; @@ -1250,7 +1230,12 @@ class LoadListener extends Handler implements EventHandler { */ void setUrl(String url) { if (url != null) { - mUrl = URLUtil.stripAnchor(url); + if (URLUtil.isDataUrl(url)) { + // Don't strip anchor as that is a valid part of the URL + mUrl = url; + } else { + mUrl = URLUtil.stripAnchor(url); + } mUri = null; if (URLUtil.isNetworkUrl(mUrl)) { try { diff --git a/core/java/android/webkit/MimeTypeMap.java b/core/java/android/webkit/MimeTypeMap.java index 2700aa510900e6e7d72ce70d9e46de64f607c840..85cb8c0a37774d888062d184b5f5ed97228dcfe5 100644 --- a/core/java/android/webkit/MimeTypeMap.java +++ b/core/java/android/webkit/MimeTypeMap.java @@ -65,7 +65,7 @@ public /* package */ class MimeTypeMap { // if the filename contains special characters, we don't // consider it valid for our matching purposes: if (filename.length() > 0 && - Pattern.matches("[a-zA-Z_0-9\\.\\-]+", filename)) { + Pattern.matches("[a-zA-Z_0-9\\.\\-\\(\\)]+", filename)) { int dotPos = filename.lastIndexOf('.'); if (0 <= dotPos) { return filename.substring(dotPos + 1); diff --git a/core/java/android/webkit/Network.java b/core/java/android/webkit/Network.java index ea42e587f9479f2b9d2f77cf51f04fc9e34c6925..74622b3b3883e886bd52a2fb3292396176294082 100644 --- a/core/java/android/webkit/Network.java +++ b/core/java/android/webkit/Network.java @@ -155,7 +155,7 @@ class Network { */ public boolean requestURL(String method, Map headers, - String postData, + byte [] postData, LoadListener loader, boolean isHighPriority) { @@ -178,9 +178,8 @@ class Network { InputStream bodyProvider = null; int bodyLength = 0; if (postData != null) { - byte[] data = postData.getBytes(); - bodyLength = data.length; - bodyProvider = new ByteArrayInputStream(data); + bodyLength = postData.length; + bodyProvider = new ByteArrayInputStream(postData); } RequestQueue q = mRequestQueue; diff --git a/core/java/android/webkit/TextDialog.java b/core/java/android/webkit/TextDialog.java index 95209c7c54fa468b306ee6bcf61b67d6087b807b..4e9370c898c296aeaab92d2f2724b6ee50a5f97e 100644 --- a/core/java/android/webkit/TextDialog.java +++ b/core/java/android/webkit/TextDialog.java @@ -124,6 +124,10 @@ import android.widget.AutoCompleteTextView; int flags = paint.getFlags() | Paint.SUBPIXEL_TEXT_FLAG | Paint.ANTI_ALIAS_FLAG & ~Paint.DEV_KERN_TEXT_FLAG; paint.setFlags(flags); + // Set the text color to black, regardless of the theme. This ensures + // that other applications that use embedded WebViews will properly + // display the text in textfields. + setTextColor(Color.BLACK); } @Override @@ -395,6 +399,7 @@ import android.widget.AutoCompleteTextView; * focus to the host. */ /* package */ void remove() { + mHandler.removeMessages(LONGPRESS); mWebView.removeView(this); mWebView.requestFocus(); } @@ -532,6 +537,7 @@ import android.widget.AutoCompleteTextView; mPreChange = text.toString(); Editable edit = (Editable) getText(); edit.replace(0, edit.length(), text); + updateCachedTextfield(); } /** diff --git a/core/java/android/webkit/URLUtil.java b/core/java/android/webkit/URLUtil.java index 43666c166b9002a7a0099c7b2f8662e9fbfad64c..0e8144edd60a20ed638df09994b5a5643e0717f9 100644 --- a/core/java/android/webkit/URLUtil.java +++ b/core/java/android/webkit/URLUtil.java @@ -145,6 +145,7 @@ public final class URLUtil { /** * @return True iff the url is an proxy url to allow cookieless network * requests from a file url. + * @deprecated Cookieless proxy is no longer supported. */ public static boolean isCookielessProxyUrl(String url) { return (null != url) && url.startsWith(PROXY_BASE); diff --git a/core/java/android/webkit/WebBackForwardList.java b/core/java/android/webkit/WebBackForwardList.java index c86b21d18e7434849eceb291f040f8149a8c3db2..9dea5ecbecd44e8940d34b3c4398a165aff7acee 100644 --- a/core/java/android/webkit/WebBackForwardList.java +++ b/core/java/android/webkit/WebBackForwardList.java @@ -133,7 +133,7 @@ public class WebBackForwardList implements Cloneable, Serializable { } /* Remove the item at the given index. Called by JNI only. */ - private void removeHistoryItem(int index) { + private synchronized void removeHistoryItem(int index) { // XXX: This is a special case. Since the callback is only triggered // when removing the first item, we can assert that the index is 0. // This lets us change the current index without having to query the diff --git a/core/java/android/webkit/WebHistoryItem.java b/core/java/android/webkit/WebHistoryItem.java index 5570af862bd73e50f96c6cca1a5e4667a5b94983..a408e0670d087eba4a00651d3b8e7a6bb074128f 100644 --- a/core/java/android/webkit/WebHistoryItem.java +++ b/core/java/android/webkit/WebHistoryItem.java @@ -33,6 +33,8 @@ public class WebHistoryItem implements Cloneable { private String mTitle; // The base url of this item. private String mUrl; + // The original requested url of this item. + private String mOriginalUrl; // The favicon for this item. private Bitmap mFavicon; // The pre-flattened data used for saving the state. @@ -94,6 +96,18 @@ public class WebHistoryItem implements Cloneable { return mUrl; } + /** + * Return the original url of this history item. This was the requested + * url, the final url may be different as there might have been + * redirects while loading the site. + * @return The original url of this history item. + * + * @hide pending API Council approval + */ + public String getOriginalUrl() { + return mOriginalUrl; + } + /** * Return the document title of this history item. * @return The document title of this history item. @@ -154,8 +168,10 @@ public class WebHistoryItem implements Cloneable { private native void inflate(int nativeFrame, byte[] data); /* Called by jni when the item is updated */ - private void update(String url, String title, Bitmap favicon, byte[] data) { + private void update(String url, String originalUrl, String title, + Bitmap favicon, byte[] data) { mUrl = url; + mOriginalUrl = originalUrl; mTitle = title; mFavicon = favicon; mFlattenedData = data; diff --git a/core/java/android/webkit/WebSettings.java b/core/java/android/webkit/WebSettings.java index de64b30040b33898dfe275e2a05d09f3d84a5f79..1a7c4ff3647763db403b45820e43a2ef39a5f939 100644 --- a/core/java/android/webkit/WebSettings.java +++ b/core/java/android/webkit/WebSettings.java @@ -20,6 +20,8 @@ import android.content.Context; import android.os.Build; import android.os.Handler; import android.os.Message; +import java.lang.SecurityException; +import android.content.pm.PackageManager; import java.util.Locale; @@ -111,6 +113,7 @@ public class WebSettings { // retrieve the values. After setXXX, postSync() needs to be called. // XXX: The default values need to match those in WebSettings.cpp private LayoutAlgorithm mLayoutAlgorithm = LayoutAlgorithm.NARROW_COLUMNS; + private Context mContext; private TextSize mTextSize = TextSize.NORMAL; private String mStandardFontFamily = "sans-serif"; private String mFixedFontFamily = "monospace"; @@ -119,7 +122,9 @@ public class WebSettings { private String mCursiveFontFamily = "cursive"; private String mFantasyFontFamily = "fantasy"; private String mDefaultTextEncoding = "Latin-1"; - private String mUserAgent = ANDROID_USERAGENT; + private String mUserAgent; + private boolean mUseDefaultUserAgent; + private String mAcceptLanguage; private String mPluginsPath = ""; private int mMinimumFontSize = 8; private int mMinimumLogicalFontSize = 8; @@ -127,12 +132,14 @@ public class WebSettings { private int mDefaultFixedFontSize = 13; private boolean mLoadsImagesAutomatically = true; private boolean mBlockNetworkImage = false; + private boolean mBlockNetworkLoads = false; private boolean mJavaScriptEnabled = false; private boolean mPluginsEnabled = false; private boolean mJavaScriptCanOpenWindowsAutomatically = false; private boolean mUseDoubleTree = false; private boolean mUseWideViewport = false; private boolean mSupportMultipleWindows = false; + private boolean mShrinksStandaloneImagesToFit = false; // Don't need to synchronize the get/set methods as they // are basic types, also none of these values are used in // native WebCore code. @@ -144,6 +151,7 @@ public class WebSettings { private boolean mNeedInitialFocus = true; private boolean mNavDump = false; private boolean mSupportZoom = true; + private boolean mAllowFileAccess = true; // Class to handle messages before WebCore is ready. private class EventHandler { @@ -212,57 +220,112 @@ public class WebSettings { // User agent strings. private static final String DESKTOP_USERAGENT = - "Mozilla/5.0 (Macintosh; U; Intel Mac OS X; en) AppleWebKit/522+ " + - "(KHTML, like Gecko) Safari/419.3"; - private static final String IPHONE_USERAGENT = "Mozilla/5.0 (iPhone; U; " + - "CPU like Mac OS X; en) AppleWebKit/420+ (KHTML, like Gecko) " + - "Version/3.0 Mobile/1A543 Safari/419.3"; - private static String ANDROID_USERAGENT; - + "Mozilla/5.0 (Macintosh; U; Intel Mac OS X; en)" + + " AppleWebKit/528.5+ (KHTML, like Gecko) Version/3.1.2" + + " Safari/525.20.1"; + private static final String IPHONE_USERAGENT = + "Mozilla/5.0 (iPhone; U; CPU iPhone 2_1 like Mac OS X; en)" + + " AppleWebKit/528.5+ (KHTML, like Gecko) Version/3.1.2" + + " Mobile/5F136 Safari/525.20.1"; + private static Locale sLocale; + private static Object sLockForLocaleSettings; + /** * Package constructor to prevent clients from creating a new settings * instance. */ - WebSettings(Context context) { - if (ANDROID_USERAGENT == null) { - StringBuffer arg = new StringBuffer(); - // Add version - final String version = Build.VERSION.RELEASE; - if (version.length() > 0) { - arg.append(version); - } else { - // default to "1.0" - arg.append("1.0"); + WebSettings(Context context) { + mEventHandler = new EventHandler(); + mContext = context; + + if (sLockForLocaleSettings == null) { + sLockForLocaleSettings = new Object(); + sLocale = Locale.getDefault(); + } + mAcceptLanguage = getCurrentAcceptLanguage(); + mUserAgent = getCurrentUserAgent(); + mUseDefaultUserAgent = true; + + verifyNetworkAccess(); + } + + /** + * Looks at sLocale and returns current AcceptLanguage String. + * @return Current AcceptLanguage String. + */ + private String getCurrentAcceptLanguage() { + Locale locale; + synchronized(sLockForLocaleSettings) { + locale = sLocale; + } + StringBuffer buffer = new StringBuffer(); + final String language = locale.getLanguage(); + if (language != null) { + buffer.append(language); + final String country = locale.getCountry(); + if (country != null) { + buffer.append("-"); + buffer.append(country); } - arg.append("; "); - // Initialize the mobile user agent with the default locale. - final Locale l = Locale.getDefault(); - final String language = l.getLanguage(); - if (language != null) { - arg.append(language.toLowerCase()); - final String country = l.getCountry(); + } + if (!locale.equals(Locale.US)) { + buffer.append(", "); + java.util.Locale us = Locale.US; + if (us.getLanguage() != null) { + buffer.append(us.getLanguage()); + final String country = us.getCountry(); if (country != null) { - arg.append("-"); - arg.append(country.toLowerCase()); + buffer.append("-"); + buffer.append(country); } - } else { - // default to "en" - arg.append("en"); } - // Add device name - final String device = Build.DEVICE; - if (device.length() > 0) { - arg.append("; "); - arg.append(device); + } + + return buffer.toString(); + } + + /** + * Looks at sLocale and mContext and returns current UserAgent String. + * @return Current UserAgent String. + */ + private synchronized String getCurrentUserAgent() { + Locale locale; + synchronized(sLockForLocaleSettings) { + locale = sLocale; + } + StringBuffer buffer = new StringBuffer(); + // Add version + final String version = Build.VERSION.RELEASE; + if (version.length() > 0) { + buffer.append(version); + } else { + // default to "1.0" + buffer.append("1.0"); + } + buffer.append("; "); + final String language = locale.getLanguage(); + if (language != null) { + buffer.append(language.toLowerCase()); + final String country = locale.getCountry(); + if (country != null) { + buffer.append("-"); + buffer.append(country.toLowerCase()); } - final String base = context.getResources().getText( - com.android.internal.R.string.web_user_agent).toString(); - ANDROID_USERAGENT = String.format(base, arg); - mUserAgent = ANDROID_USERAGENT; + } else { + // default to "en" + buffer.append("en"); } - mEventHandler = new EventHandler(); + + final String device = Build.DEVICE; + if (device.length() > 0) { + buffer.append("; "); + buffer.append(device); + } + final String base = mContext.getResources().getText( + com.android.internal.R.string.web_user_agent).toString(); + return String.format(base, buffer); } - + /** * Enables dumping the pages navigation cache to a text file. */ @@ -291,6 +354,21 @@ public class WebSettings { return mSupportZoom; } + /** + * Enable or disable file access within WebView. File access is enabled by + * default. + */ + public void setAllowFileAccess(boolean allow) { + mAllowFileAccess = allow; + } + + /** + * Returns true if this WebView supports file access. + */ + public boolean getAllowFileAccess() { + return mAllowFileAccess; + } + /** * Store whether the WebView is saving form data. */ @@ -377,34 +455,48 @@ public class WebSettings { * Tell the WebView about user-agent string. * @param ua 0 if the WebView should use an Android user-agent string, * 1 if the WebView should use a desktop user-agent string. - * 2 if the WebView should use an iPhone user-agent string. + * + * @deprecated Please use setUserAgentString instead. */ + @Deprecated public synchronized void setUserAgent(int ua) { - if (ua == 0 && !ANDROID_USERAGENT.equals(mUserAgent)) { - mUserAgent = ANDROID_USERAGENT; - postSync(); - } else if (ua == 1 && !DESKTOP_USERAGENT.equals(mUserAgent)) { - mUserAgent = DESKTOP_USERAGENT; - postSync(); - } else if (ua == 2 && !IPHONE_USERAGENT.equals(mUserAgent)) { - mUserAgent = IPHONE_USERAGENT; - postSync(); + String uaString = null; + if (ua == 1) { + if (DESKTOP_USERAGENT.equals(mUserAgent)) { + return; // do nothing + } else { + uaString = DESKTOP_USERAGENT; + } + } else if (ua == 2) { + if (IPHONE_USERAGENT.equals(mUserAgent)) { + return; // do nothing + } else { + uaString = IPHONE_USERAGENT; + } + } else if (ua != 0) { + return; // do nothing } + setUserAgentString(uaString); } /** * Return user-agent as int * @return int 0 if the WebView is using an Android user-agent string. * 1 if the WebView is using a desktop user-agent string. - * 2 if the WebView is using an iPhone user-agent string. + * -1 if the WebView is using user defined user-agent string. + * + * @deprecated Please use getUserAgentString instead. */ + @Deprecated public synchronized int getUserAgent() { if (DESKTOP_USERAGENT.equals(mUserAgent)) { return 1; } else if (IPHONE_USERAGENT.equals(mUserAgent)) { return 2; + } else if (mUseDefaultUserAgent) { + return 0; } - return 0; + return -1; } /** @@ -706,6 +798,40 @@ public class WebSettings { public synchronized boolean getBlockNetworkImage() { return mBlockNetworkImage; } + + /** + * @hide + * Tell the WebView to block all network load requests. + * @param flag True if the WebView should block all network loads + */ + public synchronized void setBlockNetworkLoads(boolean flag) { + if (mBlockNetworkLoads != flag) { + mBlockNetworkLoads = flag; + verifyNetworkAccess(); + } + } + + /** + * @hide + * Return true if the WebView will block all network loads. + * @return True if the WebView blocks all network loads. + */ + public synchronized boolean getBlockNetworkLoads() { + return mBlockNetworkLoads; + } + + + private void verifyNetworkAccess() { + if (!mBlockNetworkLoads) { + if (mContext.checkPermission("android.permission.INTERNET", + android.os.Process.myPid(), 0) != + PackageManager.PERMISSION_GRANTED) { + throw new SecurityException + ("Permission denied - " + + "application missing INTERNET permission"); + } + } + } /** * Tell the WebView to enable javascript execution. @@ -806,11 +932,69 @@ public class WebSettings { return mDefaultTextEncoding; } - /* Package api to grab the user agent string. */ - /*package*/ synchronized String getUserAgentString() { + /** + * Set the WebView's user-agent string. If the string "ua" is null or empty, + * it will use the system default user-agent string. + */ + public synchronized void setUserAgentString(String ua) { + if (ua == null || ua.length() == 0) { + synchronized(sLockForLocaleSettings) { + Locale currentLocale = Locale.getDefault(); + if (!sLocale.equals(currentLocale)) { + sLocale = currentLocale; + mAcceptLanguage = getCurrentAcceptLanguage(); + } + } + ua = getCurrentUserAgent(); + mUseDefaultUserAgent = true; + } else { + mUseDefaultUserAgent = false; + } + + if (!ua.equals(mUserAgent)) { + mUserAgent = ua; + postSync(); + } + } + + /** + * Return the WebView's user-agent string. + */ + public synchronized String getUserAgentString() { + if (DESKTOP_USERAGENT.equals(mUserAgent) || + IPHONE_USERAGENT.equals(mUserAgent) || + !mUseDefaultUserAgent) { + return mUserAgent; + } + + boolean doPostSync = false; + synchronized(sLockForLocaleSettings) { + Locale currentLocale = Locale.getDefault(); + if (!sLocale.equals(currentLocale)) { + sLocale = currentLocale; + mUserAgent = getCurrentUserAgent(); + mAcceptLanguage = getCurrentAcceptLanguage(); + doPostSync = true; + } + } + if (doPostSync) { + postSync(); + } return mUserAgent; } + /* package api to grab the Accept Language string. */ + /*package*/ synchronized String getAcceptLanguage() { + synchronized(sLockForLocaleSettings) { + Locale currentLocale = Locale.getDefault(); + if (!sLocale.equals(currentLocale)) { + sLocale = currentLocale; + mAcceptLanguage = getCurrentAcceptLanguage(); + } + } + return mAcceptLanguage; + } + /** * Tell the WebView whether it needs to set a node to have focus when * {@link WebView#requestFocus(int, android.graphics.Rect)} is called. @@ -863,6 +1047,20 @@ public class WebSettings { public int getCacheMode() { return mOverrideCacheMode; } + + /** + * If set, webkit alternately shrinks and expands images viewed outside + * of an HTML page to fit the screen. This conflicts with attempts by + * the UI to zoom in and out of an image, so it is set false by default. + * @param shrink Set true to let webkit shrink the standalone image to fit. + * {@hide} + */ + public void setShrinksStandaloneImagesToFit(boolean shrink) { + if (mShrinksStandaloneImagesToFit != shrink) { + mShrinksStandaloneImagesToFit = shrink; + postSync(); + } + } /** * Transfer messages from the queue to the new WebCoreThread. Called from diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java index 6623257d948ca832cf01458669b67ed1bd1b1eab..7467b832affbd190b729f843ac5ddc972744b06c 100644 --- a/core/java/android/webkit/WebView.java +++ b/core/java/android/webkit/WebView.java @@ -56,6 +56,7 @@ import android.view.ViewConfiguration; import android.view.ViewGroup; import android.view.ViewParent; import android.view.ViewTreeObserver; +import android.view.inputmethod.InputMethodManager; import android.webkit.WebViewCore.EventHub; import android.widget.AbsoluteLayout; import android.widget.AdapterView; @@ -94,6 +95,12 @@ public class WebView extends AbsoluteLayout implements ViewTreeObserver.OnGlobalFocusChangeListener, ViewGroup.OnHierarchyChangeListener { + // if AUTO_REDRAW_HACK is true, then the CALL key will toggle redrawing + // the screen all-the-time. Good for profiling our drawing code + static private final boolean AUTO_REDRAW_HACK = false; + // true means redraw the screen all-the-time. Only with AUTO_REDRAW_HACK + private boolean mAutoRedraw; + // keep debugging parameters near the top of the file static final String LOGTAG = "webview"; static final boolean DEBUG = false; @@ -112,7 +119,8 @@ public class WebView extends AbsoluteLayout (com.android.internal.R.id.zoomMagnify); } - public void show(boolean canZoomOut) { + public void show(boolean showZoom, boolean canZoomOut) { + mZoomControls.setVisibility(showZoom ? View.VISIBLE : View.GONE); mZoomMagnify.setVisibility(canZoomOut ? View.VISIBLE : View.GONE); fade(View.VISIBLE, 0.0f, 1.0f); } @@ -210,6 +218,17 @@ public class WebView extends AbsoluteLayout */ private long mLastTouchTime; + /** + * Time of the last time sending touch event to WebViewCore + */ + private long mLastSentTouchTime; + + /** + * The minimum elapsed time before sending another ACTION_MOVE event to + * WebViewCore + */ + private static final int TOUCH_SENT_INTERVAL = 100; + /** * Helper class to get velocity for fling */ @@ -226,6 +245,7 @@ public class WebView extends AbsoluteLayout private static final int TOUCH_SHORTPRESS_MODE = 5; private static final int TOUCH_DOUBLECLICK_MODE = 6; private static final int TOUCH_DONE_MODE = 7; + private static final int TOUCH_SELECT_MODE = 8; // touch mode values specific to scale+scroll private static final int FIRST_SCROLL_ZOOM = 9; private static final int SCROLL_ZOOM_ANIMATION_IN = 9; @@ -234,6 +254,9 @@ public class WebView extends AbsoluteLayout private static final int LAST_SCROLL_ZOOM = 11; // end of touch mode values specific to scale+scroll + // Whether to forward the touch events to WebCore + private boolean mForwardTouchEvents = false; + // If updateTextEntry gets called while we are out of focus, use this // variable to remember to do it next time we gain focus. private boolean mNeedsUpdateTextEntry = false; @@ -337,7 +360,9 @@ public class WebView extends AbsoluteLayout static final int NOTIFY_FOCUS_SET_MSG_ID = 20; static final int MARK_NODE_INVALID_ID = 21; static final int UPDATE_CLIPBOARD = 22; - static final int LONG_PRESS_TRACKBALL = 24; + static final int LONG_PRESS_ENTER = 23; + static final int PREVENT_TOUCH_ID = 24; + static final int WEBCORE_NEED_TOUCH_EVENTS = 25; // width which view is considered to be fully zoomed out static final int ZOOM_OUT_WIDTH = 1024; @@ -524,23 +549,23 @@ public class WebView extends AbsoluteLayout setVerticalScrollBarEnabled(true); } - /* package */ boolean onSavePassword(String host, String username, + /* package */ boolean onSavePassword(String schemePlusHost, String username, String password, final Message resumeMsg) { boolean rVal = false; if (resumeMsg == null) { // null resumeMsg implies saving password silently - mDatabase.setUsernamePassword(host, username, password); + mDatabase.setUsernamePassword(schemePlusHost, username, password); } else { final Message remember = mPrivateHandler.obtainMessage( REMEMBER_PASSWORD); - remember.getData().putString("host", host); + remember.getData().putString("host", schemePlusHost); remember.getData().putString("username", username); remember.getData().putString("password", password); remember.obj = resumeMsg; final Message neverRemember = mPrivateHandler.obtainMessage( NEVER_REMEMBER_PASSWORD); - neverRemember.getData().putString("host", host); + neverRemember.getData().putString("host", schemePlusHost); neverRemember.getData().putString("username", username); neverRemember.getData().putString("password", password); neverRemember.obj = resumeMsg; @@ -749,14 +774,36 @@ public class WebView extends AbsoluteLayout public static void disablePlatformNotifications() { Network.disablePlatformNotifications(); } + + /** + * Inform WebView of the network state. This is used to set + * the javascript property window.navigator.isOnline and + * generates the online/offline event as specified in HTML5, sec. 5.7.7 + * @param networkUp boolean indicating if network is available + * + * @hide pending API Council approval + */ + public void setNetworkAvailable(boolean networkUp) { + BrowserFrame.sJavaBridge.setNetworkOnLine(networkUp); + } /** - * Save the state of this WebView used in Activity.onSaveInstanceState. + * Save the state of this WebView used in + * {@link android.app.Activity#onSaveInstanceState}. Please note that this + * method no longer stores the display data for this WebView. The previous + * behavior could potentially leak files if {@link #restoreState} was never + * called. See {@link #savePicture} and {@link #restorePicture} for saving + * and restoring the display data. * @param outState The Bundle to store the WebView state. * @return The same copy of the back/forward list used to save the state. If * saveState fails, the returned list will be null. + * @see #savePicture + * @see #restorePicture */ public WebBackForwardList saveState(Bundle outState) { + if (outState == null) { + return null; + } // We grab a copy of the back/forward list because a client of WebView // may have invalidated the history list by calling clearHistory. WebBackForwardList list = copyBackForwardList(); @@ -782,29 +829,6 @@ public class WebView extends AbsoluteLayout return null; } history.add(data); - if (i == currentIndex) { - Picture p = capturePicture(); - String path = mContext.getDir("thumbnails", 0).getPath() - + File.separatorChar + hashCode() + "_pic.save"; - File f = new File(path); - try { - final FileOutputStream out = new FileOutputStream(f); - p.writeToStream(out); - out.close(); - } catch (FileNotFoundException e){ - e.printStackTrace(); - } catch (IOException e) { - e.printStackTrace(); - } catch (RuntimeException e) { - e.printStackTrace(); - } - if (f.length() > 0) { - outState.putString("picture", path); - outState.putInt("scrollX", mScrollX); - outState.putInt("scrollY", mScrollY); - outState.putFloat("scale", mActualScale); - } - } } outState.putSerializable("history", history); if (mCertificate != null) { @@ -814,17 +838,104 @@ public class WebView extends AbsoluteLayout return list; } + /** + * Save the current display data to the Bundle given. Used in conjunction + * with {@link #saveState}. + * @param b A Bundle to store the display data. + * @param dest The file to store the serialized picture data. Will be + * overwritten with this WebView's picture data. + * @return True if the picture was successfully saved. + */ + public boolean savePicture(Bundle b, File dest) { + if (dest == null || b == null) { + return false; + } + final Picture p = capturePicture(); + try { + final FileOutputStream out = new FileOutputStream(dest); + p.writeToStream(out); + out.close(); + } catch (FileNotFoundException e){ + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } catch (RuntimeException e) { + e.printStackTrace(); + } + if (dest.length() > 0) { + b.putInt("scrollX", mScrollX); + b.putInt("scrollY", mScrollY); + b.putFloat("scale", mActualScale); + return true; + } + return false; + } + + /** + * Restore the display data that was save in {@link #savePicture}. Used in + * conjunction with {@link #restoreState}. + * @param b A Bundle containing the saved display data. + * @param src The file where the picture data was stored. + * @return True if the picture was successfully restored. + */ + public boolean restorePicture(Bundle b, File src) { + if (src == null || b == null) { + return false; + } + if (src.exists()) { + Picture p = null; + try { + final FileInputStream in = new FileInputStream(src); + p = Picture.createFromStream(in); + in.close(); + } catch (FileNotFoundException e){ + e.printStackTrace(); + } catch (RuntimeException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } + if (p != null) { + int sx = b.getInt("scrollX", 0); + int sy = b.getInt("scrollY", 0); + float scale = b.getFloat("scale", 1.0f); + mDrawHistory = true; + mHistoryPicture = p; + mScrollX = sx; + mScrollY = sy; + mHistoryWidth = Math.round(p.getWidth() * scale); + mHistoryHeight = Math.round(p.getHeight() * scale); + // as getWidth() / getHeight() of the view are not + // available yet, set up mActualScale, so that when + // onSizeChanged() is called, the rest will be set + // correctly + mActualScale = scale; + invalidate(); + return true; + } + } + return false; + } + /** * Restore the state of this WebView from the given map used in - * Activity.onThaw. This method should be called to restore the state of - * the WebView before using the object. If it is called after the WebView - * has had a chance to build state (load pages, create a back/forward list, - * etc.) there may be undesirable side-effects. + * {@link android.app.Activity#onRestoreInstanceState}. This method should + * be called to restore the state of the WebView before using the object. If + * it is called after the WebView has had a chance to build state (load + * pages, create a back/forward list, etc.) there may be undesirable + * side-effects. Please note that this method no longer restores the + * display data for this WebView. See {@link #savePicture} and {@link + * #restorePicture} for saving and restoring the display data. * @param inState The incoming Bundle of state. * @return The restored back/forward list or null if restoreState failed. + * @see #savePicture + * @see #restorePicture */ public WebBackForwardList restoreState(Bundle inState) { WebBackForwardList returnList = null; + if (inState == null) { + return returnList; + } if (inState.containsKey("index") && inState.containsKey("history")) { mCertificate = SslCertificate.restoreState( inState.getBundle("certificate")); @@ -853,42 +964,6 @@ public class WebView extends AbsoluteLayout WebHistoryItem item = new WebHistoryItem(data); list.addHistoryItem(item); } - if (inState.containsKey("picture")) { - String path = inState.getString("picture"); - File f = new File(path); - if (f.exists()) { - Picture p = null; - try { - final FileInputStream in = new FileInputStream(f); - p = Picture.createFromStream(in); - in.close(); - f.delete(); - } catch (FileNotFoundException e){ - e.printStackTrace(); - } catch (RuntimeException e) { - e.printStackTrace(); - } catch (IOException e) { - e.printStackTrace(); - } - if (p != null) { - int sx = inState.getInt("scrollX", 0); - int sy = inState.getInt("scrollY", 0); - float scale = inState.getFloat("scale", 1.0f); - mDrawHistory = true; - mHistoryPicture = p; - mScrollX = sx; - mScrollY = sy; - mHistoryWidth = Math.round(p.getWidth() * scale); - mHistoryHeight = Math.round(p.getHeight() * scale); - // as getWidth() / getHeight() of the view are not - // available yet, set up mActualScale, so that when - // onSizeChanged() is called, the rest will be set - // correctly - mActualScale = scale; - invalidate(); - } - } - } // Grab the most recent copy to return to the caller. returnList = copyBackForwardList(); // Update the copy to have the correct index. @@ -929,14 +1004,22 @@ public class WebView extends AbsoluteLayout * Load the given data into the WebView, use the provided URL as the base * URL for the content. The base URL is the URL that represents the page * that is loaded through this interface. As such, it is used for the - * history entry and to resolve any relative URLs. - * The failUrl is used if browser fails to load the data provided. If it - * is empty or null, and the load fails, then no history entry is created. + * history entry and to resolve any relative URLs. The failUrl is used if + * browser fails to load the data provided. If it is empty or null, and the + * load fails, then no history entry is created. + *

              + * Note for post 1.0. Due to the change in the WebKit, the access to asset + * files through "file:///android_asset/" for the sub resources is more + * restricted. If you provide null or empty string as baseUrl, you won't be + * able to access asset files. If the baseUrl is anything other than + * http(s)/ftp(s)/about/javascript as scheme, you can access asset files for + * sub resources. + * * @param baseUrl Url to resolve relative paths with, if null defaults to - * "about:blank" + * "about:blank" * @param data A String of data in the given encoding. * @param mimeType The MIMEType of the data. i.e. text/html. If null, - * defaults to "text/html" + * defaults to "text/html" * @param encoding The encoding of the data. i.e. utf-8, us-ascii * @param failUrl URL to use if the content fails to load or null. */ @@ -1133,7 +1216,7 @@ public class WebView extends AbsoluteLayout public void clearView() { mContentWidth = 0; mContentHeight = 0; - mWebViewCore.clearContentPicture(); + mWebViewCore.sendMessage(EventHub.CLEAR_CONTENT); } /** @@ -1197,7 +1280,7 @@ public class WebView extends AbsoluteLayout clearTextEntry(); ExtendedZoomControls zoomControls = (ExtendedZoomControls) getZoomControls(); - zoomControls.show(canZoomScrollOut()); + zoomControls.show(true, canZoomScrollOut()); zoomControls.requestFocus(); mPrivateHandler.removeCallbacks(mZoomControlRunnable); mPrivateHandler.postDelayed(mZoomControlRunnable, @@ -1206,11 +1289,15 @@ public class WebView extends AbsoluteLayout /** * Return a HitTestResult based on the current focus node. If a HTML::a tag - * is found, the HitTestResult type is set to ANCHOR_TYPE and the url has to - * be retrieved through {@link #requestFocusNodeHref} asynchronously. If a - * HTML::img tag is found, the HitTestResult type is set to IMAGE_TYPE and - * the url has to be retrieved through {@link #requestFocusNodeHref} - * asynchronously. If a phone number is found, the HitTestResult type is set + * is found and the anchor has a non-javascript url, the HitTestResult type + * is set to SRC_ANCHOR_TYPE and the url is set in the "extra" field. If the + * anchor does not have a url or if it is a javascript url, the type will + * be UNKNOWN_TYPE and the url has to be retrieved through + * {@link #requestFocusNodeHref} asynchronously. If a HTML::img tag is + * found, the HitTestResult type is set to IMAGE_TYPE and the url is set in + * the "extra" field. A type of + * SRC_IMAGE_ANCHOR_TYPE indicates an anchor with a url that has an image as + * a child node. If a phone number is found, the HitTestResult type is set * to PHONE_TYPE and the phone number is set in the "extra" field of * HitTestResult. If a map address is found, the HitTestResult type is set * to GEO_TYPE and the address is set in the "extra" field of HitTestResult. @@ -1227,42 +1314,38 @@ public class WebView extends AbsoluteLayout if (nativeUpdateFocusNode()) { FocusNode node = mFocusNode; - if (node.mIsAnchor && node.mText == null) { - result.setType(HitTestResult.ANCHOR_TYPE); - } else if (node.mIsTextField || node.mIsTextArea) { + if (node.mIsTextField || node.mIsTextArea) { result.setType(HitTestResult.EDIT_TEXT_TYPE); - } else { + } else if (node.mText != null) { String text = node.mText; - if (text != null) { - if (text.startsWith(SCHEME_TEL)) { - result.setType(HitTestResult.PHONE_TYPE); - result.setExtra(text.substring(SCHEME_TEL.length())); - } else if (text.startsWith(SCHEME_MAILTO)) { - result.setType(HitTestResult.EMAIL_TYPE); - result.setExtra(text.substring(SCHEME_MAILTO.length())); - } else if (text.startsWith(SCHEME_GEO)) { - result.setType(HitTestResult.GEO_TYPE); - result.setExtra(URLDecoder.decode(text - .substring(SCHEME_GEO.length()))); - } + if (text.startsWith(SCHEME_TEL)) { + result.setType(HitTestResult.PHONE_TYPE); + result.setExtra(text.substring(SCHEME_TEL.length())); + } else if (text.startsWith(SCHEME_MAILTO)) { + result.setType(HitTestResult.EMAIL_TYPE); + result.setExtra(text.substring(SCHEME_MAILTO.length())); + } else if (text.startsWith(SCHEME_GEO)) { + result.setType(HitTestResult.GEO_TYPE); + result.setExtra(URLDecoder.decode(text + .substring(SCHEME_GEO.length()))); + } else if (node.mIsAnchor) { + result.setType(HitTestResult.SRC_ANCHOR_TYPE); + result.setExtra(text); } } } int type = result.getType(); if (type == HitTestResult.UNKNOWN_TYPE - || type == HitTestResult.ANCHOR_TYPE) { + || type == HitTestResult.SRC_ANCHOR_TYPE) { // Now check to see if it is an image. int contentX = viewToContent((int) mLastTouchX + mScrollX); int contentY = viewToContent((int) mLastTouchY + mScrollY); - if (nativeIsImage(contentX, contentY)) { + String text = nativeImageURI(contentX, contentY); + if (text != null) { result.setType(type == HitTestResult.UNKNOWN_TYPE ? HitTestResult.IMAGE_TYPE : - HitTestResult.IMAGE_ANCHOR_TYPE); - } - if (nativeHasSrcUrl()) { - result.setType(result.getType() == HitTestResult.ANCHOR_TYPE ? - HitTestResult.SRC_ANCHOR_TYPE : HitTestResult.SRC_IMAGE_ANCHOR_TYPE); + result.setExtra(text); } } return result; @@ -1284,12 +1367,15 @@ public class WebView extends AbsoluteLayout if (nativeUpdateFocusNode()) { FocusNode node = mFocusNode; if (node.mIsAnchor) { + // NOTE: We may already have the url of the anchor stored in + // node.mText but it may be out of date or the caller may want + // to know about javascript urls. mWebViewCore.sendMessage(EventHub.REQUEST_FOCUS_HREF, node.mFramePointer, node.mNodePointer, hrefMsg); } } } - + /** * Request the url of the image last touched by the user. msg will be sent * to its target with a String representing the url as its object. @@ -1298,13 +1384,13 @@ public class WebView extends AbsoluteLayout * as the data member with "url" as key. The result can be null. */ public void requestImageRef(Message msg) { - if (msg == null || mNativeClass == 0) { - return; - } int contentX = viewToContent((int) mLastTouchX + mScrollX); int contentY = viewToContent((int) mLastTouchY + mScrollY); - mWebViewCore.sendMessage(EventHub.REQUEST_IMAGE_HREF, contentX, - contentY, msg); + String ref = nativeImageURI(contentX, contentY); + Bundle data = msg.getData(); + data.putString("url", ref); + msg.setData(data); + msg.sendToTarget(); } private static int pinLoc(int x, int viewMax, int docMax) { @@ -1340,6 +1426,25 @@ public class WebView extends AbsoluteLayout return Math.round(x * mActualScale); } + // Called by JNI to invalidate the View, given rectangle coordinates in + // content space + private void viewInvalidate(int l, int t, int r, int b) { + invalidate(contentToView(l), contentToView(t), contentToView(r), + contentToView(b)); + } + + // Called by JNI to invalidate the View after a delay, given rectangle + // coordinates in content space + private void viewInvalidateDelayed(long delay, int l, int t, int r, int b) { + postInvalidateDelayed(delay, contentToView(l), contentToView(t), + contentToView(r), contentToView(b)); + } + + private Rect contentToView(Rect x) { + return new Rect(contentToView(x.left), contentToView(x.top) + , contentToView(x.right), contentToView(x.bottom)); + } + /* call from webcoreview.draw(), so we're still executing in the UI thread */ private void recordNewContentSize(int w, int h, boolean updateLayout) { @@ -1420,15 +1525,29 @@ public class WebView extends AbsoluteLayout // Used to avoid sending many visible rect messages. private Rect mLastVisibleRectSent; + private Rect mLastGlobalRect; private Rect sendOurVisibleRect() { Rect rect = new Rect(); calcOurContentVisibleRect(rect); + if (mFindIsUp) { + rect.bottom -= viewToContent(FIND_HEIGHT); + } // Rect.equals() checks for null input. if (!rect.equals(mLastVisibleRectSent)) { - mWebViewCore.sendMessage(EventHub.SET_VISIBLE_RECT, rect); + mWebViewCore.sendMessage(EventHub.SET_SCROLL_OFFSET, + rect.left, rect.top); mLastVisibleRectSent = rect; } + Rect globalRect = new Rect(); + if (getGlobalVisibleRect(globalRect) + && !globalRect.equals(mLastGlobalRect)) { + // TODO: the global offset is only used by windowRect() + // in ChromeClientAndroid ; other clients such as touch + // and mouse events could return view + screen relative points. + mWebViewCore.sendMessage(EventHub.SET_GLOBAL_BOUNDS, globalRect); + mLastGlobalRect = globalRect; + } return rect; } @@ -1488,12 +1607,19 @@ public class WebView extends AbsoluteLayout } } + // Make sure this stays in sync with the actual height of the FindDialog. + private static final int FIND_HEIGHT = 79; + @Override protected int computeVerticalScrollRange() { if (mDrawHistory) { return mHistoryHeight; } else { - return contentToView(mContentHeight); + int height = contentToView(mContentHeight); + if (mFindIsUp) { + height += FIND_HEIGHT; + } + return height; } } @@ -1507,6 +1633,21 @@ public class WebView extends AbsoluteLayout WebHistoryItem h = mCallbackProxy.getBackForwardList().getCurrentItem(); return h != null ? h.getUrl() : null; } + + /** + * Get the original url for the current page. This is not always the same + * as the url passed to WebViewClient.onPageStarted because although the + * load for that url has begun, the current page may not have changed. + * Also, there may have been redirects resulting in a different url to that + * originally requested. + * @return The url that was originally requested for the current page. + * + * @hide pending API Council approval + */ + public String getOriginalUrl() { + WebHistoryItem h = mCallbackProxy.getBackForwardList().getCurrentItem(); + return h != null ? h.getOriginalUrl() : null; + } /** * Get the title for the current page. This is the title of the current page @@ -1612,82 +1753,35 @@ public class WebView extends AbsoluteLayout } /* - * Making the find methods private since we are disabling for 1.0 - * - * Find and highlight the next occurance of the String find, beginning with - * the current selection. Wraps the page infinitely, and scrolls. When - * WebCore determines whether it has found it, the response message is sent - * to its target with true(1) or false(0) as arg1 depending on whether the - * text was found. - * @param find String to find. - * @param response A Message object that will be dispatched with the result - * as the arg1 member. A result of 1 means the search - * succeeded. - */ - private void findNext(String find, Message response) { - if (response == null) { - return; - } - Message m = Message.obtain(null, EventHub.FIND, 1, 0, response); - m.getData().putString("find", find); - mWebViewCore.sendMessage(m); - } - - /* - * Making the find methods private since we are disabling for 1.0 - * - * Find and highlight the previous occurance of the String find, beginning - * with the current selection. - * @param find String to find. - * @param response A Message object that will be dispatched with the result - * as the arg1 member. A result of 1 means the search - * succeeded. - */ - private void findPrevious(String find, Message response) { - if (response == null) { - return; - } - Message m = Message.obtain(null, EventHub.FIND, -1, 0, response); - m.getData().putString("find", find); - mWebViewCore.sendMessage(m); - } - - /* - * Making the find methods private since we are disabling for 1.0 + * Highlight and scroll to the next occurance of String in findAll. + * Wraps the page infinitely, and scrolls. Must be called after + * calling findAll. * - * Find and highlight the first occurance of find, beginning with the start - * of the page. - * @param find String to find. - * @param response A Message object that will be dispatched with the result - * as the arg1 member. A result of 1 means the search - * succeeded. + * @param forward Direction to search. */ - private void findFirst(String find, Message response) { - if (response == null) { - return; - } - Message m = Message.obtain(null, EventHub.FIND, 0, 0, response); - m.getData().putString("find", find); - mWebViewCore.sendMessage(m); + public void findNext(boolean forward) { + nativeFindNext(forward); } /* - * Making the find methods private since we are disabling for 1.0 - * * Find all instances of find on the page and highlight them. * @param find String to find. - * @param response A Message object that will be dispatched with the result - * as the arg1 member. The result will be the number of - * matches to the String find. + * @return int The number of occurances of the String "find" + * that were found. */ - private void findAll(String find, Message response) { - if (response == null) { - return; - } - Message m = Message.obtain(null, EventHub.FIND_ALL, 0, 0, response); - m.getData().putString("find", find); - mWebViewCore.sendMessage(m); + public int findAll(String find) { + mFindIsUp = true; + int result = nativeFindAll(find.toLowerCase(), find.toUpperCase()); + invalidate(); + return result; } + + // Used to know whether the find dialog is open. Affects whether + // or not we draw the highlights for matches. + private boolean mFindIsUp; + + private native int nativeFindAll(String findLower, String findUpper); + private native void nativeFindNext(boolean forward); /** * Return the first substring consisting of the address of a physical @@ -1714,12 +1808,15 @@ public class WebView extends AbsoluteLayout } /* - * Making the find methods private since we are disabling for 1.0 - * * Clear the highlighting surrounding text matches created by findAll. */ - private void clearMatches() { - mWebViewCore.sendMessage(EventHub.CLEAR_MATCHES); + public void clearMatches() { + mFindIsUp = false; + nativeSetFindIsDown(); + // Now that the dialog has been removed, ensure that we scroll to a + // location that is not beyond the end of the page. + pinScrollTo(mScrollX, mScrollY, false); + invalidate(); } /** @@ -2023,10 +2120,21 @@ public class WebView extends AbsoluteLayout nativeRecomputeFocus(); // Update the buttons in the picture, so when we draw the picture // to the screen, they are in the correct state. - nativeRecordButtons(); + // Tell the native side if user is a) touching the screen, + // b) pressing the trackball down, or c) pressing the enter key + // If the focus is a button, we need to draw it in the pressed + // state. + // If mNativeClass is 0, we should not reach here, so we do not + // need to check it again. + nativeRecordButtons(mTouchMode == TOUCH_SHORTPRESS_START_MODE + || mTrackballDown || mGotEnterDown, false); drawCoreAndFocusRing(canvas, mBackgroundColor, mDrawFocusRing); } canvas.restoreToCount(sc); + + if (AUTO_REDRAW_HACK && mAutoRedraw) { + invalidate(); + } } @Override @@ -2097,7 +2205,12 @@ public class WebView extends AbsoluteLayout if (mNativeClass == 0) return; if (mShiftIsPressed) { - nativeDrawSelection(canvas, mSelectX, mSelectY, mExtendSelection); + if (mTouchSelection) { + nativeDrawSelectionRegion(canvas); + } else { + nativeDrawSelection(canvas, mSelectX, mSelectY, + mExtendSelection); + } } else if (drawFocus) { if (mTouchMode == TOUCH_SHORTPRESS_START_MODE) { mTouchMode = TOUCH_SHORTPRESS_MODE; @@ -2111,7 +2224,14 @@ public class WebView extends AbsoluteLayout } nativeDrawFocusRing(canvas); } + // When the FindDialog is up, only draw the matches if we are not in + // the process of scrolling them into view. + if (mFindIsUp && !animateScroll) { + nativeDrawMatches(canvas); + } } + + private native void nativeDrawMatches(Canvas canvas); private float scrollZoomGridScale(float invScale) { float griddedInvScale = (int) (invScale * SCROLL_ZOOM_GRID) @@ -2163,19 +2283,40 @@ public class WebView extends AbsoluteLayout Rect scrollFrame = new Rect(); scrollFrame.set(mZoomScrollX, mZoomScrollY, mZoomScrollX + width, mZoomScrollY + height); - if (mContentWidth == width) { - float offsetX = (width * halfScale - width) / 2; + if (mContentWidth * mZoomScrollLimit < width) { + float scale = zoomFrameScaleX(width, halfScale, 1.0f); + float offsetX = (width * scale - width) * 0.5f; scrollFrame.left -= offsetX; scrollFrame.right += offsetX; } - if (mContentHeight == height) { - float offsetY = (height * halfScale - height) / 2; + if (mContentHeight * mZoomScrollLimit < height) { + float scale = zoomFrameScaleY(height, halfScale, 1.0f); + float offsetY = (height * scale - height) * 0.5f; scrollFrame.top -= offsetY; scrollFrame.bottom += offsetY; } return scrollFrame; } + private float zoomFrameScaleX(int width, float halfScale, float noScale) { + // mContentWidth > width > mContentWidth * mZoomScrollLimit + if (mContentWidth <= width) { + return halfScale; + } + float part = (width - mContentWidth * mZoomScrollLimit) + / (width * (1 - mZoomScrollLimit)); + return halfScale * part + noScale * (1.0f - part); + } + + private float zoomFrameScaleY(int height, float halfScale, float noScale) { + if (mContentHeight <= height) { + return halfScale; + } + float part = (height - mContentHeight * mZoomScrollLimit) + / (height * (1 - mZoomScrollLimit)); + return halfScale * part + noScale * (1.0f - part); + } + private float scrollZoomMagScale(float invScale) { return (invScale * 2 + mInvActualScale) / 3; } @@ -2252,8 +2393,14 @@ public class WebView extends AbsoluteLayout } int sc = canvas.save(); canvas.clipRect(scrollFrame); - float halfX = maxX > 0 ? (float) mZoomScrollX / maxX : 0.5f; - float halfY = maxY > 0 ? (float) mZoomScrollY / maxY : 0.5f; + float halfX = (float) mZoomScrollX / maxX; + if (mContentWidth * mZoomScrollLimit < width) { + halfX = zoomFrameScaleX(width, 0.5f, halfX); + } + float halfY = (float) mZoomScrollY / maxY; + if (mContentHeight * mZoomScrollLimit < height) { + halfY = zoomFrameScaleY(height, 0.5f, halfY); + } canvas.scale(halfScale, halfScale, mZoomScrollX + width * halfX , mZoomScrollY + height * halfY); if (LOGV_ENABLED) { @@ -2350,7 +2497,10 @@ public class WebView extends AbsoluteLayout } private void zoomScrollOut() { - if (canZoomScrollOut() == false) return; + if (canZoomScrollOut() == false) { + mTouchMode = TOUCH_DONE_MODE; + return; + } startZoomScrollOut(); mTouchMode = SCROLL_ZOOM_ANIMATION_OUT; invalidate(); @@ -2377,8 +2527,8 @@ public class WebView extends AbsoluteLayout + " mZoomScrollLimit=" + mZoomScrollLimit + " x=" + x); } x += maxScreenX * mLastScrollX / maxZoomX - mLastTouchX; - x = Math.max(0, Math.min(maxScreenX, x)); - mZoomScrollX = (int) (x * maxZoomX / maxScreenX); + x *= Math.max(maxZoomX / maxScreenX, mZoomScrollInvLimit); + mZoomScrollX = Math.max(0, Math.min(maxZoomX, (int) x)); } int maxZoomY = mContentHeight - height; if (maxZoomY > 0) { @@ -2390,8 +2540,8 @@ public class WebView extends AbsoluteLayout + " mZoomScrollLimit=" + mZoomScrollLimit + " y=" + y); } y += maxScreenY * mLastScrollY / maxZoomY - mLastTouchY; - y = Math.max(0, Math.min(maxScreenY, y)); - mZoomScrollY = (int) (y * maxZoomY / maxScreenY); + y *= Math.max(maxZoomY / maxScreenY, mZoomScrollInvLimit); + mZoomScrollY = Math.max(0, Math.min(maxZoomY, (int) y)); } if (oldX != mZoomScrollX || oldY != mZoomScrollY) { invalidate(); @@ -2540,6 +2690,13 @@ public class WebView extends AbsoluteLayout new WebViewCore.FocusData(mFocusData)); } + // Called by JNI when a touch event puts a textfield into focus. + private void displaySoftKeyboard() { + InputMethodManager imm = (InputMethodManager) + getContext().getSystemService(Context.INPUT_METHOD_SERVICE); + imm.showSoftInput(mTextEntry); + } + // Used to register the global focus change listener one time to avoid // multiple references to WebView private boolean mGlobalFocusChangeListenerAdded; @@ -2663,7 +2820,8 @@ public class WebView extends AbsoluteLayout ArrayList pastEntries = mDatabase.getFormData(mUrl, mName); if (pastEntries.size() > 0) { ArrayAdapter adapter = new ArrayAdapter( - mContext, com.android.internal.R.layout.simple_list_item_1, + mContext, com.android.internal.R.layout + .search_dropdown_item_1line, pastEntries); ((HashMap) mUpdateMessage.obj).put("adapter", adapter); mUpdateMessage.sendToTarget(); @@ -2679,152 +2837,166 @@ public class WebView extends AbsoluteLayout mTextEntry.setRect(x, y, width, height); } - // These variables are used to determine long press with the enter key, or + // This is used to determine long press with the enter key, or // a center key. Does not affect long press with the trackball/touch. - private long mDownTime = 0; - private boolean mGotDown = false; + private boolean mGotEnterDown = false; // Enable copy/paste with trackball here. // This should be left disabled until the framework can guarantee // delivering matching key-up and key-down events for the shift key - private static final boolean ENABLE_COPY_PASTE = false; + private static final boolean ENABLE_COPY_PASTE = true; @Override public boolean onKeyDown(int keyCode, KeyEvent event) { - if (mTouchMode >= FIRST_SCROLL_ZOOM && mTouchMode <= LAST_SCROLL_ZOOM) { + if (LOGV_ENABLED) { + Log.v(LOGTAG, "keyDown at " + System.currentTimeMillis() + + ", " + event); + } + + if (mNativeClass == 0) { return false; } - if (keyCode != KeyEvent.KEYCODE_DPAD_CENTER && - keyCode != KeyEvent.KEYCODE_ENTER) { - mGotDown = false; + + // do this hack up front, so it always works, regardless of touch-mode + if (AUTO_REDRAW_HACK && (keyCode == KeyEvent.KEYCODE_CALL)) { + mAutoRedraw = !mAutoRedraw; + if (mAutoRedraw) { + invalidate(); + } + return true; } - if (mAltIsPressed == false && (keyCode == KeyEvent.KEYCODE_ALT_LEFT - || keyCode == KeyEvent.KEYCODE_ALT_RIGHT)) { - mAltIsPressed = true; + + // Bubble up the key event if + // 1. it is a system key; or + // 2. the host application wants to handle it; or + // 3. webview is in scroll-zoom state; + if (event.isSystem() + || mCallbackProxy.uiOverrideKeyEvent(event) + || (mTouchMode >= FIRST_SCROLL_ZOOM && mTouchMode <= LAST_SCROLL_ZOOM)) { + return false; } + if (ENABLE_COPY_PASTE && mShiftIsPressed == false && (keyCode == KeyEvent.KEYCODE_SHIFT_LEFT || keyCode == KeyEvent.KEYCODE_SHIFT_RIGHT)) { mExtendSelection = false; mShiftIsPressed = true; - if (mNativeClass != 0 && nativeUpdateFocusNode()) { + if (nativeUpdateFocusNode()) { FocusNode node = mFocusNode; - mSelectX = node.mBounds.left; - mSelectY = node.mBounds.top; + mSelectX = contentToView(node.mBounds.left); + mSelectY = contentToView(node.mBounds.top); } else { - mSelectX = mScrollX + SELECT_CURSOR_OFFSET; - mSelectY = mScrollY + SELECT_CURSOR_OFFSET; + mSelectX = mScrollX + (int) mLastTouchX; + mSelectY = mScrollY + (int) mLastTouchY; } } - if (keyCode == KeyEvent.KEYCODE_CALL) { - if (mNativeClass != 0 && nativeUpdateFocusNode()) { - FocusNode node = mFocusNode; - String text = node.mText; - if (!node.mIsTextField && !node.mIsTextArea && text != null && - text.startsWith(SCHEME_TEL)) { - Intent intent = new Intent(Intent.ACTION_DIAL, - Uri.parse(text)); - getContext().startActivity(intent); - return true; - } + + if (keyCode >= KeyEvent.KEYCODE_DPAD_UP + && keyCode <= KeyEvent.KEYCODE_DPAD_RIGHT) { + // always handle the navigation keys in the UI thread + switchOutDrawHistory(); + if (navHandledKey(keyCode, 1, false, event.getEventTime())) { + playSoundEffect(keyCodeToSoundsEffect(keyCode)); + return true; } + // Bubble up the key event as WebView doesn't handle it return false; } - if (event.isSystem() || mCallbackProxy.uiOverrideKeyEvent(event)) { - return false; - } - if (LOGV_ENABLED) { - Log.v(LOGTAG, "keyDown at " + System.currentTimeMillis() - + ", " + event); - } - boolean isArrowKey = keyCode == KeyEvent.KEYCODE_DPAD_UP || - keyCode == KeyEvent.KEYCODE_DPAD_DOWN || - keyCode == KeyEvent.KEYCODE_DPAD_LEFT || - keyCode == KeyEvent.KEYCODE_DPAD_RIGHT; - if (isArrowKey && event.getEventTime() - mTrackballLastTime - <= TRACKBALL_KEY_TIMEOUT) { - if (LOGV_ENABLED) Log.v(LOGTAG, "ignore arrow"); + if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER + || keyCode == KeyEvent.KEYCODE_ENTER) { + switchOutDrawHistory(); + if (event.getRepeatCount() == 0) { + mGotEnterDown = true; + mPrivateHandler.sendMessageDelayed(mPrivateHandler + .obtainMessage(LONG_PRESS_ENTER), LONG_PRESS_TIMEOUT); + nativeRecordButtons(true, true); + // FIXME, currently in webcore keydown it doesn't do anything. + // In keyup, it calls both keydown and keyup, we should fix it. + mWebViewCore.sendMessage(EventHub.KEY_DOWN, keyCode, + EventHub.KEYEVENT_UNHANDLED_TYPE, event); + return true; + } + // Bubble up the key event as WebView doesn't handle it return false; } - boolean weHandledTheKey = false; - if (event.getMetaState() == 0) { + if (getSettings().getNavDump()) { switch (keyCode) { - case KeyEvent.KEYCODE_DPAD_UP: - case KeyEvent.KEYCODE_DPAD_DOWN: - case KeyEvent.KEYCODE_DPAD_RIGHT: - case KeyEvent.KEYCODE_DPAD_LEFT: - // TODO: alternatively we can do panning as touch does - switchOutDrawHistory(); - weHandledTheKey = navHandledKey(keyCode, 1, false - , event.getEventTime()); - if (weHandledTheKey) { - playSoundEffect(keyCodeToSoundsEffect(keyCode)); - } + case KeyEvent.KEYCODE_4: + // "/data/data/com.android.browser/displayTree.txt" + nativeDumpDisplayTree(getUrl()); break; - case KeyEvent.KEYCODE_DPAD_CENTER: - case KeyEvent.KEYCODE_ENTER: - if (event.getRepeatCount() == 0) { - switchOutDrawHistory(); - mDownTime = event.getEventTime(); - mGotDown = true; - return true; - } - if (mGotDown && event.getEventTime() - mDownTime > - ViewConfiguration.getLongPressTimeout()) { - performLongClick(); - mGotDown = false; - return true; - } + case KeyEvent.KEYCODE_5: + case KeyEvent.KEYCODE_6: + // 5: dump the dom tree to the file + // "/data/data/com.android.browser/domTree.txt" + // 6: dump the dom tree to the adb log + mWebViewCore.sendMessage(EventHub.DUMP_DOMTREE, + (keyCode == KeyEvent.KEYCODE_5) ? 1 : 0, 0); break; - case KeyEvent.KEYCODE_9: - if (mNativeClass != 0 && getSettings().getNavDump()) { - debugDump(); - } + case KeyEvent.KEYCODE_7: + case KeyEvent.KEYCODE_8: + // 7: dump the render tree to the file + // "/data/data/com.android.browser/renderTree.txt" + // 8: dump the render tree to the adb log + mWebViewCore.sendMessage(EventHub.DUMP_RENDERTREE, + (keyCode == KeyEvent.KEYCODE_7) ? 1 : 0, 0); break; - default: + case KeyEvent.KEYCODE_9: + debugDump(); break; } } - // suppress sending arrow keys to webkit - if (!weHandledTheKey && !isArrowKey) { - mWebViewCore.sendMessage(EventHub.KEY_DOWN, keyCode, 0, event); + if (nativeFocusNodeWantsKeyEvents()) { + mWebViewCore.sendMessage(EventHub.KEY_DOWN, keyCode, + EventHub.KEYEVENT_FOCUS_NODE_TYPE, event); + // return true as DOM handles the key + return true; + } else if (false) { // reserved to check the meta tag + // pass the key to DOM + mWebViewCore.sendMessage(EventHub.KEY_DOWN, keyCode, + EventHub.KEYEVENT_UNHANDLED_TYPE, event); + // return true as DOM handles the key + return true; } - return weHandledTheKey; + // Bubble up the key event as WebView doesn't handle it + return false; } @Override public boolean onKeyUp(int keyCode, KeyEvent event) { - if (keyCode == KeyEvent.KEYCODE_SHIFT_LEFT - || keyCode == KeyEvent.KEYCODE_SHIFT_RIGHT) { - if (mExtendSelection) { - // copy region so core operates on copy without touching orig. - Region selection = new Region(nativeGetSelection()); - if (selection.isEmpty() == false) { - Toast.makeText(mContext - , com.android.internal.R.string.text_copied - , Toast.LENGTH_SHORT).show(); - mWebViewCore.sendMessage(EventHub.GET_SELECTION, selection); - } - } - mShiftIsPressed = false; - return true; - } if (LOGV_ENABLED) { - Log.v(LOGTAG, "MT keyUp at" + System.currentTimeMillis() + Log.v(LOGTAG, "keyUp at " + System.currentTimeMillis() + ", " + event); } - if (keyCode == KeyEvent.KEYCODE_ALT_LEFT - || keyCode == KeyEvent.KEYCODE_ALT_RIGHT) { - mAltIsPressed = false; + + if (mNativeClass == 0) { + return false; } + + // special CALL handling when focus node's href is "tel:XXX" + if (keyCode == KeyEvent.KEYCODE_CALL && nativeUpdateFocusNode()) { + FocusNode node = mFocusNode; + String text = node.mText; + if (!node.mIsTextField && !node.mIsTextArea && text != null + && text.startsWith(SCHEME_TEL)) { + Intent intent = new Intent(Intent.ACTION_DIAL, Uri.parse(text)); + getContext().startActivity(intent); + return true; + } + } + + // Bubble up the key event if + // 1. it is a system key; or + // 2. the host application wants to handle it; if (event.isSystem() || mCallbackProxy.uiOverrideKeyEvent(event)) { return false; } + // special handling in scroll_zoom state if (mTouchMode >= FIRST_SCROLL_ZOOM && mTouchMode <= LAST_SCROLL_ZOOM) { if (KeyEvent.KEYCODE_DPAD_CENTER == keyCode && mTouchMode != SCROLL_ZOOM_ANIMATION_IN) { @@ -2835,64 +3007,112 @@ public class WebView extends AbsoluteLayout } return false; } - Rect visibleRect = sendOurVisibleRect(); - // Note that sendOurVisibleRect calls viewToContent, so the coordinates - // should be in content coordinates. - boolean nodeOnScreen = false; - boolean isTextField = false; - boolean isTextArea = false; - FocusNode node = null; - if (mNativeClass != 0 && nativeUpdateFocusNode()) { - node = mFocusNode; - isTextField = node.mIsTextField; - isTextArea = node.mIsTextArea; - nodeOnScreen = Rect.intersects(node.mBounds, visibleRect); - } - - if (KeyEvent.KEYCODE_DPAD_CENTER == keyCode) { - if (mShiftIsPressed) { - return false; - } - if (getSettings().supportZoom()) { - if (mTouchMode == TOUCH_DOUBLECLICK_MODE) { - zoomScrollOut(); - } else { - if (LOGV_ENABLED) Log.v(LOGTAG, "TOUCH_DOUBLECLICK_MODE"); - mPrivateHandler.sendMessageDelayed(mPrivateHandler - .obtainMessage(SWITCH_TO_ENTER), TAP_TIMEOUT); - mTouchMode = TOUCH_DOUBLECLICK_MODE; - } + + if (ENABLE_COPY_PASTE && (keyCode == KeyEvent.KEYCODE_SHIFT_LEFT + || keyCode == KeyEvent.KEYCODE_SHIFT_RIGHT)) { + if (commitCopy()) { return true; - } else { - keyCode = KeyEvent.KEYCODE_ENTER; } } - if (KeyEvent.KEYCODE_ENTER == keyCode) { - if (LOGV_ENABLED) Log.v(LOGTAG, "KEYCODE_ENTER == keyCode"); - if (!nodeOnScreen) { - return false; + + if (keyCode >= KeyEvent.KEYCODE_DPAD_UP + && keyCode <= KeyEvent.KEYCODE_DPAD_RIGHT) { + // always handle the navigation keys in the UI thread + // Bubble up the key event as WebView doesn't handle it + return false; + } + + if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER + || keyCode == KeyEvent.KEYCODE_ENTER) { + // remove the long press message first + mPrivateHandler.removeMessages(LONG_PRESS_ENTER); + mGotEnterDown = false; + + if (KeyEvent.KEYCODE_DPAD_CENTER == keyCode) { + if (mShiftIsPressed) { + return false; + } + if (getSettings().supportZoom()) { + if (mTouchMode == TOUCH_DOUBLECLICK_MODE) { + zoomScrollOut(); + } else { + if (LOGV_ENABLED) { + Log.v(LOGTAG, "TOUCH_DOUBLECLICK_MODE"); + } + mPrivateHandler.sendMessageDelayed(mPrivateHandler + .obtainMessage(SWITCH_TO_ENTER), TAP_TIMEOUT); + mTouchMode = TOUCH_DOUBLECLICK_MODE; + } + return true; + } + } + + Rect visibleRect = sendOurVisibleRect(); + // Note that sendOurVisibleRect calls viewToContent, so the + // coordinates should be in content coordinates. + boolean nodeOnScreen = false; + boolean isTextField = false; + boolean isTextArea = false; + FocusNode node = null; + if (nativeUpdateFocusNode()) { + node = mFocusNode; + isTextField = node.mIsTextField; + isTextArea = node.mIsTextArea; + nodeOnScreen = Rect.intersects(node.mBounds, visibleRect); } - if (node != null && !isTextField && !isTextArea) { + if (nodeOnScreen && !isTextField && !isTextArea) { nativeSetFollowedLink(true); - mWebViewCore.sendMessage(EventHub.SET_FINAL_FOCUS, + mWebViewCore.sendMessage(EventHub.SET_FINAL_FOCUS, EventHub.BLOCK_FOCUS_CHANGE_UNTIL_KEY_UP, 0, new WebViewCore.FocusData(mFocusData)); - if (mCallbackProxy.uiOverrideUrlLoading(node.mText)) { - return true; - } playSoundEffect(SoundEffectConstants.CLICK); + if (!mCallbackProxy.uiOverrideUrlLoading(node.mText)) { + mWebViewCore.sendMessage(EventHub.KEY_UP, keyCode, + EventHub.KEYEVENT_UNHANDLED_TYPE, event); + } + return true; } - } - if (!nodeOnScreen) { - // FIXME: Want to give Callback a chance to handle it, and - // possibly pass down to javascript. + // Bubble up the key event as WebView doesn't handle it return false; } - if (LOGV_ENABLED) Log.v(LOGTAG, "onKeyUp send EventHub.KEY_UP"); - mWebViewCore.sendMessage(EventHub.KEY_UP, keyCode, 0, event); - return true; + + if (nativeFocusNodeWantsKeyEvents()) { + mWebViewCore.sendMessage(EventHub.KEY_UP, keyCode, + EventHub.KEYEVENT_FOCUS_NODE_TYPE, event); + // return true as DOM handles the key + return true; + } else if (false) { // reserved to check the meta tag + // pass the key to DOM + mWebViewCore.sendMessage(EventHub.KEY_UP, keyCode, + EventHub.KEYEVENT_UNHANDLED_TYPE, event); + // return true as DOM handles the key + return true; + } + + // Bubble up the key event as WebView doesn't handle it + return false; } - + + private boolean commitCopy() { + boolean copiedSomething = false; + if (mExtendSelection) { + // copy region so core operates on copy without touching orig. + Region selection = new Region(nativeGetSelection()); + if (selection.isEmpty() == false) { + Toast.makeText(mContext + , com.android.internal.R.string.text_copied + , Toast.LENGTH_SHORT).show(); + mWebViewCore.sendMessage(EventHub.GET_SELECTION, selection); + copiedSomething = true; + } + } + mShiftIsPressed = false; + if (mTouchMode == TOUCH_SELECT_MODE) { + mTouchMode = TOUCH_INIT_MODE; + } + return copiedSomething; + } + // Set this as a hierarchy change listener so we can know when this view // is removed and still have access to our parent. @Override @@ -2962,6 +3182,7 @@ public class WebView extends AbsoluteLayout // we regain focus. mDrawFocusRing = false; mGotKeyDown = false; + mShiftIsPressed = false; if (inEditingMode()) { clearTextEntry(); mNeedsUpdateTextEntry = true; @@ -3055,8 +3276,7 @@ public class WebView extends AbsoluteLayout @Override public boolean onTouchEvent(MotionEvent ev) { - if (mNativeClass == 0 || !isClickable() || !isLongClickable() || - !hasFocus()) { + if (mNativeClass == 0 || !isClickable() || !isLongClickable()) { return false; } @@ -3069,6 +3289,32 @@ public class WebView extends AbsoluteLayout float x = ev.getX(); float y = ev.getY(); long eventTime = ev.getEventTime(); + + // Due to the touch screen edge effect, a touch closer to the edge + // always snapped to the edge. As getViewWidth() can be different from + // getWidth() due to the scrollbar, adjusting the point to match + // getViewWidth(). Same applied to the height. + if (x > getViewWidth() - 1) { + x = getViewWidth() - 1; + } + if (y > getViewHeight() - 1) { + y = getViewHeight() - 1; + } + + // pass the touch events from UI thread to WebCore thread + if (mForwardTouchEvents && mTouchMode != SCROLL_ZOOM_OUT + && mTouchMode != SCROLL_ZOOM_ANIMATION_IN + && mTouchMode != SCROLL_ZOOM_ANIMATION_OUT + && (action != MotionEvent.ACTION_MOVE || + eventTime - mLastSentTouchTime > TOUCH_SENT_INTERVAL)) { + WebViewCore.TouchEventData ted = new WebViewCore.TouchEventData(); + ted.mAction = action; + ted.mX = viewToContent((int) x + mScrollX); + ted.mY = viewToContent((int) y + mScrollY);; + mWebViewCore.sendMessage(EventHub.TOUCH_EVENT, ted); + mLastSentTouchTime = eventTime; + } + switch (action) { case MotionEvent.ACTION_DOWN: { if (mTouchMode == SCROLL_ZOOM_ANIMATION_IN @@ -3083,6 +3329,16 @@ public class WebView extends AbsoluteLayout mScroller.abortAnimation(); mTouchMode = TOUCH_DRAG_START_MODE; mPrivateHandler.removeMessages(RESUME_WEBCORE_UPDATE); + } else if (mShiftIsPressed) { + mSelectX = mScrollX + (int) x; + mSelectY = mScrollY + (int) y; + mTouchMode = TOUCH_SELECT_MODE; + if (LOGV_ENABLED) { + Log.v(LOGTAG, "select=" + mSelectX + "," + mSelectY); + } + nativeMoveSelection(viewToContent(mSelectX) + , viewToContent(mSelectY), false); + mTouchSelection = mExtendSelection = true; } else { mTouchMode = TOUCH_INIT_MODE; } @@ -3116,6 +3372,17 @@ public class WebView extends AbsoluteLayout int deltaY = (int) (mLastTouchY - y); if (mTouchMode != TOUCH_DRAG_MODE) { + if (mTouchMode == TOUCH_SELECT_MODE) { + mSelectX = mScrollX + (int) x; + mSelectY = mScrollY + (int) y; + if (LOGV_ENABLED) { + Log.v(LOGTAG, "xtend=" + mSelectX + "," + mSelectY); + } + nativeMoveSelection(viewToContent(mSelectX) + , viewToContent(mSelectY), true); + invalidate(); + break; + } if ((deltaX * deltaX + deltaY * deltaY) < TOUCH_SLOP_SQUARE) { break; @@ -3214,11 +3481,13 @@ public class WebView extends AbsoluteLayout mUserScroll = true; } - if (mZoomControls != null && mMinZoomScale < mMaxZoomScale) { + boolean showPlusMinus = mMinZoomScale < mMaxZoomScale; + boolean showMagnify = canZoomScrollOut(); + if (mZoomControls != null && (showPlusMinus || showMagnify)) { if (mZoomControls.getVisibility() == View.VISIBLE) { mPrivateHandler.removeCallbacks(mZoomControlRunnable); } else { - mZoomControls.show(canZoomScrollOut()); + mZoomControls.show(showPlusMinus, showMagnify); } mPrivateHandler.postDelayed(mZoomControlRunnable, ZOOM_CONTROLS_TIMEOUT); @@ -3244,6 +3513,10 @@ public class WebView extends AbsoluteLayout doShortPress(); } break; + case TOUCH_SELECT_MODE: + commitCopy(); + mTouchSelection = mExtendSelection = false; + break; case SCROLL_ZOOM_ANIMATION_IN: case SCROLL_ZOOM_ANIMATION_OUT: // no action during scroll animation @@ -3349,6 +3622,7 @@ public class WebView extends AbsoluteLayout private int mTrackballXMove = 0; private int mTrackballYMove = 0; private boolean mExtendSelection = false; + private boolean mTouchSelection = false; private static final int TRACKBALL_KEY_TIMEOUT = 1000; private static final int TRACKBALL_TIMEOUT = 200; private static final int TRACKBALL_WAIT = 100; @@ -3359,7 +3633,6 @@ public class WebView extends AbsoluteLayout private int mSelectX = 0; private int mSelectY = 0; private boolean mShiftIsPressed = false; - private boolean mAltIsPressed = false; private boolean mTrackballDown = false; private long mTrackballUpTime = 0; private long mLastFocusTime = 0; @@ -3386,17 +3659,18 @@ public class WebView extends AbsoluteLayout @Override public boolean onTrackballEvent(MotionEvent ev) { long time = ev.getEventTime(); - if (mAltIsPressed) { + if ((ev.getMetaState() & KeyEvent.META_ALT_ON) != 0) { if (ev.getY() > 0) pageDown(true); if (ev.getY() < 0) pageUp(true); return true; } if (ev.getAction() == MotionEvent.ACTION_DOWN) { mPrivateHandler.removeMessages(SWITCH_TO_ENTER); - mPrivateHandler.sendMessageDelayed( - mPrivateHandler.obtainMessage(LONG_PRESS_TRACKBALL), 1000); mTrackTrackball = true; mTrackballDown = true; + if (mNativeClass != 0) { + nativeRecordButtons(true, true); + } if (time - mLastFocusTime <= TRACKBALL_TIMEOUT && !mLastFocusBounds.equals(nativeGetFocusRingBounds())) { nativeSelectBestAt(mLastFocusBounds); @@ -3408,7 +3682,8 @@ public class WebView extends AbsoluteLayout } return false; // let common code in onKeyDown at it } else if (mTrackTrackball) { - mPrivateHandler.removeMessages(LONG_PRESS_TRACKBALL); + // LONG_PRESS_ENTER is set in common onKeyDown + mPrivateHandler.removeMessages(LONG_PRESS_ENTER); mTrackTrackball = false; } if (ev.getAction() == MotionEvent.ACTION_UP) { @@ -3823,13 +4098,7 @@ public class WebView extends AbsoluteLayout return; } switchOutDrawHistory(); - // mLastTouchX and mLastTouchY are the point in the current viewport - int contentX = viewToContent((int) mLastTouchX + mScrollX); - int contentY = viewToContent((int) mLastTouchY + mScrollY); - int contentSize = ViewConfiguration.getTouchSlop(); - nativeMotionUp(contentX, contentY, contentSize, true); - - // call uiOverride next to check whether it is a special node, + // call uiOverride to check whether it is a special node, // phone/email/address, which are not handled by WebKit if (nativeUpdateFocusNode()) { FocusNode node = mFocusNode; @@ -3840,6 +4109,11 @@ public class WebView extends AbsoluteLayout } playSoundEffect(SoundEffectConstants.CLICK); } + // mLastTouchX and mLastTouchY are the point in the current viewport + int contentX = viewToContent((int) mLastTouchX + mScrollX); + int contentY = viewToContent((int) mLastTouchY + mScrollY); + int contentSize = ViewConfiguration.getTouchSlop(); + nativeMotionUp(contentX, contentY, contentSize, true); } @Override @@ -3907,6 +4181,8 @@ public class WebView extends AbsoluteLayout mHeightCanMeasure = false; } } + } else { + mHeightCanMeasure = false; } if (mNativeClass != 0) { nativeSetHeightCanMeasure(mHeightCanMeasure); @@ -3915,6 +4191,8 @@ public class WebView extends AbsoluteLayout if (widthMode == MeasureSpec.UNSPECIFIED) { mWidthCanMeasure = true; measuredWidth = contentWidth; + } else { + mWidthCanMeasure = false; } synchronized (this) { @@ -4076,10 +4354,14 @@ public class WebView extends AbsoluteLayout break; case NEW_PICTURE_MSG_ID: // called for new content - final Point viewSize = (Point) msg.obj; + final WebViewCore.DrawData draw = + (WebViewCore.DrawData) msg.obj; + final Point viewSize = draw.mViewPoint; if (mZoomScale > 0) { - if (Math.abs(mZoomScale * viewSize.x - - getViewWidth()) < 1) { + // use the same logic in sendViewSizeZoom() to make sure + // the mZoomScale has matched the viewSize so that we + // can clear mZoomScale + if (Math.round(getViewWidth() / mZoomScale) == viewSize.x) { mZoomScale = 0; mWebViewCore.sendMessage(EventHub.SET_SNAP_ANCHOR, 0, 0); @@ -4091,8 +4373,14 @@ public class WebView extends AbsoluteLayout // received in the fixed dimension. final boolean updateLayout = viewSize.x == mLastWidthSent && viewSize.y == mLastHeightSent; - recordNewContentSize(msg.arg1, msg.arg2, updateLayout); - invalidate(); + recordNewContentSize(draw.mWidthHeight.x, + draw.mWidthHeight.y, updateLayout); + if (LOGV_ENABLED) { + Rect b = draw.mInvalRegion.getBounds(); + Log.v(LOGTAG, "NEW_PICTURE_MSG_ID {" + + b.left+","+b.top+","+b.right+","+b.bottom+"}"); + } + invalidate(contentToView(draw.mInvalRegion.getBounds())); if (mPictureListener != null) { mPictureListener.onNewPicture(WebView.this, capturePicture()); } @@ -4156,6 +4444,7 @@ public class WebView extends AbsoluteLayout } int initialScale = msg.arg1; int viewportWidth = msg.arg2; + // by default starting a new page with 100% zoom scale. float scale = 1.0f; if (mInitialScale > 0) { scale = mInitialScale / 100.0f; @@ -4165,10 +4454,15 @@ public class WebView extends AbsoluteLayout // to 0 mLastWidthSent = 0; } - // by default starting a new page with 100% zoom scale. - scale = initialScale == 0 ? (viewportWidth > 0 ? - ((float) width / viewportWidth) : 1.0f) - : initialScale / 100.0f; + if (initialScale == 0) { + // if viewportWidth is defined and it is smaller + // than the view width, zoom in to fill the view + if (viewportWidth > 0 && viewportWidth < width) { + scale = (float) width / viewportWidth; + } + } else { + scale = initialScale / 100.0f; + } } setNewZoomScale(scale, false); break; @@ -4213,10 +4507,32 @@ public class WebView extends AbsoluteLayout WebViewCore.resumeUpdate(mWebViewCore); break; - case LONG_PRESS_TRACKBALL: + case LONG_PRESS_ENTER: + // as this is shared by keydown and trackballdown, reset all + // the states + mGotEnterDown = false; mTrackTrackball = false; mTrackballDown = false; - performLongClick(); + // LONG_PRESS_ENTER is sent as a delayed message. If we + // switch to windows overview, the WebView will be + // temporarily removed from the view system. In that case, + // do nothing. + if (getParent() != null) { + performLongClick(); + } + break; + + case WEBCORE_NEED_TOUCH_EVENTS: + mForwardTouchEvents = (msg.arg1 != 0); + break; + + case PREVENT_TOUCH_ID: + // update may have already been paused by touch; restore since + // this effectively aborts touch and skips logic in touch up + if (mTouchMode == TOUCH_DRAG_MODE) { + WebViewCore.resumeUpdate(mWebViewCore); + } + mTouchMode = TOUCH_DONE_MODE; break; default: @@ -4514,10 +4830,7 @@ public class WebView extends AbsoluteLayout } Rect contentFocus = nativeGetFocusRingBounds(); if (contentFocus.isEmpty()) return keyHandled; - Rect viewFocus = new Rect(contentToView(contentFocus.left) - , contentToView(contentFocus.top) - , contentToView(contentFocus.right) - , contentToView(contentFocus.bottom)); + Rect viewFocus = contentToView(contentFocus); Rect visRect = new Rect(); calcOurVisibleRect(visRect); Rect outset = new Rect(visRect); @@ -4559,7 +4872,7 @@ public class WebView extends AbsoluteLayout public void debugDump() { nativeDebugDump(); - mWebViewCore.sendMessage(EventHub.DUMP_WEBKIT); + mWebViewCore.sendMessage(EventHub.DUMP_NAVTREE); } /** @@ -4583,6 +4896,7 @@ public class WebView extends AbsoluteLayout private native void nativeDrawFocusRing(Canvas content); private native void nativeDrawSelection(Canvas content , int x, int y, boolean extendSelection); + private native void nativeDrawSelectionRegion(Canvas content); private native boolean nativeUpdateFocusNode(); private native Rect nativeGetFocusRingBounds(); private native Rect nativeGetNavBounds(); @@ -4593,17 +4907,27 @@ public class WebView extends AbsoluteLayout boolean noScroll); private native void nativeNotifyFocusSet(boolean inEditingMode); private native void nativeRecomputeFocus(); - private native void nativeRecordButtons(); + // Like many other of our native methods, you must make sure that + // mNativeClass is not null before calling this method. + private native void nativeRecordButtons(boolean pressed, + boolean invalidate); private native void nativeResetFocus(); private native void nativeResetNavClipBounds(); private native void nativeSelectBestAt(Rect rect); + private native void nativeSetFindIsDown(); private native void nativeSetFollowedLink(boolean followed); private native void nativeSetHeightCanMeasure(boolean measure); private native void nativeSetNavBounds(Rect rect); private native void nativeSetNavClipBounds(Rect rect); - private native boolean nativeHasSrcUrl(); - private native boolean nativeIsImage(int x, int y); + private native String nativeImageURI(int x, int y); + /** + * Returns true if the native focus nodes says it wants to handle key events + * (ala plugins). This can only be called if mNativeClass is non-zero! + */ + private native boolean nativeFocusNodeWantsKeyEvents(); private native void nativeMoveSelection(int x, int y , boolean extendSelection); private native Region nativeGetSelection(); + + private native void nativeDumpDisplayTree(String urlOrNull); } diff --git a/core/java/android/webkit/WebViewCore.java b/core/java/android/webkit/WebViewCore.java index 263346ee447bcc8f98c749b3f7e991e682bd83ab..9e413f90eda5b7dd2a9a707ebb6292e896f64d16 100644 --- a/core/java/android/webkit/WebViewCore.java +++ b/core/java/android/webkit/WebViewCore.java @@ -70,13 +70,6 @@ final class WebViewCore { // The BrowserFrame is an interface to the native Frame component. private BrowserFrame mBrowserFrame; - - /* This is a ring of pictures for content. After B is built, it is swapped - with A. - */ - private Picture mContentPictureA = new Picture(); // draw() - private Picture mContentPictureB = new Picture(); // nativeDraw() - /* * range is from 200 to 10,000. 0 is a special value means device-width. -1 * means undefined. @@ -196,7 +189,8 @@ final class WebViewCore { sWebCoreHandler.removeMessages(WebCoreThread.INITIALIZE, this); } - /* Get the BrowserFrame component. This is used for subwindow creation. */ + /* Get the BrowserFrame component. This is used for subwindow creation and + * is called only from BrowserFrame in the WebCore thread. */ /* package */ BrowserFrame getBrowserFrame() { return mBrowserFrame; } @@ -278,30 +272,40 @@ final class WebViewCore { static native String nativeFindAddress(String addr); /** - * Find and highlight an occurance of text matching find - * @param find The text to find. - * @param forward If true, search forward. Else, search backwards. - * @param fromSelection Whether to start from the current selection or from - * the beginning of the viewable page. - * @return boolean Whether the text was found. + * Empty the picture set. */ - private native boolean nativeFind(String find, - boolean forward, - boolean fromSelection); - + private native void nativeClearContent(); + + /** + * Create a flat picture from the set of pictures. + */ + private native void nativeCopyContentToPicture(Picture picture); + + /** + * Draw the picture set with a background color. Returns true + * if some individual picture took too long to draw and can be + * split into parts. Called from the UI thread. + */ + private native boolean nativeDrawContent(Canvas canvas, int color); + /** - * Find all occurances of text matching find and highlight them. - * @param find The text to find. - * @return int The number of occurances of find found. + * Redraw a portion of the picture set. The Point wh returns the + * width and height of the overall picture. */ - private native int nativeFindAll(String find); + private native boolean nativeRecordContent(Region invalRegion, Point wh); /** - * Clear highlights on text created by nativeFindAll. + * Splits slow parts of the picture set. Called from the webkit + * thread after nativeDrawContent returns true. */ - private native void nativeClearMatches(); + private native void nativeSplitContent(); + + // these must be kept lock-step with the KeyState enum in WebViewCore.h + static private final int KEY_ACTION_DOWN = 0; + static private final int KEY_ACTION_UP = 1; - private native void nativeDraw(Picture content); + private native boolean nativeSendKeyToFocusNode(int keyCode, int unichar, + int repeatCount, boolean isShift, boolean isAlt, int keyAction); private native boolean nativeKeyUp(int keycode, int keyvalue); @@ -343,21 +347,12 @@ final class WebViewCore { private native String nativeRetrieveHref(int framePtr, int nodePtr); - /** - * Return the url of the image located at (x,y) in content coordinates, or - * null if there is no image at that point. - * - * @param x x content ordinate - * @param y y content ordinate - * @return String url of the image located at (x,y), or null if there is - * no image there. - */ - private native String nativeRetrieveImageRef(int x, int y); - private native void nativeTouchUp(int touchGeneration, int buildGeneration, int framePtr, int nodePtr, int x, int y, int size, boolean isClick, boolean retry); + private native boolean nativeHandleTouchEvent(int action, int x, int y); + private native void nativeUnblockFocus(); private native void nativeUpdateFrameCache(); @@ -368,7 +363,11 @@ final class WebViewCore { private native void nativeSetBackgroundColor(int color); - private native void nativeDump(); + private native void nativeDumpDomTree(boolean useFile); + + private native void nativeDumpRenderTree(boolean useFile); + + private native void nativeDumpNavTree(); private native void nativeRefreshPlugins(boolean reloadOpenPages); @@ -393,6 +392,10 @@ final class WebViewCore { private native String nativeGetSelection(Region sel); + // Register a scheme to be treated as local scheme so that it can access + // local asset files for resources + private native void nativeRegisterURLSchemeAsLocal(String scheme); + // EventHub for processing messages private final EventHub mEventHub; // WebCore thread handler @@ -421,10 +424,7 @@ final class WebViewCore { switch (msg.what) { case INITIALIZE: WebViewCore core = (WebViewCore) msg.obj; - synchronized (core) { - core.initialize(); - core.notify(); - } + core.initialize(); break; case REDUCE_PRIORITY: @@ -501,6 +501,12 @@ final class WebViewCore { boolean mRetry; } + static class TouchEventData { + int mAction; // MotionEvent.getAction() + int mX; + int mY; + } + class EventHub { // Message Ids static final int LOAD_URL = 100; @@ -510,7 +516,7 @@ final class WebViewCore { static final int KEY_UP = 104; static final int VIEW_SIZE_CHANGED = 105; static final int GO_BACK_FORWARD = 106; - static final int SET_VISIBLE_RECT = 107; + static final int SET_SCROLL_OFFSET = 107; static final int RESTORE_STATE = 108; static final int PAUSE_TIMERS = 109; static final int RESUME_TIMERS = 110; @@ -519,16 +525,13 @@ final class WebViewCore { static final int SET_SELECTION = 113; static final int REPLACE_TEXT = 114; static final int PASS_TO_JS = 115; - static final int FIND = 116; + static final int SET_GLOBAL_BOUNDS = 116; static final int UPDATE_CACHE_AND_TEXT_ENTRY = 117; - static final int FIND_ALL = 118; - static final int CLEAR_MATCHES = 119; static final int DOC_HAS_IMAGES = 120; static final int SET_SNAP_ANCHOR = 121; static final int DELETE_SELECTION = 122; static final int LISTBOX_CHOICES = 123; static final int SINGLE_LISTBOX_CHOICE = 124; - static final int DUMP_WEBKIT = 125; static final int SET_BACKGROUND_COLOR = 126; static final int UNBLOCK_FOCUS = 127; static final int SAVE_DOCUMENT_STATE = 128; @@ -536,9 +539,10 @@ final class WebViewCore { static final int WEBKIT_DRAW = 130; static final int SYNC_SCROLL = 131; static final int REFRESH_PLUGINS = 132; - + static final int SPLIT_PICTURE_SET = 133; + static final int CLEAR_CONTENT = 134; + // UI nav messages - static final int REQUEST_IMAGE_HREF = 134; static final int SET_FINAL_FOCUS = 135; static final int SET_KIT_FOCUS = 136; static final int REQUEST_FOCUS_HREF = 137; @@ -547,6 +551,8 @@ final class WebViewCore { // motion static final int TOUCH_UP = 140; + // message used to pass UI touch events to WebCore + static final int TOUCH_EVENT = 141; // Network-based messaging static final int CLEAR_SSL_PREF_TABLE = 150; @@ -554,6 +560,12 @@ final class WebViewCore { // Test harness messages static final int REQUEST_EXT_REPRESENTATION = 160; static final int REQUEST_DOC_AS_TEXT = 161; + + // debugging + static final int DUMP_DOMTREE = 170; + static final int DUMP_RENDERTREE = 171; + static final int DUMP_NAVTREE = 172; + // private message ids private static final int DESTROY = 200; @@ -561,6 +573,19 @@ final class WebViewCore { static final int NO_FOCUS_CHANGE_BLOCK = 0; static final int BLOCK_FOCUS_CHANGE_UNTIL_KEY_UP = 1; + /* The KEY_DOWN and KEY_UP messages pass the keyCode in arg1, and a + "type" in arg2. These are the types, and they describe what the + circumstances were that prompted the UI thread to send the keyevent + to webkit. + + FOCUS_NODE - the currently focused node says it wants key events + (e.g. plugins) + UNHANDLED - the UI side did not handle the key, so we give webkit + a shot at it. + */ + static final int KEYEVENT_FOCUS_NODE_TYPE = 0; + static final int KEYEVENT_UNHANDLED_TYPE = 1; + // Private handler for WebCore messages. private Handler mHandler; // Message queue for containing messages before the WebCore thread is @@ -607,8 +632,30 @@ final class WebViewCore { case LOAD_DATA: HashMap loadParams = (HashMap) msg.obj; - mBrowserFrame.loadData( - (String) loadParams.get("baseUrl"), + String baseUrl = (String) loadParams.get("baseUrl"); + if (baseUrl != null) { + int i = baseUrl.indexOf(':'); + if (i > 0) { + /* + * In 1.0, {@link + * WebView#loadDataWithBaseURL} can access + * local asset files as long as the data is + * valid. In the new WebKit, the restriction + * is tightened. To be compatible with 1.0, + * we automatically add the scheme of the + * baseUrl for local access as long as it is + * not http(s)/ftp(s)/about/javascript + */ + String scheme = baseUrl.substring(0, i); + if (!scheme.startsWith("http") && + !scheme.startsWith("ftp") && + !scheme.startsWith("about") && + !scheme.startsWith("javascript")) { + nativeRegisterURLSchemeAsLocal(scheme); + } + } + } + mBrowserFrame.loadData(baseUrl, (String) loadParams.get("data"), (String) loadParams.get("mimeType"), (String) loadParams.get("encoding"), @@ -622,8 +669,7 @@ final class WebViewCore { // up with native side if (mBrowserFrame.committed() && !mBrowserFrame.firstLayoutDone()) { - mBrowserFrame.didFirstLayout(mBrowserFrame - .currentUrl()); + mBrowserFrame.didFirstLayout(); } // Do this after syncing up the layout state. stopLoading(); @@ -634,11 +680,11 @@ final class WebViewCore { break; case KEY_DOWN: - keyDown(msg.arg1, (KeyEvent) msg.obj); + keyDown(msg.arg1, msg.arg2, (KeyEvent) msg.obj); break; case KEY_UP: - keyUp(msg.arg1, (KeyEvent) msg.obj); + keyUp(msg.arg1, msg.arg2, (KeyEvent) msg.obj); break; case VIEW_SIZE_CHANGED: @@ -646,12 +692,16 @@ final class WebViewCore { ((Float) msg.obj).floatValue()); break; - case SET_VISIBLE_RECT: - Rect r = (Rect) msg.obj; + case SET_SCROLL_OFFSET: // note: these are in document coordinates // (inv-zoom) - nativeSetVisibleRect(r.left, r.top, r.width(), - r.height()); + nativeSetScrollOffset(msg.arg1, msg.arg2); + break; + + case SET_GLOBAL_BOUNDS: + Rect r = (Rect) msg.obj; + nativeSetGlobalBounds(r.left, r.top, r.width(), + r.height()); break; case GO_BACK_FORWARD: @@ -745,30 +795,6 @@ final class WebViewCore { break; } - case FIND: - /* arg1: - * 1 - Find next - * -1 - Find previous - * 0 - Find first - */ - Message response = (Message) msg.obj; - boolean find = nativeFind(msg.getData().getString("find"), - msg.arg1 != -1, msg.arg1 != 0); - response.arg1 = find ? 1 : 0; - response.sendToTarget(); - break; - - case FIND_ALL: - int found = nativeFindAll(msg.getData().getString("find")); - Message resAll = (Message) msg.obj; - resAll.arg1 = found; - resAll.sendToTarget(); - break; - - case CLEAR_MATCHES: - nativeClearMatches(); - break; - case CLEAR_SSL_PREF_TABLE: Network.getInstance(mContext) .clearUserSslPrefTable(); @@ -784,6 +810,17 @@ final class WebViewCore { touchUpData.mRetry); break; + case TOUCH_EVENT: { + TouchEventData ted = (TouchEventData) msg.obj; + if (nativeHandleTouchEvent(ted.mAction, ted.mX, + ted.mY)) { + Message.obtain(mWebView.mPrivateHandler, + WebView.PREVENT_TOUCH_ID) + .sendToTarget(); + } + break; + } + case ADD_JS_INTERFACE: HashMap map = (HashMap) msg.obj; Object obj = map.get("object"); @@ -826,27 +863,17 @@ final class WebViewCore { case REQUEST_FOCUS_HREF: { Message hrefMsg = (Message) msg.obj; String res = nativeRetrieveHref(msg.arg1, msg.arg2); - Bundle data = hrefMsg.getData(); - data.putString("url", res); - hrefMsg.setData(data); + hrefMsg.getData().putString("url", res); hrefMsg.sendToTarget(); break; } - case REQUEST_IMAGE_HREF: { - Message refMsg = (Message) msg.obj; - String ref = - nativeRetrieveImageRef(msg.arg1, msg.arg2); - Bundle data = refMsg.getData(); - data.putString("url", ref); - refMsg.setData(data); - refMsg.sendToTarget(); - break; - } - case UPDATE_CACHE_AND_TEXT_ENTRY: nativeUpdateFrameCache(); - sendViewInvalidate(); + // FIXME: this should provide a minimal rectangle + if (mWebView != null) { + mWebView.postInvalidate(); + } sendUpdateTextEntry(); break; @@ -901,9 +928,17 @@ final class WebViewCore { , WebView.UPDATE_CLIPBOARD, str) .sendToTarget(); break; - - case DUMP_WEBKIT: - nativeDump(); + + case DUMP_DOMTREE: + nativeDumpDomTree(msg.arg1 == 1); + break; + + case DUMP_RENDERTREE: + nativeDumpRenderTree(msg.arg1 == 1); + break; + + case DUMP_NAVTREE: + nativeDumpNavTree(); break; case SYNC_SCROLL: @@ -914,6 +949,18 @@ final class WebViewCore { case REFRESH_PLUGINS: nativeRefreshPlugins(msg.arg1 != 0); break; + + case SPLIT_PICTURE_SET: + nativeSplitContent(); + mSplitPictureIsScheduled = false; + break; + + case CLEAR_CONTENT: + // Clear the view so that onDraw() will draw nothing + // but white background + // (See public method WebView.clearView) + nativeClearContent(); + break; } } }; @@ -982,6 +1029,7 @@ final class WebViewCore { private synchronized void removeMessages() { // reset mDrawIsScheduled flag as WEBKIT_DRAW may be removed mDrawIsScheduled = false; + mSplitPictureIsScheduled = false; if (mMessages != null) { mMessages.clear(); } else { @@ -1001,7 +1049,7 @@ final class WebViewCore { // Methods called by host activity (in the same thread) //------------------------------------------------------------------------- - public void stopLoading() { + void stopLoading() { if (LOGV_ENABLED) Log.v(LOGTAG, "CORE stopLoading"); if (mBrowserFrame != null) { mBrowserFrame.stopLoading(); @@ -1082,23 +1130,48 @@ final class WebViewCore { mBrowserFrame.loadUrl(url); } - private void keyDown(int code, KeyEvent event) { + private void keyDown(int code, int target, KeyEvent event) { if (LOGV_ENABLED) { Log.v(LOGTAG, "CORE keyDown at " + System.currentTimeMillis() + ", " + event); } + switch (target) { + case EventHub.KEYEVENT_UNHANDLED_TYPE: + break; + case EventHub.KEYEVENT_FOCUS_NODE_TYPE: + if (nativeSendKeyToFocusNode(code, event.getUnicodeChar(), + event.getRepeatCount(), + event.isShiftPressed(), + event.isAltPressed(), + KEY_ACTION_DOWN)) { + return; + } + break; + } + // If we get here, no one handled it, so call our proxy mCallbackProxy.onUnhandledKeyEvent(event); } - private void keyUp(int code, KeyEvent event) { + private void keyUp(int code, int target, KeyEvent event) { if (LOGV_ENABLED) { Log.v(LOGTAG, "CORE keyUp at " + System.currentTimeMillis() + ", " + event); } - if (!nativeKeyUp(code, event.getUnicodeChar())) { - mCallbackProxy.onUnhandledKeyEvent(event); + switch (target) { + case EventHub.KEYEVENT_UNHANDLED_TYPE: + if (!nativeKeyUp(code, event.getUnicodeChar())) { + mCallbackProxy.onUnhandledKeyEvent(event); + } + break; + case EventHub.KEYEVENT_FOCUS_NODE_TYPE: + nativeSendKeyToFocusNode(code, event.getUnicodeChar(), + event.getRepeatCount(), + event.isShiftPressed(), + event.isAltPressed(), + KEY_ACTION_UP); + break; + } } - } // These values are used to avoid requesting a layout based on old values private int mCurrentViewWidth = 0; @@ -1140,8 +1213,9 @@ final class WebViewCore { mCurrentViewHeight = h; if (needInvalidate) { // ensure {@link #webkitDraw} is called as we were blocking in - // {@link #contentInvalidate} when mCurrentViewWidth is 0 - contentInvalidate(); + // {@link #contentDraw} when mCurrentViewWidth is 0 + if (LOGV_ENABLED) Log.v(LOGTAG, "viewSizeChanged"); + contentDraw(); } mEventHub.sendMessage(Message.obtain(null, EventHub.UPDATE_CACHE_AND_TEXT_ENTRY)); @@ -1156,30 +1230,42 @@ final class WebViewCore { // Used to avoid posting more than one draw message. private boolean mDrawIsScheduled; + + // Used to avoid posting more than one split picture message. + private boolean mSplitPictureIsScheduled; + + // Used to suspend drawing. + private boolean mDrawIsPaused; // Used to end scale+scroll mode, accessed by both threads boolean mEndScaleZoom = false; + public class DrawData { + public DrawData() { + mInvalRegion = new Region(); + mWidthHeight = new Point(); + } + public Region mInvalRegion; + public Point mViewPoint; + public Point mWidthHeight; + } + private void webkitDraw() { mDrawIsScheduled = false; - nativeDraw(mContentPictureB); - int w; - int h; - synchronized (this) { - Picture temp = mContentPictureB; - mContentPictureB = mContentPictureA; - mContentPictureA = temp; - w = mContentPictureA.getWidth(); - h = mContentPictureA.getHeight(); + DrawData draw = new DrawData(); + if (LOGV_ENABLED) Log.v(LOGTAG, "webkitDraw start"); + if (nativeRecordContent(draw.mInvalRegion, draw.mWidthHeight) + == false) { + if (LOGV_ENABLED) Log.v(LOGTAG, "webkitDraw abort"); + return; } - if (mWebView != null) { // Send the native view size that was used during the most recent // layout. + draw.mViewPoint = new Point(mCurrentViewWidth, mCurrentViewHeight); + if (LOGV_ENABLED) Log.v(LOGTAG, "webkitDraw NEW_PICTURE_MSG_ID"); Message.obtain(mWebView.mPrivateHandler, - WebView.NEW_PICTURE_MSG_ID, w, h, - new Point(mCurrentViewWidth, mCurrentViewHeight)) - .sendToTarget(); + WebView.NEW_PICTURE_MSG_ID, draw).sendToTarget(); if (mWebkitScrollX != 0 || mWebkitScrollY != 0) { // as we have the new picture, try to sync the scroll position Message.obtain(mWebView.mPrivateHandler, @@ -1217,37 +1303,18 @@ final class WebViewCore { df = mScrollFilter; } canvas.setDrawFilter(df); - synchronized (this) { - Picture picture = mContentPictureA; - int sc = canvas.save(Canvas.CLIP_SAVE_FLAG); - Rect clip = new Rect(0, 0, picture.getWidth(), picture.getHeight()); - canvas.clipRect(clip, Region.Op.DIFFERENCE); - canvas.drawColor(color); - canvas.restoreToCount(sc); - // experiment commented out - // if (TEST_BUCKET) { - // nativeDrawContentPicture(canvas); - // } else { - canvas.drawPicture(picture); - // } - } + boolean tookTooLong = nativeDrawContent(canvas, color); canvas.setDrawFilter(null); - } - - /* package */ void clearContentPicture() { - // experiment commented out - // if (TEST_BUCKET) { - // nativeClearContentPicture(); - // } - synchronized (this) { - mContentPictureA = new Picture(); + if (tookTooLong && mSplitPictureIsScheduled == false) { + mSplitPictureIsScheduled = true; + sendMessage(EventHub.SPLIT_PICTURE_SET); } } /*package*/ Picture copyContentPicture() { - synchronized (this) { - return new Picture(mContentPictureA); - } + Picture result = new Picture(); + nativeCopyContentToPicture(result); + return result; } static void pauseUpdate(WebViewCore core) { @@ -1263,7 +1330,7 @@ final class WebViewCore { // webcore thread priority is still lowered. if (core != null) { synchronized (core) { - core.mDrawIsScheduled = true; + core.mDrawIsPaused = true; core.mEventHub.removeMessages(EventHub.WEBKIT_DRAW); } } @@ -1278,7 +1345,9 @@ final class WebViewCore { if (core != null) { synchronized (core) { core.mDrawIsScheduled = false; - core.contentInvalidate(); + core.mDrawIsPaused = false; + if (LOGV_ENABLED) Log.v(LOGTAG, "resumeUpdate"); + core.contentDraw(); } } } @@ -1309,7 +1378,7 @@ final class WebViewCore { //------------------------------------------------------------------------- // called from JNI or WebView thread - /* package */ void contentInvalidate() { + /* package */ void contentDraw() { // don't update the Picture until we have an initial width and finish // the first layout if (mCurrentViewWidth == 0 || !mBrowserFrame.firstLayoutDone()) { @@ -1317,14 +1386,14 @@ final class WebViewCore { } // only fire an event if this is our first request synchronized (this) { - if (mDrawIsScheduled) { + if (mDrawIsPaused || mDrawIsScheduled) { return; } mDrawIsScheduled = true; mEventHub.sendMessage(Message.obtain(null, EventHub.WEBKIT_DRAW)); } } - + // called by JNI private void contentScrollBy(int dx, int dy) { if (!mBrowserFrame.firstLayoutDone()) { @@ -1397,6 +1466,7 @@ final class WebViewCore { sWebCoreHandler.removeMessages(WebCoreThread.CACHE_TICKER); sWebCoreHandler.sendMessage(sWebCoreHandler .obtainMessage(WebCoreThread.CACHE_TICKER)); + contentDraw(); } // called by JNI @@ -1408,9 +1478,9 @@ final class WebViewCore { } // called by JNI - private void sendViewInvalidate() { + private void sendViewInvalidate(int left, int top, int right, int bottom) { if (mWebView != null) { - mWebView.postInvalidate(); + mWebView.postInvalidate(left, top, right, bottom); } } @@ -1421,7 +1491,7 @@ final class WebViewCore { private native void setViewportSettingsFromNative(); // called by JNI - private void didFirstLayout(String url) { + private void didFirstLayout() { // Trick to ensure that the Picture has the exact height for the content // by forcing to layout with 0 height after the page is ready, which is // indicated by didFirstLayout. This is essential to get rid of the @@ -1435,7 +1505,7 @@ final class WebViewCore { mWebView.mLastHeightSent, -1.0f)); } - mBrowserFrame.didFirstLayout(url); + mBrowserFrame.didFirstLayout(); // reset the scroll position as it is a new page now mWebkitScrollX = mWebkitScrollY = 0; @@ -1517,7 +1587,16 @@ final class WebViewCore { mRestoredScale = scale; } } - + + // called by JNI + private void needTouchEvents(boolean need) { + if (mWebView != null) { + Message.obtain(mWebView.mPrivateHandler, + WebView.WEBCORE_NEED_TOUCH_EVENTS, need ? 1 : 0, 0) + .sendToTarget(); + } + } + // called by JNI private void updateTextfield(int ptr, boolean changeToPassword, String text, int textGeneration) { @@ -1530,9 +1609,10 @@ final class WebViewCore { } } - // these must be in document space (i.e. not scaled/zoomed. - private native void nativeSetVisibleRect(int x, int y, int width, - int height); + // these must be in document space (i.e. not scaled/zoomed). + private native void nativeSetScrollOffset(int dx, int dy); + + private native void nativeSetGlobalBounds(int x, int y, int w, int h); // called by JNI private void requestListBox(String[] array, boolean[] enabledArray, diff --git a/core/java/android/webkit/WebViewDatabase.java b/core/java/android/webkit/WebViewDatabase.java index b367e270417356230f1230bca22c56e102f1a1b4..96f36983343a51e3bb33e8935620d922e8e2e91d 100644 --- a/core/java/android/webkit/WebViewDatabase.java +++ b/core/java/android/webkit/WebViewDatabase.java @@ -39,7 +39,7 @@ public class WebViewDatabase { // log tag protected static final String LOGTAG = "webviewdatabase"; - private static final int DATABASE_VERSION = 8; + private static final int DATABASE_VERSION = 9; // 2 -> 3 Modified Cache table to allow cache of redirects // 3 -> 4 Added Oma-Downloads table // 4 -> 5 Modified Cache table to support persistent contentLength @@ -47,6 +47,7 @@ public class WebViewDatabase { // 5 -> 6 Add INDEX for cache table // 6 -> 7 Change cache localPath from int to String // 7 -> 8 Move cache to its own db + // 8 -> 9 Store both scheme and host when storing passwords private static final int CACHE_DATABASE_VERSION = 1; private static WebViewDatabase mInstance = null; @@ -172,7 +173,6 @@ public class WebViewDatabase { mDatabase.beginTransaction(); try { upgradeDatabase(); - bootstrapDatabase(); mDatabase.setTransactionSuccessful(); } finally { mDatabase.endTransaction(); @@ -200,6 +200,10 @@ public class WebViewDatabase { } finally { mCacheDatabase.endTransaction(); } + // Erase the files from the file system in the + // case that the database was updated and the + // there were existing cache content + CacheManager.removeAllCacheFiles(); } if (mCacheDatabase != null) { @@ -237,24 +241,26 @@ public class WebViewDatabase { if (oldVersion != 0) { Log.i(LOGTAG, "Upgrading database from version " + oldVersion + " to " - + DATABASE_VERSION + ", which will destroy all old data"); + + DATABASE_VERSION + ", which will destroy old data"); + } + boolean justPasswords = 8 == oldVersion && 9 == DATABASE_VERSION; + if (!justPasswords) { + mDatabase.execSQL("DROP TABLE IF EXISTS " + + mTableNames[TABLE_COOKIES_ID]); + mDatabase.execSQL("DROP TABLE IF EXISTS cache"); + mDatabase.execSQL("DROP TABLE IF EXISTS " + + mTableNames[TABLE_FORMURL_ID]); + mDatabase.execSQL("DROP TABLE IF EXISTS " + + mTableNames[TABLE_FORMDATA_ID]); + mDatabase.execSQL("DROP TABLE IF EXISTS " + + mTableNames[TABLE_HTTPAUTH_ID]); } - mDatabase.execSQL("DROP TABLE IF EXISTS " - + mTableNames[TABLE_COOKIES_ID]); - mDatabase.execSQL("DROP TABLE IF EXISTS cache"); mDatabase.execSQL("DROP TABLE IF EXISTS " + mTableNames[TABLE_PASSWORD_ID]); - mDatabase.execSQL("DROP TABLE IF EXISTS " - + mTableNames[TABLE_FORMURL_ID]); - mDatabase.execSQL("DROP TABLE IF EXISTS " - + mTableNames[TABLE_FORMDATA_ID]); - mDatabase.execSQL("DROP TABLE IF EXISTS " - + mTableNames[TABLE_HTTPAUTH_ID]); + mDatabase.setVersion(DATABASE_VERSION); - } - private static void bootstrapDatabase() { - if (mDatabase != null) { + if (!justPasswords) { // cookies mDatabase.execSQL("CREATE TABLE " + mTableNames[TABLE_COOKIES_ID] + " (" + ID_COL + " INTEGER PRIMARY KEY, " @@ -265,14 +271,6 @@ public class WebViewDatabase { mDatabase.execSQL("CREATE INDEX cookiesIndex ON " + mTableNames[TABLE_COOKIES_ID] + " (path)"); - // password - mDatabase.execSQL("CREATE TABLE " + mTableNames[TABLE_PASSWORD_ID] - + " (" + ID_COL + " INTEGER PRIMARY KEY, " - + PASSWORD_HOST_COL + " TEXT, " + PASSWORD_USERNAME_COL - + " TEXT, " + PASSWORD_PASSWORD_COL + " TEXT," + " UNIQUE (" - + PASSWORD_HOST_COL + ", " + PASSWORD_USERNAME_COL - + ") ON CONFLICT REPLACE);"); - // formurl mDatabase.execSQL("CREATE TABLE " + mTableNames[TABLE_FORMURL_ID] + " (" + ID_COL + " INTEGER PRIMARY KEY, " + FORMURL_URL_COL @@ -295,6 +293,13 @@ public class WebViewDatabase { + HTTPAUTH_HOST_COL + ", " + HTTPAUTH_REALM_COL + ", " + HTTPAUTH_USERNAME_COL + ") ON CONFLICT REPLACE);"); } + // passwords + mDatabase.execSQL("CREATE TABLE " + mTableNames[TABLE_PASSWORD_ID] + + " (" + ID_COL + " INTEGER PRIMARY KEY, " + + PASSWORD_HOST_COL + " TEXT, " + PASSWORD_USERNAME_COL + + " TEXT, " + PASSWORD_PASSWORD_COL + " TEXT," + " UNIQUE (" + + PASSWORD_HOST_COL + ", " + PASSWORD_USERNAME_COL + + ") ON CONFLICT REPLACE);"); } private static void upgradeCacheDatabase() { @@ -639,10 +644,11 @@ public class WebViewDatabase { if (cursor.moveToFirst()) { int batchSize = 100; StringBuilder pathStr = new StringBuilder(20 + 16 * batchSize); - pathStr.append("DELETE FROM cache WHERE filepath = ?"); + pathStr.append("DELETE FROM cache WHERE filepath IN (?"); for (int i = 1; i < batchSize; i++) { - pathStr.append(" OR filepath = ?"); + pathStr.append(", ?"); } + pathStr.append(")"); SQLiteStatement statement = mCacheDatabase.compileStatement(pathStr .toString()); // as bindString() uses 1-based index, initialize index to 1 @@ -658,6 +664,7 @@ public class WebViewDatabase { pathList.add(filePath); if (index++ == batchSize) { statement.execute(); + statement.clearBindings(); index = 1; } } while (cursor.moveToNext() && amount > 0); @@ -679,19 +686,20 @@ public class WebViewDatabase { /** * Set password. Tuple (PASSWORD_HOST_COL, PASSWORD_USERNAME_COL) is unique. * - * @param host The host for the password + * @param schemePlusHost The scheme and host for the password * @param username The username for the password. If it is null, it means * password can't be saved. * @param password The password */ - void setUsernamePassword(String host, String username, String password) { - if (host == null || mDatabase == null) { + void setUsernamePassword(String schemePlusHost, String username, + String password) { + if (schemePlusHost == null || mDatabase == null) { return; } synchronized (mPasswordLock) { final ContentValues c = new ContentValues(); - c.put(PASSWORD_HOST_COL, host); + c.put(PASSWORD_HOST_COL, schemePlusHost); c.put(PASSWORD_USERNAME_COL, username); c.put(PASSWORD_PASSWORD_COL, password); mDatabase.insert(mTableNames[TABLE_PASSWORD_ID], PASSWORD_HOST_COL, @@ -702,12 +710,12 @@ public class WebViewDatabase { /** * Retrieve the username and password for a given host * - * @param host The host which passwords applies to + * @param schemePlusHost The scheme and host which passwords applies to * @return String[] if found, String[0] is username, which can be null and * String[1] is password. Return null if it can't find anything. */ - String[] getUsernamePassword(String host) { - if (host == null || mDatabase == null) { + String[] getUsernamePassword(String schemePlusHost) { + if (schemePlusHost == null || mDatabase == null) { return null; } @@ -718,8 +726,8 @@ public class WebViewDatabase { synchronized (mPasswordLock) { String[] ret = null; Cursor cursor = mDatabase.query(mTableNames[TABLE_PASSWORD_ID], - columns, selection, new String[] { host }, null, null, - null); + columns, selection, new String[] { schemePlusHost }, null, + null, null); if (cursor.moveToFirst()) { ret = new String[2]; ret[0] = cursor.getString( diff --git a/core/java/android/webkit/gears/AndroidWifiDataProvider.java b/core/java/android/webkit/gears/AndroidWifiDataProvider.java new file mode 100644 index 0000000000000000000000000000000000000000..7379f595358870dca401bdb2ec71270f18260153 --- /dev/null +++ b/core/java/android/webkit/gears/AndroidWifiDataProvider.java @@ -0,0 +1,136 @@ +// Copyright 2008, Google Inc. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// 2. Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// 3. Neither the name of Google Inc. nor the names of its contributors may be +// used to endorse or promote products derived from this software without +// specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED +// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO +// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +package android.webkit.gears; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.net.wifi.ScanResult; +import android.net.wifi.WifiManager; +import android.os.Handler; +import android.os.Looper; +import android.util.Config; +import android.util.Log; +import android.webkit.WebView; +import java.util.List; + +/** + * WiFi data provider implementation for Android. + * {@hide} + */ +public final class AndroidWifiDataProvider extends BroadcastReceiver { + /** + * Logging tag + */ + private static final String TAG = "Gears-J-WifiProvider"; + /** + * Our Wifi manager instance. + */ + private WifiManager mWifiManager; + /** + * The native object ID. + */ + private long mNativeObject; + /** + * The Context instance. + */ + private Context mContext; + + /** + * Constructs a instance of this class and registers for wifi scan + * updates. Note that this constructor must be called on a Looper + * thread. Suitable threads can be created on the native side using + * the AndroidLooperThread C++ class. + */ + public AndroidWifiDataProvider(WebView webview, long object) { + mNativeObject = object; + mContext = webview.getContext(); + mWifiManager = + (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE); + if (mWifiManager == null) { + Log.e(TAG, + "AndroidWifiDataProvider: could not get location manager."); + throw new NullPointerException( + "AndroidWifiDataProvider: locationManager is null."); + } + + // Create a Handler that identifies the message loop associated + // with the current thread. Note that it is not necessary to + // override handleMessage() at all since the Intent + // ReceiverDispatcher (see the ActivityThread class) only uses + // this handler to post a Runnable to this thread's loop. + Handler handler = new Handler(Looper.myLooper()); + + IntentFilter filter = new IntentFilter(); + filter.addAction(mWifiManager.SCAN_RESULTS_AVAILABLE_ACTION); + mContext.registerReceiver(this, filter, null, handler); + + // Get the last scan results and pass them to the native side. + // We can't just invoke the callback here, so we queue a message + // to this thread's loop. + handler.post(new Runnable() { + public void run() { + onUpdateAvailable(mWifiManager.getScanResults(), mNativeObject); + } + }); + } + + /** + * Called when the provider is no longer needed. + */ + public void shutdown() { + mContext.unregisterReceiver(this); + if (Config.LOGV) { + Log.v(TAG, "Wifi provider closed."); + } + } + + /** + * This method is called when the AndroidWifiDataProvider is receiving an + * Intent broadcast. + * @param context The Context in which the receiver is running. + * @param intent The Intent being received. + */ + public void onReceive(Context context, Intent intent) { + if (intent.getAction().equals( + mWifiManager.SCAN_RESULTS_AVAILABLE_ACTION)) { + if (Config.LOGV) { + Log.v(TAG, "Wifi scan resulst available"); + } + onUpdateAvailable(mWifiManager.getScanResults(), mNativeObject); + } + } + + /** + * The native method called when new wifi data is available. + * @param scanResults is a list of ScanResults to pass to the native side. + * @param nativeObject is a pointer to the corresponding + * AndroidWifiDataProvider C++ instance. + */ + private static native void onUpdateAvailable( + List scanResults, long nativeObject); +} diff --git a/core/java/android/webkit/gears/DesktopAndroid.java b/core/java/android/webkit/gears/DesktopAndroid.java index 00a9a47e5a28636801fcdb11e9ac20cc25b20e44..ee8ca498562be7a0fd46fa751448bc78e221971b 100644 --- a/core/java/android/webkit/gears/DesktopAndroid.java +++ b/core/java/android/webkit/gears/DesktopAndroid.java @@ -40,8 +40,6 @@ import android.webkit.WebView; public class DesktopAndroid { private static final String TAG = "Gears-J-Desktop"; - private static final String BROWSER = "com.android.browser"; - private static final String BROWSER_ACTIVITY = BROWSER + ".BrowserActivity"; private static final String EXTRA_SHORTCUT_DUPLICATE = "duplicate"; private static final String ACTION_INSTALL_SHORTCUT = "com.android.launcher.action.INSTALL_SHORTCUT"; @@ -78,11 +76,9 @@ public class DesktopAndroid { String url, String imagePath) { Context context = webview.getContext(); - ComponentName browser = new ComponentName(BROWSER, BROWSER_ACTIVITY); - Intent viewWebPage = new Intent(Intent.ACTION_VIEW); - viewWebPage.setComponent(browser); viewWebPage.setData(Uri.parse(url)); + viewWebPage.addCategory(Intent.CATEGORY_BROWSABLE); Intent intent = new Intent(ACTION_INSTALL_SHORTCUT); intent.putExtra(Intent.EXTRA_SHORTCUT_INTENT, viewWebPage); diff --git a/core/java/android/webkit/gears/HttpRequestAndroid.java b/core/java/android/webkit/gears/HttpRequestAndroid.java index 8668c545a674cc36165f3c411888c7e224a243eb..30f855f0c892b40522278f8f19d2b8aa419ca1d6 100644 --- a/core/java/android/webkit/gears/HttpRequestAndroid.java +++ b/core/java/android/webkit/gears/HttpRequestAndroid.java @@ -163,7 +163,20 @@ public final class HttpRequestAndroid { // Setup the connection. This doesn't go to the wire yet - it // doesn't block. try { - connection = (HttpURLConnection) new URL(url).openConnection(); + URL url_object = new URL(url); + // Check that the protocol is indeed HTTP(S). + String protocol = url_object.getProtocol(); + if (protocol == null) { + log("null protocol for URL " + url); + return false; + } + protocol = protocol.toLowerCase(); + if (!"http".equals(protocol) && !"https".equals(protocol)) { + log("Url has wrong protocol: " + url); + return false; + } + + connection = (HttpURLConnection) url_object.openConnection(); connection.setRequestMethod(method); // Manually follow redirects. connection.setInstanceFollowRedirects(false); @@ -197,11 +210,13 @@ public final class HttpRequestAndroid { log("interrupt() called but no child thread"); return; } - if (inBlockingOperation) { - log("Interrupting blocking operation"); - childThread.interrupt(); - } else { - log("Nothing to interrupt"); + synchronized (this) { + if (inBlockingOperation) { + log("Interrupting blocking operation"); + childThread.interrupt(); + } else { + log("Nothing to interrupt"); + } } } @@ -472,7 +487,7 @@ public final class HttpRequestAndroid { String encoding = cacheResult.getEncoding(); // Encoding may not be specified. No default. String contentType = mimeType; - if (encoding != null) { + if (encoding != null && encoding.length() > 0) { contentType += "; charset=" + encoding; } setResponseHeader(KEY_CONTENT_TYPE, contentType); diff --git a/core/java/android/webkit/gears/NativeDialog.java b/core/java/android/webkit/gears/NativeDialog.java new file mode 100644 index 0000000000000000000000000000000000000000..9e2b3754bd09e356d43ae5717f5ed110be8d51a4 --- /dev/null +++ b/core/java/android/webkit/gears/NativeDialog.java @@ -0,0 +1,142 @@ +// Copyright 2008 The Android Open Source Project +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// 2. Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// 3. Neither the name of Google Inc. nor the names of its contributors may be +// used to endorse or promote products derived from this software without +// specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED +// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO +// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +package android.webkit.gears; + +import android.content.ActivityNotFoundException; +import android.content.Context; +import android.content.Intent; +import android.util.Log; + +import java.io.File; +import java.lang.InterruptedException; +import java.util.concurrent.locks.Condition; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; + +/** + * Utility class to call a modal native dialog on Android + * The dialog itself is an Activity defined in the Browser. + * @hide + */ +public class NativeDialog { + + private static final String TAG = "Gears-J-NativeDialog"; + + private final String DIALOG_PACKAGE = "com.android.browser"; + private final String DIALOG_CLASS = DIALOG_PACKAGE + ".GearsNativeDialog"; + + private static Lock mLock = new ReentrantLock(); + private static Condition mDialogFinished = mLock.newCondition(); + private static String mResults = null; + + private static boolean mAsynchronousDialog; + + /** + * Utility function to build the intent calling the + * dialog activity + */ + private Intent createIntent(String type, String arguments) { + Intent intent = new Intent(); + intent.setClassName(DIALOG_PACKAGE, DIALOG_CLASS); + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + intent.putExtra("dialogArguments", arguments); + intent.putExtra("dialogType", type); + return intent; + } + + /** + * Opens a native dialog synchronously and waits for its completion. + * + * The dialog is an activity (GearsNativeDialog) provided by the Browser + * that we call via startActivity(). Contrary to a normal activity though, + * we need to block until it returns. To do so, we define a static lock + * object in this class, which GearsNativeDialog can unlock once done + */ + public String showDialog(Context context, String file, + String arguments) { + + try { + mAsynchronousDialog = false; + mLock.lock(); + File path = new File(file); + String fileName = path.getName(); + String type = fileName.substring(0, fileName.indexOf(".html")); + Intent intent = createIntent(type, arguments); + + mResults = null; + context.startActivity(intent); + mDialogFinished.await(); + } catch (InterruptedException e) { + Log.e(TAG, "exception e: " + e); + } catch (ActivityNotFoundException e) { + Log.e(TAG, "exception e: " + e); + } finally { + mLock.unlock(); + } + + return mResults; + } + + /** + * Opens a native dialog asynchronously + * + * The dialog is an activity (GearsNativeDialog) provided by the + * Browser. + */ + public void showAsyncDialog(Context context, String type, + String arguments) { + mAsynchronousDialog = true; + Intent intent = createIntent(type, arguments); + context.startActivity(intent); + } + + /** + * Static method that GearsNativeDialog calls to unlock us + */ + public static void signalFinishedDialog() { + if (!mAsynchronousDialog) { + mLock.lock(); + mDialogFinished.signal(); + mLock.unlock(); + } else { + // we call the native callback + closeAsynchronousDialog(mResults); + } + } + + /** + * Static method that GearsNativeDialog calls to set the + * dialog's result + */ + public static void closeDialog(String res) { + mResults = res; + } + + /** + * Native callback method + */ + private native static void closeAsynchronousDialog(String res); +} diff --git a/core/java/android/webkit/gears/PluginSettings.java b/core/java/android/webkit/gears/PluginSettings.java new file mode 100644 index 0000000000000000000000000000000000000000..2d0cc13e6e5a4769991ef0cd35bf42c4e158eb48 --- /dev/null +++ b/core/java/android/webkit/gears/PluginSettings.java @@ -0,0 +1,79 @@ +// Copyright 2008 The Android Open Source Project +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// 2. Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// 3. Neither the name of Google Inc. nor the names of its contributors may be +// used to endorse or promote products derived from this software without +// specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED +// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO +// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +package android.webkit.gears; + +import android.content.Context; +import android.util.Log; +import android.webkit.Plugin; +import android.webkit.Plugin.PreferencesClickHandler; + +/** + * Simple bridge class intercepting the click in the + * browser plugin list and calling the Gears settings + * dialog. + */ +public class PluginSettings { + + private static final String TAG = "Gears-J-PluginSettings"; + private Context mContext; + + public PluginSettings(Plugin plugin) { + plugin.setClickHandler(new ClickHandler()); + } + + /** + * We do not call the dialog synchronously here as the main + * message loop would be blocked, so we call it via a secondary thread. + */ + private class ClickHandler implements PreferencesClickHandler { + public void handleClickEvent(Context context) { + mContext = context.getApplicationContext(); + Thread startDialog = new Thread(new StartDialog(context)); + startDialog.start(); + } + } + + /** + * Simple wrapper class to call the gears native method in + * a separate thread (the native code will then instanciate a NativeDialog + * object which will start the GearsNativeDialog activity defined in + * the Browser). + */ + private class StartDialog implements Runnable { + Context mContext; + + public StartDialog(Context context) { + mContext = context; + } + + public void run() { + runSettingsDialog(mContext); + } + } + + private static native void runSettingsDialog(Context c); + +} diff --git a/core/java/android/webkit/gears/UrlInterceptHandlerGears.java b/core/java/android/webkit/gears/UrlInterceptHandlerGears.java index 95fc30f3f744b8323893a019bf4b32017fb09194..288240ea8e2ace367bb167c65fbf2c5841c6a461 100644 --- a/core/java/android/webkit/gears/UrlInterceptHandlerGears.java +++ b/core/java/android/webkit/gears/UrlInterceptHandlerGears.java @@ -407,6 +407,8 @@ public class UrlInterceptHandlerGears implements UrlInterceptHandler { true); // forceCache if (cacheResult == null) { + // With the no-cache policy we could end up + // with a null result return null; } @@ -444,8 +446,7 @@ public class UrlInterceptHandlerGears implements UrlInterceptHandler { // be used for input. cacheResult = CacheManager.getCacheFile(gearsUrl, null); if (cacheResult != null) { - if (logEnabled) - log("Returning surrogate result"); + log("Returning surrogate result"); return cacheResult; } else { // Not an expected condition, but handle gracefully. Perhaps out @@ -476,7 +477,10 @@ public class UrlInterceptHandlerGears implements UrlInterceptHandler { } /** - * Convenience debug function. Calls Android logging mechanism. + * Convenience debug function. Calls the Android logging + * mechanism. logEnabled is not a constant, so if the string + * evaluation is potentially expensive, the caller also needs to + * check it. * @param str String to log to the Android console. */ private void log(String str) { diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java index 19b1ce01dd66981c3f2909161b72a16d6eee0536..14405225b484b57a300914d1e16f59b690cf1c32 100644 --- a/core/java/android/widget/AbsListView.java +++ b/core/java/android/widget/AbsListView.java @@ -58,6 +58,8 @@ import java.util.List; * @attr ref android.R.styleable#AbsListView_textFilterEnabled * @attr ref android.R.styleable#AbsListView_transcriptMode * @attr ref android.R.styleable#AbsListView_cacheColorHint + * @attr ref android.R.styleable#AbsListView_fastScrollEnabled + * @attr ref android.R.styleable#AbsListView_smoothScrollbar */ public abstract class AbsListView extends AdapterView implements TextWatcher, ViewTreeObserver.OnGlobalLayoutListener, Filter.FilterListener, @@ -116,6 +118,11 @@ public abstract class AbsListView extends AdapterView implements Te * Indicates the view is in the process of being flung */ static final int TOUCH_MODE_FLING = 4; + + /** + * Indicates that the user is currently dragging the fast scroll thumb + */ + static final int TOUCH_MODE_FAST_SCROLL = 5; /** * Regular layout - usually an unsolicited layout from the view system @@ -304,6 +311,11 @@ public abstract class AbsListView extends AdapterView implements Te * bitmap cache after scrolling. */ boolean mScrollingCacheEnabled; + + /** + * Whether or not to enable the fast scroll feature on this list + */ + boolean mFastScrollEnabled; /** * Optional callback to notify client when scroll position has changed @@ -320,6 +332,12 @@ public abstract class AbsListView extends AdapterView implements Te */ EditText mTextFilter; + /** + * Indicates whether to use pixels-based or position-based scrollbar + * properties. + */ + private boolean mSmoothScrollbarEnabled = true; + /** * Indicates that this view supports filtering */ @@ -400,6 +418,11 @@ public abstract class AbsListView extends AdapterView implements Te */ private int mLastScrollState = OnScrollListener.SCROLL_STATE_IDLE; + /** + * Helper object that renders and controls the fast scroll thumb. + */ + private FastScroller mFastScroller; + /** * Interface definition for a callback to be invoked when the list or grid * has been scrolled. @@ -493,10 +516,83 @@ public abstract class AbsListView extends AdapterView implements Te int color = a.getColor(R.styleable.AbsListView_cacheColorHint, 0); setCacheColorHint(color); + + boolean enableFastScroll = a.getBoolean(R.styleable.AbsListView_fastScrollEnabled, false); + setFastScrollEnabled(enableFastScroll); + boolean smoothScrollbar = a.getBoolean(R.styleable.AbsListView_smoothScrollbar, true); + setSmoothScrollbarEnabled(smoothScrollbar); + a.recycle(); } + /** + * Enables fast scrolling by letting the user quickly scroll through lists by + * dragging the fast scroll thumb. The adapter attached to the list may want + * to implement {@link SectionIndexer} if it wishes to display alphabet preview and + * jump between sections of the list. + * @see SectionIndexer + * @see #isFastScrollEnabled() + * @param enabled whether or not to enable fast scrolling + */ + public void setFastScrollEnabled(boolean enabled) { + mFastScrollEnabled = enabled; + if (enabled) { + if (mFastScroller == null) { + mFastScroller = new FastScroller(getContext(), this); + } + } else { + if (mFastScroller != null) { + mFastScroller.stop(); + mFastScroller = null; + } + } + } + + /** + * Returns the current state of the fast scroll feature. + * @see #setFastScrollEnabled(boolean) + * @return true if fast scroll is enabled, false otherwise + */ + @ViewDebug.ExportedProperty + public boolean isFastScrollEnabled() { + return mFastScrollEnabled; + } + + /** + * When smooth scrollbar is enabled, the position and size of the scrollbar thumb + * is computed based on the number of visible pixels in the visible items. This + * however assumes that all list items have the same height. If you use a list in + * which items have different heights, the scrollbar will change appearance as the + * user scrolls through the list. To avoid this issue, you need to disable this + * property. + * + * When smooth scrollbar is disabled, the position and size of the scrollbar thumb + * is based solely on the number of items in the adapter and the position of the + * visible items inside the adapter. This provides a stable scrollbar as the user + * navigates through a list of items with varying heights. + * + * @param enabled Whether or not to enable smooth scrollbar. + * + * @see #setSmoothScrollbarEnabled(boolean) + * @attr ref android.R.styleable#AbsListView_smoothScrollbar + */ + public void setSmoothScrollbarEnabled(boolean enabled) { + mSmoothScrollbarEnabled = enabled; + } + + /** + * Returns the current state of the fast scroll feature. + * + * @return True if smooth scrollbar is enabled is enabled, false otherwise. + * + * @see #setSmoothScrollbarEnabled(boolean) + */ + @ViewDebug.ExportedProperty + public boolean isSmoothScrollbarEnabled() { + return mSmoothScrollbarEnabled; + } + /** * Set the listener that will receive notifications every time the list scrolls. * @@ -511,6 +607,9 @@ public abstract class AbsListView extends AdapterView implements Te * Notify our scroll listener (if there is one) of a change in scroll state */ void invokeOnItemScrollListener() { + if (mFastScroller != null) { + mFastScroller.onScroll(this, mFirstPosition, getChildCount(), mItemCount); + } if (mOnScrollListener != null) { mOnScrollListener.onScroll(this, mFirstPosition, getChildCount(), mItemCount); } @@ -525,6 +624,7 @@ public abstract class AbsListView extends AdapterView implements Te * @see #setScrollingCacheEnabled(boolean) * @see View#setDrawingCacheEnabled(boolean) */ + @ViewDebug.ExportedProperty public boolean isScrollingCacheEnabled() { return mScrollingCacheEnabled; } @@ -571,6 +671,7 @@ public abstract class AbsListView extends AdapterView implements Te * @see #setTextFilterEnabled(boolean) * @see Filterable */ + @ViewDebug.ExportedProperty public boolean isTextFilterEnabled() { return mTextFilterEnabled; } @@ -595,10 +696,12 @@ public abstract class AbsListView extends AdapterView implements Te setWillNotDraw(false); setAlwaysDrawnWithCacheEnabled(false); setScrollingCacheEnabled(true); + setScrollContainer(true); } private void useDefaultSelector() { - setSelector(getResources().getDrawable(com.android.internal.R.drawable.list_selector_background)); + setSelector(getResources().getDrawable( + com.android.internal.R.drawable.list_selector_background)); } /** @@ -607,6 +710,7 @@ public abstract class AbsListView extends AdapterView implements Te * * @return true if the content is stacked from the bottom edge, false otherwise */ + @ViewDebug.ExportedProperty public boolean isStackFromBottom() { return mStackFromBottom; } @@ -843,35 +947,54 @@ public abstract class AbsListView extends AdapterView implements Te protected int computeVerticalScrollExtent() { final int count = getChildCount(); if (count > 0) { - int extent = count * 100; + if (mSmoothScrollbarEnabled) { + int extent = count * 100; + + View view = getChildAt(0); + final int top = view.getTop(); + int height = view.getHeight(); + if (height > 0) { + extent += (top * 100) / height; + } - View view = getChildAt(0); - final int top = view.getTop(); - int height = view.getHeight(); - if (height > 0) { - extent += (top * 100) / height; - } + view = getChildAt(count - 1); + final int bottom = view.getBottom(); + height = view.getHeight(); + if (height > 0) { + extent -= ((bottom - getHeight()) * 100) / height; + } - view = getChildAt(count - 1); - final int bottom = view.getBottom(); - height = view.getHeight(); - if (height > 0) { - extent -= ((bottom - getHeight()) * 100) / height; + return extent; + } else { + return 1; } - - return extent; } return 0; } @Override protected int computeVerticalScrollOffset() { - if (mFirstPosition >= 0 && getChildCount() > 0) { - final View view = getChildAt(0); - final int top = view.getTop(); - int height = view.getHeight(); - if (height > 0) { - return Math.max(mFirstPosition * 100 - (top * 100) / height, 0); + final int firstPosition = mFirstPosition; + final int childCount = getChildCount(); + if (firstPosition >= 0 && childCount > 0) { + if (mSmoothScrollbarEnabled) { + final View view = getChildAt(0); + final int top = view.getTop(); + int height = view.getHeight(); + if (height > 0) { + return Math.max(firstPosition * 100 - (top * 100) / height, 0); + } + } else { + int index; + final int count = mItemCount; + if (firstPosition == 0) { + index = 0; + } else if (firstPosition + childCount == count) { + index = count; + } else { + index = firstPosition + childCount / 2; + } + return (int) (firstPosition + childCount * (index / (float) count)); } } return 0; @@ -879,7 +1002,7 @@ public abstract class AbsListView extends AdapterView implements Te @Override protected int computeVerticalScrollRange() { - return Math.max(mItemCount * 100, 0); + return mSmoothScrollbarEnabled ? Math.max(mItemCount * 100, 0) : mItemCount; } @Override @@ -1140,6 +1263,9 @@ public abstract class AbsListView extends AdapterView implements Te mDataChanged = true; rememberSyncState(); } + if (mFastScroller != null) { + mFastScroller.onSizeChanged(w, h, oldw, oldh); + } } /** @@ -1669,6 +1795,13 @@ public abstract class AbsListView extends AdapterView implements Te @Override public boolean onTouchEvent(MotionEvent ev) { + + if (mFastScroller != null) { + boolean intercepted = mFastScroller.onTouchEvent(ev); + if (intercepted) { + return true; + } + } final int action = ev.getAction(); final int x = (int) ev.getX(); final int y = (int) ev.getY(); @@ -1684,28 +1817,30 @@ public abstract class AbsListView extends AdapterView implements Te switch (action) { case MotionEvent.ACTION_DOWN: { int motionPosition = pointToPosition(x, y); - if ((mTouchMode != TOUCH_MODE_FLING) && (motionPosition >= 0) - && (getAdapter().isEnabled(motionPosition))) { - // User clicked on an actual view (and was not stopping a fling). It might be a - // click or a scroll. Assume it is a click until proven otherwise - mTouchMode = TOUCH_MODE_DOWN; - // FIXME Debounce - if (mPendingCheckForTap == null) { - mPendingCheckForTap = new CheckForTap(); - } - postDelayed(mPendingCheckForTap, ViewConfiguration.getTapTimeout()); - } else { - if (ev.getEdgeFlags() != 0 && motionPosition < 0) { - // If we couldn't find a view to click on, but the down event was touching - // the edge, we will bail out and try again. This allows the edge correcting - // code in ViewRoot to try to find a nearby view to select - return false; + if (!mDataChanged) { + if ((mTouchMode != TOUCH_MODE_FLING) && (motionPosition >= 0) + && (getAdapter().isEnabled(motionPosition))) { + // User clicked on an actual view (and was not stopping a fling). It might be a + // click or a scroll. Assume it is a click until proven otherwise + mTouchMode = TOUCH_MODE_DOWN; + // FIXME Debounce + if (mPendingCheckForTap == null) { + mPendingCheckForTap = new CheckForTap(); + } + postDelayed(mPendingCheckForTap, ViewConfiguration.getTapTimeout()); + } else { + if (ev.getEdgeFlags() != 0 && motionPosition < 0) { + // If we couldn't find a view to click on, but the down event was touching + // the edge, we will bail out and try again. This allows the edge correcting + // code in ViewRoot to try to find a nearby view to select + return false; + } + // User clicked on whitespace, or stopped a fling. It is a scroll. + createScrollingCache(); + mTouchMode = TOUCH_MODE_SCROLL; + motionPosition = findMotionRow(y); + reportScrollStateChange(OnScrollListener.SCROLL_STATE_TOUCH_SCROLL); } - // User clicked on whitespace, or stopped a fling. It is a scroll. - createScrollingCache(); - mTouchMode = TOUCH_MODE_SCROLL; - motionPosition = findMotionRow(y); - reportScrollStateChange(OnScrollListener.SCROLL_STATE_TOUCH_SCROLL); } if (motionPosition >= 0) { @@ -1897,6 +2032,14 @@ public abstract class AbsListView extends AdapterView implements Te return true; } + + @Override + public void draw(Canvas canvas) { + super.draw(canvas); + if (mFastScroller != null) { + mFastScroller.draw(canvas); + } + } @Override public boolean onInterceptTouchEvent(MotionEvent ev) { @@ -1904,6 +2047,14 @@ public abstract class AbsListView extends AdapterView implements Te int x = (int) ev.getX(); int y = (int) ev.getY(); View v; + + if (mFastScroller != null) { + boolean intercepted = mFastScroller.onInterceptTouchEvent(ev); + if (intercepted) { + return true; + } + } + switch (action) { case MotionEvent.ACTION_DOWN: { int motionPosition = findMotionRow(y); @@ -1965,7 +2116,14 @@ public abstract class AbsListView extends AdapterView implements Te } } - private void reportScrollStateChange(int newState) { + /** + * Fires an "on scroll state changed" event to the registered + * {@link android.widget.AbsListView.OnScrollListener}, if any. The state change + * is fired only if the specified state is different from the previously known state. + * + * @param newState The new scroll state. + */ + void reportScrollStateChange(int newState) { if (newState != mLastScrollState) { if (mOnScrollListener != null) { mOnScrollListener.onScrollStateChanged(this, newState); @@ -2013,10 +2171,7 @@ public abstract class AbsListView extends AdapterView implements Te private void endFling() { mTouchMode = TOUCH_MODE_REST; - if (mOnScrollListener != null) { - mOnScrollListener.onScrollStateChanged(AbsListView.this, - OnScrollListener.SCROLL_STATE_IDLE); - } + reportScrollStateChange(OnScrollListener.SCROLL_STATE_IDLE); clearScrollingCache(); } @@ -2411,7 +2566,9 @@ public abstract class AbsListView extends AdapterView implements Te if (selectedPos >= 0) { mLayoutMode = LAYOUT_SPECIFIC; setSelectionInt(selectedPos); + invokeOnItemScrollListener(); } + reportScrollStateChange(OnScrollListener.SCROLL_STATE_IDLE); return selectedPos >= 0; } @@ -2547,7 +2704,7 @@ public abstract class AbsListView extends AdapterView implements Te // Make sure we have a window before showing the popup if (getWindowVisibility() == View.VISIBLE) { int screenHeight = WindowManagerImpl.getDefault().getDefaultDisplay().getHeight(); - final int[] xy = mLocation; + final int[] xy = new int[2]; getLocationOnScreen(xy); int bottomGap = screenHeight - xy[1] - getHeight() + 20; mPopup.showAtLocation(this, Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL, @@ -2689,6 +2846,7 @@ public abstract class AbsListView extends AdapterView implements Te com.android.internal.R.layout.typing_filter, null); mTextFilter.addTextChangedListener(this); p.setFocusable(false); + p.setTouchable(false); p.setContentView(mTextFilter); p.setWidth(LayoutParams.WRAP_CONTENT); p.setHeight(LayoutParams.WRAP_CONTENT); diff --git a/core/java/android/widget/AbsSeekBar.java b/core/java/android/widget/AbsSeekBar.java index 1fa7318b1d5911249e9d24777b0c9b5b2ac2df39..65ca8850a48e0fadd424de7c00c3577735069807 100644 --- a/core/java/android/widget/AbsSeekBar.java +++ b/core/java/android/widget/AbsSeekBar.java @@ -242,6 +242,7 @@ public abstract class AbsSeekBar extends ProgressBar { case MotionEvent.ACTION_MOVE: trackTouchEvent(event); + attemptClaimDrag(); break; case MotionEvent.ACTION_UP: @@ -281,6 +282,16 @@ public abstract class AbsSeekBar extends ProgressBar { setProgress((int) progress, true); } + + /** + * Tries to claim the user's drag motion, and requests disallowing any + * ancestors from stealing events in the drag. + */ + private void attemptClaimDrag() { + if (mParent != null) { + mParent.requestDisallowInterceptTouchEvent(true); + } + } /** * This is called when the user has started touching this widget. diff --git a/core/java/android/widget/AbsoluteLayout.java b/core/java/android/widget/AbsoluteLayout.java index 36a3b10dc7cd1b0a797003d5254bee35ce0dd67d..c77f7aec62f1348c65a42d7ba37c370869b27d80 100644 --- a/core/java/android/widget/AbsoluteLayout.java +++ b/core/java/android/widget/AbsoluteLayout.java @@ -32,7 +32,11 @@ import android.widget.RemoteViews.RemoteView; *

              XML attributes

              See {@link * android.R.styleable#ViewGroup ViewGroup Attributes}, {@link * android.R.styleable#View View Attributes}

              + * + * @deprecated Use {@link android.widget.FrameLayout}, {@link android.widget.RelativeLayout} + * or a custom layout instead. */ +@Deprecated @RemoteView public class AbsoluteLayout extends ViewGroup { public AbsoluteLayout(Context context) { diff --git a/core/java/android/widget/AdapterView.java b/core/java/android/widget/AdapterView.java index e096612836b4f46d2828802a34d4bb7af4e90eb6..173e80f54f75ee3051ac8e774ce18b4c9338eea8 100644 --- a/core/java/android/widget/AdapterView.java +++ b/core/java/android/widget/AdapterView.java @@ -140,7 +140,7 @@ public abstract class AdapterView extends ViewGroup { * The position within the adapter's data set of the item to select * during the next layout. */ - @ViewDebug.ExportedProperty + @ViewDebug.ExportedProperty int mNextSelectedPosition = INVALID_POSITION; /** @@ -151,7 +151,7 @@ public abstract class AdapterView extends ViewGroup { /** * The position within the adapter's data set of the currently selected item. */ - @ViewDebug.ExportedProperty + @ViewDebug.ExportedProperty int mSelectedPosition = INVALID_POSITION; /** @@ -520,6 +520,7 @@ public abstract class AdapterView extends ViewGroup { * * @return int Position (starting at 0), or {@link #INVALID_POSITION} if there is nothing selected. */ + @ViewDebug.CapturedViewProperty public int getSelectedItemPosition() { return mNextSelectedPosition; } @@ -528,6 +529,7 @@ public abstract class AdapterView extends ViewGroup { * @return The id corresponding to the currently selected item, or {@link #INVALID_ROW_ID} * if nothing is selected. */ + @ViewDebug.CapturedViewProperty public long getSelectedItemId() { return mNextSelectedRowId; } @@ -557,6 +559,7 @@ public abstract class AdapterView extends ViewGroup { * AdapterView. (This is the number of data items, which may be * larger than the number of visible view.) */ + @ViewDebug.CapturedViewProperty public int getCount() { return mItemCount; } diff --git a/core/java/android/widget/AlphabetIndexer.java b/core/java/android/widget/AlphabetIndexer.java new file mode 100644 index 0000000000000000000000000000000000000000..bbabaaaf74ac6a18893dc53f52f24a96201a2276 --- /dev/null +++ b/core/java/android/widget/AlphabetIndexer.java @@ -0,0 +1,283 @@ +/* + * 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 android.widget; + +import android.database.Cursor; +import android.database.DataSetObserver; +import android.util.SparseIntArray; + +/** + * A helper class for adapters that implement the SectionIndexer interface. + * If the items in the adapter are sorted by simple alphabet-based sorting, then + * this class provides a way to do fast indexing of large lists using binary search. + * It caches the indices that have been determined through the binary search and also + * invalidates the cache if changes occur in the cursor. + *

              + * Your adapter is responsible for updating the cursor by calling {@link #setCursor} if the + * cursor changes. {@link #getPositionForSection} method does the binary search for the starting + * index of a given section (alphabet). + * @hide pending API council approval + */ +public class AlphabetIndexer extends DataSetObserver implements SectionIndexer { + + /** + * Cursor that is used by the adapter of the list view. + */ + protected Cursor mDataCursor; + + /** + * The index of the cursor column that this list is sorted on. + */ + protected int mColumnIndex; + + /** + * The string of characters that make up the indexing sections. + */ + protected CharSequence mAlphabet; + + /** + * Cached length of the alphabet array. + */ + private int mAlphabetLength; + + /** + * This contains a cache of the computed indices so far. It will get reset whenever + * the dataset changes or the cursor changes. + */ + private SparseIntArray mAlphaMap; + + /** + * Use a collator to compare strings in a localized manner. + */ + private java.text.Collator mCollator; + + /** + * The section array converted from the alphabet string. + */ + private String[] mAlphabetArray; + + /** + * Constructs the indexer. + * @param cursor the cursor containing the data set + * @param sortedColumnIndex the column number in the cursor that is sorted + * alphabetically + * @param alphabet string containing the alphabet, with space as the first character. + * For example, use the string " ABCDEFGHIJKLMNOPQRSTUVWXYZ" for English indexing. + * The characters must be uppercase and be sorted in ascii/unicode order. Basically + * characters in the alphabet will show up as preview letters. + */ + public AlphabetIndexer(Cursor cursor, int sortedColumnIndex, CharSequence alphabet) { + mDataCursor = cursor; + mColumnIndex = sortedColumnIndex; + mAlphabet = alphabet; + mAlphabetLength = alphabet.length(); + mAlphabetArray = new String[mAlphabetLength]; + for (int i = 0; i < mAlphabetLength; i++) { + mAlphabetArray[i] = Character.toString(mAlphabet.charAt(i)); + } + mAlphaMap = new SparseIntArray(mAlphabetLength); + if (cursor != null) { + cursor.registerDataSetObserver(this); + } + // Get a Collator for the current locale for string comparisons. + mCollator = java.text.Collator.getInstance(); + mCollator.setStrength(java.text.Collator.PRIMARY); + } + + /** + * Returns the section array constructed from the alphabet provided in the constructor. + * @return the section array + */ + public Object[] getSections() { + return mAlphabetArray; + } + + /** + * Sets a new cursor as the data set and resets the cache of indices. + * @param cursor the new cursor to use as the data set + */ + public void setCursor(Cursor cursor) { + if (mDataCursor != null) { + mDataCursor.unregisterDataSetObserver(this); + } + mDataCursor = cursor; + if (cursor != null) { + mDataCursor.registerDataSetObserver(this); + } + mAlphaMap.clear(); + } + + /** + * Default implementation compares the first character of word with letter. + */ + protected int compare(String word, String letter) { + return mCollator.compare(word.substring(0, 1), letter); + } + + /** + * Performs a binary search or cache lookup to find the first row that + * matches a given section's starting letter. + * @param sectionIndex the section to search for + * @return the row index of the first occurrence, or the nearest next letter. + * For instance, if searching for "T" and no "T" is found, then the first + * row starting with "U" or any higher letter is returned. If there is no + * data following "T" at all, then the list size is returned. + */ + public int getPositionForSection(int sectionIndex) { + final SparseIntArray alphaMap = mAlphaMap; + final Cursor cursor = mDataCursor; + + if (cursor == null || mAlphabet == null) { + return 0; + } + + // Check bounds + if (sectionIndex <= 0) { + return 0; + } + if (sectionIndex >= mAlphabetLength) { + sectionIndex = mAlphabetLength - 1; + } + + int savedCursorPos = cursor.getPosition(); + + int count = cursor.getCount(); + int start = 0; + int end = count; + int pos; + + char letter = mAlphabet.charAt(sectionIndex); + String targetLetter = Character.toString(letter); + int key = letter; + // Check map + if (Integer.MIN_VALUE != (pos = alphaMap.get(key, Integer.MIN_VALUE))) { + // Is it approximate? Using negative value to indicate that it's + // an approximation and positive value when it is the accurate + // position. + if (pos < 0) { + pos = -pos; + end = pos; + } else { + // Not approximate, this is the confirmed start of section, return it + return pos; + } + } + + // Do we have the position of the previous section? + if (sectionIndex > 0) { + int prevLetter = + mAlphabet.charAt(sectionIndex - 1); + int prevLetterPos = alphaMap.get(prevLetter, Integer.MIN_VALUE); + if (prevLetterPos != Integer.MIN_VALUE) { + start = Math.abs(prevLetterPos); + } + } + + // Now that we have a possibly optimized start and end, let's binary search + + pos = (end + start) / 2; + + while (pos < end) { + // Get letter at pos + cursor.moveToPosition(pos); + String curName = cursor.getString(mColumnIndex); + if (curName == null) { + if (pos == 0) { + break; + } else { + pos--; + continue; + } + } + int diff = compare(curName, targetLetter); + if (diff != 0) { + // Commenting out approximation code because it doesn't work for certain + // lists with custom comparators + // Enter approximation in hash if a better solution doesn't exist + // String startingLetter = Character.toString(getFirstLetter(curName)); + // int startingLetterKey = startingLetter.charAt(0); + // int curPos = alphaMap.get(startingLetterKey, Integer.MIN_VALUE); + // if (curPos == Integer.MIN_VALUE || Math.abs(curPos) > pos) { + // Negative pos indicates that it is an approximation + // alphaMap.put(startingLetterKey, -pos); + // } + // if (mCollator.compare(startingLetter, targetLetter) < 0) { + if (diff < 0) { + start = pos + 1; + if (start >= count) { + pos = count; + break; + } + } else { + end = pos; + } + } else { + // They're the same, but that doesn't mean it's the start + if (start == pos) { + // This is it + break; + } else { + // Need to go further lower to find the starting row + end = pos; + } + } + pos = (start + end) / 2; + } + alphaMap.put(key, pos); + cursor.moveToPosition(savedCursorPos); + return pos; + } + + /** + * Returns the section index for a given position in the list by querying the item + * and comparing it with all items in the section array. + */ + public int getSectionForPosition(int position) { + int savedCursorPos = mDataCursor.getPosition(); + mDataCursor.moveToPosition(position); + mDataCursor.moveToPosition(savedCursorPos); + String curName = mDataCursor.getString(mColumnIndex); + // Linear search, as there are only a few items in the section index + // Could speed this up later if it actually gets used. + for (int i = 0; i < mAlphabetLength; i++) { + char letter = mAlphabet.charAt(i); + String targetLetter = Character.toString(letter); + if (compare(curName, targetLetter) == 0) { + return i; + } + } + return 0; // Don't recognize the letter - falls under zero'th section + } + + /* + * @hide + */ + @Override + public void onChanged() { + super.onChanged(); + mAlphaMap.clear(); + } + + /* + * @hide + */ + @Override + public void onInvalidated() { + super.onInvalidated(); + mAlphaMap.clear(); + } +} diff --git a/core/java/android/widget/AnalogClock.java b/core/java/android/widget/AnalogClock.java index 808104e894aa3330682990e4c01dd0070e05272d..fbb010515801a5a28568132f1b66c0bc5bf80722 100644 --- a/core/java/android/widget/AnalogClock.java +++ b/core/java/android/widget/AnalogClock.java @@ -25,9 +25,9 @@ import android.content.res.TypedArray; import android.graphics.Canvas; import android.graphics.drawable.Drawable; import android.os.Handler; +import android.text.format.Time; import android.util.AttributeSet; import android.view.View; -import android.pim.Time; import java.util.TimeZone; diff --git a/core/java/android/widget/AppSecurityPermissions.java b/core/java/android/widget/AppSecurityPermissions.java index 582117f21d3cb6e014be5804971e7ad75f48305b..5fa00e7d443a701a56dd8f6e74604142671ea96c 100755 --- a/core/java/android/widget/AppSecurityPermissions.java +++ b/core/java/android/widget/AppSecurityPermissions.java @@ -18,7 +18,6 @@ package android.widget; import com.android.internal.R; import android.content.Context; -import android.content.pm.ApplicationInfo; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.PackageParser; @@ -31,9 +30,17 @@ import android.util.DisplayMetrics; import android.util.Log; import android.view.LayoutInflater; import android.view.View; + import java.io.File; +import java.text.Collator; import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; import java.util.Set; /** @@ -56,15 +63,15 @@ public class AppSecurityPermissions implements View.OnClickListener { BOTH } - private final String TAG = "AppSecurityPermissions"; + private final static String TAG = "AppSecurityPermissions"; private boolean localLOGV = false; private Context mContext; private LayoutInflater mInflater; private PackageManager mPm; private LinearLayout mPermsView; - private HashMap mDangerousMap; - private HashMap mNormalMap; - private ArrayList mPermsList; + private Map mDangerousMap; + private Map mNormalMap; + private List mPermsList; private String mDefaultGrpLabel; private String mDefaultGrpName="DefaultGrp"; private String mPermFormat; @@ -79,18 +86,129 @@ public class AppSecurityPermissions implements View.OnClickListener { private State mCurrentState; private LinearLayout mNonDangerousList; private LinearLayout mDangerousList; - private HashMap mGroupLabelCache; + private HashMap mGroupLabelCache; private View mNoPermsView; - - public AppSecurityPermissions(Context context) { - this(context, null); - } - - public AppSecurityPermissions(Context context, ArrayList permList) { + + public AppSecurityPermissions(Context context, List permList) { mContext = context; - mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); - mPm = context.getPackageManager(); + mPm = mContext.getPackageManager(); mPermsList = permList; + } + + public AppSecurityPermissions(Context context, String packageName) { + mContext = context; + mPm = mContext.getPackageManager(); + mPermsList = new ArrayList(); + Set permSet = new HashSet(); + PackageInfo pkgInfo; + try { + pkgInfo = mPm.getPackageInfo(packageName, PackageManager.GET_PERMISSIONS); + } catch (NameNotFoundException e) { + Log.w(TAG, "Could'nt retrieve permissions for package:"+packageName); + return; + } + // Extract all user permissions + if((pkgInfo.applicationInfo != null) && (pkgInfo.applicationInfo.uid != -1)) { + getAllUsedPermissions(pkgInfo.applicationInfo.uid, permSet); + } + for(PermissionInfo tmpInfo : permSet) { + mPermsList.add(tmpInfo); + } + } + + public AppSecurityPermissions(Context context, PackageParser.Package pkg) { + mContext = context; + mPm = mContext.getPackageManager(); + mPermsList = new ArrayList(); + Set permSet = new HashSet(); + if(pkg == null) { + return; + } + // Extract shared user permissions if any + if(pkg.mSharedUserId != null) { + int sharedUid; + try { + sharedUid = mPm.getUidForSharedUser(pkg.mSharedUserId); + } catch (NameNotFoundException e) { + Log.w(TAG, "Could'nt retrieve shared user id for:"+pkg.packageName); + return; + } + getAllUsedPermissions(sharedUid, permSet); + } else { + ArrayList strList = pkg.requestedPermissions; + int size; + if((strList == null) || ((size = strList.size()) == 0)) { + return; + } + // Extract permissions defined in current package + extractPerms(strList.toArray(new String[size]), permSet); + } + for(PermissionInfo tmpInfo : permSet) { + mPermsList.add(tmpInfo); + } + } + + public PackageParser.Package getPackageInfo(Uri packageURI) { + final String archiveFilePath = packageURI.getPath(); + PackageParser packageParser = new PackageParser(archiveFilePath); + File sourceFile = new File(archiveFilePath); + DisplayMetrics metrics = new DisplayMetrics(); + metrics.setToDefaults(); + return packageParser.parsePackage(sourceFile, archiveFilePath, metrics, 0); + } + + private void getAllUsedPermissions(int sharedUid, Set permSet) { + String sharedPkgList[] = mPm.getPackagesForUid(sharedUid); + if(sharedPkgList == null || (sharedPkgList.length == 0)) { + return; + } + for(String sharedPkg : sharedPkgList) { + getPermissionsForPackage(sharedPkg, permSet); + } + } + + private void getPermissionsForPackage(String packageName, + Set permSet) { + PackageInfo pkgInfo; + try { + pkgInfo = mPm.getPackageInfo(packageName, PackageManager.GET_PERMISSIONS); + } catch (NameNotFoundException e) { + Log.w(TAG, "Could'nt retrieve permissions for package:"+packageName); + return; + } + if(pkgInfo == null) { + return; + } + String strList[] = pkgInfo.requestedPermissions; + if(strList == null) { + return; + } + extractPerms(strList, permSet); + } + + private void extractPerms(String strList[], Set permSet) { + if((strList == null) || (strList.length == 0)) { + return; + } + for(String permName:strList) { + try { + PermissionInfo tmpPermInfo = mPm.getPermissionInfo(permName, 0); + if(tmpPermInfo != null) { + permSet.add(tmpPermInfo); + } + } catch (NameNotFoundException e) { + Log.i(TAG, "Ignoring unknown permission:"+permName); + } + } + } + + public int getPermissionCount() { + return mPermsList.size(); + } + + public View getPermissionsView() { + + mInflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE); mPermsView = (LinearLayout) mInflater.inflate(R.layout.app_perms_summary, null); mShowMore = mPermsView.findViewById(R.id.show_more); mShowMoreIcon = (ImageView) mShowMore.findViewById(R.id.show_more_icon); @@ -112,32 +230,9 @@ public class AppSecurityPermissions implements View.OnClickListener { mDangerousIcon = mContext.getResources().getDrawable(R.drawable.ic_bullet_key_permission); mShowMaxIcon = mContext.getResources().getDrawable(R.drawable.expander_ic_maximized); mShowMinIcon = mContext.getResources().getDrawable(R.drawable.expander_ic_minimized); - } - - public void setSecurityPermissionsView() { - setPermissions(mPermsList); - } - - public void setSecurityPermissionsView(Uri pkgURI) { - final String archiveFilePath = pkgURI.getPath(); - PackageParser packageParser = new PackageParser(archiveFilePath); - File sourceFile = new File(archiveFilePath); - DisplayMetrics metrics = new DisplayMetrics(); - metrics.setToDefaults(); - PackageParser.Package pkgInfo = packageParser.parsePackage(sourceFile, - archiveFilePath, metrics, 0); - mPermsList = generatePermissionsInfo(pkgInfo.requestedPermissions); - //For packages that havent been installed we need the application info object - //to load the labels and other resources. - setPermissions(mPermsList, pkgInfo.applicationInfo); - } - - public void setSecurityPermissionsView(PackageInfo pInfo) { - mPermsList = generatePermissionsInfo(pInfo.requestedPermissions); + + // Set permissions view setPermissions(mPermsList); - } - - public View getPermissionsView() { return mPermsView; } @@ -164,74 +259,30 @@ public class AppSecurityPermissions implements View.OnClickListener { * is null the other non null value is returned without formatting * this is to placate initial error checks */ - private String formatPermissions(String groupDesc, String permDesc) { + private String formatPermissions(String groupDesc, CharSequence permDesc) { if(groupDesc == null) { - return permDesc; - } - groupDesc = canonicalizeGroupDesc(groupDesc); - if(permDesc == null) { - return groupDesc; + if(permDesc == null) { + return null; + } + return permDesc.toString(); } - return String.format(mPermFormat, groupDesc, permDesc); - } - - /** - * Utility method that concatenates two strings defined by mPermFormat. - */ - private String formatPermissions(String groupDesc, CharSequence permDesc) { groupDesc = canonicalizeGroupDesc(groupDesc); if(permDesc == null) { return groupDesc; } - // Format only if str1 and str2 are not null. - return formatPermissions(groupDesc, permDesc.toString()); + // groupDesc and permDesc are non null + return String.format(mPermFormat, groupDesc, permDesc.toString()); } - private ArrayList generatePermissionsInfo(String[] strList) { - ArrayList permInfoList = new ArrayList(); - if(strList == null) { - return permInfoList; - } - PermissionInfo tmpPermInfo = null; - for(int i = 0; i < strList.length; i++) { - try { - tmpPermInfo = mPm.getPermissionInfo(strList[i], 0); - permInfoList.add(tmpPermInfo); - } catch (NameNotFoundException e) { - Log.i(TAG, "Ignoring unknown permisison:"+strList[i]); - continue; - } - } - return permInfoList; - } - - private ArrayList generatePermissionsInfo(ArrayList strList) { - ArrayList permInfoList = new ArrayList(); - if(strList != null) { - PermissionInfo tmpPermInfo = null; - for(String permName:strList) { - try { - tmpPermInfo = mPm.getPermissionInfo(permName, 0); - permInfoList.add(tmpPermInfo); - } catch (NameNotFoundException e) { - Log.i(TAG, "Ignoring unknown permisison:"+permName); - continue; - } - } - } - return permInfoList; - } - - private String getGroupLabel(String grpName) { + private CharSequence getGroupLabel(String grpName) { if (grpName == null) { //return default label return mDefaultGrpLabel; } - String cachedLabel = mGroupLabelCache.get(grpName); + CharSequence cachedLabel = mGroupLabelCache.get(grpName); if (cachedLabel != null) { return cachedLabel; } - PermissionGroupInfo pgi; try { pgi = mPm.getPermissionGroupInfo(grpName, 0); @@ -239,7 +290,7 @@ public class AppSecurityPermissions implements View.OnClickListener { Log.i(TAG, "Invalid group name:" + grpName); return null; } - String label = pgi.loadLabel(mPm).toString(); + CharSequence label = pgi.loadLabel(mPm).toString(); mGroupLabelCache.put(grpName, label); return label; } @@ -249,13 +300,13 @@ public class AppSecurityPermissions implements View.OnClickListener { * list of permission descriptions. */ private void displayPermissions(boolean dangerous) { - HashMap permInfoMap = dangerous ? mDangerousMap : mNormalMap; + Map permInfoMap = dangerous ? mDangerousMap : mNormalMap; LinearLayout permListView = dangerous ? mDangerousList : mNonDangerousList; permListView.removeAllViews(); Set permInfoStrSet = permInfoMap.keySet(); for (String loopPermGrpInfoStr : permInfoStrSet) { - String grpLabel = getGroupLabel(loopPermGrpInfoStr); + CharSequence grpLabel = getGroupLabel(loopPermGrpInfoStr); //guaranteed that grpLabel wont be null since permissions without groups //will belong to the default group if(localLOGV) Log.i(TAG, "Adding view group:" + grpLabel + ", desc:" @@ -269,7 +320,7 @@ public class AppSecurityPermissions implements View.OnClickListener { mNoPermsView.setVisibility(View.VISIBLE); } - private View getPermissionItemView(String grpName, String permList, + private View getPermissionItemView(CharSequence grpName, String permList, boolean dangerous) { View permView = mInflater.inflate(R.layout.app_permission_item, null); Drawable icon = dangerous ? mDangerousIcon : mNormalIcon; @@ -334,35 +385,105 @@ public class AppSecurityPermissions implements View.OnClickListener { } return false; } - - private void setPermissions(ArrayList permList) { - setPermissions(permList, null); + + /* + * Utility method that aggregates all permission descriptions categorized by group + * Say group1 has perm11, perm12, perm13, the group description will be + * perm11_Desc, perm12_Desc, perm13_Desc + */ + private void aggregateGroupDescs( + Map > map, Map retMap) { + if(map == null) { + return; + } + if(retMap == null) { + return; + } + Set grpNames = map.keySet(); + Iterator grpNamesIter = grpNames.iterator(); + while(grpNamesIter.hasNext()) { + String grpDesc = null; + String grpNameKey = grpNamesIter.next(); + List grpPermsList = map.get(grpNameKey); + if(grpPermsList == null) { + continue; + } + for(PermissionInfo permInfo: grpPermsList) { + CharSequence permDesc = permInfo.loadLabel(mPm); + grpDesc = formatPermissions(grpDesc, permDesc); + } + // Insert grpDesc into map + if(grpDesc != null) { + if(localLOGV) Log.i(TAG, "Group:"+grpNameKey+" description:"+grpDesc.toString()); + retMap.put(grpNameKey, grpDesc.toString()); + } + } } - private void setPermissions(ArrayList permList, ApplicationInfo appInfo) { - mDangerousMap = new HashMap(); - mNormalMap = new HashMap(); - mGroupLabelCache = new HashMap(); + private static class PermissionInfoComparator implements Comparator { + private PackageManager mPm; + private final Collator sCollator = Collator.getInstance(); + PermissionInfoComparator(PackageManager pm) { + mPm = pm; + } + public final int compare(PermissionInfo a, PermissionInfo b) { + CharSequence sa = a.loadLabel(mPm); + CharSequence sb = b.loadLabel(mPm); + return sCollator.compare(sa, sb); + } + } + + private void setPermissions(List permList) { + mGroupLabelCache = new HashMap(); //add the default label so that uncategorized permissions can go here mGroupLabelCache.put(mDefaultGrpName, mDefaultGrpLabel); + + // Map containing group names and a list of permissions under that group + // categorized as dangerous + mDangerousMap = new HashMap(); + // Map containing group names and a list of permissions under that group + // categorized as normal + mNormalMap = new HashMap(); + + // Additional structures needed to ensure that permissions are unique under + // each group + Map> dangerousMap = + new HashMap>(); + Map > normalMap = + new HashMap>(); + PermissionInfoComparator permComparator = new PermissionInfoComparator(mPm); + if (permList != null) { + // First pass to group permissions for (PermissionInfo pInfo : permList) { + if(localLOGV) Log.i(TAG, "Processing permission:"+pInfo.name); if(!isDisplayablePermission(pInfo)) { + if(localLOGV) Log.i(TAG, "Permission:"+pInfo.name+" is not displayable"); continue; } - String grpName = (pInfo.group == null) ? mDefaultGrpName : pInfo.group; - HashMap permInfoMap = + Map > permInfoMap = (pInfo.protectionLevel == PermissionInfo.PROTECTION_DANGEROUS) ? - mDangerousMap : mNormalMap; - // Check to make sure we have a label for the group - if (getGroupLabel(grpName) == null) { - continue; + dangerousMap : normalMap; + String grpName = (pInfo.group == null) ? mDefaultGrpName : pInfo.group; + if(localLOGV) Log.i(TAG, "Permission:"+pInfo.name+" belongs to group:"+grpName); + List grpPermsList = permInfoMap.get(grpName); + if(grpPermsList == null) { + grpPermsList = new ArrayList(); + permInfoMap.put(grpName, grpPermsList); + grpPermsList.add(pInfo); + } else { + int idx = Collections.binarySearch(grpPermsList, pInfo, permComparator); + if(localLOGV) Log.i(TAG, "idx="+idx+", list.size="+grpPermsList.size()); + if (idx < 0) { + idx = -idx-1; + grpPermsList.add(idx, pInfo); + } } - CharSequence permDesc = pInfo.loadLabel(mPm); - String grpDesc = permInfoMap.get(grpName); - permInfoMap.put(grpName, formatPermissions(grpDesc, permDesc)); - if(localLOGV) Log.i(TAG, pInfo.name + " : " + permDesc+" : " + grpName); } + // Second pass to actually form the descriptions + // Look at dangerous permissions first + aggregateGroupDescs(dangerousMap, mDangerousMap); + aggregateGroupDescs(normalMap, mNormalMap); } mCurrentState = State.NO_PERMS; diff --git a/core/java/android/widget/ArrayAdapter.java b/core/java/android/widget/ArrayAdapter.java index fe50a01b07a5159437ed0fca9ec3b77e0911ebb9..c65a3ceaf4ef6efa34f6f0ee7028107abe663074 100644 --- a/core/java/android/widget/ArrayAdapter.java +++ b/core/java/android/widget/ArrayAdapter.java @@ -28,7 +28,7 @@ import java.util.List; /** * A ListAdapter that manages a ListView backed by an array of arbitrary - * objects. By default this class expects that the provided resource id referecnes + * objects. By default this class expects that the provided resource id references * a single TextView. If you want to use a more complex layout, use the constructors that * also takes a field id. That field id should reference a TextView in the larger layout * resource. @@ -179,7 +179,7 @@ public class ArrayAdapter extends BaseAdapter implements Filterable { } /** - * Inserts the spcified object at the specified index in the array. + * Inserts the specified object at the specified index in the array. * * @param object The object to insert into the array. * @param index The index at which the object must be inserted. @@ -385,7 +385,7 @@ public class ArrayAdapter extends BaseAdapter implements Filterable { } /** - *

              An array filters constrains the content of the array adapter with + *

              An array filter constrains the content of the array adapter with * a prefix. Each item that does not start with the supplied prefix * is removed from the list.

              */ diff --git a/core/java/android/widget/AutoCompleteTextView.java b/core/java/android/widget/AutoCompleteTextView.java index e1f6fa8a44a0488f97b646995f9ca1b8fa48b78f..d8fa603781c4efcdcc3ef410c7115cea437cdd83 100644 --- a/core/java/android/widget/AutoCompleteTextView.java +++ b/core/java/android/widget/AutoCompleteTextView.java @@ -23,11 +23,17 @@ import android.graphics.drawable.Drawable; import android.text.Editable; import android.text.Selection; import android.text.TextUtils; +import android.text.TextWatcher; import android.util.AttributeSet; +import android.util.Log; import android.view.KeyEvent; import android.view.LayoutInflater; +import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; +import android.view.inputmethod.CompletionInfo; +import android.view.inputmethod.InputMethodManager; +import android.view.inputmethod.EditorInfo; import com.android.internal.R; @@ -55,7 +61,7 @@ import com.android.internal.R; * super.onCreate(icicle); * setContentView(R.layout.countries); * - * ArrayAdapter adapter = new ArrayAdapter(this, + * ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, * android.R.layout.simple_dropdown_item_1line, COUNTRIES); * AutoCompleteTextView textView = (AutoCompleteTextView) * findViewById(R.id.countries_list); @@ -74,6 +80,9 @@ import com.android.internal.R; * @attr ref android.R.styleable#AutoCompleteTextView_dropDownSelector */ public class AutoCompleteTextView extends EditText implements Filter.FilterListener { + static final boolean DEBUG = false; + static final String TAG = "AutoCompleteTextView"; + private static final int HINT_VIEW_ID = 0x17; private CharSequence mHintText; @@ -85,6 +94,8 @@ public class AutoCompleteTextView extends EditText implements Filter.FilterListe private PopupWindow mPopup; private DropDownListView mDropDownList; + private int mDropDownVerticalOffset; + private int mDropDownHorizontalOffset; private Drawable mDropDownListHighlight; @@ -94,7 +105,12 @@ public class AutoCompleteTextView extends EditText implements Filter.FilterListe private final DropDownItemClickListener mDropDownItemClickListener = new DropDownItemClickListener(); - private boolean mTextChanged; + private int mLastKeyCode = KeyEvent.KEYCODE_UNKNOWN; + private boolean mOpenBefore; + + private Validator mValidator = null; + + private AutoCompleteTextView.ListSelectorHider mHideSelector; public AutoCompleteTextView(Context context) { this(context, null); @@ -107,7 +123,8 @@ public class AutoCompleteTextView extends EditText implements Filter.FilterListe public AutoCompleteTextView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); - mPopup = new PopupWindow(context, attrs, com.android.internal.R.attr.autoCompleteTextViewStyle); + mPopup = new PopupWindow(context, attrs, + com.android.internal.R.attr.autoCompleteTextViewStyle); TypedArray a = context.obtainStyledAttributes( @@ -120,13 +137,34 @@ public class AutoCompleteTextView extends EditText implements Filter.FilterListe mDropDownListHighlight = a.getDrawable( R.styleable.AutoCompleteTextView_dropDownSelector); + mDropDownVerticalOffset = (int) + a.getDimension(R.styleable.AutoCompleteTextView_dropDownVerticalOffset, 0.0f); + mDropDownHorizontalOffset = (int) + a.getDimension(R.styleable.AutoCompleteTextView_dropDownHorizontalOffset, 0.0f); mHintResource = a.getResourceId(R.styleable.AutoCompleteTextView_completionHintView, R.layout.simple_dropdown_hint); + // A little trickiness for backwards compatibility: if the app + // didn't specify an explicit content type, then we will fill in the + // auto complete flag for them. + int contentType = a.getInt( + R.styleable.AutoCompleteTextView_inputType, + EditorInfo.TYPE_NULL); + if (contentType == EditorInfo.TYPE_NULL) { + contentType = getInputType(); + if ((contentType&EditorInfo.TYPE_MASK_CLASS) + == EditorInfo.TYPE_CLASS_TEXT) { + contentType |= EditorInfo.TYPE_TEXT_FLAG_AUTO_COMPLETE; + setRawInputType(contentType); + } + } + a.recycle(); setFocusable(true); + + addTextChangedListener(new MyWatcher()); } /** @@ -209,7 +247,10 @@ public class AutoCompleteTextView extends EditText implements Filter.FilterListe * in the drop down list.

              * * @return the item click listener + * + * @deprecated Use {@link #getOnItemClickListener()} intead */ + @Deprecated public AdapterView.OnItemClickListener getItemClickListener() { return mItemClickListener; } @@ -219,11 +260,34 @@ public class AutoCompleteTextView extends EditText implements Filter.FilterListe * item in the drop down list.

              * * @return the item selected listener + * + * @deprecated Use {@link #getOnItemSelectedListener()} intead */ + @Deprecated public AdapterView.OnItemSelectedListener getItemSelectedListener() { return mItemSelectedListener; } + /** + *

              Returns the listener that is notified whenever the user clicks an item + * in the drop down list.

              + * + * @return the item click listener + */ + public AdapterView.OnItemClickListener getOnItemClickListener() { + return mItemClickListener; + } + + /** + *

              Returns the listener that is notified whenever the user selects an + * item in the drop down list.

              + * + * @return the item selected listener + */ + public AdapterView.OnItemSelectedListener getOnItemSelectedListener() { + return mItemSelectedListener; + } + /** *

              Returns a filterable list adapter used for auto completion.

              * @@ -257,6 +321,19 @@ public class AutoCompleteTextView extends EditText implements Filter.FilterListe } } + @Override + public boolean onKeyPreIme(int keyCode, KeyEvent event) { + if (isPopupShowing()) { + // special case for the back key, we do not even try to send it + // to the drop down list but instead, consume it immediately + if (keyCode == KeyEvent.KEYCODE_BACK) { + dismissDropDown(); + return true; + } + } + return super.onKeyPreIme(keyCode, event); + } + @Override public boolean onKeyUp(int keyCode, KeyEvent event) { if (isPopupShowing()) { @@ -280,18 +357,41 @@ public class AutoCompleteTextView extends EditText implements Filter.FilterListe public boolean onKeyDown(int keyCode, KeyEvent event) { // when the drop down is shown, we drive it directly if (isPopupShowing()) { - // special case for the back key, we do not even try to send it - // to the drop down list but instead, consume it immediately - if (keyCode == KeyEvent.KEYCODE_BACK) { - dismissDropDown(); - return true; - // the key events are forwarded to the list in the drop down view // note that ListView handles space but we don't want that to happen - } else if (keyCode != KeyEvent.KEYCODE_SPACE) { - boolean consumed = mDropDownList.onKeyDown(keyCode, event); - + if (keyCode != KeyEvent.KEYCODE_SPACE) { + int curIndex = mDropDownList.getSelectedItemPosition(); + boolean consumed; + if (keyCode == KeyEvent.KEYCODE_DPAD_UP && curIndex <= 0) { + // When the selection is at the top, we block the key + // event to prevent focus from moving. + mDropDownList.hideSelector(); + mPopup.setInputMethodMode(PopupWindow.INPUT_METHOD_NEEDED); + mPopup.update(); + return true; + } + consumed = mDropDownList.onKeyDown(keyCode, event); + if (DEBUG) Log.v(TAG, "Key down: code=" + keyCode + " list consumed=" + + consumed); if (consumed) { + // If it handled the key event, then the user is + // navigating in the list, so we should put it in front. + mPopup.setInputMethodMode(PopupWindow.INPUT_METHOD_NOT_NEEDED); + // Here's a little trick we need to do to make sure that + // the list view is actually showing its focus indicator, + // by ensuring it has focus and getting its window out + // of touch mode. + mDropDownList.requestFocusFromTouch(); + if (false) { + // Update whether the pop-up is in front of or behind + // the input method, depending on whether the user has + // moved down in it. + mPopup.setInputMethodMode(curIndex > 0 + ? PopupWindow.INPUT_METHOD_NOT_NEEDED + : PopupWindow.INPUT_METHOD_NEEDED); + } + mPopup.update(); + switch (keyCode) { // avoid passing the focus from the text view to the // next component @@ -301,22 +401,14 @@ public class AutoCompleteTextView extends EditText implements Filter.FilterListe case KeyEvent.KEYCODE_DPAD_UP: return true; } - } else{ - int index = mDropDownList.getSelectedItemPosition(); - switch (keyCode) { - case KeyEvent.KEYCODE_DPAD_UP: - if (index == 0) { - return true; - } - break; + } else { + if (keyCode == KeyEvent.KEYCODE_DPAD_DOWN) { // when the selection is at the bottom, we block the // event to avoid going to the next focusable widget - case KeyEvent.KEYCODE_DPAD_DOWN: - Adapter adapter = mDropDownList.getAdapter(); - if (index == adapter.getCount() - 1) { - return true; - } - break; + Adapter adapter = mDropDownList.getAdapter(); + if (curIndex == adapter.getCount() - 1) { + return true; + } } } } @@ -327,37 +419,9 @@ public class AutoCompleteTextView extends EditText implements Filter.FilterListe } } - // when text is changed, inserted or deleted, we attempt to show - // the drop down - boolean openBefore = isPopupShowing(); - mTextChanged = false; - + mLastKeyCode = keyCode; boolean handled = super.onKeyDown(keyCode, event); - - // if the list was open before the keystroke, but closed afterwards, - // then something in the keystroke processing (an input filter perhaps) - // called performCompletion() and we shouldn't do any more processing. - if (openBefore && !isPopupShowing()) { - return handled; - } - - if (mTextChanged) { // would have been set in onTextChanged() - // the drop down is shown only when a minimum number of characters - // was typed in the text view - if (enoughToFilter()) { - if (mFilter != null) { - performFiltering(getText(), keyCode); - } - } else { - // drop down is automatically dismissed when enough characters - // are deleted from the text view - dismissDropDown(); - if (mFilter != null) { - mFilter.filter(null); - } - } - return true; - } + mLastKeyCode = KeyEvent.KEYCODE_UNKNOWN; return handled; } @@ -369,14 +433,58 @@ public class AutoCompleteTextView extends EditText implements Filter.FilterListe * triggered. */ public boolean enoughToFilter() { + if (DEBUG) Log.v(TAG, "Enough to filter: len=" + getText().length() + + " threshold=" + mThreshold); return getText().length() >= mThreshold; } - @Override - protected void onTextChanged(CharSequence text, int start, int before, - int after) { - super.onTextChanged(text, start, before, after); - mTextChanged = true; + /** + * This is used to watch for edits to the text view. Note that we call + * to methods on the auto complete text view class so that we can access + * private vars without going through thunks. + */ + private class MyWatcher implements TextWatcher { + public void afterTextChanged(Editable s) { + doAfterTextChanged(); + } + public void beforeTextChanged(CharSequence s, int start, int count, int after) { + doBeforeTextChanged(); + } + public void onTextChanged(CharSequence s, int start, int before, int count) { + } + } + + void doBeforeTextChanged() { + // when text is changed, inserted or deleted, we attempt to show + // the drop down + mOpenBefore = isPopupShowing(); + if (DEBUG) Log.v(TAG, "before text changed: open=" + mOpenBefore); + } + + void doAfterTextChanged() { + // if the list was open before the keystroke, but closed afterwards, + // then something in the keystroke processing (an input filter perhaps) + // called performCompletion() and we shouldn't do any more processing. + if (DEBUG) Log.v(TAG, "after text changed: openBefore=" + mOpenBefore + + " open=" + isPopupShowing()); + if (mOpenBefore && !isPopupShowing()) { + return; + } + + // the drop down is shown only when a minimum number of characters + // was typed in the text view + if (enoughToFilter()) { + if (mFilter != null) { + performFiltering(getText(), mLastKeyCode); + } + } else { + // drop down is automatically dismissed when enough characters + // are deleted from the text view + dismissDropDown(); + if (mFilter != null) { + mFilter.filter(null); + } + } } /** @@ -407,7 +515,8 @@ public class AutoCompleteTextView extends EditText implements Filter.FilterListe * text.

              * * @param text the filtering pattern - * @param keyCode the last character inserted in the edit box + * @param keyCode the last character inserted in the edit box; beware that + * this will be null when text is being added through a soft input method. */ @SuppressWarnings({ "UnusedDeclaration" }) protected void performFiltering(CharSequence text, int keyCode) { @@ -423,6 +532,19 @@ public class AutoCompleteTextView extends EditText implements Filter.FilterListe performCompletion(null, -1, -1); } + @Override public void onCommitCompletion(CompletionInfo completion) { + if (isPopupShowing()) { + replaceText(completion.getText()); + if (mItemClickListener != null) { + final DropDownListView list = mDropDownList; + // Note that we don't have a View here, so we will need to + // supply null. Hopefully no existing apps crash... + mItemClickListener.onItemClick(list, null, completion.getPosition(), + completion.getId()); + } + } + } + private void performCompletion(View selectedView, int position, long id) { if (isPopupShowing()) { Object selectedItem; @@ -464,7 +586,7 @@ public class AutoCompleteTextView extends EditText implements Filter.FilterListe public void onFilterComplete(int count) { /* - * This checks enoughToFilter() again because filtering requests + * This checks enoughToFilter() again because filtering requests * are asynchronous, so the result may come back after enough text * has since been deleted to make it no longer appropriate * to filter. @@ -497,22 +619,32 @@ public class AutoCompleteTextView extends EditText implements Filter.FilterListe } } + @Override + protected void onDetachedFromWindow() { + dismissDropDown(); + super.onDetachedFromWindow(); + } + /** *

              Closes the drop down if present on screen.

              */ public void dismissDropDown() { - mPopup.dismiss(); - if (mDropDownList != null) { - // start next time with no selection - mDropDownList.hideSelector(); + InputMethodManager imm = InputMethodManager.peekInstance(); + if (imm != null) { + imm.displayCompletions(this, null); } + mPopup.dismiss(); + mPopup.setContentView(null); + mDropDownList = null; } @Override protected boolean setFrame(int l, int t, int r, int b) { boolean result = super.setFrame(l, t, r, b); - mPopup.update(this, getMeasuredWidth(), -1); + if (mPopup.isShowing()) { + mPopup.update(this, getMeasuredWidth() - mPaddingLeft - mPaddingRight, -1); + } return result; } @@ -523,11 +655,20 @@ public class AutoCompleteTextView extends EditText implements Filter.FilterListe public void showDropDown() { int height = buildDropDown(); if (mPopup.isShowing()) { - mPopup.update(this, getMeasuredWidth() - mPaddingLeft - mPaddingRight, height); + mPopup.update(this, mDropDownHorizontalOffset, mDropDownVerticalOffset, + getMeasuredWidth() - mPaddingLeft - mPaddingRight, height); } else { - mPopup.setHeight(height); + mPopup.setWindowLayoutMode(0, ViewGroup.LayoutParams.WRAP_CONTENT); mPopup.setWidth(getMeasuredWidth() - mPaddingLeft - mPaddingRight); - mPopup.showAsDropDown(this); + mPopup.setHeight(height); + mPopup.setInputMethodMode(PopupWindow.INPUT_METHOD_NEEDED); + mPopup.setOutsideTouchable(true); + mPopup.setTouchInterceptor(new PopupTouchIntercepter()); + mPopup.showAsDropDown(this, mDropDownHorizontalOffset, mDropDownVerticalOffset); + mDropDownList.hideSelector(); + mDropDownList.setSelection(0); + mDropDownList.requestFocus(); + post(mHideSelector); } } @@ -541,14 +682,34 @@ public class AutoCompleteTextView extends EditText implements Filter.FilterListe ViewGroup dropDownView; int otherHeights = 0; + if (mAdapter != null) { + InputMethodManager imm = InputMethodManager.peekInstance(); + if (imm != null) { + int N = mAdapter.getCount(); + if (N > 20) N = 20; + CompletionInfo[] completions = new CompletionInfo[N]; + for (int i=0; inull if it was not set. + * + * @see #setValidator(android.widget.AutoCompleteTextView.Validator) + * @see #performValidation() + */ + public Validator getValidator() { + return mValidator; + } + + /** + * If a validator was set on this view and the current string is not valid, + * ask the validator to fix it. + * + * @see #getValidator() + * @see #setValidator(android.widget.AutoCompleteTextView.Validator) + */ + public void performValidation() { + if (mValidator == null) return; + + CharSequence text = getText(); + + if (!TextUtils.isEmpty(text) && !mValidator.isValid(text)) { + setText(mValidator.fixText(text)); + } + } + + /** + * Returns the Filter obtained from {@link Filterable#getFilter}, + * or null if {@link #setAdapter} was not called with + * a Filterable. + */ + protected Filter getFilter() { + return mFilter; + } + + private class ListSelectorHider implements Runnable { + public void run() { + if (mDropDownList != null) { + mDropDownList.hideSelector(); + } + } + } + + private class PopupTouchIntercepter implements OnTouchListener { + public boolean onTouch(View v, MotionEvent event) { + if (event.getAction() == MotionEvent.ACTION_DOWN) { + mPopup.setInputMethodMode(PopupWindow.INPUT_METHOD_NOT_NEEDED); + mPopup.update(); + } + return false; + } + } + private class DropDownItemClickListener implements AdapterView.OnItemClickListener { public void onItemClick(AdapterView parent, View v, int position, long id) { performCompletion(v, position, id); @@ -701,6 +929,21 @@ public class AutoCompleteTextView extends EditText implements Filter.FilterListe public boolean hasFocus() { return true; } + + protected int[] onCreateDrawableState(int extraSpace) { + int[] res = super.onCreateDrawableState(extraSpace); + if (false) { + StringBuilder sb = new StringBuilder("Created drawable state: ["); + for (int i=0; i 0) sb.append(", "); + sb.append("0x"); + sb.append(Integer.toHexString(res[i])); + } + sb.append("]"); + Log.i(TAG, sb.toString()); + } + return res; + } } /** @@ -709,54 +952,26 @@ public class AutoCompleteTextView extends EditText implements Filter.FilterListe * this View with an incorrect value in it, all we can do is try to fix it ourselves * when this happens. */ - static public interface Validator { + public interface Validator { /** - * @return true if the text currently in the text editor is valid. + * Validates the specified text. + * + * @return true If the text currently in the text editor is valid. + * + * @see #fixText(CharSequence) */ boolean isValid(CharSequence text); /** - * @param invalidText a string that doesn't pass validation: - * isValid(invalidText) returns false - * @return a string based on invalidText such as invoking isValid() on it returns true. + * Corrects the specified text to make it valid. + * + * @param invalidText A string that doesn't pass validation: isValid(invalidText) + * returns false + * + * @return A string based on invalidText such as invoking isValid() on it returns true. + * + * @see #isValid(CharSequence) */ CharSequence fixText(CharSequence invalidText); } - - private Validator mValidator = null; - - public void setValidator(Validator validator) { - mValidator = validator; - } - - /** - * Returns the Validator set with {@link #setValidator}, - * or null if it was not set. - */ - public Validator getValidator() { - return mValidator; - } - - /** - * If a validator was set on this view and the current string is not valid, - * ask the validator to fix it. - */ - public void performValidation() { - if (mValidator == null) return; - - CharSequence text = getText(); - - if (!TextUtils.isEmpty(text) && !mValidator.isValid(text)) { - setText(mValidator.fixText(text)); - } - } - - /** - * Returns the Filter obtained from {@link Filterable#getFilter}, - * or null if {@link #setAdapter} was not called with - * a Filterable. - */ - protected Filter getFilter() { - return mFilter; - } } diff --git a/core/java/android/widget/BaseExpandableListAdapter.java b/core/java/android/widget/BaseExpandableListAdapter.java index 3a8bb2aea46e9bca0356f7b05ec7bf008fbd587a..1bba7f06374eb72503e29466c0070701797d1b11 100644 --- a/core/java/android/widget/BaseExpandableListAdapter.java +++ b/core/java/android/widget/BaseExpandableListAdapter.java @@ -71,7 +71,7 @@ public abstract class BaseExpandableListAdapter implements ExpandableListAdapter *

              * Base implementation returns a long: *

            • bit 0: Whether this ID points to a child (unset) or group (set), so for this method - * this bit will be 0. + * this bit will be 1. *
            • bit 1-31: Lower 31 bits of the groupId *
            • bit 32-63: Lower 32 bits of the childId. *

              @@ -86,7 +86,7 @@ public abstract class BaseExpandableListAdapter implements ExpandableListAdapter *

              * Base implementation returns a long: *

            • bit 0: Whether this ID points to a child (unset) or group (set), so for this method - * this bit will be 1. + * this bit will be 0. *
            • bit 1-31: Lower 31 bits of the groupId *
            • bit 32-63: Lower 32 bits of the childId. *

              diff --git a/core/java/android/widget/Chronometer.java b/core/java/android/widget/Chronometer.java index 31d20630dd43c9fe9b1c14435c0712f8cfe441d3..7086ae2510bb1a160672cc5aa45e8b30f5e210b6 100644 --- a/core/java/android/widget/Chronometer.java +++ b/core/java/android/widget/Chronometer.java @@ -22,7 +22,7 @@ import android.graphics.Canvas; import android.os.Handler; import android.os.Message; import android.os.SystemClock; -import android.pim.DateUtils; +import android.text.format.DateUtils; import android.util.AttributeSet; import android.util.Log; import android.widget.RemoteViews.RemoteView; diff --git a/core/java/android/widget/CursorAdapter.java b/core/java/android/widget/CursorAdapter.java index cacaeab8e6295e95442c6d587a364f0dba12a613..555f2161af548b9ca38ca537343cdd3d54c18378 100644 --- a/core/java/android/widget/CursorAdapter.java +++ b/core/java/android/widget/CursorAdapter.java @@ -357,9 +357,8 @@ public abstract class CursorAdapter extends BaseAdapter implements Filterable, @Override public void onChange(boolean selfChange) { - if (mAutoRequery && mCursor != null) { - if (Config.LOGV) Log.v("Cursor", "Auto requerying " + mCursor + - " due to update"); + if (mAutoRequery && mCursor != null && !mCursor.isClosed()) { + if (Config.LOGV) Log.v("Cursor", "Auto requerying " + mCursor + " due to update"); mDataValid = mCursor.requery(); } } diff --git a/core/java/android/widget/CursorTreeAdapter.java b/core/java/android/widget/CursorTreeAdapter.java index fa8fd4b23c0b42630f98fead590da127f016f7e2..7b9b7bdafc0f331a8b76a2a867a37d80c2c90009 100644 --- a/core/java/android/widget/CursorTreeAdapter.java +++ b/core/java/android/widget/CursorTreeAdapter.java @@ -450,10 +450,9 @@ public abstract class CursorTreeAdapter extends BaseExpandableListAdapter implem } void changeCursor(Cursor cursor, boolean releaseCursors) { - if (mCursor != null) { - mCursor.unregisterContentObserver(mContentObserver); - mCursor.unregisterDataSetObserver(mDataSetObserver); - } + if (cursor == mCursor) return; + + deactivate(); mCursor = cursor; if (cursor != null) { cursor.registerContentObserver(mContentObserver); diff --git a/core/java/android/widget/DatePicker.java b/core/java/android/widget/DatePicker.java index c03bd324933ff1164cf318950dc35915db8925ff..67010b2dcece8f99ecbb22afbabefdb9a7db0c5b 100644 --- a/core/java/android/widget/DatePicker.java +++ b/core/java/android/widget/DatePicker.java @@ -21,7 +21,7 @@ import android.content.Context; import android.content.res.TypedArray; import android.os.Parcel; import android.os.Parcelable; -import android.pim.DateFormat; +import android.text.format.DateFormat; import android.util.AttributeSet; import android.util.SparseArray; import android.view.LayoutInflater; diff --git a/core/java/android/widget/DigitalClock.java b/core/java/android/widget/DigitalClock.java index 3ca2c81eca763a268ca0dfb2b84ca352dae4f4ba..379883a53b6eeaf3e8965ed3de1d2753490fe28d 100644 --- a/core/java/android/widget/DigitalClock.java +++ b/core/java/android/widget/DigitalClock.java @@ -21,8 +21,8 @@ import android.content.res.Resources; import android.database.ContentObserver; import android.os.Handler; import android.os.SystemClock; -import android.pim.DateFormat; import android.provider.Settings; +import android.text.format.DateFormat; import android.util.AttributeSet; import java.util.Calendar; @@ -105,13 +105,7 @@ public class DigitalClock extends TextView { * Pulls 12/24 mode from system settings */ private boolean get24HourMode() { - String value = Settings.System.getString( - getContext().getContentResolver(), - Settings.System.TIME_12_24); - - if (value == null || value.equals("12")) - return false; - return true; + return android.text.format.DateFormat.is24HourFormat(getContext()); } private void setFormat() { diff --git a/core/java/android/widget/EditText.java b/core/java/android/widget/EditText.java index e89a2bd02cb97d7b188c4b6131cab4d08981c1ac..57aca240502b0e78a4e8bc6e1468ff25ed236312 100644 --- a/core/java/android/widget/EditText.java +++ b/core/java/android/widget/EditText.java @@ -19,7 +19,6 @@ package android.widget; import android.text.*; import android.text.method.*; import android.content.Context; -import android.content.res.Resources; import android.util.AttributeSet; @@ -99,4 +98,13 @@ public class EditText extends TextView { public void extendSelection(int index) { Selection.extendSelection(getText(), index); } + + @Override + public void setEllipsize(TextUtils.TruncateAt ellipsis) { + if (ellipsis == TextUtils.TruncateAt.MARQUEE) { + throw new IllegalArgumentException("EditText cannot use the ellipsize mode " + + "TextUtils.TruncateAt.MARQUEE"); + } + super.setEllipsize(ellipsis); + } } diff --git a/core/java/android/widget/ExpandableListConnector.java b/core/java/android/widget/ExpandableListConnector.java index ddedea33c3e220b65e5d3a2cbc02898f209c6231..ccce7c1764dcba6a8be7e9feed648aa221391e27 100644 --- a/core/java/android/widget/ExpandableListConnector.java +++ b/core/java/android/widget/ExpandableListConnector.java @@ -19,11 +19,13 @@ package android.widget; import android.database.DataSetObserver; import android.os.Parcel; import android.os.Parcelable; -import android.view.KeyEvent; +import android.os.SystemClock; import android.view.View; import android.view.ViewGroup; import java.util.ArrayList; +import java.util.Collections; +import java.util.List; /* * Implementation notes: @@ -120,7 +122,7 @@ class ExpandableListConnector extends BaseAdapter implements Filterable { * either), so flPos must be a group and its group pos will be the * same as its flPos */ - return new PositionMetadata(flPos, ExpandableListPosition.GROUP, flPos, + return PositionMetadata.obtain(flPos, ExpandableListPosition.GROUP, flPos, -1, null, 0); } @@ -159,7 +161,7 @@ class ExpandableListConnector extends BaseAdapter implements Filterable { * The flat list position is this middle group's flat list * position, so we've found an exact hit */ - return new PositionMetadata(flPos, ExpandableListPosition.GROUP, + return PositionMetadata.obtain(flPos, ExpandableListPosition.GROUP, midExpGm.gPos, -1, midExpGm, midExpGroupIndex); } else if (flPos <= midExpGm.lastChildFlPos /* && flPos > midGm.flPos as deduced from previous @@ -172,7 +174,7 @@ class ExpandableListConnector extends BaseAdapter implements Filterable { * the group */ final int childPos = flPos - (midExpGm.flPos + 1); - return new PositionMetadata(flPos, ExpandableListPosition.CHILD, + return PositionMetadata.obtain(flPos, ExpandableListPosition.CHILD, midExpGm.gPos, childPos, midExpGm, midExpGroupIndex); } } @@ -184,11 +186,13 @@ class ExpandableListConnector extends BaseAdapter implements Filterable { */ - /* If we are to expand this group later, where would it go in the - * mExpGroupMetadataList ? */ + /** + * If we are to expand this group later, where would it go in the + * mExpGroupMetadataList ? + */ int insertPosition = 0; - /* What is its group position from the list of all groups? */ + /** What is its group position in the list of all groups? */ int groupPos = 0; /* @@ -237,7 +241,7 @@ class ExpandableListConnector extends BaseAdapter implements Filterable { throw new RuntimeException("Unknown state"); } - return new PositionMetadata(flPos, ExpandableListPosition.GROUP, groupPos, -1, + return PositionMetadata.obtain(flPos, ExpandableListPosition.GROUP, groupPos, -1, null, insertPosition); } @@ -250,7 +254,7 @@ class ExpandableListConnector extends BaseAdapter implements Filterable { * @param pos a {@link ExpandableListPosition} representing either a group position * or child position * @return the flat list position encompassed in a {@link PositionMetadata} - * object that contains additional useful info for insertion, etc. + * object that contains additional useful info for insertion, etc., or null. */ PositionMetadata getFlattenedPos(final ExpandableListPosition pos) { final ArrayList egml = mExpGroupMetadataList; @@ -268,7 +272,7 @@ class ExpandableListConnector extends BaseAdapter implements Filterable { * its flPos will be the same as its group pos. The * insert position is 0 (since the list is empty). */ - return new PositionMetadata(pos.groupPos, pos.type, + return PositionMetadata.obtain(pos.groupPos, pos.type, pos.groupPos, pos.childPos, null, 0); } @@ -298,11 +302,11 @@ class ExpandableListConnector extends BaseAdapter implements Filterable { if (pos.type == ExpandableListPosition.GROUP) { /* If it's a group, give them this matched group's flPos */ - return new PositionMetadata(midExpGm.flPos, pos.type, + return PositionMetadata.obtain(midExpGm.flPos, pos.type, pos.groupPos, pos.childPos, midExpGm, midExpGroupIndex); } else if (pos.type == ExpandableListPosition.CHILD) { /* If it's a child, calculate the flat list pos */ - return new PositionMetadata(midExpGm.flPos + pos.childPos + return PositionMetadata.obtain(midExpGm.flPos + pos.childPos + 1, pos.type, pos.groupPos, pos.childPos, midExpGm, midExpGroupIndex); } else { @@ -341,7 +345,7 @@ class ExpandableListConnector extends BaseAdapter implements Filterable { leftExpGm.lastChildFlPos + (pos.groupPos - leftExpGm.gPos); - return new PositionMetadata(flPos, pos.type, pos.groupPos, + return PositionMetadata.obtain(flPos, pos.type, pos.groupPos, pos.childPos, null, leftExpGroupIndex); } else if (rightExpGroupIndex < midExpGroupIndex) { @@ -355,7 +359,7 @@ class ExpandableListConnector extends BaseAdapter implements Filterable { final int flPos = rightExpGm.flPos - (rightExpGm.gPos - pos.groupPos); - return new PositionMetadata(flPos, pos.type, pos.groupPos, + return PositionMetadata.obtain(flPos, pos.type, pos.groupPos, pos.childPos, null, rightExpGroupIndex); } else { return null; @@ -370,13 +374,18 @@ class ExpandableListConnector extends BaseAdapter implements Filterable { @Override public boolean isEnabled(int flatListPos) { final ExpandableListPosition pos = getUnflattenedPos(flatListPos).position; - + + boolean retValue; if (pos.type == ExpandableListPosition.CHILD) { - return mExpandableListAdapter.isChildSelectable(pos.groupPos, pos.childPos); + retValue = mExpandableListAdapter.isChildSelectable(pos.groupPos, pos.childPos); } else { // Groups are always selectable - return true; + retValue = true; } + + pos.recycle(); + + return retValue; } public int getCount() { @@ -391,62 +400,80 @@ class ExpandableListConnector extends BaseAdapter implements Filterable { public Object getItem(int flatListPos) { final PositionMetadata posMetadata = getUnflattenedPos(flatListPos); + Object retValue; if (posMetadata.position.type == ExpandableListPosition.GROUP) { - return mExpandableListAdapter + retValue = mExpandableListAdapter .getGroup(posMetadata.position.groupPos); } else if (posMetadata.position.type == ExpandableListPosition.CHILD) { - return mExpandableListAdapter.getChild(posMetadata.position.groupPos, + retValue = mExpandableListAdapter.getChild(posMetadata.position.groupPos, posMetadata.position.childPos); } else { // TODO: clean exit throw new RuntimeException("Flat list position is of unknown type"); } + + posMetadata.recycle(); + + return retValue; } public long getItemId(int flatListPos) { final PositionMetadata posMetadata = getUnflattenedPos(flatListPos); final long groupId = mExpandableListAdapter.getGroupId(posMetadata.position.groupPos); + long retValue; if (posMetadata.position.type == ExpandableListPosition.GROUP) { - return mExpandableListAdapter.getCombinedGroupId(groupId); + retValue = mExpandableListAdapter.getCombinedGroupId(groupId); } else if (posMetadata.position.type == ExpandableListPosition.CHILD) { final long childId = mExpandableListAdapter.getChildId(posMetadata.position.groupPos, posMetadata.position.childPos); - return mExpandableListAdapter.getCombinedChildId(groupId, childId); + retValue = mExpandableListAdapter.getCombinedChildId(groupId, childId); } else { // TODO: clean exit throw new RuntimeException("Flat list position is of unknown type"); } + + posMetadata.recycle(); + + return retValue; } public View getView(int flatListPos, View convertView, ViewGroup parent) { final PositionMetadata posMetadata = getUnflattenedPos(flatListPos); + View retValue; if (posMetadata.position.type == ExpandableListPosition.GROUP) { - return mExpandableListAdapter.getGroupView(posMetadata.position.groupPos, posMetadata + retValue = mExpandableListAdapter.getGroupView(posMetadata.position.groupPos, posMetadata .isExpanded(), convertView, parent); } else if (posMetadata.position.type == ExpandableListPosition.CHILD) { final boolean isLastChild = posMetadata.groupMetadata.lastChildFlPos == flatListPos; - final View view = mExpandableListAdapter.getChildView(posMetadata.position.groupPos, + retValue = mExpandableListAdapter.getChildView(posMetadata.position.groupPos, posMetadata.position.childPos, isLastChild, convertView, parent); - - return view; } else { // TODO: clean exit throw new RuntimeException("Flat list position is of unknown type"); } + + posMetadata.recycle(); + + return retValue; } @Override public int getItemViewType(int flatListPos) { final ExpandableListPosition pos = getUnflattenedPos(flatListPos).position; + int retValue; if (pos.type == ExpandableListPosition.GROUP) { - return 0; + retValue = 0; } else { - return 1; + retValue = 1; } + + pos.recycle(); + + return retValue; } @Override @@ -464,22 +491,51 @@ class ExpandableListConnector extends BaseAdapter implements Filterable { * positions. * * @param forceChildrenCountRefresh Forces refreshing of the children count - * for all expanded groups. + * for all expanded groups. + * @param syncGroupPositions Whether to search for the group positions + * based on the group IDs. This should only be needed when calling + * this from an onChanged callback. */ - private void refreshExpGroupMetadataList(boolean forceChildrenCountRefresh) { + @SuppressWarnings("unchecked") + private void refreshExpGroupMetadataList(boolean forceChildrenCountRefresh, + boolean syncGroupPositions) { final ArrayList egml = mExpGroupMetadataList; - final int egmlSize = egml.size(); + int egmlSize = egml.size(); int curFlPos = 0; /* Update child count as we go through */ mTotalExpChildrenCount = 0; - GroupMetadata curGm; + if (syncGroupPositions) { + // We need to check whether any groups have moved positions + boolean positionsChanged = false; + + for (int i = egmlSize - 1; i >= 0; i--) { + GroupMetadata curGm = egml.get(i); + int newGPos = findGroupPosition(curGm.gId, curGm.gPos); + if (newGPos != curGm.gPos) { + if (newGPos == AdapterView.INVALID_POSITION) { + // Doh, just remove it from the list of expanded groups + egml.remove(i); + egmlSize--; + } + + curGm.gPos = newGPos; + if (!positionsChanged) positionsChanged = true; + } + } + + if (positionsChanged) { + // At least one group changed positions, so re-sort + Collections.sort(egml); + } + } + int gChildrenCount; int lastGPos = 0; for (int i = 0; i < egmlSize; i++) { /* Store in local variable since we'll access freq */ - curGm = egml.get(i); + GroupMetadata curGm = egml.get(i); /* * Get the number of children, try to refrain from calling @@ -518,8 +574,13 @@ class ExpandableListConnector extends BaseAdapter implements Filterable { * @param groupPos position of the group to collapse */ boolean collapseGroup(int groupPos) { - return collapseGroup(getFlattenedPos(new ExpandableListPosition(ExpandableListPosition.GROUP, - groupPos, -1, -1))); + PositionMetadata pm = getFlattenedPos(ExpandableListPosition.obtain( + ExpandableListPosition.GROUP, groupPos, -1, -1)); + if (pm == null) return false; + + boolean retValue = collapseGroup(pm); + pm.recycle(); + return retValue; } boolean collapseGroup(PositionMetadata posMetadata) { @@ -538,7 +599,7 @@ class ExpandableListConnector extends BaseAdapter implements Filterable { mExpGroupMetadataList.remove(posMetadata.groupMetadata); // Refresh the metadata - refreshExpGroupMetadataList(false); + refreshExpGroupMetadataList(false, false); // Notify of change notifyDataSetChanged(); @@ -554,8 +615,11 @@ class ExpandableListConnector extends BaseAdapter implements Filterable { * @param groupPos the group to be expanded */ boolean expandGroup(int groupPos) { - return expandGroup(getFlattenedPos(new ExpandableListPosition(ExpandableListPosition.GROUP, - groupPos, -1, -1))); + PositionMetadata pm = getFlattenedPos(ExpandableListPosition.obtain( + ExpandableListPosition.GROUP, groupPos, -1, -1)); + boolean retValue = expandGroup(pm); + pm.recycle(); + return retValue; } boolean expandGroup(PositionMetadata posMetadata) { @@ -590,16 +654,16 @@ class ExpandableListConnector extends BaseAdapter implements Filterable { } } - GroupMetadata expandedGm = new GroupMetadata(); - - expandedGm.gPos = posMetadata.position.groupPos; - expandedGm.flPos = GroupMetadata.REFRESH; - expandedGm.lastChildFlPos = GroupMetadata.REFRESH; + GroupMetadata expandedGm = GroupMetadata.obtain( + GroupMetadata.REFRESH, + GroupMetadata.REFRESH, + posMetadata.position.groupPos, + mExpandableListAdapter.getGroupId(posMetadata.position.groupPos)); mExpGroupMetadataList.add(posMetadata.groupInsertIndex, expandedGm); // Refresh the metadata - refreshExpGroupMetadataList(false); + refreshExpGroupMetadataList(false, false); // Notify of change notifyDataSetChanged(); @@ -669,7 +733,7 @@ class ExpandableListConnector extends BaseAdapter implements Filterable { } mExpGroupMetadataList = expandedGroupMetadataList; - refreshExpGroupMetadataList(true); + refreshExpGroupMetadataList(true, false); } @Override @@ -678,17 +742,104 @@ class ExpandableListConnector extends BaseAdapter implements Filterable { return adapter != null ? adapter.isEmpty() : true; } + /** + * Searches the expandable list adapter for a group position matching the + * given group ID. The search starts at the given seed position and then + * alternates between moving up and moving down until 1) we find the right + * position, or 2) we run out of time, or 3) we have looked at every + * position + * + * @return Position of the row that matches the given row ID, or + * {@link AdapterView#INVALID_POSITION} if it can't be found + * @see AdapterView#findSyncPosition() + */ + int findGroupPosition(long groupIdToMatch, int seedGroupPosition) { + int count = mExpandableListAdapter.getGroupCount(); + + if (count == 0) { + return AdapterView.INVALID_POSITION; + } + + // If there isn't a selection don't hunt for it + if (groupIdToMatch == AdapterView.INVALID_ROW_ID) { + return AdapterView.INVALID_POSITION; + } + + // Pin seed to reasonable values + seedGroupPosition = Math.max(0, seedGroupPosition); + seedGroupPosition = Math.min(count - 1, seedGroupPosition); + + long endTime = SystemClock.uptimeMillis() + AdapterView.SYNC_MAX_DURATION_MILLIS; + + long rowId; + + // first position scanned so far + int first = seedGroupPosition; + + // last position scanned so far + int last = seedGroupPosition; + + // True if we should move down on the next iteration + boolean next = false; + + // True when we have looked at the first item in the data + boolean hitFirst; + + // True when we have looked at the last item in the data + boolean hitLast; + + // Get the item ID locally (instead of getItemIdAtPosition), so + // we need the adapter + ExpandableListAdapter adapter = getAdapter(); + if (adapter == null) { + return AdapterView.INVALID_POSITION; + } + + while (SystemClock.uptimeMillis() <= endTime) { + rowId = adapter.getGroupId(seedGroupPosition); + if (rowId == groupIdToMatch) { + // Found it! + return seedGroupPosition; + } + + hitLast = last == count - 1; + hitFirst = first == 0; + + if (hitLast && hitFirst) { + // Looked at everything + break; + } + + if (hitFirst || (next && !hitLast)) { + // Either we hit the top, or we are trying to move down + last++; + seedGroupPosition = last; + // Try going up next time + next = false; + } else if (hitLast || (!next && !hitFirst)) { + // Either we hit the bottom, or we are trying to move up + first--; + seedGroupPosition = first; + // Try going down next time + next = true; + } + + } + + return AdapterView.INVALID_POSITION; + } + protected class MyDataSetObserver extends DataSetObserver { @Override public void onChanged() { - refreshExpGroupMetadataList(true); + refreshExpGroupMetadataList(true, true); notifyDataSetChanged(); } @Override public void onInvalidated() { - refreshExpGroupMetadataList(true); + refreshExpGroupMetadataList(true, true); notifyDataSetInvalidated(); } @@ -699,7 +850,7 @@ class ExpandableListConnector extends BaseAdapter implements Filterable { * position to either a) group position for groups, or b) child position for * children */ - static class GroupMetadata implements Parcelable { + static class GroupMetadata implements Parcelable, Comparable { final static int REFRESH = -1; /** This group's flat list position */ @@ -717,6 +868,31 @@ class ExpandableListConnector extends BaseAdapter implements Filterable { * This group's group position */ int gPos; + + /** + * This group's id + */ + long gId; + + private GroupMetadata() { + } + + static GroupMetadata obtain(int flPos, int lastChildFlPos, int gPos, long gId) { + GroupMetadata gm = new GroupMetadata(); + gm.flPos = flPos; + gm.lastChildFlPos = lastChildFlPos; + gm.gPos = gPos; + gm.gId = gId; + return gm; + } + + public int compareTo(Object another) { + if (another == null || !(another instanceof GroupMetadata)) { + throw new ClassCastException(); + } + + return gPos - ((GroupMetadata) another).gPos; + } public int describeContents() { return 0; @@ -726,16 +902,18 @@ class ExpandableListConnector extends BaseAdapter implements Filterable { dest.writeInt(flPos); dest.writeInt(lastChildFlPos); dest.writeInt(gPos); + dest.writeLong(gId); } public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { public GroupMetadata createFromParcel(Parcel in) { - GroupMetadata gm = new GroupMetadata(); - gm.flPos = in.readInt(); - gm.lastChildFlPos = in.readInt(); - gm.gPos = in.readInt(); + GroupMetadata gm = GroupMetadata.obtain( + in.readInt(), + in.readInt(), + in.readInt(), + in.readLong()); return gm; } @@ -752,6 +930,11 @@ class ExpandableListConnector extends BaseAdapter implements Filterable { * where to insert into the flat list, etc.) */ static public class PositionMetadata { + + private static final int MAX_POOL_SIZE = 5; + private static ArrayList sPool = + new ArrayList(MAX_POOL_SIZE); + /** Data type to hold the position and its type (child/group) */ public ExpandableListPosition position; @@ -771,17 +954,46 @@ class ExpandableListConnector extends BaseAdapter implements Filterable { */ public int groupInsertIndex; - public PositionMetadata(int flatListPos, int type, int groupPos, - int childPos) { - position = new ExpandableListPosition(type, groupPos, childPos, flatListPos); + private void resetState() { + position = null; + groupMetadata = null; + groupInsertIndex = 0; + } + + /** + * Use {@link #obtain(int, int, int, int, GroupMetadata, int)} + */ + private PositionMetadata() { } - protected PositionMetadata(int flatListPos, int type, int groupPos, + static PositionMetadata obtain(int flatListPos, int type, int groupPos, int childPos, GroupMetadata groupMetadata, int groupInsertIndex) { - position = new ExpandableListPosition(type, groupPos, childPos, flatListPos); - - this.groupMetadata = groupMetadata; - this.groupInsertIndex = groupInsertIndex; + PositionMetadata pm = getRecycledOrCreate(); + pm.position = ExpandableListPosition.obtain(type, groupPos, childPos, flatListPos); + pm.groupMetadata = groupMetadata; + pm.groupInsertIndex = groupInsertIndex; + return pm; + } + + private static PositionMetadata getRecycledOrCreate() { + PositionMetadata pm; + synchronized (sPool) { + if (sPool.size() > 0) { + pm = sPool.remove(0); + } else { + return new PositionMetadata(); + } + } + pm.resetState(); + return pm; + } + + public void recycle() { + synchronized (sPool) { + if (sPool.size() < MAX_POOL_SIZE) { + sPool.add(this); + } + } } /** diff --git a/core/java/android/widget/ExpandableListPosition.java b/core/java/android/widget/ExpandableListPosition.java index 71e970c321899a5b11e0df53d61c75233d2f5168..e8d61137d9dcd2bf7f80caecc1a6ec6b4ee908ec 100644 --- a/core/java/android/widget/ExpandableListPosition.java +++ b/core/java/android/widget/ExpandableListPosition.java @@ -16,6 +16,8 @@ package android.widget; +import java.util.ArrayList; + /** * ExpandableListPosition can refer to either a group's position or a child's * position. Referring to a child's position requires both a group position (the @@ -24,6 +26,11 @@ package android.widget; * {@link #obtainGroupPosition(int)}. */ class ExpandableListPosition { + + private static final int MAX_POOL_SIZE = 5; + private static ArrayList sPool = + new ArrayList(MAX_POOL_SIZE); + /** * This data type represents a child position */ @@ -56,21 +63,14 @@ class ExpandableListPosition { */ public int type; - ExpandableListPosition(int type, int groupPos, int childPos, int flatListPos) { - this.type = type; - this.flatListPos = flatListPos; - this.groupPos = groupPos; - this.childPos = childPos; + private void resetState() { + groupPos = 0; + childPos = 0; + flatListPos = 0; + type = 0; } - - /** - * Used internally by the {@link #obtainChildPosition} and - * {@link #obtainGroupPosition} methods to construct a new object. - */ - private ExpandableListPosition(int type, int groupPos, int childPos) { - this.type = type; - this.groupPos = groupPos; - this.childPos = childPos; + + private ExpandableListPosition() { } long getPackedPosition() { @@ -79,11 +79,11 @@ class ExpandableListPosition { } static ExpandableListPosition obtainGroupPosition(int groupPosition) { - return new ExpandableListPosition(GROUP, groupPosition, 0); + return obtain(GROUP, groupPosition, 0, 0); } static ExpandableListPosition obtainChildPosition(int groupPosition, int childPosition) { - return new ExpandableListPosition(CHILD, groupPosition, childPosition); + return obtain(CHILD, groupPosition, childPosition, 0); } static ExpandableListPosition obtainPosition(long packedPosition) { @@ -91,12 +91,45 @@ class ExpandableListPosition { return null; } - final int type = ExpandableListView.getPackedPositionType(packedPosition) == - ExpandableListView.PACKED_POSITION_TYPE_CHILD ? CHILD : GROUP; - - return new ExpandableListPosition(type, ExpandableListView - .getPackedPositionGroup(packedPosition), ExpandableListView - .getPackedPositionChild(packedPosition)); + ExpandableListPosition elp = getRecycledOrCreate(); + elp.groupPos = ExpandableListView.getPackedPositionGroup(packedPosition); + if (ExpandableListView.getPackedPositionType(packedPosition) == + ExpandableListView.PACKED_POSITION_TYPE_CHILD) { + elp.type = CHILD; + elp.childPos = ExpandableListView.getPackedPositionChild(packedPosition); + } else { + elp.type = GROUP; + } + return elp; + } + + static ExpandableListPosition obtain(int type, int groupPos, int childPos, int flatListPos) { + ExpandableListPosition elp = getRecycledOrCreate(); + elp.type = type; + elp.groupPos = groupPos; + elp.childPos = childPos; + elp.flatListPos = flatListPos; + return elp; + } + + private static ExpandableListPosition getRecycledOrCreate() { + ExpandableListPosition elp; + synchronized (sPool) { + if (sPool.size() > 0) { + elp = sPool.remove(0); + } else { + return new ExpandableListPosition(); + } + } + elp.resetState(); + return elp; } + public void recycle() { + synchronized (sPool) { + if (sPool.size() < MAX_POOL_SIZE) { + sPool.add(this); + } + } + } } diff --git a/core/java/android/widget/ExpandableListView.java b/core/java/android/widget/ExpandableListView.java index 138cace1d274c330e9bdbdbe69721e6117dae005..3de561ace86843c63a881108066e33783ceeecd6 100644 --- a/core/java/android/widget/ExpandableListView.java +++ b/core/java/android/widget/ExpandableListView.java @@ -25,6 +25,7 @@ import android.content.res.TypedArray; import android.graphics.Canvas; import android.graphics.Rect; import android.graphics.drawable.Drawable; +import android.graphics.drawable.ColorDrawable; import android.os.Parcel; import android.os.Parcelable; import android.util.AttributeSet; @@ -184,7 +185,8 @@ public class ExpandableListView extends ListView { /** Drawable to be used as a divider when it is adjacent to any children */ private Drawable mChildDivider; - + private boolean mClipChildDivider; + public ExpandableListView(Context context) { this(context, null); } @@ -245,7 +247,7 @@ public class ExpandableListView extends ListView { final int myB = mBottom; - PositionMetadata pos; + PositionMetadata pos = null; View item; Drawable indicator; int t, b; @@ -297,28 +299,27 @@ public class ExpandableListView extends ListView { lastItemType = pos.position.type; } - if (indicatorRect.left == indicatorRect.right) { - // The left and right bounds are the same, so nothing will be drawn - continue; - } - - // Use item's full height + the divider height - if (mStackFromBottom) { - // See ListView#dispatchDraw - indicatorRect.top = t - mDividerHeight; - indicatorRect.bottom = b; - } else { - indicatorRect.top = t; - indicatorRect.bottom = b + mDividerHeight; + if (indicatorRect.left != indicatorRect.right) { + // Use item's full height + the divider height + if (mStackFromBottom) { + // See ListView#dispatchDraw + indicatorRect.top = t - mDividerHeight; + indicatorRect.bottom = b; + } else { + indicatorRect.top = t; + indicatorRect.bottom = b + mDividerHeight; + } + + // Get the indicator (with its state set to the item's state) + indicator = getIndicator(pos); + if (indicator != null) { + // Draw the indicator + indicator.setBounds(indicatorRect); + indicator.draw(canvas); + } } - // Get the indicator (with its state set to the item's state) - indicator = getIndicator(pos); - if (indicator == null) continue; - - // Draw the indicator - indicator.setBounds(indicatorRect); - indicator.draw(canvas); + pos.recycle(); } if (clipToPadding) { @@ -376,6 +377,7 @@ public class ExpandableListView extends ListView { */ public void setChildDivider(Drawable childDivider) { mChildDivider = childDivider; + mClipChildDivider = childDivider != null && childDivider instanceof ColorDrawable; } @Override @@ -387,14 +389,25 @@ public class ExpandableListView extends ListView { if (flatListPosition >= 0) { PositionMetadata pos = mConnector.getUnflattenedPos(flatListPosition); // If this item is a child, or it is a non-empty group that is expanded - if ((pos.position.type == ExpandableListPosition.CHILD) - || (pos.isExpanded() && - pos.groupMetadata.lastChildFlPos != pos.groupMetadata.flPos)) { + if ((pos.position.type == ExpandableListPosition.CHILD) || (pos.isExpanded() && + pos.groupMetadata.lastChildFlPos != pos.groupMetadata.flPos)) { // These are the cases where we draw the child divider - mChildDivider.setBounds(bounds); - mChildDivider.draw(canvas); + final Drawable divider = mChildDivider; + final boolean clip = mClipChildDivider; + if (!clip) { + divider.setBounds(bounds); + } else { + canvas.save(); + canvas.clipRect(bounds); + } + divider.draw(canvas); + if (clip) { + canvas.restore(); + } + pos.recycle(); return; } + pos.recycle(); } // Otherwise draw the default divider @@ -495,6 +508,7 @@ public class ExpandableListView extends ListView { id = getChildOrGroupId(posMetadata.position); + boolean returnValue; if (posMetadata.position.type == ExpandableListPosition.GROUP) { /* It's a group, so handle collapsing/expanding */ @@ -513,6 +527,7 @@ public class ExpandableListView extends ListView { if (mOnGroupClickListener != null) { if (mOnGroupClickListener.onGroupClick(this, v, posMetadata.position.groupPos, id)) { + posMetadata.recycle(); return true; } } @@ -527,7 +542,7 @@ public class ExpandableListView extends ListView { } } - return true; + returnValue = true; } else { /* It's a child, so pass on event */ if (mOnChildClickListener != null) { @@ -536,8 +551,12 @@ public class ExpandableListView extends ListView { posMetadata.position.childPos, id); } - return false; + returnValue = false; } + + posMetadata.recycle(); + + return returnValue; } /** @@ -676,7 +695,10 @@ public class ExpandableListView extends ListView { * in packed position representation. */ public long getExpandableListPosition(int flatListPosition) { - return mConnector.getUnflattenedPos(flatListPosition).position.getPackedPosition(); + PositionMetadata pm = mConnector.getUnflattenedPos(flatListPosition); + long packedPos = pm.position.getPackedPosition(); + pm.recycle(); + return packedPos; } /** @@ -691,8 +713,11 @@ public class ExpandableListView extends ListView { * @return The flat list position for the given child or group. */ public int getFlatListPosition(long packedPosition) { - return mConnector.getFlattenedPos(ExpandableListPosition.obtainPosition(packedPosition)). - position.flatListPos; + PositionMetadata pm = mConnector.getFlattenedPos(ExpandableListPosition + .obtainPosition(packedPosition)); + int retValue = pm.position.flatListPos; + pm.recycle(); + return retValue; } /** @@ -737,8 +762,11 @@ public class ExpandableListView extends ListView { */ public void setSelectedGroup(int groupPosition) { ExpandableListPosition elGroupPos = ExpandableListPosition - .obtainGroupPosition(groupPosition); - super.setSelection(mConnector.getFlattenedPos(elGroupPos).position.flatListPos); + .obtainGroupPosition(groupPosition); + PositionMetadata pm = mConnector.getFlattenedPos(elGroupPos); + elGroupPos.recycle(); + super.setSelection(pm.position.flatListPos); + pm.recycle(); } /** @@ -775,6 +803,9 @@ public class ExpandableListView extends ListView { super.setSelection(flatChildPos.position.flatListPos); + elChildPos.recycle(); + flatChildPos.recycle(); + return true; } @@ -883,11 +914,15 @@ public class ExpandableListView extends ListView { @Override ContextMenuInfo createContextMenuInfo(View view, int flatListPosition, long id) { - ExpandableListPosition pos = mConnector.getUnflattenedPos(flatListPosition).position; + PositionMetadata pm = mConnector.getUnflattenedPos(flatListPosition); + ExpandableListPosition pos = pm.position; + pm.recycle(); id = getChildOrGroupId(pos); + long packedPosition = pos.getPackedPosition(); + pos.recycle(); - return new ExpandableListContextMenuInfo(view, pos.getPackedPosition(), id); + return new ExpandableListContextMenuInfo(view, packedPosition, id); } /** diff --git a/core/java/android/widget/FastScroller.java b/core/java/android/widget/FastScroller.java new file mode 100644 index 0000000000000000000000000000000000000000..bdcfeef859c2a6b3821e85d048970530490be8e5 --- /dev/null +++ b/core/java/android/widget/FastScroller.java @@ -0,0 +1,471 @@ +/* + * 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 android.widget; + +import android.content.Context; +import android.content.res.ColorStateList; +import android.content.res.Resources; +import android.content.res.TypedArray; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.RectF; +import android.graphics.drawable.Drawable; +import android.os.Handler; +import android.os.SystemClock; +import android.util.TypedValue; +import android.view.MotionEvent; + +/** + * Helper class for AbsListView to draw and control the Fast Scroll thumb + */ +class FastScroller { + + + // Scroll thumb not showing + private static final int STATE_NONE = 0; + // Not implemented yet - fade-in transition + private static final int STATE_ENTER = 1; + // Scroll thumb visible and moving along with the scrollbar + private static final int STATE_VISIBLE = 2; + // Scroll thumb being dragged by user + private static final int STATE_DRAGGING = 3; + // Scroll thumb fading out due to inactivity timeout + private static final int STATE_EXIT = 4; + + private Drawable mThumbDrawable; + private Drawable mOverlayDrawable; + + private int mThumbH; + private int mThumbW; + private int mThumbY; + + private RectF mOverlayPos; + private int mOverlaySize = 104; + + private AbsListView mList; + private boolean mScrollCompleted; + private int mVisibleItem; + private Paint mPaint; + private int mListOffset; + + private Object [] mSections; + private String mSectionText; + private boolean mDrawOverlay; + private ScrollFade mScrollFade; + + private int mState; + + private Handler mHandler = new Handler(); + + private BaseAdapter mListAdapter; + private SectionIndexer mSectionIndexer; + + private boolean mChangedBounds; + + public FastScroller(Context context, AbsListView listView) { + mList = listView; + init(context); + } + + public void setState(int state) { + switch (state) { + case STATE_NONE: + mHandler.removeCallbacks(mScrollFade); + mList.invalidate(); + break; + case STATE_VISIBLE: + if (mState != STATE_VISIBLE) { // Optimization + resetThumbPos(); + } + // Fall through + case STATE_DRAGGING: + mHandler.removeCallbacks(mScrollFade); + break; + case STATE_EXIT: + int viewWidth = mList.getWidth(); + mList.invalidate(viewWidth - mThumbW, mThumbY, viewWidth, mThumbY + mThumbH); + break; + } + mState = state; + } + + public int getState() { + return mState; + } + + private void resetThumbPos() { + final int viewWidth = mList.getWidth(); + // Bounds are always top right. Y coordinate get's translated during draw + mThumbDrawable.setBounds(viewWidth - mThumbW, 0, viewWidth, mThumbH); + mThumbDrawable.setAlpha(ScrollFade.ALPHA_MAX); + } + + private void useThumbDrawable(Drawable drawable) { + mThumbDrawable = drawable; + mThumbW = 64; //mCurrentThumb.getIntrinsicWidth(); + mThumbH = 52; //mCurrentThumb.getIntrinsicHeight(); + mChangedBounds = true; + } + + private void init(Context context) { + // Get both the scrollbar states drawables + final Resources res = context.getResources(); + useThumbDrawable(res.getDrawable( + com.android.internal.R.drawable.scrollbar_handle_accelerated_anim2)); + + mOverlayDrawable = res.getDrawable( + com.android.internal.R.drawable.menu_submenu_background); + + mScrollCompleted = true; + + getSections(); + + mOverlayPos = new RectF(); + mScrollFade = new ScrollFade(); + mPaint = new Paint(); + mPaint.setAntiAlias(true); + mPaint.setTextAlign(Paint.Align.CENTER); + mPaint.setTextSize(mOverlaySize / 2); + TypedArray ta = context.getTheme().obtainStyledAttributes(new int[] { + android.R.attr.textColorPrimary }); + ColorStateList textColor = ta.getColorStateList(ta.getIndex(0)); + int textColorNormal = textColor.getDefaultColor(); + mPaint.setColor(textColorNormal); + mPaint.setStyle(Paint.Style.FILL_AND_STROKE); + + mState = STATE_NONE; + } + + void stop() { + setState(STATE_NONE); + } + + public void draw(Canvas canvas) { + + if (mState == STATE_NONE) { + // No need to draw anything + return; + } + + final int y = mThumbY; + final int viewWidth = mList.getWidth(); + final FastScroller.ScrollFade scrollFade = mScrollFade; + + int alpha = -1; + if (mState == STATE_EXIT) { + alpha = scrollFade.getAlpha(); + if (alpha < ScrollFade.ALPHA_MAX / 2) { + mThumbDrawable.setAlpha(alpha * 2); + } + int left = viewWidth - (mThumbW * alpha) / ScrollFade.ALPHA_MAX; + mThumbDrawable.setBounds(left, 0, viewWidth, mThumbH); + mChangedBounds = true; + } + + canvas.translate(0, y); + mThumbDrawable.draw(canvas); + canvas.translate(0, -y); + + // If user is dragging the scroll bar, draw the alphabet overlay + if (mState == STATE_DRAGGING && mDrawOverlay) { + mOverlayDrawable.draw(canvas); + final Paint paint = mPaint; + float descent = paint.descent(); + final RectF rectF = mOverlayPos; + canvas.drawText(mSectionText, (int) (rectF.left + rectF.right) / 2, + (int) (rectF.bottom + rectF.top) / 2 + mOverlaySize / 4 - descent, paint); + } else if (mState == STATE_EXIT) { + if (alpha == 0) { // Done with exit + setState(STATE_NONE); + } else { + mList.invalidate(viewWidth - mThumbW, y, viewWidth, y + mThumbH); + } + } + } + + void onSizeChanged(int w, int h, int oldw, int oldh) { + if (mThumbDrawable != null) { + mThumbDrawable.setBounds(w - mThumbW, 0, w, mThumbH); + } + final RectF pos = mOverlayPos; + pos.left = (w - mOverlaySize) / 2; + pos.right = pos.left + mOverlaySize; + pos.top = h / 10; // 10% from top + pos.bottom = pos.top + mOverlaySize; + if (mOverlayDrawable != null) { + mOverlayDrawable.setBounds((int) pos.left, (int) pos.top, + (int) pos.right, (int) pos.bottom); + } + } + + void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, + int totalItemCount) { + + if (totalItemCount - visibleItemCount > 0 && mState != STATE_DRAGGING ) { + mThumbY = ((mList.getHeight() - mThumbH) * firstVisibleItem) + / (totalItemCount - visibleItemCount); + if (mChangedBounds) { + resetThumbPos(); + mChangedBounds = false; + } + } + mScrollCompleted = true; + if (firstVisibleItem == mVisibleItem) { + return; + } + mVisibleItem = firstVisibleItem; + if (mState != STATE_DRAGGING) { + setState(STATE_VISIBLE); + mHandler.postDelayed(mScrollFade, 1500); + } + } + + private void getSections() { + Adapter adapter = mList.getAdapter(); + mSectionIndexer = null; + if (adapter instanceof HeaderViewListAdapter) { + mListOffset = ((HeaderViewListAdapter)adapter).getHeadersCount(); + adapter = ((HeaderViewListAdapter)adapter).getWrappedAdapter(); + } + if (adapter instanceof ExpandableListConnector) { + ExpandableListAdapter expAdapter = ((ExpandableListConnector)adapter).getAdapter(); + if (expAdapter instanceof SectionIndexer) { + mSectionIndexer = (SectionIndexer) expAdapter; + mListAdapter = (BaseAdapter) adapter; + mSections = mSectionIndexer.getSections(); + } + } else { + if (adapter instanceof SectionIndexer) { + mListAdapter = (BaseAdapter) adapter; + mSectionIndexer = (SectionIndexer) adapter; + mSections = mSectionIndexer.getSections(); + + } else { + mListAdapter = (BaseAdapter) adapter; + mSections = new String[] { " " }; + } + } + } + + private void scrollTo(float position) { + int count = mList.getCount(); + mScrollCompleted = false; + float fThreshold = (1.0f / count) / 8; + final Object[] sections = mSections; + int sectionIndex; + if (sections != null && sections.length > 1) { + final int nSections = sections.length; + int section = (int) (position * nSections); + if (section >= nSections) { + section = nSections - 1; + } + int exactSection = section; + sectionIndex = section; + int index = mSectionIndexer.getPositionForSection(section); + // Given the expected section and index, the following code will + // try to account for missing sections (no names starting with..) + // It will compute the scroll space of surrounding empty sections + // and interpolate the currently visible letter's range across the + // available space, so that there is always some list movement while + // the user moves the thumb. + int nextIndex = count; + int prevIndex = index; + int prevSection = section; + int nextSection = section + 1; + // Assume the next section is unique + if (section < nSections - 1) { + nextIndex = mSectionIndexer.getPositionForSection(section + 1); + } + + // Find the previous index if we're slicing the previous section + if (nextIndex == index) { + // Non-existent letter + while (section > 0) { + section--; + prevIndex = mSectionIndexer.getPositionForSection(section); + if (prevIndex != index) { + prevSection = section; + sectionIndex = section; + break; + } + } + } + // Find the next index, in case the assumed next index is not + // unique. For instance, if there is no P, then request for P's + // position actually returns Q's. So we need to look ahead to make + // sure that there is really a Q at Q's position. If not, move + // further down... + int nextNextSection = nextSection + 1; + while (nextNextSection < nSections && + mSectionIndexer.getPositionForSection(nextNextSection) == nextIndex) { + nextNextSection++; + nextSection++; + } + // Compute the beginning and ending scroll range percentage of the + // currently visible letter. This could be equal to or greater than + // (1 / nSections). + float fPrev = (float) prevSection / nSections; + float fNext = (float) nextSection / nSections; + if (prevSection == exactSection && position - fPrev < fThreshold) { + index = prevIndex; + } else { + index = prevIndex + (int) ((nextIndex - prevIndex) * (position - fPrev) + / (fNext - fPrev)); + } + // Don't overflow + if (index > count - 1) index = count - 1; + + if (mList instanceof ExpandableListView) { + ExpandableListView expList = (ExpandableListView) mList; + expList.setSelectionFromTop(expList.getFlatListPosition( + ExpandableListView.getPackedPositionForGroup(index + mListOffset)), 0); + } else if (mList instanceof ListView) { + ((ListView)mList).setSelectionFromTop(index + mListOffset, 0); + } else { + mList.setSelection(index + mListOffset); + } + } else { + int index = (int) (position * count); + if (mList instanceof ExpandableListView) { + ExpandableListView expList = (ExpandableListView) mList; + expList.setSelectionFromTop(expList.getFlatListPosition( + ExpandableListView.getPackedPositionForGroup(index + mListOffset)), 0); + } else if (mList instanceof ListView) { + ((ListView)mList).setSelectionFromTop(index + mListOffset, 0); + } else { + mList.setSelection(index + mListOffset); + } + sectionIndex = -1; + } + + if (sectionIndex >= 0) { + String text = mSectionText = sections[sectionIndex].toString(); + mDrawOverlay = (text.length() != 1 || text.charAt(0) != ' ') && + sectionIndex < sections.length; + } else { + mDrawOverlay = false; + } + } + + private void cancelFling() { + // Cancel the list fling + MotionEvent cancelFling = MotionEvent.obtain(0, 0, MotionEvent.ACTION_CANCEL, 0, 0, 0); + mList.onTouchEvent(cancelFling); + cancelFling.recycle(); + } + + boolean onInterceptTouchEvent(MotionEvent ev) { + if (mState > STATE_NONE && ev.getAction() == MotionEvent.ACTION_DOWN) { + if (ev.getX() > mList.getWidth() - mThumbW && ev.getY() >= mThumbY && + ev.getY() <= mThumbY + mThumbH) { + setState(STATE_DRAGGING); + return true; + } + } + return false; + } + + boolean onTouchEvent(MotionEvent me) { + if (mState == STATE_NONE) { + return false; + } + if (me.getAction() == MotionEvent.ACTION_DOWN) { + if (me.getX() > mList.getWidth() - mThumbW + && me.getY() >= mThumbY + && me.getY() <= mThumbY + mThumbH) { + + setState(STATE_DRAGGING); + if (mListAdapter == null && mList != null) { + getSections(); + } + + cancelFling(); + return true; + } + } else if (me.getAction() == MotionEvent.ACTION_UP) { + if (mState == STATE_DRAGGING) { + setState(STATE_VISIBLE); + final Handler handler = mHandler; + handler.removeCallbacks(mScrollFade); + handler.postDelayed(mScrollFade, 1000); + return true; + } + } else if (me.getAction() == MotionEvent.ACTION_MOVE) { + if (mState == STATE_DRAGGING) { + final int viewHeight = mList.getHeight(); + // Jitter + int newThumbY = (int) me.getY() - mThumbH + 10; + if (newThumbY < 0) { + newThumbY = 0; + } else if (newThumbY + mThumbH > viewHeight) { + newThumbY = viewHeight - mThumbH; + } + if (Math.abs(mThumbY - newThumbY) < 2) { + return true; + } + mThumbY = newThumbY; + // If the previous scrollTo is still pending + if (mScrollCompleted) { + scrollTo((float) mThumbY / (viewHeight - mThumbH)); + } + return true; + } + } + return false; + } + + public class ScrollFade implements Runnable { + + long mStartTime; + long mFadeDuration; + static final int ALPHA_MAX = 208; + static final long FADE_DURATION = 200; + + void startFade() { + mFadeDuration = FADE_DURATION; + mStartTime = SystemClock.uptimeMillis(); + setState(STATE_EXIT); + } + + int getAlpha() { + if (getState() != STATE_EXIT) { + return ALPHA_MAX; + } + int alpha; + long now = SystemClock.uptimeMillis(); + if (now > mStartTime + mFadeDuration) { + alpha = 0; + } else { + alpha = (int) (ALPHA_MAX - ((now - mStartTime) * ALPHA_MAX) / mFadeDuration); + } + return alpha; + } + + public void run() { + if (getState() != STATE_EXIT) { + startFade(); + return; + } + + if (getAlpha() > 0) { + mList.invalidate(); + } else { + setState(STATE_NONE); + } + } + } +} diff --git a/core/java/android/widget/Gallery.java b/core/java/android/widget/Gallery.java index acf9400df3e99fb52d2636cad8339cf0f71f54cd..d886155f3aef17f4b95c6bb4f834e3e089c366b6 100644 --- a/core/java/android/widget/Gallery.java +++ b/core/java/android/widget/Gallery.java @@ -122,7 +122,7 @@ public class Gallery extends AbsSpinner implements GestureDetector.OnGestureList * Whether to continuously callback on the item selected listener during a * fling. */ - private boolean mShouldCallbackDuringFling; + private boolean mShouldCallbackDuringFling = true; /** * Whether to callback when an item that is not selected is clicked. @@ -133,6 +133,13 @@ public class Gallery extends AbsSpinner implements GestureDetector.OnGestureList * If true, do not callback to item selected listener. */ private boolean mSuppressSelectionChanged; + + /** + * If true, we have received the "invoke" (center or enter buttons) key + * down. This is checked before we action on the "invoke" key up, and is + * subsequently cleared. + */ + private boolean mReceivedInvokeKeyDown; private AdapterContextMenuInfo mContextMenuInfo; @@ -882,8 +889,8 @@ public class Gallery extends AbsSpinner implements GestureDetector.OnGestureList */ mParent.requestDisallowInterceptTouchEvent(true); - // As the user scrolls, we want to callback selection changes so related - // into on the screen is up-to-date with the user's selection + // As the user scrolls, we want to callback selection changes so related- + // info on the screen is up-to-date with the gallery's selection if (mSuppressSelectionChanged) { mSuppressSelectionChanged = false; } @@ -1062,6 +1069,11 @@ public class Gallery extends AbsSpinner implements GestureDetector.OnGestureList playSoundEffect(SoundEffectConstants.NAVIGATION_RIGHT); } return true; + + case KeyEvent.KEYCODE_DPAD_CENTER: + case KeyEvent.KEYCODE_ENTER: + mReceivedInvokeKeyDown = true; + // fallthrough to default handling } return super.onKeyDown(keyCode, event); @@ -1072,19 +1084,26 @@ public class Gallery extends AbsSpinner implements GestureDetector.OnGestureList switch (keyCode) { case KeyEvent.KEYCODE_DPAD_CENTER: case KeyEvent.KEYCODE_ENTER: { - if (mItemCount > 0) { - - dispatchPress(mSelectedChild); - postDelayed(new Runnable() { - public void run() { - dispatchUnpress(); - } - }, ViewConfiguration.getPressedStateDuration()); - - int selectedIndex = mSelectedPosition - mFirstPosition; - performItemClick(getChildAt(selectedIndex), mSelectedPosition, mAdapter - .getItemId(mSelectedPosition)); + + if (mReceivedInvokeKeyDown) { + if (mItemCount > 0) { + + dispatchPress(mSelectedChild); + postDelayed(new Runnable() { + public void run() { + dispatchUnpress(); + } + }, ViewConfiguration.getPressedStateDuration()); + + int selectedIndex = mSelectedPosition - mFirstPosition; + performItemClick(getChildAt(selectedIndex), mSelectedPosition, mAdapter + .getItemId(mSelectedPosition)); + } } + + // Clear the flag + mReceivedInvokeKeyDown = false; + return true; } } diff --git a/core/java/android/widget/GridView.java b/core/java/android/widget/GridView.java index 268bf846a7081f42a08b68871db8e06b8be6cdbf..38bfc7c17b44ba524186d9c6b7693749350bd30c 100644 --- a/core/java/android/widget/GridView.java +++ b/core/java/android/widget/GridView.java @@ -36,7 +36,8 @@ public class GridView extends AbsListView { public static final int NO_STRETCH = 0; public static final int STRETCH_SPACING = 1; public static final int STRETCH_COLUMN_WIDTH = 2; - + public static final int STRETCH_SPACING_UNIFORM = 3; + public static final int AUTO_FIT = -1; private int mNumColumns = AUTO_FIT; @@ -228,12 +229,12 @@ public class GridView extends AbsListView { } private View makeRow(int startPos, int y, boolean flow) { - int last; - int nextLeft = mListPadding.left; - final int columnWidth = mColumnWidth; final int horizontalSpacing = mHorizontalSpacing; + int last; + int nextLeft = mListPadding.left + ((mStretchMode == STRETCH_SPACING_UNIFORM) ? horizontalSpacing : 0); + if (!mStackFromBottom) { last = Math.min(startPos + mNumColumns, mItemCount); } else { @@ -878,6 +879,17 @@ public class GridView extends AbsListView { mHorizontalSpacing = requestedHorizontalSpacing + spaceLeftOver; } break; + + case STRETCH_SPACING_UNIFORM: + // Stretch the spacing between columns + mColumnWidth = requestedColumnWidth; + if (mNumColumns > 1) { + mHorizontalSpacing = requestedHorizontalSpacing + + spaceLeftOver / (mNumColumns + 1); + } else { + mHorizontalSpacing = requestedHorizontalSpacing + spaceLeftOver; + } + break; } break; @@ -1379,7 +1391,6 @@ public class GridView extends AbsListView { handled = arrowScroll(FOCUS_LEFT); break; - case KeyEvent.KEYCODE_DPAD_RIGHT: handled = arrowScroll(FOCUS_RIGHT); break; @@ -1420,7 +1431,6 @@ public class GridView extends AbsListView { } break; } - } if (!handled) { @@ -1460,6 +1470,7 @@ public class GridView extends AbsListView { if (nextPage >= 0) { setSelectionInt(nextPage); + invokeOnItemScrollListener(); return true; } @@ -1478,10 +1489,12 @@ public class GridView extends AbsListView { if (direction == FOCUS_UP) { mLayoutMode = LAYOUT_SET_SELECTION; setSelectionInt(0); + invokeOnItemScrollListener(); moved = true; } else if (direction == FOCUS_DOWN) { mLayoutMode = LAYOUT_SET_SELECTION; setSelectionInt(mItemCount - 1); + invokeOnItemScrollListener(); moved = true; } @@ -1547,6 +1560,7 @@ public class GridView extends AbsListView { if (moved) { playSoundEffect(SoundEffectConstants.getContantForFocusDirection(direction)); + invokeOnItemScrollListener(); } return moved; @@ -1684,7 +1698,7 @@ public class GridView extends AbsListView { * Control how items are stretched to fill their space. * * @param stretchMode Either {@link #NO_STRETCH}, - * {@link #STRETCH_SPACING}, or {@link #STRETCH_COLUMN_WIDTH}. + * {@link #STRETCH_SPACING}, {@link #STRETCH_SPACING_UNIFORM}, or {@link #STRETCH_COLUMN_WIDTH}. * * @attr ref android.R.styleable#GridView_stretchMode */ diff --git a/core/java/android/widget/LinearLayout.java b/core/java/android/widget/LinearLayout.java index de74fa4a2491f393a98b395c4c4ba3a5b0a40544..36ed8bd401d1ec0515390fbd1cf3b042912966e4 100644 --- a/core/java/android/widget/LinearLayout.java +++ b/core/java/android/widget/LinearLayout.java @@ -952,12 +952,13 @@ public class LinearLayout extends ViewGroup { if (majorGravity != Gravity.TOP) { switch (majorGravity) { case Gravity.BOTTOM: - childTop = mBottom - mTop - mPaddingBottom - mTotalLength; + // mTotalLength contains the padding already, we add the top + // padding to compensate + childTop = mBottom - mTop + mPaddingTop - mTotalLength; break; case Gravity.CENTER_VERTICAL: - childTop += ((mBottom - mTop - mPaddingTop - mPaddingBottom) - - mTotalLength) / 2; + childTop += ((mBottom - mTop) - mTotalLength) / 2; break; } @@ -1039,12 +1040,13 @@ public class LinearLayout extends ViewGroup { if (majorGravity != Gravity.LEFT) { switch (majorGravity) { case Gravity.RIGHT: - childLeft = mRight - mLeft - mPaddingRight - mTotalLength; + // mTotalLength contains the padding already, we add the left + // padding to compensate + childLeft = mRight - mLeft + mPaddingLeft - mTotalLength; break; case Gravity.CENTER_HORIZONTAL: - childLeft += ((mRight - mLeft - mPaddingLeft - mPaddingRight) - - mTotalLength) / 2; + childLeft += ((mRight - mLeft) - mTotalLength) / 2; break; } } diff --git a/core/java/android/widget/ListView.java b/core/java/android/widget/ListView.java index d52e51f3230107ba0b64b1ce336f7ddaef4150c4..dfc7bc38431838dd5ef26069a7b91b03a070a56d 100644 --- a/core/java/android/widget/ListView.java +++ b/core/java/android/widget/ListView.java @@ -21,6 +21,7 @@ import android.content.res.TypedArray; import android.graphics.Canvas; import android.graphics.Rect; import android.graphics.drawable.Drawable; +import android.graphics.drawable.ColorDrawable; import android.os.Parcel; import android.os.Parcelable; import android.util.AttributeSet; @@ -36,6 +37,7 @@ import android.view.ViewParent; import android.view.SoundEffectConstants; import com.google.android.collect.Lists; +import com.android.internal.R; import java.util.ArrayList; @@ -57,6 +59,8 @@ import java.util.ArrayList; * @attr ref android.R.styleable#ListView_divider * @attr ref android.R.styleable#ListView_dividerHeight * @attr ref android.R.styleable#ListView_choiceMode + * @attr ref android.R.styleable#ListView_headerDividersEnabled + * @attr ref android.R.styleable#ListView_footerDividersEnabled */ public class ListView extends AbsListView { /** @@ -92,10 +96,16 @@ public class ListView extends AbsListView { */ private static final int MIN_SCROLL_PREVIEW_PIXELS = 2; - // TODO: document - class FixedViewInfo { + /** + * A class that represents a fixed view in a list, for example a header at the top + * or a footer at the bottom. + */ + public class FixedViewInfo { + /** The view to add to the list */ public View view; + /** The data backing the view. This is returned from {@link ListAdapter#getItem(int)}. */ public Object data; + /** true if the fixed view should be selectable in the list */ public boolean isSelectable; } @@ -104,6 +114,9 @@ public class ListView extends AbsListView { Drawable mDivider; int mDividerHeight; + private boolean mClipDivider; + private boolean mHeaderDividersEnabled; + private boolean mFooterDividersEnabled; private boolean mAreAllItemsSelectable = true; @@ -137,8 +150,8 @@ public class ListView extends AbsListView { public ListView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); - TypedArray a = - context.obtainStyledAttributes(attrs, com.android.internal.R.styleable.ListView, defStyle, 0); + TypedArray a = context.obtainStyledAttributes(attrs, + com.android.internal.R.styleable.ListView, defStyle, 0); CharSequence[] entries = a.getTextArray( com.android.internal.R.styleable.ListView_entries); @@ -149,19 +162,20 @@ public class ListView extends AbsListView { final Drawable d = a.getDrawable(com.android.internal.R.styleable.ListView_divider); if (d != null) { - // If a divider is specified use its intrinsic height for divider height setDivider(d); - } else { + } - // Else use the height specified, zero being the default - final int dividerHeight = a.getDimensionPixelSize( - com.android.internal.R.styleable.ListView_dividerHeight, 0); - if (dividerHeight != 0) { - setDividerHeight(dividerHeight); - } + // Use the height specified, zero being the default + final int dividerHeight = a.getDimensionPixelSize( + com.android.internal.R.styleable.ListView_dividerHeight, 0); + if (dividerHeight != 0) { + setDividerHeight(dividerHeight); } + mHeaderDividersEnabled = a.getBoolean(R.styleable.ListView_headerDividersEnabled, true); + mFooterDividersEnabled = a.getBoolean(R.styleable.ListView_footerDividersEnabled, true); + a.recycle(); } @@ -198,8 +212,7 @@ public class ListView extends AbsListView { // We only are looking to see if we are too low, not too high delta = 0; } - } - else { + } else { // we are too high, slide all views down to align with bottom child = getChildAt(childCount - 1); delta = child.getBottom() - (getHeight() - mListPadding.bottom); @@ -1989,6 +2002,7 @@ public class ListView extends AbsListView { } setSelectionInt(position); + invokeOnItemScrollListener(); invalidate(); return true; @@ -2014,6 +2028,7 @@ public class ListView extends AbsListView { if (position >= 0) { mLayoutMode = LAYOUT_FORCE_TOP; setSelectionInt(position); + invokeOnItemScrollListener(); } moved = true; } @@ -2023,6 +2038,7 @@ public class ListView extends AbsListView { if (position >= 0) { mLayoutMode = LAYOUT_FORCE_BOTTOM; setSelectionInt(position); + invokeOnItemScrollListener(); } moved = true; } @@ -2739,36 +2755,46 @@ public class ListView extends AbsListView { bounds.right = mRight - mLeft - mPaddingRight; final int count = getChildCount(); - int i; + final int headerCount = mHeaderViewInfos.size(); + final int footerLimit = mItemCount - mFooterViewInfos.size() - 1; + final boolean headerDividers = mHeaderDividersEnabled; + final boolean footerDividers = mFooterDividersEnabled; + final int first = mFirstPosition; - if (mStackFromBottom) { - int top; - int listTop = mListPadding.top; - - for (i = 0; i < count; ++i) { - View child = getChildAt(i); - top = child.getTop(); - if (top > listTop) { - bounds.top = top - dividerHeight; - bounds.bottom = top; - // Give the method the child ABOVE the divider, so we - // subtract one from our child - // position. Give -1 when there is no child above the - // divider. - drawDivider(canvas, bounds, i - 1); + if (!mStackFromBottom) { + int bottom; + int listBottom = mBottom - mTop - mListPadding.bottom; + + for (int i = 0; i < count; i++) { + if ((headerDividers || first + i >= headerCount) && + (footerDividers || first + i < footerLimit)) { + View child = getChildAt(i); + bottom = child.getBottom(); + if (bottom < listBottom) { + bounds.top = bottom; + bounds.bottom = bottom + dividerHeight; + drawDivider(canvas, bounds, i); + } } } } else { - int bottom; - int listBottom = getHeight() - mListPadding.bottom; - - for (i = 0; i < count; ++i) { - View child = getChildAt(i); - bottom = child.getBottom(); - if (bottom < listBottom) { - bounds.top = bottom; - bounds.bottom = bottom + dividerHeight; - drawDivider(canvas, bounds, i); + int top; + int listTop = mListPadding.top; + + for (int i = 0; i < count; i++) { + if ((headerDividers || first + i >= headerCount) && + (footerDividers || first + i < footerLimit)) { + View child = getChildAt(i); + top = child.getTop(); + if (top > listTop) { + bounds.top = top - dividerHeight; + bounds.bottom = top; + // Give the method the child ABOVE the divider, so we + // subtract one from our child + // position. Give -1 when there is no child above the + // divider. + drawDivider(canvas, bounds, i - 1); + } } } } @@ -2789,8 +2815,21 @@ public class ListView extends AbsListView { */ void drawDivider(Canvas canvas, Rect bounds, int childIndex) { // This widget draws the same divider for all children - mDivider.setBounds(bounds); - mDivider.draw(canvas); + final Drawable divider = mDivider; + final boolean clipDivider = mClipDivider; + + if (!clipDivider) { + divider.setBounds(bounds); + } else { + canvas.save(); + canvas.clipRect(bounds); + } + + divider.draw(canvas); + + if (clipDivider) { + canvas.restore(); + } } /** @@ -2811,8 +2850,10 @@ public class ListView extends AbsListView { public void setDivider(Drawable divider) { if (divider != null) { mDividerHeight = divider.getIntrinsicHeight(); + mClipDivider = divider instanceof ColorDrawable; } else { mDividerHeight = 0; + mClipDivider = false; } mDivider = divider; requestLayoutIfNecessary(); @@ -2836,6 +2877,32 @@ public class ListView extends AbsListView { requestLayoutIfNecessary(); } + /** + * Enables or disables the drawing of the divider for header views. + * + * @param headerDividersEnabled True to draw the headers, false otherwise. + * + * @see #setFooterDividersEnabled(boolean) + * @see #addHeaderView(android.view.View) + */ + public void setHeaderDividersEnabled(boolean headerDividersEnabled) { + mHeaderDividersEnabled = headerDividersEnabled; + invalidate(); + } + + /** + * Enables or disables the drawing of the divider for footer views. + * + * @param footerDividersEnabled True to draw the footers, false otherwise. + * + * @see #setHeaderDividersEnabled(boolean) + * @see #addFooterView(android.view.View) + */ + public void setFooterDividersEnabled(boolean footerDividersEnabled) { + mFooterDividersEnabled = footerDividersEnabled; + invalidate(); + } + @Override protected void onFocusChanged(boolean gainFocus, int direction, Rect previouslyFocusedRect) { super.onFocusChanged(gainFocus, direction, previouslyFocusedRect); diff --git a/core/java/android/widget/MediaController.java b/core/java/android/widget/MediaController.java index ad8433f3f4ccaf64dc769aa1d7a2908ea78a46ca..6c0c164e2e59586e701b830d5a09d6a03cfc9980 100644 --- a/core/java/android/widget/MediaController.java +++ b/core/java/android/widget/MediaController.java @@ -271,6 +271,7 @@ public class MediaController extends FrameLayout { p.y = anchorpos[1] + mAnchor.getHeight() - p.height; p.format = PixelFormat.TRANSLUCENT; p.type = WindowManager.LayoutParams.TYPE_APPLICATION_PANEL; + p.flags |= WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM; p.token = null; p.windowAnimations = 0; // android.R.style.DropDownAnimationDown; mWindowManager.addView(mDecor, p); @@ -387,6 +388,7 @@ public class MediaController extends FrameLayout { int keyCode = event.getKeyCode(); if (event.getRepeatCount() == 0 && event.isDown() && ( keyCode == KeyEvent.KEYCODE_HEADSETHOOK || + keyCode == KeyEvent.KEYCODE_PLAYPAUSE || keyCode == KeyEvent.KEYCODE_SPACE)) { doPauseResume(); show(sDefaultTimeout); diff --git a/core/java/android/widget/PopupWindow.java b/core/java/android/widget/PopupWindow.java index 6a7b1fb2d1bcb76d59117c5e58331fa31f0c1744..b5c438478620b87b8ca1f5be156e3a3237ba21b1 100644 --- a/core/java/android/widget/PopupWindow.java +++ b/core/java/android/widget/PopupWindow.java @@ -22,9 +22,9 @@ import android.view.KeyEvent; import android.view.MotionEvent; import android.view.View; import android.view.WindowManager; -import android.view.WindowManagerImpl; import android.view.Gravity; import android.view.ViewGroup; +import android.view.View.OnTouchListener; import android.graphics.PixelFormat; import android.graphics.Rect; import android.graphics.drawable.Drawable; @@ -43,31 +43,58 @@ import android.util.AttributeSet; */ public class PopupWindow { /** - * The height of the status bar so we know how much of the screen we can - * actually be displayed in. - *

              - * TODO: This IS NOT the right way to do this. - * Instead of knowing how much of the screen is available, a popup that - * wants anchor and maximize space shouldn't be setting a height, instead - * the PopupViewContainer should have its layout height as fill_parent and - * properly position the popup. + * Mode for {@link #setInputMethodMode(int): the requirements for the + * input method should be based on the focusability of the popup. That is + * if it is focusable than it needs to work with the input method, else + * it doesn't. + */ + public static final int INPUT_METHOD_FROM_FOCUSABLE = 0; + + /** + * Mode for {@link #setInputMethodMode(int): this popup always needs to + * work with an input method, regardless of whether it is focusable. This + * means that it will always be displayed so that the user can also operate + * the input method while it is shown. */ - private static final int STATUS_BAR_HEIGHT = 30; + + public static final int INPUT_METHOD_NEEDED = 1; + + /** + * Mode for {@link #setInputMethodMode(int): this popup never needs to + * work with an input method, regardless of whether it is focusable. This + * means that it will always be displayed to use as much space on the + * screen as needed, regardless of whether this covers the input method. + */ + public static final int INPUT_METHOD_NOT_NEEDED = 2; + + private final Context mContext; + private final WindowManager mWindowManager; private boolean mIsShowing; + private boolean mIsDropdown; private View mContentView; private View mPopupView; private boolean mFocusable; + private int mInputMethodMode = INPUT_METHOD_FROM_FOCUSABLE; + private boolean mTouchable = true; + private boolean mOutsideTouchable = false; + private boolean mClippingEnabled = true; + private OnTouchListener mTouchInterceptor; + + private int mWidthMode; private int mWidth; + private int mHeightMode; private int mHeight; + private int mPopupWidth; + private int mPopupHeight; + private int[] mDrawingLocation = new int[2]; - private int[] mRootLocation = new int[2]; + private int[] mScreenLocation = new int[2]; private Rect mTempRect = new Rect(); - private Context mContext; private Drawable mBackground; private boolean mAboveAnchor; @@ -106,6 +133,8 @@ public class PopupWindow { */ public PopupWindow(Context context, AttributeSet attrs, int defStyle) { mContext = context; + mWindowManager = (WindowManager)context.getSystemService( + Context.WINDOW_SERVICE); TypedArray a = context.obtainStyledAttributes( @@ -183,6 +212,9 @@ public class PopupWindow { */ public PopupWindow(View contentView, int width, int height, boolean focusable) { + mContext = contentView.getContext(); + mWindowManager = (WindowManager)mContext.getSystemService( + Context.WINDOW_SERVICE); setContentView(contentView); setWidth(width); setHeight(height); @@ -218,11 +250,15 @@ public class PopupWindow { } /** - * set the flag on popup to ignore cheek press events - * This method has to be invoked before displaying the content view - * of the popup for the window flags to take effect and will be ignored - * if the pop up is already displayed. By default this flag is set to false + * Set the flag on popup to ignore cheek press eventt; by default this flag + * is set to false * which means the pop wont ignore cheek press dispatch events. + * + *

              If the popup is showing, calling this method will take effect only + * the next time the popup is shown or through a manual call to one of + * the {@link #update()} methods.

              + * + * @see #update() */ public void setIgnoreCheekPress() { mIgnoreCheekPress = true; @@ -230,9 +266,17 @@ public class PopupWindow { /** - *

              Change the animation style for this popup.

              + *

              Change the animation style resource for this popup.

              + * + *

              If the popup is showing, calling this method will take effect only + * the next time the popup is shown or through a manual call to one of + * the {@link #update()} methods.

              * - * @param animationStyle animation style to use when the popup appears and disappears + * @param animationStyle animation style to use when the popup appears + * and disappears. Set to -1 for the default animation, 0 for no + * animation, or a resource identifier for an explicit animation. + * + * @see #update() */ public void setAnimationStyle(int animationStyle) { mAnimationStyle = animationStyle; @@ -253,7 +297,8 @@ public class PopupWindow { *

              Change the popup's content. The content is represented by an instance * of {@link android.view.View}.

              * - *

              This method has no effect if called when the popup is showing.

              + *

              This method has no effect if called when the popup is showing. To + * apply it while a popup is showing, call

              * * @param contentView the new content for the popup * @@ -268,6 +313,14 @@ public class PopupWindow { mContentView = contentView; } + /** + * Set a callback for all touch events being dispatched to the popup + * window. + */ + public void setTouchInterceptor(OnTouchListener l) { + mTouchInterceptor = l; + } + /** *

              Indicate whether the popup window can grab the focus.

              * @@ -282,20 +335,168 @@ public class PopupWindow { /** *

              Changes the focusability of the popup window. When focusable, the * window will grab the focus from the current focused widget if the popup - * contains a focusable {@link android.view.View}.

              + * contains a focusable {@link android.view.View}. By default a popup + * window is not focusable.

              * *

              If the popup is showing, calling this method will take effect only - * the next time the popup is shown.

              + * the next time the popup is shown or through a manual call to one of + * the {@link #update()} methods.

              * - * @param focusable true if the popup should grab focus, false otherwise + * @param focusable true if the popup should grab focus, false otherwise. * * @see #isFocusable() * @see #isShowing() + * @see #update() */ public void setFocusable(boolean focusable) { mFocusable = focusable; } + /** + * Return the current value in {@link #setInputMethodMode(int)}. + * + * @see #setInputMethodMode(int) + */ + public int getInputMethodMode() { + return mInputMethodMode; + + } + + /** + * Control how the popup operates with an input method: one of + * {@link #INPUT_METHOD_FROM_FOCUSABLE}, {@link #INPUT_METHOD_NEEDED}, + * or {@link #INPUT_METHOD_NOT_NEEDED}. + * + *

              If the popup is showing, calling this method will take effect only + * the next time the popup is shown or through a manual call to one of + * the {@link #update()} methods.

              + * + * @see #getInputMethodMode() + * @see #update() + */ + public void setInputMethodMode(int mode) { + mInputMethodMode = mode; + } + + /** + *

              Indicates whether the popup window receives touch events.

              + * + * @return true if the popup is touchable, false otherwise + * + * @see #setTouchable(boolean) + */ + public boolean isTouchable() { + return mTouchable; + } + + /** + *

              Changes the touchability of the popup window. When touchable, the + * window will receive touch events, otherwise touch events will go to the + * window below it. By default the window is touchable.

              + * + *

              If the popup is showing, calling this method will take effect only + * the next time the popup is shown or through a manual call to one of + * the {@link #update()} methods.

              + * + * @param touchable true if the popup should receive touch events, false otherwise + * + * @see #isTouchable() + * @see #isShowing() + * @see #update() + */ + public void setTouchable(boolean touchable) { + mTouchable = touchable; + } + + /** + *

              Indicates whether the popup window will be informed of touch events + * outside of its window.

              + * + * @return true if the popup is outside touchable, false otherwise + * + * @see #setOutsideTouchable(boolean) + */ + public boolean isOutsideTouchable() { + return mOutsideTouchable; + } + + /** + *

              Controls whether the pop-up will be informed of touch events outside + * of its window. This only makes sense for pop-ups that are touchable + * but not focusable, which means touches outside of the window will + * be delivered to the window behind. The default is false.

              + * + *

              If the popup is showing, calling this method will take effect only + * the next time the popup is shown or through a manual call to one of + * the {@link #update()} methods.

              + * + * @param touchable true if the popup should receive outside + * touch events, false otherwise + * + * @see #isOutsideTouchable() + * @see #isShowing() + * @see #update() + */ + public void setOutsideTouchable(boolean touchable) { + mOutsideTouchable = touchable; + } + + /** + *

              Indicates whether clipping of the popup window is enabled.

              + * + * @return true if the clipping is enabled, false otherwise + * + * @see #setClippingEnabled(boolean) + */ + public boolean isClippingEnabled() { + return mClippingEnabled; + } + + /** + *

              Allows the popup window to extend beyond the bounds of the screen. By default the + * window is clipped to the screen boundaries. Setting this to false will allow windows to be + * accurately positioned.

              + * + *

              If the popup is showing, calling this method will take effect only + * the next time the popup is shown or through a manual call to one of + * the {@link #update()} methods.

              + * + * @param enabled false if the window should be allowed to extend outside of the screen + * @see #isShowing() + * @see #isClippingEnabled() + * @see #update() + */ + public void setClippingEnabled(boolean enabled) { + mClippingEnabled = enabled; + } + + /** + *

              Change the width and height measure specs that are given to the + * window manager by the popup. By default these are 0, meaning that + * the current width or height is requested as an explicit size from + * the window manager. You can supply + * {@link ViewGroup.LayoutParams#WRAP_CONTENT} or + * {@link ViewGroup.LayoutParams#FILL_PARENT} to have that measure + * spec supplied instead, replacing the absolute width and height that + * has been set in the popup.

              + * + *

              If the popup is showing, calling this method will take effect only + * the next time the popup is shown.

              + * + * @param widthSpec an explicit width measure spec mode, either + * {@link ViewGroup.LayoutParams#WRAP_CONTENT}, + * {@link ViewGroup.LayoutParams#FILL_PARENT}, or 0 to use the absolute + * width. + * @param heightSpec an explicit height measure spec mode, either + * {@link ViewGroup.LayoutParams#WRAP_CONTENT}, + * {@link ViewGroup.LayoutParams#FILL_PARENT}, or 0 to use the absolute + * height. + */ + public void setWindowLayoutMode(int widthSpec, int heightSpec) { + mWidthMode = widthSpec; + mHeightMode = heightSpec; + } + /** *

              Return this popup's height MeasureSpec

              * @@ -377,11 +578,10 @@ public class PopupWindow { } mIsShowing = true; + mIsDropdown = false; WindowManager.LayoutParams p = createPopupLayout(parent.getWindowToken()); - if (mAnimationStyle != -1) { - p.windowAnimations = mAnimationStyle; - } + p.windowAnimations = computeAnimationResource(); preparePopup(p); if (gravity == Gravity.NO_GRAVITY) { @@ -426,6 +626,7 @@ public class PopupWindow { } mIsShowing = true; + mIsDropdown = true; WindowManager.LayoutParams p = createPopupLayout(anchor.getWindowToken()); preparePopup(p); @@ -433,13 +634,9 @@ public class PopupWindow { mPopupView.refreshDrawableState(); } mAboveAnchor = findDropDownPosition(anchor, p, xoff, yoff); - if (mAnimationStyle == -1) { - p.windowAnimations = mAboveAnchor - ? com.android.internal.R.style.Animation_DropDownUp - : com.android.internal.R.style.Animation_DropDownDown; - } else { - p.windowAnimations = mAnimationStyle; - } + if (mHeightMode < 0) p.height = mHeightMode; + if (mWidthMode < 0) p.width = mWidthMode; + p.windowAnimations = computeAnimationResource(); invokePopup(p); } @@ -479,7 +676,8 @@ public class PopupWindow { } else { mPopupView = mContentView; } - + mPopupWidth = p.width; + mPopupHeight = p.height; } /** @@ -491,8 +689,7 @@ public class PopupWindow { * @param p the layout parameters of the popup's content view */ private void invokePopup(WindowManager.LayoutParams p) { - WindowManagerImpl wm = WindowManagerImpl.getDefault(); - wm.addView(mPopupView, p); + mWindowManager.addView(mPopupView, p); } /** @@ -518,18 +715,56 @@ public class PopupWindow { } else { p.format = PixelFormat.TRANSLUCENT; } - if(mIgnoreCheekPress) { - p.flags |= WindowManager.LayoutParams.FLAG_IGNORE_CHEEK_PRESSES; - } - if (!mFocusable) { - p.flags |= WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE; - } + p.flags = computeFlags(p.flags); p.type = WindowManager.LayoutParams.TYPE_APPLICATION_PANEL; p.token = token; return p; } + private int computeFlags(int curFlags) { + curFlags &= ~( + WindowManager.LayoutParams.FLAG_IGNORE_CHEEK_PRESSES | + WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | + WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE | + WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH | + WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS | + WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM); + if(mIgnoreCheekPress) { + curFlags |= WindowManager.LayoutParams.FLAG_IGNORE_CHEEK_PRESSES; + } + if (!mFocusable) { + curFlags |= WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE; + if (mInputMethodMode == INPUT_METHOD_NEEDED) { + curFlags |= WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM; + } + } else if (mInputMethodMode == INPUT_METHOD_NOT_NEEDED) { + curFlags |= WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM; + } + if (!mTouchable) { + curFlags |= WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE; + } + if (mTouchable) { + curFlags |= WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH; + } + if (!mClippingEnabled) { + curFlags |= WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS; + } + return curFlags; + } + + private int computeAnimationResource() { + if (mAnimationStyle == -1) { + if (mIsDropdown) { + return mAboveAnchor + ? com.android.internal.R.style.Animation_DropDownUp + : com.android.internal.R.style.Animation_DropDownDown; + } + return 0; + } + return mAnimationStyle; + } + /** *

              Positions the popup window on screen. When the popup window is too * tall to fit under the anchor, a parent scroll view is seeked and scrolled @@ -548,33 +783,48 @@ public class PopupWindow { anchor.getLocationInWindow(mDrawingLocation); p.x = mDrawingLocation[0] + xoff; p.y = mDrawingLocation[1] + anchor.getMeasuredHeight() + yoff; - + boolean onTop = false; - if (p.y + p.height > WindowManagerImpl.getDefault().getDefaultDisplay().getHeight()) { + p.gravity = Gravity.LEFT | Gravity.TOP; + + anchor.getLocationOnScreen(mScreenLocation); + final Rect displayFrame = new Rect(); + anchor.getWindowVisibleDisplayFrame(displayFrame); + + final View root = anchor.getRootView(); + if (mScreenLocation[1] + anchor.getMeasuredHeight() + yoff + mPopupHeight > displayFrame.bottom + || p.x + mPopupWidth - root.getWidth() > 0) { // if the drop down disappears at the bottom of the screen. we try to // scroll a parent scrollview or move the drop down back up on top of // the edit box - View root = anchor.getRootView(); - root.getLocationInWindow(mRootLocation); - int delta = p.y + p.height - mRootLocation[1] - root.getHeight(); - - if (delta > 0 || p.x + p.width - mRootLocation[0] - root.getWidth() > 0) { - Rect r = new Rect(anchor.getScrollX(), anchor.getScrollY(), - p.width, p.height + anchor.getMeasuredHeight()); - - onTop = !anchor.requestRectangleOnScreen(r, true); - - if (onTop) { - p.y -= anchor.getMeasuredHeight() + p.height; - } else { - anchor.getLocationOnScreen(mDrawingLocation); - p.x = mDrawingLocation[0] + xoff; - p.y = mDrawingLocation[1] + anchor.getMeasuredHeight() + yoff; - } + int scrollX = anchor.getScrollX(); + int scrollY = anchor.getScrollY(); + Rect r = new Rect(scrollX, scrollY, scrollX + mPopupWidth, + scrollY + mPopupHeight + anchor.getMeasuredHeight()); + anchor.requestRectangleOnScreen(r, true); + + // now we re-evaluate the space available, and decide from that + // whether the pop-up will go above or below the anchor. + anchor.getLocationInWindow(mDrawingLocation); + p.x = mDrawingLocation[0] + xoff; + p.y = mDrawingLocation[1] + anchor.getMeasuredHeight() + yoff; + + // determine whether there is more space above or below the anchor + anchor.getLocationOnScreen(mScreenLocation); + + onTop = (displayFrame.bottom - mScreenLocation[1] - anchor.getMeasuredHeight() - yoff) + < (mScreenLocation[1] - yoff - displayFrame.top); + if (onTop) { + p.gravity = Gravity.LEFT | Gravity.BOTTOM; + p.y = root.getHeight() - mDrawingLocation[1] - yoff; + } else { + p.y = mDrawingLocation[1] + anchor.getMeasuredHeight() + yoff; } } + p.gravity |= Gravity.DISPLAY_CLIP_VERTICAL; + return onTop; } @@ -589,18 +839,18 @@ public class PopupWindow { * shown. */ public int getMaxAvailableHeight(View anchor) { - // TODO: read comment on STATUS_BAR_HEIGHT - final int screenHeight = WindowManagerImpl.getDefault().getDefaultDisplay().getHeight() - - STATUS_BAR_HEIGHT; + final Rect displayFrame = new Rect(); + anchor.getWindowVisibleDisplayFrame(displayFrame); final int[] anchorPos = mDrawingLocation; anchor.getLocationOnScreen(anchorPos); - anchorPos[1] -= STATUS_BAR_HEIGHT; - - final int distanceFromAnchorToBottom = screenHeight - (anchorPos[1] + anchor.getHeight()); + final int distanceToBottom = displayFrame.bottom + - (anchorPos[1] + anchor.getHeight()); + final int distanceToTop = anchorPos[1] - displayFrame.top; + // anchorPos[1] is distance from anchor to top of screen - int returnedHeight = Math.max(anchorPos[1], distanceFromAnchorToBottom); + int returnedHeight = Math.max(distanceToBottom, distanceToTop); if (mBackground != null) { mBackground.getPadding(mTempRect); returnedHeight -= mTempRect.top + mTempRect.bottom; @@ -618,11 +868,11 @@ public class PopupWindow { */ public void dismiss() { if (isShowing() && mPopupView != null) { - WindowManagerImpl wm = WindowManagerImpl.getDefault(); - wm.removeView(mPopupView); + mWindowManager.removeView(mPopupView); if (mPopupView != mContentView && mPopupView instanceof ViewGroup) { ((ViewGroup) mPopupView).removeView(mContentView); } + mPopupView = null; mIsShowing = false; if (mOnDismissListener != null) { @@ -640,9 +890,45 @@ public class PopupWindow { mOnDismissListener = onDismissListener; } + /** + * Updates the state of the popup window, if it is currently being displayed, + * from the currently set state. This include: + * {@link #setClippingEnabled(boolean)}, {@link #setFocusable(boolean)}, + * {@link #setIgnoreCheekPress()}, {@link #setInputMethodMode(int)}, + * {@link #setTouchable(boolean)}, and {@link #setAnimationStyle(int)}. + */ + public void update() { + if (!isShowing() || mContentView == null) { + return; + } + + WindowManager.LayoutParams p = (WindowManager.LayoutParams) + mPopupView.getLayoutParams(); + + boolean update = false; + + final int newAnim = computeAnimationResource(); + if (newAnim != p.windowAnimations) { + p.windowAnimations = newAnim; + update = true; + } + + final int newFlags = computeFlags(p.flags); + if (newFlags != p.flags) { + p.flags = newFlags; + update = true; + } + + if (update) { + mWindowManager.updateViewLayout(mPopupView, p); + } + } + /** *

              Updates the position and the dimension of the popup window. Width and - * height can be set to -1 to update location only.

              + * height can be set to -1 to update location only. Calling this function + * also updates the window with the current popup state as + * described for {@link #update()}.

              * * @param x the new x location * @param y the new y location @@ -667,13 +953,15 @@ public class PopupWindow { boolean update = false; - if (width != -1 && p.width != width) { - p.width = width; + final int finalWidth = mWidthMode < 0 ? mWidthMode : p.width; + if (width != -1 && p.width != finalWidth) { + p.width = finalWidth; update = true; } - if (height != -1 && p.height != height) { - p.height = height; + final int finalHeight = mHeightMode < 0 ? mHeightMode : p.height; + if (height != -1 && p.height != finalHeight) { + p.height = finalHeight; update = true; } @@ -687,6 +975,18 @@ public class PopupWindow { update = true; } + final int newAnim = computeAnimationResource(); + if (newAnim != p.windowAnimations) { + p.windowAnimations = newAnim; + update = true; + } + + final int newFlags = computeFlags(p.flags); + if (newFlags != p.flags) { + p.flags = newFlags; + update = true; + } + if (update) { if (mPopupView != mContentView) { final View popupViewContainer = mPopupView; @@ -704,14 +1004,15 @@ public class PopupWindow { } } - WindowManagerImpl wm = WindowManagerImpl.getDefault(); - wm.updateViewLayout(mPopupView, p); + mWindowManager.updateViewLayout(mPopupView, p); } } /** *

              Updates the position and the dimension of the popup window. Width and - * height can be set to -1 to update location only.

              + * height can be set to -1 to update location only. Calling this function + * also updates the window with the current popup state as + * described for {@link #update()}.

              * * @param anchor the popup's anchor view * @param width the new width, can be -1 to ignore @@ -723,7 +1024,9 @@ public class PopupWindow { /** *

              Updates the position and the dimension of the popup window. Width and - * height can be set to -1 to update location only.

              + * height can be set to -1 to update location only. Calling this function + * also updates the window with the current popup state as + * described for {@link #update()}.

              * * @param anchor the popup's anchor view * @param xoff x offset from the view's left edge @@ -739,17 +1042,25 @@ public class PopupWindow { WindowManager.LayoutParams p = (WindowManager.LayoutParams) mPopupView.getLayoutParams(); - int x = p.x; - int y = p.y; + if (width == -1) { + width = mPopupWidth; + } else { + mPopupWidth = width; + } + if (height == -1) { + height = mPopupHeight; + } else { + mPopupHeight = height; + } + findDropDownPosition(anchor, p, xoff, yoff); - - update(x, y, width, height); + update(p.x, p.y, width, height); } /** * Listener that is called when this popup window is dismissed. */ - interface OnDismissListener { + public interface OnDismissListener { /** * Called when this popup window is dismissed. */ @@ -784,6 +1095,14 @@ public class PopupWindow { } } + @Override + public boolean dispatchTouchEvent(MotionEvent ev) { + if (mTouchInterceptor != null && mTouchInterceptor.onTouch(this, ev)) { + return true; + } + return super.dispatchTouchEvent(ev); + } + @Override public boolean onTouchEvent(MotionEvent event) { final int x = (int) event.getX(); @@ -793,6 +1112,9 @@ public class PopupWindow { && ((x < 0) || (x >= getWidth()) || (y < 0) || (y >= getHeight()))) { dismiss(); return true; + } else if (event.getAction() == MotionEvent.ACTION_OUTSIDE) { + dismiss(); + return true; } else { return super.onTouchEvent(event); } diff --git a/core/java/android/widget/ProgressBar.java b/core/java/android/widget/ProgressBar.java index c1de010637830f68c7e33cba92f871cade846866..abba6d02e9e36cd1fff13be363b6d0ba05d62b71 100644 --- a/core/java/android/widget/ProgressBar.java +++ b/core/java/android/widget/ProgressBar.java @@ -22,6 +22,7 @@ import android.graphics.Bitmap; import android.graphics.BitmapShader; import android.graphics.Canvas; import android.graphics.Shader; +import android.graphics.Rect; import android.graphics.drawable.AnimationDrawable; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.ClipDrawable; @@ -40,6 +41,8 @@ import android.view.animation.Interpolator; import android.view.animation.LinearInterpolator; import android.view.animation.Transformation; import android.widget.RemoteViews.RemoteView; +import android.os.Parcel; +import android.os.Parcelable; import android.os.SystemClock; import com.android.internal.R; @@ -427,7 +430,7 @@ public class ProgressBar extends View { Drawable getCurrentDrawable() { return mCurrentDrawable; } - + @Override protected boolean verifyDrawable(Drawable who) { return who == mProgressDrawable || who == mIndeterminateDrawable @@ -700,7 +703,7 @@ public class ProgressBar extends View { mAnimation = null; mTransformation = null; if (mIndeterminateDrawable instanceof AnimationDrawable) { - ((AnimationDrawable)mIndeterminateDrawable).stop(); + ((AnimationDrawable) mIndeterminateDrawable).stop(); mShouldStartAnimationDrawable = false; } } @@ -754,17 +757,31 @@ public class ProgressBar extends View { @Override public void invalidateDrawable(Drawable dr) { if (!mInDrawing) { - super.invalidateDrawable(dr); + if (dr == mProgressDrawable || dr == mIndeterminateDrawable) { + final Rect dirty = dr.getBounds(); + final int scrollX = mScrollX + mPaddingLeft; + final int scrollY = mScrollY + mPaddingRight; + + invalidate(dirty.left + scrollX, dirty.top + scrollY, + dirty.right + scrollX, dirty.bottom + scrollY); + } else { + super.invalidateDrawable(dr); + } } } @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { - Drawable d = mCurrentDrawable; - if (d != null) { - // onDraw will translate the canvas so we draw starting at 0,0 - d.setBounds(0, 0, w - mPaddingRight - mPaddingLeft, - h - mPaddingBottom - mPaddingTop); + // onDraw will translate the canvas so we draw starting at 0,0 + int right = w - mPaddingRight - mPaddingLeft; + int bottom = h - mPaddingBottom - mPaddingTop; + + if (mIndeterminateDrawable != null) { + mIndeterminateDrawable.setBounds(0, 0, right, bottom); + } + + if (mProgressDrawable != null) { + mProgressDrawable.setBounds(0, 0, right, bottom); } } @@ -795,8 +812,9 @@ public class ProgressBar extends View { } d.draw(canvas); canvas.restore(); - if (mShouldStartAnimationDrawable && mCurrentDrawable instanceof AnimationDrawable) { - ((AnimationDrawable)mCurrentDrawable).start(); + if (mShouldStartAnimationDrawable && d instanceof AnimationDrawable) { + ((AnimationDrawable) d).start(); + mShouldStartAnimationDrawable = false; } } } @@ -817,4 +835,64 @@ public class ProgressBar extends View { setMeasuredDimension(resolveSize(dw, widthMeasureSpec), resolveSize(dh, heightMeasureSpec)); } + + static class SavedState extends BaseSavedState { + int progress; + int secondaryProgress; + + /** + * Constructor called from {@link ProgressBar#onSaveInstanceState()} + */ + SavedState(Parcelable superState) { + super(superState); + } + + /** + * Constructor called from {@link #CREATOR} + */ + private SavedState(Parcel in) { + super(in); + progress = in.readInt(); + secondaryProgress = in.readInt(); + } + + @Override + public void writeToParcel(Parcel out, int flags) { + super.writeToParcel(out, flags); + out.writeInt(progress); + out.writeInt(secondaryProgress); + } + + public static final Parcelable.Creator CREATOR + = new Parcelable.Creator() { + public SavedState createFromParcel(Parcel in) { + return new SavedState(in); + } + + public SavedState[] newArray(int size) { + return new SavedState[size]; + } + }; + } + + @Override + public Parcelable onSaveInstanceState() { + // Force our ancestor class to save its state + Parcelable superState = super.onSaveInstanceState(); + SavedState ss = new SavedState(superState); + + ss.progress = mProgress; + ss.secondaryProgress = mSecondaryProgress; + + return ss; + } + + @Override + public void onRestoreInstanceState(Parcelable state) { + SavedState ss = (SavedState) state; + super.onRestoreInstanceState(ss.getSuperState()); + + setProgress(ss.progress); + setSecondaryProgress(ss.secondaryProgress); + } } diff --git a/core/java/android/widget/ScrollBarDrawable.java b/core/java/android/widget/ScrollBarDrawable.java index 5df2b6d1e025e07780415f8bc70db03c43b84b96..17f912822e46a99b1d038e1d60c476f33f3db30e 100644 --- a/core/java/android/widget/ScrollBarDrawable.java +++ b/core/java/android/widget/ScrollBarDrawable.java @@ -111,7 +111,10 @@ public class ScrollBarDrawable extends Drawable { } Rect r = getBounds(); - + if (canvas.quickReject(r.left, r.top, r.right, r.bottom, + Canvas.EdgeType.AA)) { + return; + } if (drawTrack) { drawTrack(canvas, r, vertical); } diff --git a/core/java/android/widget/ScrollView.java b/core/java/android/widget/ScrollView.java index 23a27acb367ecedab78da4a4e604c6c085e180cb..a2133b29c6d2d3df2a7a3b291cadf1cf05bc60cf 100644 --- a/core/java/android/widget/ScrollView.java +++ b/core/java/android/widget/ScrollView.java @@ -20,6 +20,8 @@ import android.content.Context; import android.content.res.TypedArray; import android.graphics.Rect; import android.util.AttributeSet; +import android.util.Config; +import android.util.Log; import android.view.FocusFinder; import android.view.KeyEvent; import android.view.MotionEvent; @@ -57,6 +59,9 @@ import java.util.List; *

              ScrollView only supports vertical scrolling. */ public class ScrollView extends FrameLayout { + static final String TAG = "ScrollView"; + static final boolean localLOGV = false || Config.LOGV; + private static final int ANIMATED_SCROLL_GAP = 250; /** @@ -194,6 +199,7 @@ public class ScrollView extends FrameLayout { setFocusable(true); setDescendantFocusability(FOCUS_AFTER_DESCENDANTS); setWillNotDraw(false); + setScrollContainer(true); } @Override @@ -839,12 +845,16 @@ public class ScrollView extends FrameLayout { public final void smoothScrollBy(int dx, int dy) { long duration = AnimationUtils.currentAnimationTimeMillis() - mLastScroll; if (duration > ANIMATED_SCROLL_GAP) { + if (localLOGV) Log.v(TAG, "Smooth scroll: mScrollY=" + mScrollY + + " dy=" + dy); mScroller.startScroll(mScrollX, mScrollY, dx, dy); invalidate(); } else { if (!mScroller.isFinished()) { mScroller.abortAnimation(); } + if (localLOGV) Log.v(TAG, "Immediate scroll: mScrollY=" + mScrollY + + " dy=" + dy); scrollBy(dx, dy); } mLastScroll = AnimationUtils.currentAnimationTimeMillis(); @@ -927,14 +937,19 @@ public class ScrollView extends FrameLayout { View child = getChildAt(0); mScrollX = clamp(x, this.getWidth(), child.getWidth()); mScrollY = clamp(y, this.getHeight(), child.getHeight()); + if (localLOGV) Log.v(TAG, "mScrollY=" + mScrollY + " y=" + y + + " height=" + this.getHeight() + + " child height=" + child.getHeight()); } else { mScrollX = x; mScrollY = y; } if (oldX != mScrollX || oldY != mScrollY) { onScrollChanged(mScrollX, mScrollY, oldX, oldY); - postInvalidate(); // So we draw again } + + // Keep on drawing until the animation has finished. + postInvalidate(); } } @@ -1005,6 +1020,9 @@ public class ScrollView extends FrameLayout { int scrollYDelta = 0; + if (localLOGV) Log.v(TAG, "child=" + rect.toShortString() + + " screenTop=" + screenTop + " screenBottom=" + screenBottom + + " height=" + height); if (rect.bottom > screenBottom && rect.top > screenTop) { // need to move down to get it in view: move down just enough so // that the entire rectangle is in view (or at least the first @@ -1021,6 +1039,8 @@ public class ScrollView extends FrameLayout { // make sure we aren't scrolling beyond the end of our content int bottom = getChildAt(getChildCount() - 1).getBottom(); int distanceToBottom = bottom - screenBottom; + if (localLOGV) Log.v(TAG, "scrollYDelta=" + scrollYDelta + + " distanceToBottom=" + distanceToBottom); scrollYDelta = Math.min(scrollYDelta, distanceToBottom); } else if (rect.top < screenTop && rect.bottom < screenBottom) { @@ -1098,8 +1118,7 @@ public class ScrollView extends FrameLayout { rectangle.offset(child.getLeft() - child.getScrollX(), child.getTop() - child.getScrollY()); - // note: until bug 1137695 is fixed, disable smooth scrolling for this api - return scrollToChildRect(rectangle, true);//immediate); + return scrollToChildRect(rectangle, immediate); } @Override @@ -1122,6 +1141,24 @@ public class ScrollView extends FrameLayout { scrollTo(mScrollX, mScrollY); } + @Override + protected void onSizeChanged(int w, int h, int oldw, int oldh) { + super.onSizeChanged(w, h, oldw, oldh); + + View currentFocused = findFocus(); + if (null == currentFocused || this == currentFocused) + return; + + final int maxJump = mBottom - mTop; + + if (isWithinDeltaOfScreen(currentFocused, maxJump)) { + currentFocused.getDrawingRect(mTempRect); + offsetDescendantRectToMyCoords(currentFocused, mTempRect); + int scrollDelta = computeScrollDeltaToGetChildRectOnScreen(mTempRect); + doScrollY(scrollDelta); + } + } + /** * Return true if child is an descendant of parent, (or equal to the parent). */ diff --git a/core/java/android/widget/SectionIndexer.java b/core/java/android/widget/SectionIndexer.java new file mode 100644 index 0000000000000000000000000000000000000000..24f894cbe0adaa7243587b7611f92158c5539ec2 --- /dev/null +++ b/core/java/android/widget/SectionIndexer.java @@ -0,0 +1,52 @@ +/* + * 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 android.widget; + +/** + * Interface that should be implemented on Adapters to enable fast scrolling + * in an {@link AbsListView} between sections of the list. A section is a group of list items + * to jump to that have something in common. For example, they may begin with the + * same letter or they may be songs from the same artist. + */ +public interface SectionIndexer { + /** + * This provides the list view with an array of section objects. In the simplest + * case these are Strings, each containing one letter of the alphabet. + * They could be more complex objects that indicate the grouping for the adapter's + * consumption. The list view will call toString() on the objects to get the + * preview letter to display while scrolling. + * @return the array of objects that indicate the different sections of the list. + */ + Object[] getSections(); + + /** + * Provides the starting index in the list for a given section. + * @param section the index of the section to jump to. + * @return the starting position of that section. If the section is out of bounds, the + * position must be clipped to fall within the size of the list. + */ + int getPositionForSection(int section); + + /** + * This is a reverse mapping to fetch the section index for a given position + * in the list. + * @param position the position for which to return the section + * @return the section index. If the position is out of bounds, the section index + * must be clipped to fall within the size of the section array. + */ + int getSectionForPosition(int position); +} diff --git a/core/java/android/widget/SimpleAdapter.java b/core/java/android/widget/SimpleAdapter.java index df52b6983b9d9645a607173dc21fb5e344733911..261da9ff46a8a4ce97e8746dec9c01ffadc4d6e5 100644 --- a/core/java/android/widget/SimpleAdapter.java +++ b/core/java/android/widget/SimpleAdapter.java @@ -115,10 +115,22 @@ public class SimpleAdapter extends BaseAdapter implements Filterable { View v; if (convertView == null) { v = mInflater.inflate(resource, parent, false); + + final int[] to = mTo; + final int count = to.length; + final View[] holder = new View[count]; + + for (int i = 0; i < count; i++) { + holder[i] = v.findViewById(to[i]); + } + + v.setTag(holder); } else { v = convertView; } + bindView(position, v); + return v; } @@ -143,12 +155,14 @@ public class SimpleAdapter extends BaseAdapter implements Filterable { return; } + final ViewBinder binder = mViewBinder; + final View[] holder = (View[]) view.getTag(); final String[] from = mFrom; final int[] to = mTo; - final int len = to.length; + final int count = to.length; - for (int i = 0; i < len; i++) { - final View v = view.findViewById(to[i]); + for (int i = 0; i < count; i++) { + final View v = holder[i]; if (v != null) { final Object data = dataSet.get(from[i]); String text = data == null ? "" : data.toString(); @@ -157,8 +171,8 @@ public class SimpleAdapter extends BaseAdapter implements Filterable { } boolean bound = false; - if (mViewBinder != null) { - bound = mViewBinder.setViewValue(v, data, text); + if (binder != null) { + bound = binder.setViewValue(v, data, text); } if (!bound) { diff --git a/core/java/android/widget/SimpleCursorAdapter.java b/core/java/android/widget/SimpleCursorAdapter.java index 4d2fab3512d5007a64c15cc8e48512822633ef2d..74a996405d1eb0c5c6b8c95014c845fdc225f3ac 100644 --- a/core/java/android/widget/SimpleCursorAdapter.java +++ b/core/java/android/widget/SimpleCursorAdapter.java @@ -20,6 +20,7 @@ import android.content.Context; import android.database.Cursor; import android.net.Uri; import android.view.View; +import android.view.ViewGroup; /** * An easy adapter to map columns from a cursor to TextViews or ImageViews @@ -79,14 +80,36 @@ public class SimpleCursorAdapter extends ResourceCursorAdapter { * are given the values of the first N columns in the from * parameter. */ - public SimpleCursorAdapter(Context context, int layout, Cursor c, - String[] from, int[] to) { + public SimpleCursorAdapter(Context context, int layout, Cursor c, String[] from, int[] to) { super(context, layout, c); mTo = to; mOriginalFrom = from; findColumns(from); } - + + @Override + public View newView(Context context, Cursor cursor, ViewGroup parent) { + return generateViewHolder(super.newView(context, cursor, parent)); + } + + @Override + public View newDropDownView(Context context, Cursor cursor, ViewGroup parent) { + return generateViewHolder(super.newDropDownView(context, cursor, parent)); + } + + private View generateViewHolder(View v) { + final int[] to = mTo; + final int count = to.length; + final View[] holder = new View[count]; + + for (int i = 0; i < count; i++) { + holder[i] = v.findViewById(to[i]); + } + v.setTag(holder); + + return v; + } + /** * Binds all of the field names passed into the "to" parameter of the * constructor with their corresponding cursor columns as specified in the @@ -113,17 +136,22 @@ public class SimpleCursorAdapter extends ResourceCursorAdapter { */ @Override public void bindView(View view, Context context, Cursor cursor) { - for (int i = 0; i < mTo.length; i++) { - final View v = view.findViewById(mTo[i]); + final View[] holder = (View[]) view.getTag(); + final ViewBinder binder = mViewBinder; + final int count = mTo.length; + final int[] from = mFrom; + + for (int i = 0; i < count; i++) { + final View v = holder[i]; if (v != null) { - String text = cursor.getString(mFrom[i]); + String text = cursor.getString(from[i]); if (text == null) { text = ""; } boolean bound = false; - if (mViewBinder != null) { - bound = mViewBinder.setViewValue(v, cursor, mFrom[i]); + if (binder != null) { + bound = binder.setViewValue(v, cursor, from[i]); } if (!bound) { diff --git a/core/java/android/widget/TableLayout.java b/core/java/android/widget/TableLayout.java index d72ffb1e3ab57d0e94a8270c2dcaa9f2512396c7..afa2f3b2faeea02b90e036dd5e2d3486883a7a68 100644 --- a/core/java/android/widget/TableLayout.java +++ b/core/java/android/widget/TableLayout.java @@ -101,11 +101,9 @@ public class TableLayout extends LinearLayout { public TableLayout(Context context, AttributeSet attrs) { super(context, attrs); - TypedArray a = - context.obtainStyledAttributes(attrs, R.styleable.TableLayout); + TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.TableLayout); - String stretchedColumns = - a.getString(R.styleable.TableLayout_stretchColumns); + String stretchedColumns = a.getString(R.styleable.TableLayout_stretchColumns); if (stretchedColumns != null) { if (stretchedColumns.charAt(0) == '*') { mStretchAllColumns = true; @@ -114,8 +112,7 @@ public class TableLayout extends LinearLayout { } } - String shrinkedColumns = - a.getString(R.styleable.TableLayout_shrinkColumns); + String shrinkedColumns = a.getString(R.styleable.TableLayout_shrinkColumns); if (shrinkedColumns != null) { if (shrinkedColumns.charAt(0) == '*') { mShrinkAllColumns = true; @@ -124,8 +121,7 @@ public class TableLayout extends LinearLayout { } } - String collapsedColumns = - a.getString(R.styleable.TableLayout_collapseColumns); + String collapsedColumns = a.getString(R.styleable.TableLayout_collapseColumns); if (collapsedColumns != null) { mCollapsedColumns = parseColumns(collapsedColumns); } @@ -356,7 +352,7 @@ public class TableLayout extends LinearLayout { * @return true if the column is shrinkable, false otherwise. Default is false. */ public boolean isColumnShrinkable(int columnIndex) { - return mShrinkAllColumns || mStretchableColumns.get(columnIndex); + return mShrinkAllColumns || mShrinkableColumns.get(columnIndex); } /** diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java index bd5db334d657080a6a3559a1a42bd4fa9272f306..9e5f0195c8c9b93458bdb62238e6cfa6169151cb 100644 --- a/core/java/android/widget/TextView.java +++ b/core/java/android/widget/TextView.java @@ -20,6 +20,7 @@ import android.content.Context; import android.content.res.ColorStateList; import android.content.res.Resources; import android.content.res.TypedArray; +import android.content.res.XmlResourceParser; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.Path; @@ -27,10 +28,12 @@ import android.graphics.Rect; import android.graphics.RectF; import android.graphics.Typeface; import android.graphics.drawable.Drawable; +import android.os.Bundle; import android.os.Handler; import android.os.Parcel; import android.os.Parcelable; import android.os.SystemClock; +import android.os.Message; import android.text.BoringLayout; import android.text.DynamicLayout; import android.text.Editable; @@ -49,12 +52,16 @@ import android.text.StaticLayout; import android.text.TextPaint; import android.text.TextUtils; import android.text.TextWatcher; +import android.text.method.DateKeyListener; +import android.text.method.DateTimeKeyListener; import android.text.method.DialerKeyListener; import android.text.method.DigitsKeyListener; import android.text.method.KeyListener; import android.text.method.LinkMovementMethod; import android.text.method.MetaKeyKeyListener; import android.text.method.MovementMethod; +import android.text.method.TimeKeyListener; + import android.text.method.PasswordTransformationMethod; import android.text.method.SingleLineTransformationMethod; import android.text.method.TextKeyListener; @@ -78,12 +85,22 @@ import android.view.ViewDebug; import android.view.ViewTreeObserver; import android.view.ViewGroup.LayoutParams; import android.view.animation.AnimationUtils; +import android.view.inputmethod.CompletionInfo; +import android.view.inputmethod.ExtractedText; +import android.view.inputmethod.ExtractedTextRequest; +import android.view.inputmethod.InputConnection; +import android.view.inputmethod.InputMethodManager; +import android.view.inputmethod.EditorInfo; import android.widget.RemoteViews.RemoteView; +import java.io.IOException; import java.lang.ref.WeakReference; import java.util.ArrayList; import com.android.internal.util.FastMath; +import com.android.internal.widget.EditableInputConnection; + +import org.xmlpull.v1.XmlPullParserException; /** * Displays text to the user and optionally allows them to edit it. A TextView @@ -146,6 +163,7 @@ import com.android.internal.util.FastMath; * @attr ref android.R.styleable#TextView_drawableLeft * @attr ref android.R.styleable#TextView_lineSpacingExtra * @attr ref android.R.styleable#TextView_lineSpacingMultiplier + * @attr ref android.R.styleable#TextView_marqueeRepeatLimit */ @RemoteView public class TextView extends View implements ViewTreeObserver.OnPreDrawListener { @@ -182,22 +200,44 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener private static final int SIGNED = 2; private static final int DECIMAL = 4; - private Drawable mDrawableTop, mDrawableBottom, mDrawableLeft, mDrawableRight; - private int mDrawableSizeTop, mDrawableSizeBottom, mDrawableSizeLeft, mDrawableSizeRight; - private int mDrawableWidthTop, mDrawableWidthBottom, mDrawableHeightLeft, mDrawableHeightRight; - private boolean mDrawables; - private int mDrawablePadding; + class Drawables { + final Rect mCompoundRect = new Rect(); + Drawable mDrawableTop, mDrawableBottom, mDrawableLeft, mDrawableRight; + int mDrawableSizeTop, mDrawableSizeBottom, mDrawableSizeLeft, mDrawableSizeRight; + int mDrawableWidthTop, mDrawableWidthBottom, mDrawableHeightLeft, mDrawableHeightRight; + int mDrawablePadding; + }; + private Drawables mDrawables; private CharSequence mError; private boolean mErrorWasChanged; private PopupWindow mPopup; private CharWrapper mCharWrapper = null; - private Rect mCompoundRect; private boolean mSelectionMoved = false; - /* + private Marquee mMarquee; + private boolean mRestartMarquee; + + private int mMarqueeRepeatLimit = 3; + + class InputContentType { + String privateContentType; + Bundle extras; + } + InputContentType mInputContentType; + + class InputMethodState { + Rect mCursorRectInWindow = new Rect(); + RectF mTmpRectF = new RectF(); + float[] mTmpOffset = new float[2]; + ExtractedTextRequest mExtracting; + final ExtractedText mTmpExtracted = new ExtractedText(); + } + InputMethodState mInputMethodState; + + /* * Kick-start the font cache for the zygote process (to pay the cost of * initializing freetype for our default font only once). */ @@ -221,7 +261,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); - mText = ""; mTextPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG); @@ -250,7 +289,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener * Look the appearance up without checking first if it exists because * almost every TextView has one and it greatly simplifies the logic * to be able to parse the appearance first and then let specific tags - * for this View override it. + * for this View override it. */ TypedArray appearance = null; int ap = a.getResourceId(com.android.internal.R.styleable.TextView_textAppearance, -1); @@ -317,6 +356,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener int shadowcolor = 0; float dx = 0, dy = 0, r = 0; boolean password = false; + int contentType = EditorInfo.TYPE_NULL; int n = a.getIndexCount(); for (int i = 0; i < n; i++) { @@ -461,6 +501,10 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener ellipsize = a.getInt(attr, ellipsize); break; + case com.android.internal.R.styleable.TextView_marqueeRepeatLimit: + setMarqueeRepeatLimit(a.getInt(attr, mMarqueeRepeatLimit)); + break; + case com.android.internal.R.styleable.TextView_includeFontPadding: if (!a.getBoolean(attr, true)) { setIncludeFontPadding(false); @@ -544,12 +588,37 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener case com.android.internal.R.styleable.TextView_lineSpacingMultiplier: mSpacingMult = a.getFloat(attr, mSpacingMult); break; + + case com.android.internal.R.styleable.TextView_inputType: + contentType = a.getInt(attr, mInputType); + break; + + case com.android.internal.R.styleable.TextView_editorPrivateContentType: + setPrivateContentType(a.getString(attr)); + break; + + case com.android.internal.R.styleable.TextView_editorExtras: + try { + setInputExtras(a.getResourceId(attr, 0)); + } catch (XmlPullParserException e) { + Log.w("TextView", "Failure reading input extras", e); + } catch (IOException e) { + Log.w("TextView", "Failure reading input extras", e); + } + break; } } a.recycle(); BufferType bufferType = BufferType.EDITABLE; + if ((contentType&(EditorInfo.TYPE_MASK_CLASS + |EditorInfo.TYPE_MASK_VARIATION)) + == (EditorInfo.TYPE_CLASS_TEXT + |EditorInfo.TYPE_TEXT_VARIATION_PASSWORD)) { + password = true; + } + if (inputMethod != null) { Class c; @@ -566,27 +635,58 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } catch (IllegalAccessException ex) { throw new RuntimeException(ex); } + try { + mInputType = contentType != EditorInfo.TYPE_NULL + ? contentType + : mInput.getInputType(); + } catch (IncompatibleClassChangeError e) { + mInputType = EditorInfo.TYPE_CLASS_TEXT; + } } else if (digits != null) { mInput = DigitsKeyListener.getInstance(digits.toString()); + mInputType = contentType; + } else if (contentType != EditorInfo.TYPE_NULL) { + setInputType(contentType, true); + singleLine = (contentType&(EditorInfo.TYPE_MASK_CLASS + | EditorInfo.TYPE_TEXT_FLAG_MULTI_LINE)) != + (EditorInfo.TYPE_CLASS_TEXT + | EditorInfo.TYPE_TEXT_FLAG_MULTI_LINE); } else if (phone) { mInput = DialerKeyListener.getInstance(); + contentType = EditorInfo.TYPE_CLASS_PHONE; } else if (numeric != 0) { mInput = DigitsKeyListener.getInstance((numeric & SIGNED) != 0, (numeric & DECIMAL) != 0); + contentType = EditorInfo.TYPE_CLASS_NUMBER; + if ((numeric & SIGNED) != 0) { + contentType |= EditorInfo.TYPE_NUMBER_FLAG_SIGNED; + } + if ((numeric & DECIMAL) != 0) { + contentType |= EditorInfo.TYPE_NUMBER_FLAG_DECIMAL; + } + mInputType = contentType; } else if (autotext || autocap != -1) { TextKeyListener.Capitalize cap; + contentType = EditorInfo.TYPE_CLASS_TEXT; + if (!singleLine) { + contentType |= EditorInfo.TYPE_TEXT_FLAG_MULTI_LINE; + } + switch (autocap) { case 1: cap = TextKeyListener.Capitalize.SENTENCES; + contentType |= EditorInfo.TYPE_TEXT_FLAG_CAP_SENTENCES; break; case 2: cap = TextKeyListener.Capitalize.WORDS; + contentType |= EditorInfo.TYPE_TEXT_FLAG_CAP_WORDS; break; case 3: cap = TextKeyListener.Capitalize.CHARACTERS; + contentType |= EditorInfo.TYPE_TEXT_FLAG_CAP_CHARACTERS; break; default: @@ -595,8 +695,10 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } mInput = TextKeyListener.getInstance(autotext, cap); + mInputType = contentType; } else if (editable) { mInput = TextKeyListener.getInstance(); + mInputType = EditorInfo.TYPE_CLASS_TEXT; } else { mInput = null; @@ -611,6 +713,12 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener bufferType = BufferType.EDITABLE; break; } + mInputType = EditorInfo.TYPE_CLASS_TEXT; + } + + if (password) { + mInputType = (mInputType & ~(EditorInfo.TYPE_MASK_VARIATION)) + | EditorInfo.TYPE_TEXT_VARIATION_PASSWORD; } if (selectallonfocus) { @@ -642,6 +750,10 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener case 3: setEllipsize(TextUtils.TruncateAt.END); break; + case 4: + setHorizontalFadingEdgeEnabled(true); + setEllipsize(TextUtils.TruncateAt.MARQUEE); + break; } setTextColor(textColor != null ? textColor : ColorStateList.valueOf(0xFF000000)); @@ -774,11 +886,14 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } /** - * Return the text the TextView is displaying. If setText() was called - * with an argument of BufferType.SPANNABLE or BufferType.EDITABLE, - * you can cast the return value from this method to Spannable - * or Editable, respectively. + * Return the text the TextView is displaying. If setText() was called with + * an argument of BufferType.SPANNABLE or BufferType.EDITABLE, you can cast + * the return value from this method to Spannable or Editable, respectively. + * + * Note: The content of the return value should not be modified. If you want + * a modifiable one, you should make your own copy first. */ + @ViewDebug.CapturedViewProperty public CharSequence getText() { return mText; } @@ -790,6 +905,16 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener return mText.length(); } + /** + * Return the text the TextView is displaying as an Editable object. If + * the text is not editable, null is returned. + * + * @see #getText + */ + public Editable getEditableText() { + return (mText instanceof Editable) ? (Editable)mText : null; + } + /** * @return the height of one standard line in pixels. Note that markup * within the text can cause individual lines to be taller or shorter @@ -819,7 +944,12 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener /** * Sets the key listener to be used with this TextView. This can be null - * to disallow user input. + * to disallow user input. Note that this method has significant and + * subtle interactions with soft keyboards and other input method: + * see {@link KeyListener#getInputType() KeyListener.getContentType()} + * for important details. Calling this method will replace the current + * content type of the text view with the content type returned by the + * key listener. *

              * Be warned that if you want a TextView with a key listener or movement * method not to be focusable, or if you want a TextView without a @@ -835,13 +965,37 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener * @attr ref android.R.styleable#TextView_autoText */ public void setKeyListener(KeyListener input) { - mInput = input; + setKeyListenerOnly(input); + fixFocusableAndClickableSettings(); + + if (input != null) { + try { + mInputType = mInput.getInputType(); + } catch (IncompatibleClassChangeError e) { + mInputType = EditorInfo.TYPE_CLASS_TEXT; + } + if ((mInputType&EditorInfo.TYPE_MASK_CLASS) + == EditorInfo.TYPE_CLASS_TEXT) { + if (mSingleLine) { + mInputType &= ~EditorInfo.TYPE_TEXT_FLAG_MULTI_LINE; + } else { + mInputType |= EditorInfo.TYPE_TEXT_FLAG_MULTI_LINE; + } + } + } else { + mInputType = EditorInfo.TYPE_NULL; + } + + InputMethodManager imm = InputMethodManager.peekInstance(); + if (imm != null) imm.restartInput(this); + } + private void setKeyListenerOnly(KeyListener input) { + mInput = input; if (mInput != null && !(mText instanceof Editable)) setText(mText); setFilters((Editable) mText, mFilters); - fixFocusableAndClickableSettings(); } /** @@ -873,7 +1027,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } private void fixFocusableAndClickableSettings() { - if (mMovement != null || mInput != null) { + if ((mMovement != null) || mInput != null) { setFocusable(true); setClickable(true); setLongClickable(true); @@ -917,10 +1071,11 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener * Drawable if any. */ public int getCompoundPaddingTop() { - if (mDrawableTop == null) { + final Drawables dr = mDrawables; + if (dr == null || dr.mDrawableTop == null) { return mPaddingTop; } else { - return mPaddingTop + mDrawablePadding + mDrawableSizeTop; + return mPaddingTop + dr.mDrawablePadding + dr.mDrawableSizeTop; } } @@ -929,10 +1084,11 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener * Drawable if any. */ public int getCompoundPaddingBottom() { - if (mDrawableBottom == null) { + final Drawables dr = mDrawables; + if (dr == null || dr.mDrawableBottom == null) { return mPaddingBottom; } else { - return mPaddingBottom + mDrawablePadding + mDrawableSizeBottom; + return mPaddingBottom + dr.mDrawablePadding + dr.mDrawableSizeBottom; } } @@ -941,10 +1097,11 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener * Drawable if any. */ public int getCompoundPaddingLeft() { - if (mDrawableLeft == null) { + final Drawables dr = mDrawables; + if (dr == null || dr.mDrawableLeft == null) { return mPaddingLeft; } else { - return mPaddingLeft + mDrawablePadding + mDrawableSizeLeft; + return mPaddingLeft + dr.mDrawablePadding + dr.mDrawableSizeLeft; } } @@ -953,10 +1110,11 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener * Drawable if any. */ public int getCompoundPaddingRight() { - if (mDrawableRight == null) { + final Drawables dr = mDrawables; + if (dr == null || dr.mDrawableRight == null) { return mPaddingRight; } else { - return mPaddingRight + mDrawablePadding + mDrawableSizeRight; + return mPaddingRight + dr.mDrawablePadding + dr.mDrawableSizeRight; } } @@ -1043,7 +1201,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } /** - * Returns the total top padding of the view, including the top + * Returns the total top padding of the view, including the top * Drawable if any, the extra space to keep more than maxLines * from showing, and the vertical offset for gravity, if any. */ @@ -1073,72 +1231,113 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener */ public void setCompoundDrawables(Drawable left, Drawable top, Drawable right, Drawable bottom) { - mDrawableLeft = left; - mDrawableTop = top; - mDrawableRight = right; - mDrawableBottom = bottom; + Drawables dr = mDrawables; - mDrawables = mDrawableLeft != null - || mDrawableRight != null - || mDrawableTop != null - || mDrawableBottom != null; + final boolean drawables = left != null || top != null + || right != null || bottom != null; - if (mCompoundRect == null && - (left != null || top != null || right != null || bottom != null)) { - mCompoundRect = new Rect(); - } + if (!drawables) { + // Clearing drawables... can we free the data structure? + if (dr != null) { + if (dr.mDrawablePadding == 0) { + mDrawables = null; + } else { + // We need to retain the last set padding, so just clear + // out all of the fields in the existing structure. + dr.mDrawableLeft = null; + dr.mDrawableTop = null; + dr.mDrawableRight = null; + dr.mDrawableBottom = null; + dr.mDrawableSizeLeft = dr.mDrawableHeightLeft = 0; + dr.mDrawableSizeRight = dr.mDrawableHeightRight = 0; + dr.mDrawableSizeTop = dr.mDrawableWidthTop = 0; + dr.mDrawableSizeBottom = dr.mDrawableWidthBottom = 0; + } + } + } else { + if (dr == null) { + mDrawables = dr = new Drawables(); + } + + dr.mDrawableLeft = left; + dr.mDrawableTop = top; + dr.mDrawableRight = right; + dr.mDrawableBottom = bottom; + + final Rect compoundRect = dr.mCompoundRect; + int[] state = null; - final Rect compoundRect = mCompoundRect; - int[] state = null; - - if (mDrawables) { state = getDrawableState(); - } - - if (mDrawableLeft != null) { - mDrawableLeft.setState(state); - mDrawableLeft.copyBounds(compoundRect); - mDrawableSizeLeft = compoundRect.width(); - mDrawableHeightLeft = compoundRect.height(); - } else { - mDrawableSizeLeft = mDrawableHeightLeft = 0; - } - if (mDrawableRight != null) { - mDrawableRight.setState(state); - mDrawableRight.copyBounds(compoundRect); - mDrawableSizeRight = compoundRect.width(); - mDrawableHeightRight = compoundRect.height(); - } else { - mDrawableSizeRight = mDrawableHeightRight = 0; - } + if (left != null) { + left.setState(state); + left.copyBounds(compoundRect); + dr.mDrawableSizeLeft = compoundRect.width(); + dr.mDrawableHeightLeft = compoundRect.height(); + } else { + dr.mDrawableSizeLeft = dr.mDrawableHeightLeft = 0; + } - if (mDrawableTop != null) { - mDrawableTop.setState(state); - mDrawableTop.copyBounds(compoundRect); - mDrawableSizeTop = compoundRect.height(); - mDrawableWidthTop = compoundRect.width(); - } else { - mDrawableSizeTop = mDrawableWidthTop = 0; - } + if (right != null) { + right.setState(state); + right.copyBounds(compoundRect); + dr.mDrawableSizeRight = compoundRect.width(); + dr.mDrawableHeightRight = compoundRect.height(); + } else { + dr.mDrawableSizeRight = dr.mDrawableHeightRight = 0; + } - if (mDrawableBottom != null) { - mDrawableBottom.setState(state); - mDrawableBottom.copyBounds(compoundRect); - mDrawableSizeBottom = compoundRect.height(); - mDrawableWidthBottom = compoundRect.width(); - } else { - mDrawableSizeBottom = mDrawableWidthBottom = 0; + if (top != null) { + top.setState(state); + top.copyBounds(compoundRect); + dr.mDrawableSizeTop = compoundRect.height(); + dr.mDrawableWidthTop = compoundRect.width(); + } else { + dr.mDrawableSizeTop = dr.mDrawableWidthTop = 0; + } + + if (bottom != null) { + bottom.setState(state); + bottom.copyBounds(compoundRect); + dr.mDrawableSizeBottom = compoundRect.height(); + dr.mDrawableWidthBottom = compoundRect.width(); + } else { + dr.mDrawableSizeBottom = dr.mDrawableWidthBottom = 0; + } } invalidate(); requestLayout(); } + /** + * Sets the Drawables (if any) to appear to the left of, above, + * to the right of, and below the text. Use 0 if you do not + * want a Drawable there. The Drawables' bounds will be set to + * their intrinsic bounds. + * + * @param left Resource identifier of the left Drawable. + * @param top Resource identifier of the top Drawable. + * @param right Resource identifier of the right Drawable. + * @param bottom Resource identifier of the bottom Drawable. + * + * @attr ref android.R.styleable#TextView_drawableLeft + * @attr ref android.R.styleable#TextView_drawableTop + * @attr ref android.R.styleable#TextView_drawableRight + * @attr ref android.R.styleable#TextView_drawableBottom + */ + public void setCompoundDrawablesWithIntrinsicBounds(int left, int top, int right, int bottom) { + final Resources resources = getContext().getResources(); + setCompoundDrawables(left != 0 ? resources.getDrawable(left) : null, + top != 0 ? resources.getDrawable(top) : null, + right != 0 ? resources.getDrawable(right) : null, + bottom != 0 ? resources.getDrawable(bottom) : null); + } + /** * Sets the Drawables (if any) to appear to the left of, above, * to the right of, and below the text. Use null if you do not - * want a Drawable there. The Drawables' bounds will be set to + * want a Drawable there. The Drawables' bounds will be set to * their intrinsic bounds. * * @attr ref android.R.styleable#TextView_drawableLeft @@ -1146,24 +1345,20 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener * @attr ref android.R.styleable#TextView_drawableRight * @attr ref android.R.styleable#TextView_drawableBottom */ - public void setCompoundDrawablesWithIntrinsicBounds(Drawable left, - Drawable top, - Drawable right, Drawable bottom) { + public void setCompoundDrawablesWithIntrinsicBounds(Drawable left, Drawable top, + Drawable right, Drawable bottom) { + if (left != null) { - left.setBounds(0, 0, - left.getIntrinsicWidth(), left.getIntrinsicHeight()); + left.setBounds(0, 0, left.getIntrinsicWidth(), left.getIntrinsicHeight()); } if (right != null) { - right.setBounds(0, 0, - right.getIntrinsicWidth(), right.getIntrinsicHeight()); + right.setBounds(0, 0, right.getIntrinsicWidth(), right.getIntrinsicHeight()); } if (top != null) { - top.setBounds(0, 0, - top.getIntrinsicWidth(), top.getIntrinsicHeight()); + top.setBounds(0, 0, top.getIntrinsicWidth(), top.getIntrinsicHeight()); } if (bottom != null) { - bottom.setBounds(0, 0, - bottom.getIntrinsicWidth(), bottom.getIntrinsicHeight()); + bottom.setBounds(0, 0, bottom.getIntrinsicWidth(), bottom.getIntrinsicHeight()); } setCompoundDrawables(left, top, right, bottom); } @@ -1172,9 +1367,14 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener * Returns drawables for the left, top, right, and bottom borders. */ public Drawable[] getCompoundDrawables() { - return new Drawable[] { - mDrawableLeft, mDrawableTop, mDrawableRight, mDrawableBottom - }; + final Drawables dr = mDrawables; + if (dr != null) { + return new Drawable[] { + dr.mDrawableLeft, dr.mDrawableTop, dr.mDrawableRight, dr.mDrawableBottom + }; + } else { + return new Drawable[] { null, null, null, null }; + } } /** @@ -1184,7 +1384,17 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener * @attr ref android.R.styleable#TextView_drawablePadding */ public void setCompoundDrawablePadding(int pad) { - mDrawablePadding = pad; + Drawables dr = mDrawables; + if (pad == 0) { + if (dr != null) { + dr.mDrawablePadding = pad; + } + } else { + if (dr == null) { + mDrawables = dr = new Drawables(); + } + dr.mDrawablePadding = pad; + } invalidate(); requestLayout(); @@ -1194,7 +1404,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener * Returns the padding between the compound drawables and the text. */ public int getCompoundDrawablePadding() { - return mDrawablePadding; + final Drawables dr = mDrawables; + return dr != null ? dr.mDrawablePadding : 0; } @Override @@ -1910,18 +2121,21 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener updateTextColors(); } - int[] state = getDrawableState(); - if (mDrawableTop != null && mDrawableTop.isStateful()) { - mDrawableTop.setState(state); - } - if (mDrawableBottom != null && mDrawableBottom.isStateful()) { - mDrawableBottom.setState(state); - } - if (mDrawableLeft != null && mDrawableLeft.isStateful()) { - mDrawableLeft.setState(state); - } - if (mDrawableRight != null && mDrawableRight.isStateful()) { - mDrawableRight.setState(state); + final Drawables dr = mDrawables; + if (dr != null) { + int[] state = getDrawableState(); + if (dr.mDrawableTop != null && dr.mDrawableTop.isStateful()) { + dr.mDrawableTop.setState(state); + } + if (dr.mDrawableBottom != null && dr.mDrawableBottom.isStateful()) { + dr.mDrawableBottom.setState(state); + } + if (dr.mDrawableLeft != null && dr.mDrawableLeft.isStateful()) { + dr.mDrawableLeft.setState(state); + } + if (dr.mDrawableRight != null && dr.mDrawableRight.isStateful()) { + dr.mDrawableRight.setState(state); + } } } @@ -1982,12 +2196,12 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener @Override public Parcelable onSaveInstanceState() { Parcelable superState = super.onSaveInstanceState(); - + // Save state if we are forced to boolean save = mFreezesText; int start = 0; int end = 0; - + if (mText != null) { start = Selection.getSelectionStart(mText); end = Selection.getSelectionEnd(mText); @@ -1996,7 +2210,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener save = true; } } - + if (save) { SavedState ss = new SavedState(superState); // XXX Should also save the current scroll position! @@ -2030,15 +2244,20 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener return ss; } - - return null; + + return superState; } @Override public void onRestoreInstanceState(Parcelable state) { + if (!(state instanceof SavedState)) { + super.onRestoreInstanceState(state); + return; + } + SavedState ss = (SavedState)state; super.onRestoreInstanceState(ss.getSuperState()); - + // XXX restore buffer type too, as well as lots of other stuff if (ss.text != null) { setText(ss.text); @@ -2165,6 +2384,12 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener text = ""; } + if (text instanceof Spanned && + ((Spanned) text).getSpanStart(TextUtils.TruncateAt.MARQUEE) >= 0) { + setHorizontalFadingEdgeEnabled(true); + setEllipsize(TextUtils.TruncateAt.MARQUEE); + } + int n = mFilters.length; for (int i = 0; i < n; i++) { CharSequence out = mFilters[i].filter(text, 0, text.length(), @@ -2183,11 +2408,19 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } } - if (type == BufferType.EDITABLE || mInput != null) { + boolean needEditableForNotification = false; + + if (mListeners != null && mListeners.size() != 0) { + needEditableForNotification = true; + } + + if (type == BufferType.EDITABLE || mInput != null || + needEditableForNotification) { Editable t = mEditableFactory.newEditable(text); text = t; - setFilters(t, mFilters); + InputMethodManager imm = InputMethodManager.peekInstance(); + if (imm != null) imm.restartInput(this); } else if (type == BufferType.SPANNABLE || mMovement != null) { text = mSpannableFactory.newSpannable(text); } else if (!(text instanceof CharWrapper)) { @@ -2256,7 +2489,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } if (mMovement != null) { - mMovement.initialize(this, (Spannable) text); + mMovement.initialize(this, (Spannable) text); /* * Initializing the movement method will have set the @@ -2273,6 +2506,10 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener sendOnTextChanged(text, 0, oldlen, textLength); onTextChanged(text, 0, oldlen, textLength); + + if (needEditableForNotification) { + sendAfterTextChanged((Editable) text); + } } /** @@ -2401,8 +2638,11 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener /** * Sets the text to be displayed when the text of the TextView is empty. - * Null means to use the normal empty text. The hint does not - * currently participate in determining the size of the view. + * Null means to use the normal empty text. The hint does not currently + * participate in determining the size of the view. + * + * This method is deprecated. Use {link #setHint(int, String)} or + * {link #setHint(CharSequence, String)} instead. * * @attr ref android.R.styleable#TextView_hint */ @@ -2421,6 +2661,9 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener * Sets the text to be displayed when the text of the TextView is empty, * from a resource. * + * This method is deprecated. Use {link #setHint(int, String)} or + * {link #setHint(CharSequence, String)} instead. + * * @attr ref android.R.styleable#TextView_hint */ public final void setHint(int resid) { @@ -2433,10 +2676,176 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener * * @attr ref android.R.styleable#TextView_hint */ + @ViewDebug.CapturedViewProperty public CharSequence getHint() { return mHint; } + /** + * Set the type of the content with a constant as defined for + * {@link EditorInfo#inputType}. This will take care of changing + * the key listener, by calling {@link #setKeyListener(KeyListener)}, to + * match the given content type. If the given content type is + * {@link EditorInfo#TYPE_NULL} then a soft keyboard will + * not be displayed for this text view. + * + * @see #getInputType() + * @see #setRawInputType(int) + * @see android.text.InputType + * @attr ref android.R.styleable#TextView_inputType + */ + public void setInputType(int type) { + setInputType(type, false); + if ((type&(EditorInfo.TYPE_MASK_CLASS + |EditorInfo.TYPE_MASK_VARIATION)) + == (EditorInfo.TYPE_CLASS_TEXT + |EditorInfo.TYPE_TEXT_VARIATION_PASSWORD)) { + setTransformationMethod(PasswordTransformationMethod.getInstance()); + setTypefaceByIndex(MONOSPACE, 0); + } + boolean multiLine = (type&(EditorInfo.TYPE_MASK_CLASS + | EditorInfo.TYPE_TEXT_FLAG_MULTI_LINE)) == + (EditorInfo.TYPE_CLASS_TEXT + | EditorInfo.TYPE_TEXT_FLAG_MULTI_LINE); + if (mSingleLine == multiLine) { + setSingleLine(!multiLine); + } + InputMethodManager imm = InputMethodManager.peekInstance(); + if (imm != null) imm.restartInput(this); + } + + /** + * Directly change the content type integer of the text view, without + * modifying any other state. + * @see #setContentType + * @see android.text.InputType + * @attr ref android.R.styleable#TextView_inputType + */ + public void setRawInputType(int type) { + mInputType = type; + } + + private void setInputType(int type, boolean direct) { + final int cls = type & EditorInfo.TYPE_MASK_CLASS; + KeyListener input; + if (cls == EditorInfo.TYPE_CLASS_TEXT) { + boolean autotext = (type & EditorInfo.TYPE_TEXT_FLAG_AUTO_CORRECT) + != 0; + TextKeyListener.Capitalize cap; + if ((type & EditorInfo.TYPE_TEXT_FLAG_CAP_CHARACTERS) != 0) { + cap = TextKeyListener.Capitalize.CHARACTERS; + } else if ((type & EditorInfo.TYPE_TEXT_FLAG_CAP_WORDS) != 0) { + cap = TextKeyListener.Capitalize.WORDS; + } else if ((type & EditorInfo.TYPE_TEXT_FLAG_CAP_SENTENCES) != 0) { + cap = TextKeyListener.Capitalize.SENTENCES; + } else { + cap = TextKeyListener.Capitalize.NONE; + } + input = TextKeyListener.getInstance(autotext, cap); + } else if (cls == EditorInfo.TYPE_CLASS_NUMBER) { + input = DigitsKeyListener.getInstance( + (type & EditorInfo.TYPE_NUMBER_FLAG_SIGNED) != 0, + (type & EditorInfo.TYPE_NUMBER_FLAG_DECIMAL) != 0); + } else if (cls == EditorInfo.TYPE_CLASS_DATETIME) { + switch (type & EditorInfo.TYPE_MASK_VARIATION) { + case EditorInfo.TYPE_DATETIME_VARIATION_DATE: + input = DateKeyListener.getInstance(); + break; + case EditorInfo.TYPE_DATETIME_VARIATION_TIME: + input = TimeKeyListener.getInstance(); + break; + default: + input = DateTimeKeyListener.getInstance(); + break; + } + } else if (cls == EditorInfo.TYPE_CLASS_PHONE) { + input = DialerKeyListener.getInstance(); + } else { + input = TextKeyListener.getInstance(); + } + mInputType = type; + if (direct) mInput = input; + else { + setKeyListenerOnly(input); + } + } + + /** + * Get the type of the content. + * + * @see #setInputType(int) + * @see android.text.InputType + */ + public int getInputType() { + return mInputType; + } + + /** + * Set the private content type of the text, which is the + * {@link EditorInfo#privateContentType TextBoxAttribute.privateContentType} + * field that will be filled in when creating an input connection. + * + * @see #getPrivateContentType() + * @see EditorInfo#privateContentType + * @attr ref android.R.styleable#TextView_editorPrivateContentType + */ + public void setPrivateContentType(String type) { + if (mInputContentType == null) mInputContentType = new InputContentType(); + mInputContentType.privateContentType = type; + } + + /** + * Get the private type of the content. + * + * @see #setPrivateContentType(String) + * @see EditorInfo#privateContentType + */ + public String getPrivateContentType() { + return mInputContentType != null + ? mInputContentType.privateContentType : null; + } + + /** + * Set the extra input data of the text, which is the + * {@link EditorInfo#extras TextBoxAttribute.extras} + * Bundle that will be filled in when creating an input connection. The + * given integer is the resource ID of an XML resource holding an + * {@link android.R.styleable#InputExtras <input-extras>} XML tree. + * + * @see #getInputExtras() + * @see EditorInfo#extras + * @attr ref android.R.styleable#TextView_editorExtras + */ + public void setInputExtras(int xmlResId) + throws XmlPullParserException, IOException { + XmlResourceParser parser = getResources().getXml(xmlResId); + if (mInputContentType == null) mInputContentType = new InputContentType(); + mInputContentType.extras = new Bundle(); + getResources().parseBundleExtras(parser, mInputContentType.extras); + } + + /** + * Retrieve the input extras currently associated with the text view, which + * can be viewed as well as modified. + * + * @param create If true, the extras will be created if they don't already + * exist. Otherwise, null will be returned if none have been created. + * @see #setInputExtras(int) + * @see EditorInfo#extras + * @attr ref android.R.styleable#TextView_editorExtras + */ + public Bundle getInputExtras(boolean create) { + if (mInputContentType == null) { + if (!create) return null; + mInputContentType = new InputContentType(); + } + if (mInputContentType.extras == null) { + if (!create) return null; + mInputContentType.extras = new Bundle(); + } + return mInputContentType.extras; + } + /** * Returns the error message that was set to be displayed with * {@link #setError}, or null if no error was set @@ -2481,8 +2890,13 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener mError = error; mErrorWasChanged = true; - setCompoundDrawables(mDrawableLeft, mDrawableTop, - icon, mDrawableBottom); + final Drawables dr = mDrawables; + if (dr != null) { + setCompoundDrawables(dr.mDrawableLeft, dr.mDrawableTop, + icon, dr.mDrawableBottom); + } else { + setCompoundDrawables(null, null, icon, null); + } if (error == null) { if (mPopup != null) { @@ -2525,9 +2939,11 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener * The "25" is the distance between the point and the right edge * of the background */ - + + final Drawables dr = mDrawables; return getWidth() - mPopup.getWidth() - - getPaddingRight() - mDrawableSizeRight / 2 + 25; + - getPaddingRight() + - (dr != null ? dr.mDrawableSizeRight : 0) / 2 + 25; } /** @@ -2542,17 +2958,19 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener int vspace = mBottom - mTop - getCompoundPaddingBottom() - getCompoundPaddingTop(); - int icontop = getCompoundPaddingTop() + - (vspace - mDrawableHeightRight) / 2; + final Drawables dr = mDrawables; + int icontop = getCompoundPaddingTop() + + (vspace - (dr != null ? dr.mDrawableHeightRight : 0)) / 2; /* * The "2" is the distance between the point and the top edge * of the background. */ - return icontop + mDrawableHeightRight - getHeight() - 2; + return icontop + (dr != null ? dr.mDrawableHeightRight : 0) + - getHeight() - 2; } - + private void hideError() { if (mPopup != null) { if (mPopup.isShowing()) { @@ -2599,6 +3017,11 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener mPopup.update(this, getErrorX(), getErrorY(), -1, -1); } + if (mRestartMarquee && mEllipsize == TextUtils.TruncateAt.MARQUEE) { + mRestartMarquee = false; + startMarquee(); + } + return result; } @@ -2659,10 +3082,10 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener int boxht; if (l == mHintLayout) { - boxht = getMeasuredHeight() - getCompoundPaddingTop() - + boxht = getMeasuredHeight() - getCompoundPaddingTop() - getCompoundPaddingBottom(); } else { - boxht = getMeasuredHeight() - getExtendedPaddingTop() - + boxht = getMeasuredHeight() - getExtendedPaddingTop() - getExtendedPaddingBottom(); } int textht = l.getHeight(); @@ -2690,10 +3113,10 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener int boxht; if (l == mHintLayout) { - boxht = getMeasuredHeight() - getCompoundPaddingTop() - + boxht = getMeasuredHeight() - getCompoundPaddingTop() - getCompoundPaddingBottom(); } else { - boxht = getMeasuredHeight() - getExtendedPaddingTop() - + boxht = getMeasuredHeight() - getExtendedPaddingTop() - getExtendedPaddingBottom(); } int textht = l.getHeight(); @@ -2713,15 +3136,32 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener invalidateCursor(); } else { synchronized (sTempRect) { + /* + * The reason for this concern about the thickness of the + * cursor and doing the floor/ceil on the coordinates is that + * some EditTexts (notably textfields in the Browser) have + * anti-aliased text where not all the characters are + * necessarily at integer-multiple locations. This should + * make sure the entire cursor gets invalidated instead of + * sometimes missing half a pixel. + */ + + float thick = FloatMath.ceil(mTextPaint.getStrokeWidth()); + if (thick < 1.0f) { + thick = 1.0f; + } + + thick /= 2; + mHighlightPath.computeBounds(sTempRect, false); int left = getCompoundPaddingLeft(); int top = getExtendedPaddingTop() + getVerticalOffset(true); - invalidate((int) sTempRect.left + left, - (int) sTempRect.top + top, - (int) sTempRect.right + left + 1, - (int) sTempRect.bottom + top + 1); + invalidate((int) FloatMath.floor(left + sTempRect.left - thick), + (int) FloatMath.floor(top + sTempRect.top - thick), + (int) FloatMath.ceil(left + sTempRect.right + thick), + (int) FloatMath.ceil(top + sTempRect.bottom + thick)); } } } @@ -2837,6 +3277,35 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener mPreDrawState = PREDRAW_NOT_REGISTERED; } } + + if (mError != null) { + hideError(); + } + } + + @Override + protected boolean isPaddingOffsetRequired() { + return mShadowRadius != 0; + } + + @Override + protected int getLeftPaddingOffset() { + return (int) Math.min(0, mShadowDx - mShadowRadius); + } + + @Override + protected int getTopPaddingOffset() { + return (int) Math.min(0, mShadowDy - mShadowRadius); + } + + @Override + protected int getBottomPaddingOffset() { + return (int) Math.max(0, mShadowDy + mShadowRadius); + } + + @Override + protected int getRightPaddingOffset() { + return (int) Math.max(0, mShadowDx + mShadowRadius); } @Override @@ -2855,7 +3324,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener final int bottom = mBottom; final int top = mTop; - if (mDrawables) { + final Drawables dr = mDrawables; + if (dr != null) { /* * Compound, not extended, because the icon is not clipped * if the text height is smaller. @@ -2864,37 +3334,37 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener int vspace = bottom - top - compoundPaddingBottom - compoundPaddingTop; int hspace = right - left - compoundPaddingRight - compoundPaddingLeft; - if (mDrawableLeft != null) { + if (dr.mDrawableLeft != null) { canvas.save(); canvas.translate(scrollX + mPaddingLeft, scrollY + compoundPaddingTop + - (vspace - mDrawableHeightLeft) / 2); - mDrawableLeft.draw(canvas); + (vspace - dr.mDrawableHeightLeft) / 2); + dr.mDrawableLeft.draw(canvas); canvas.restore(); } - if (mDrawableRight != null) { + if (dr.mDrawableRight != null) { canvas.save(); - canvas.translate(scrollX + right - left - mPaddingRight - mDrawableSizeRight, - scrollY + compoundPaddingTop + (vspace - mDrawableHeightRight) / 2); - mDrawableRight.draw(canvas); + canvas.translate(scrollX + right - left - mPaddingRight - dr.mDrawableSizeRight, + scrollY + compoundPaddingTop + (vspace - dr.mDrawableHeightRight) / 2); + dr.mDrawableRight.draw(canvas); canvas.restore(); } - if (mDrawableTop != null) { + if (dr.mDrawableTop != null) { canvas.save(); - canvas.translate(scrollX + compoundPaddingLeft + (hspace - mDrawableWidthTop) / 2, + canvas.translate(scrollX + compoundPaddingLeft + (hspace - dr.mDrawableWidthTop) / 2, scrollY + mPaddingTop); - mDrawableTop.draw(canvas); + dr.mDrawableTop.draw(canvas); canvas.restore(); } - if (mDrawableBottom != null) { + if (dr.mDrawableBottom != null) { canvas.save(); canvas.translate(scrollX + compoundPaddingLeft + - (hspace - mDrawableWidthBottom) / 2, - scrollY + bottom - top - mPaddingBottom - mDrawableSizeBottom); - mDrawableBottom.draw(canvas); + (hspace - dr.mDrawableWidthBottom) / 2, + scrollY + bottom - top - mPaddingBottom - dr.mDrawableSizeBottom); + dr.mDrawableBottom.draw(canvas); canvas.restore(); } } @@ -2929,7 +3399,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener canvas.save(); /* Would be faster if we didn't have to do this. Can we chop the - (displayable) text so that we don't need to do this ever? + (displayable) text so that we don't need to do this ever? */ int extendedPaddingTop = getExtendedPaddingTop(); @@ -2963,7 +3433,20 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener canvas.translate(compoundPaddingLeft, extendedPaddingTop + voffsetText); } + if (mEllipsize == TextUtils.TruncateAt.MARQUEE) { + if (!mSingleLine && getLineCount() == 1 && canMarquee() && + (mGravity & Gravity.HORIZONTAL_GRAVITY_MASK) != Gravity.LEFT) { + canvas.translate(mLayout.getLineRight(0) - (mRight - mLeft - + getCompoundPaddingLeft() - getCompoundPaddingRight()), 0.0f); + } + + if (mMarquee != null && mMarquee.isRunning()) { + canvas.translate(-mMarquee.mScroll, 0.0f); + } + } + Path highlight = null; + int selStart = -1, selEnd = -1; // If there is no movement method, then there can be no selection. // Check that first and attempt to skip everything having to do with @@ -2971,19 +3454,19 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener // XXX This is not strictly true -- a program could set the // selection manually if it really wanted to. if (mMovement != null && (isFocused() || isPressed())) { - int start = Selection.getSelectionStart(mText); - int end = Selection.getSelectionEnd(mText); + selStart = Selection.getSelectionStart(mText); + selEnd = Selection.getSelectionEnd(mText); - if (mCursorVisible && start >= 0 && isEnabled()) { + if (mCursorVisible && selStart >= 0 && isEnabled()) { if (mHighlightPath == null) mHighlightPath = new Path(); - if (start == end) { + if (selStart == selEnd) { if ((SystemClock.uptimeMillis() - mShowCursor) % (2 * BLINK) < BLINK) { if (mHighlightPathBogus) { mHighlightPath.reset(); - mLayout.getCursorPath(start, mHighlightPath, mText); + mLayout.getCursorPath(selStart, mHighlightPath, mText); mHighlightPathBogus = false; } @@ -2996,7 +3479,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } else { if (mHighlightPathBogus) { mHighlightPath.reset(); - mLayout.getSelectionPath(start, end, mHighlightPath); + mLayout.getSelectionPath(selStart, selEnd, mHighlightPath); mHighlightPathBogus = false; } @@ -3020,6 +3503,31 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } */ + InputMethodManager imm = InputMethodManager.peekInstance(); + if (highlight != null && mInputMethodState != null && imm != null) { + imm.updateSelection(this, selStart, selEnd); + + if (imm.isWatchingCursor(this)) { + final InputMethodState ims = mInputMethodState; + highlight.computeBounds(ims.mTmpRectF, true); + ims.mTmpOffset[0] = ims.mTmpOffset[1] = 0; + + canvas.getMatrix().mapPoints(ims.mTmpOffset); + ims.mTmpRectF.offset(ims.mTmpOffset[0], ims.mTmpOffset[1]); + + ims.mTmpRectF.offset(0, voffsetCursor - voffsetText); + + ims.mCursorRectInWindow.set((int)(ims.mTmpRectF.left + 0.5), + (int)(ims.mTmpRectF.top + 0.5), + (int)(ims.mTmpRectF.right + 0.5), + (int)(ims.mTmpRectF.bottom + 0.5)); + + imm.updateCursor(this, + ims.mCursorRectInWindow.left, ims.mCursorRectInWindow.top, + ims.mCursorRectInWindow.right, ims.mCursorRectInWindow.bottom); + } + } + layout.draw(canvas, highlight, mHighlightPaint, voffsetCursor - voffsetText); /* Comment out until we decide what to do about animations @@ -3050,6 +3558,14 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener r.left = (int) mLayout.getPrimaryHorizontal(sel); r.right = r.left + 1; + + // Adjust for padding and gravity. + int paddingLeft = getCompoundPaddingLeft(); + int paddingTop = getExtendedPaddingTop(); + if ((mGravity & Gravity.VERTICAL_GRAVITY_MASK) != Gravity.TOP) { + paddingTop += getVerticalOffset(false); + } + r.offset(paddingLeft, paddingTop); } /** @@ -3106,20 +3622,67 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener @Override public boolean onKeyDown(int keyCode, KeyEvent event) { - if (!isEnabled()) { + int which = doKeyDown(keyCode, event); + if (which == 0) { + // Go through default dispatching. return super.onKeyDown(keyCode, event); } + return true; + } + + @Override + public boolean onKeyMultiple(int keyCode, int repeatCount, KeyEvent event) { + KeyEvent down = new KeyEvent(event, KeyEvent.ACTION_DOWN); + + int which = doKeyDown(keyCode, down); + if (which == 0) { + // Go through default dispatching. + return super.onKeyMultiple(keyCode, repeatCount, event); + } + + // We are going to dispatch the remaining events to either the input + // or movement method. To do this, we will just send a repeated stream + // of down and up events until we have done the complete repeatCount. + // It would be nice if those interfaces had an onKeyMultiple() method, + // but adding that is a more complicated change. + KeyEvent up = new KeyEvent(event, KeyEvent.ACTION_UP); + if (which == 1) { + mInput.onKeyUp(this, (Editable)mText, keyCode, up); + while (--repeatCount > 0) { + mInput.onKeyDown(this, (Editable)mText, keyCode, down); + mInput.onKeyUp(this, (Editable)mText, keyCode, up); + } + if (mError != null && !mErrorWasChanged) { + setError(null, null); + } + + } else if (which == 2) { + mMovement.onKeyUp(this, (Spannable)mText, keyCode, up); + while (--repeatCount > 0) { + mMovement.onKeyDown(this, (Spannable)mText, keyCode, down); + mMovement.onKeyUp(this, (Spannable)mText, keyCode, up); + } + } + + return true; + } + + private int doKeyDown(int keyCode, KeyEvent event) { + if (!isEnabled()) { + return 0; + } + switch (keyCode) { case KeyEvent.KEYCODE_DPAD_CENTER: case KeyEvent.KEYCODE_ENTER: if (mSingleLine && mInput != null) { - return super.onKeyDown(keyCode, event); + return 0; } } if (mInput != null) { - /* + /* * Keep track of what the error was before doing the input * so that if an input filter changed the error, we leave * that error showing. Otherwise, we take down whatever @@ -3131,7 +3694,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener if (mError != null && !mErrorWasChanged) { setError(null, null); } - return true; + return 1; } } @@ -3140,9 +3703,9 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener if (mMovement != null && mLayout != null) if (mMovement.onKeyDown(this, (Spannable)mText, keyCode, event)) - return true; + return 2; - return super.onKeyDown(keyCode, event); + return 0; } @Override @@ -3199,6 +3762,108 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener return super.onKeyUp(keyCode, event); } + @Override public InputConnection createInputConnection(EditorInfo outAttrs) { + if (mInputType != EditorInfo.TYPE_NULL) { + if (mInputMethodState == null) { + mInputMethodState = new InputMethodState(); + } + outAttrs.inputType = mInputType; + outAttrs.hintText = mHint; + if (mInputContentType != null) { + outAttrs.privateContentType = mInputContentType.privateContentType; + outAttrs.extras = mInputContentType.extras; + } + if (mText instanceof Editable) { + InputConnection ic = new EditableInputConnection(this); + outAttrs.initialSelStart = Selection.getSelectionStart(mText); + outAttrs.initialSelEnd = Selection.getSelectionEnd(mText); + outAttrs.initialCapsMode = ic.getCursorCapsMode(mInputType); + return ic; + } + } + return null; + } + + /** + * If this TextView contains editable content, extract a portion of it + * based on the information in request in to outText. + * @return Returns true if the text is editable and was successfully + * extracted, else false. + */ + public boolean extractText(ExtractedTextRequest request, + ExtractedText outText) { + Editable content = getEditableText(); + if (content != null) { + outText.text = content.subSequence(0, content.length()); + outText.startOffset = 0; + outText.selectionStart = Selection.getSelectionStart(content); + outText.selectionEnd = Selection.getSelectionEnd(content); + return true; + } + return false; + } + + void reportExtractedText() { + if (mInputMethodState != null) { + final ExtractedTextRequest req = mInputMethodState.mExtracting; + if (req != null) { + InputMethodManager imm = InputMethodManager.peekInstance(); + if (imm != null) { + if (extractText(req, mInputMethodState.mTmpExtracted)) { + imm.updateExtractedText(this, req.token, + mInputMethodState.mTmpExtracted); + } + } + } + } + } + + /** + * Apply to this text view the given extracted text, as previously + * returned by {@link #extractText(ExtractedTextRequest, ExtractedText)}. + */ + public void setExtractedText(ExtractedText text) { + setText(text.text, TextView.BufferType.EDITABLE); + Selection.setSelection((Spannable)getText(), + text.selectionStart, text.selectionEnd); + } + + /** + * @hide + */ + public void setExtracting(ExtractedTextRequest req) { + if (mInputMethodState != null) { + mInputMethodState.mExtracting = req; + } + } + + /** + * Called by the framework in response to a text completion from + * the current input method, provided by it calling + * {@link InputConnection#commitCompletion + * InputConnection.commitCompletion()}. The default implementation does + * nothing; text views that are supporting auto-completion should override + * this to do their desired behavior. + * + * @param text The auto complete text the user has selected. + */ + public void onCommitCompletion(CompletionInfo text) { + } + + /** + * Called by the framework in response to a private command from the + * current method, provided by it calling + * {@link InputConnection#performPrivateCommand + * InputConnection.performPrivateCommand()}. + * + * @param action The action name of the command. + * @param data Any additional data for the command. This may be null. + * @return Return true if you handled the command, else false. + */ + public boolean onPrivateIMECommand(String action, Bundle data) { + return false; + } + private void nullLayouts() { if (mLayout instanceof BoringLayout && mSavedLayout == null) { mSavedLayout = (BoringLayout) mLayout; @@ -3240,6 +3905,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener BoringLayout.Metrics boring, BoringLayout.Metrics hintBoring, int ellipsisWidth, boolean bringIntoView) { + stopMarquee(); + mHighlightPathBogus = true; if (w < 0) { @@ -3371,6 +4038,18 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener if (bringIntoView) { registerForPreDraw(); } + + if (mEllipsize == TextUtils.TruncateAt.MARQUEE) { + final int height = mLayoutParams.height; + // If the size of the view does not depend on the size of the text, try to + // start the marquee immediately + if (height != LayoutParams.WRAP_CONTENT && height != LayoutParams.FILL_PARENT) { + startMarquee(); + } else { + // Defer the start of the marquee until we know our width (see setFrame()) + mRestartMarquee = true; + } + } } private static int desired(Layout layout) { @@ -3458,8 +4137,11 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener width = boring.width; } - width = Math.max(width, mDrawableWidthTop); - width = Math.max(width, mDrawableWidthBottom); + final Drawables dr = mDrawables; + if (dr != null) { + width = Math.max(width, dr.mDrawableWidthTop); + width = Math.max(width, dr.mDrawableWidthBottom); + } if (mHint != null) { int hintDes = -1; @@ -3509,7 +4191,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener // Check against our minimum width width = Math.max(width, getSuggestedMinimumWidth()); - + if (widthMode == MeasureSpec.AT_MOST) { width = Math.min(widthSize, width); } @@ -3596,8 +4278,11 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener int pad = getCompoundPaddingTop() + getCompoundPaddingBottom(); int desired = layout.getLineTop(linecount); - desired = Math.max(desired, mDrawableHeightLeft); - desired = Math.max(desired, mDrawableHeightRight); + final Drawables dr = mDrawables; + if (dr != null) { + desired = Math.max(desired, dr.mDrawableHeightLeft); + desired = Math.max(desired, dr.mDrawableHeightRight); + } desired += pad; @@ -3611,8 +4296,10 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener desired = layout.getLineTop(mMaximum) + layout.getBottomPadding(); - desired = Math.max(desired, mDrawableHeightLeft); - desired = Math.max(desired, mDrawableHeightRight); + if (dr != null) { + desired = Math.max(desired, dr.mDrawableHeightLeft); + desired = Math.max(desired, dr.mDrawableHeightRight); + } desired += pad; linecount = mMaximum; @@ -3632,7 +4319,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener // Check against our minimum height desired = Math.max(desired, getSuggestedMinimumHeight()); - + return desired; } @@ -3978,8 +4665,12 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener private void getInterestingRect(Rect r, int h, int top, int bottom, int line) { - top += getExtendedPaddingTop(); - bottom += getExtendedPaddingTop(); + int paddingTop = getExtendedPaddingTop(); + if ((mGravity & Gravity.VERTICAL_GRAVITY_MASK) != Gravity.TOP) { + paddingTop += getVerticalOffset(false); + } + top += paddingTop; + bottom += paddingTop; h += getCompoundPaddingLeft(); if (line == 0) @@ -3987,7 +4678,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener if (line == mLayout.getLineCount() - 1) bottom += getExtendedPaddingBottom(); - r.set(h, top, h, bottom); + r.set(h, top, h+1, bottom); r.offset(-mScrollX, -mScrollY); } @@ -4056,6 +4747,14 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener */ public void setSingleLine(boolean singleLine) { mSingleLine = singleLine; + if ((mInputType&EditorInfo.TYPE_MASK_CLASS) + == EditorInfo.TYPE_CLASS_TEXT) { + if (singleLine) { + mInputType &= ~EditorInfo.TYPE_TEXT_FLAG_MULTI_LINE; + } else { + mInputType |= EditorInfo.TYPE_TEXT_FLAG_MULTI_LINE; + } + } if (singleLine) { setLines(1); @@ -4088,10 +4787,21 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } } + /** + * Sets how many times to repeat the marquee animation. Only applied if the + * TextView has marquee enabled. Set to -1 to repeat indefinitely. + * + * @attr ref android.R.styleable#TextView_marqueeRepeatLimit + */ + public void setMarqueeRepeatLimit(int marqueeLimit) { + mMarqueeRepeatLimit = marqueeLimit; + } + /** * Returns where, if anywhere, words that are longer than the view * is wide should be ellipsized. */ + @ViewDebug.ExportedProperty public TextUtils.TruncateAt getEllipsize() { return mEllipsize; } @@ -4126,6 +4836,145 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } } + private boolean canMarquee() { + int width = (mRight - mLeft - getCompoundPaddingLeft() - getCompoundPaddingRight()); + return width > 0 && mLayout.getLineWidth(0) > width; + } + + private void startMarquee() { + if ((mMarquee == null || mMarquee.isStopped()) && (isFocused() || isSelected()) && + getLineCount() == 1 && canMarquee()) { + if (mMarquee == null) mMarquee = new Marquee(this); + mMarquee.start(mMarqueeRepeatLimit); + } + } + + private void stopMarquee() { + if (mMarquee != null && !mMarquee.isStopped()) { + mMarquee.stop(); + } + } + + private void startStopMarquee(boolean start) { + if (mEllipsize == TextUtils.TruncateAt.MARQUEE) { + if (start) { + startMarquee(); + } else { + stopMarquee(); + } + } + } + + private static final class Marquee extends Handler { + // TODO: Add an option to configure this + private static final int MARQUEE_DELAY = 1200; + private static final int MARQUEE_RESTART_DELAY = 1200; + private static final int MARQUEE_RESOLUTION = 1000 / 30; + private static final int MARQUEE_PIXELS_PER_SECOND = 30; + + private static final byte MARQUEE_STOPPED = 0x0; + private static final byte MARQUEE_STARTING = 0x1; + private static final byte MARQUEE_RUNNING = 0x2; + + private static final int MESSAGE_START = 0x1; + private static final int MESSAGE_TICK = 0x2; + private static final int MESSAGE_RESTART = 0x3; + + private final WeakReference mView; + + private byte mStatus = MARQUEE_STOPPED; + private float mScrollUnit; + private float mMaxScroll; + private int mRepeatLimit; + + float mScroll; + + Marquee(TextView v) { + mView = new WeakReference(v); + } + + @Override + public void handleMessage(Message msg) { + switch (msg.what) { + case MESSAGE_START: + mStatus = MARQUEE_RUNNING; + tick(); + break; + case MESSAGE_TICK: + tick(); + break; + case MESSAGE_RESTART: + if (mStatus == MARQUEE_RUNNING) { + if (mRepeatLimit >= 0) { + mRepeatLimit--; + } + start(mRepeatLimit); + } + break; + } + } + + void tick() { + if (mStatus != MARQUEE_RUNNING) { + return; + } + + removeMessages(MESSAGE_TICK); + + final TextView textView = mView.get(); + if (textView != null && (textView.isFocused() || textView.isSelected())) { + mScroll += mScrollUnit; + if (mScroll > mMaxScroll) { + mScroll = mMaxScroll; + sendEmptyMessageDelayed(MESSAGE_RESTART, MARQUEE_RESTART_DELAY); + } else { + sendEmptyMessageDelayed(MESSAGE_TICK, MARQUEE_RESOLUTION); + } + textView.invalidate(); + } + } + + void stop() { + mStatus = MARQUEE_STOPPED; + removeMessages(MESSAGE_START); + removeMessages(MESSAGE_RESTART); + removeMessages(MESSAGE_TICK); + resetScroll(); + } + + private void resetScroll() { + mScroll = 0.0f; + final TextView textView = mView.get(); + if (textView != null) textView.invalidate(); + } + + void start(int repeatLimit) { + if (repeatLimit == 0) { + stop(); + return; + } + mRepeatLimit = repeatLimit; + final TextView textView = mView.get(); + if (textView != null && textView.mLayout != null) { + mStatus = MARQUEE_STARTING; + mScroll = 0.0f; + mScrollUnit = MARQUEE_PIXELS_PER_SECOND / (float) MARQUEE_RESOLUTION; + mMaxScroll = textView.mLayout.getLineWidth(0) - (textView.getWidth() - + textView.getCompoundPaddingLeft() - textView.getCompoundPaddingRight()); + textView.invalidate(); + sendEmptyMessageDelayed(MESSAGE_START, MARQUEE_DELAY); + } + } + + boolean isRunning() { + return mStatus == MARQUEE_RUNNING; + } + + boolean isStopped() { + return mStatus == MARQUEE_STOPPED; + } + } + /** * This method is called when the text is changed, in case any * subclasses would like to know. @@ -4151,6 +5000,11 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener /** * Adds a TextWatcher to the list of those whose methods are called * whenever this TextView's text changes. + *

              + * In 1.0, the {@link TextWatcher#afterTextChanged} method was erroneously + * not called after {@link #setText} calls. Now, doing {@link #setText} + * if there are any text changed listeners forces the buffer type to + * Editable if it would not otherwise be and does call this method. */ public void addTextChangedListener(TextWatcher watcher) { if (mListeners == null) { @@ -4186,7 +5040,11 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } } - private void sendOnTextChanged(CharSequence text, int start, int before, + /** + * Not private so it can be called from an inner class without going + * through a thunk. + */ + void sendOnTextChanged(CharSequence text, int start, int before, int after) { if (mListeners != null) { final ArrayList list = mListeners; @@ -4197,7 +5055,11 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } } - private void sendAfterTextChanged(Editable text) { + /** + * Not private so it can be called from an inner class without going + * through a thunk. + */ + void sendAfterTextChanged(Editable text) { if (mListeners != null) { final ArrayList list = mListeners; final int count = list.size(); @@ -4207,105 +5069,118 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } } - private class ChangeWatcher - extends Handler - implements TextWatcher, SpanWatcher { - public void beforeTextChanged(CharSequence buffer, int start, - int before, int after) { - TextView.this.sendBeforeTextChanged(buffer, start, before, after); + /** + * Not private so it can be called from an inner class without going + * through a thunk. + */ + void handleTextChanged(CharSequence buffer, int start, + int before, int after) { + invalidate(); + + int curs = Selection.getSelectionStart(buffer); + + if (curs >= 0 || (mGravity & Gravity.VERTICAL_GRAVITY_MASK) == + Gravity.BOTTOM) { + registerForPreDraw(); } - public void onTextChanged(CharSequence buffer, int start, - int before, int after) { - invalidate(); + if (curs >= 0) { + mHighlightPathBogus = true; - int curs = Selection.getSelectionStart(buffer); + if (isFocused()) { + mShowCursor = SystemClock.uptimeMillis(); + makeBlink(); + } + } - if (curs >= 0 || (mGravity & Gravity.VERTICAL_GRAVITY_MASK) == - Gravity.BOTTOM) { - registerForPreDraw(); + checkForResize(); + + sendOnTextChanged(buffer, start, before, after); + onTextChanged(buffer, start, before, after); + } + + /** + * Not private so it can be called from an inner class without going + * through a thunk. + */ + void spanChange(Spanned buf, Object what, int o, int n) { + // XXX Make the start and end move together if this ends up + // spending too much time invalidating. + + if (what == Selection.SELECTION_END) { + mHighlightPathBogus = true; + + if (!isFocused()) { + mSelectionMoved = true; } - if (curs >= 0) { - mHighlightPathBogus = true; + if (o >= 0 || n >= 0) { + invalidateCursor(Selection.getSelectionStart(buf), o, n); + registerForPreDraw(); if (isFocused()) { mShowCursor = SystemClock.uptimeMillis(); makeBlink(); } } - - checkForResize(); - - TextView.this.sendOnTextChanged(buffer, start, before, after); - TextView.this.onTextChanged(buffer, start, before, after); } - public void afterTextChanged(Editable buffer) { - TextView.this.sendAfterTextChanged(buffer); - } - - private void spanChange(Spanned buf, Object what, int o, int n) { - // XXX Make the start and end move together if this ends up - // spending too much time invalidating. + if (what == Selection.SELECTION_START) { + mHighlightPathBogus = true; - if (what == Selection.SELECTION_END) { - mHighlightPathBogus = true; - - if (!isFocused()) { - mSelectionMoved = true; - } - - if (o >= 0 || n >= 0) { - invalidateCursor(Selection.getSelectionStart(buf), o, n); - registerForPreDraw(); + if (!isFocused()) { + mSelectionMoved = true; + } - if (isFocused()) { - mShowCursor = SystemClock.uptimeMillis(); - makeBlink(); - } - } + if (o >= 0 || n >= 0) { + invalidateCursor(Selection.getSelectionEnd(buf), o, n); } + } - if (what == Selection.SELECTION_START) { - mHighlightPathBogus = true; + if (what instanceof UpdateLayout || + what instanceof ParagraphStyle) { + invalidate(); + mHighlightPathBogus = true; + checkForResize(); + } - if (!isFocused()) { - mSelectionMoved = true; - } + if (MetaKeyKeyListener.isMetaTracker(buf, what)) { + mHighlightPathBogus = true; - if (o >= 0 || n >= 0) { - invalidateCursor(Selection.getSelectionEnd(buf), o, n); - } + if (Selection.getSelectionStart(buf) >= 0) { + invalidateCursor(); } + } + } - if (what instanceof UpdateLayout || - what instanceof ParagraphStyle) { - invalidate(); - mHighlightPathBogus = true; - checkForResize(); - } + private class ChangeWatcher + implements TextWatcher, SpanWatcher { + public void beforeTextChanged(CharSequence buffer, int start, + int before, int after) { + TextView.this.sendBeforeTextChanged(buffer, start, before, after); + } - if (MetaKeyKeyListener.isMetaTracker(buf, what)) { - mHighlightPathBogus = true; + public void onTextChanged(CharSequence buffer, int start, + int before, int after) { + TextView.this.handleTextChanged(buffer, start, before, after); + } - if (Selection.getSelectionStart(buf) >= 0) { - invalidateCursor(); - } - } + public void afterTextChanged(Editable buffer) { + TextView.this.sendAfterTextChanged(buffer); + TextView.this.reportExtractedText(); } public void onSpanChanged(Spannable buf, Object what, int s, int e, int st, int en) { - spanChange(buf, what, s, st); + TextView.this.spanChange(buf, what, s, st); } public void onSpanAdded(Spannable buf, Object what, int s, int e) { - spanChange(buf, what, -1, s); + TextView.this.spanChange(buf, what, -1, s); } public void onSpanRemoved(Spannable buf, Object what, int s, int e) { - spanChange(buf, what, s, -1); + TextView.this.spanChange(buf, what, s, -1); } } @@ -4378,6 +5253,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } } + startStopMarquee(focused); + if (mTransformation != null) { mTransformation.onFocusChanged(this, mText, focused, direction, previouslyFocusedRect); @@ -4386,6 +5263,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener super.onFocusChanged(focused, direction, previouslyFocusedRect); } + @Override public void onWindowFocusChanged(boolean hasWindowFocus) { super.onWindowFocusChanged(hasWindowFocus); @@ -4403,6 +5281,23 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener mBlink.cancel(); } } + + startStopMarquee(hasWindowFocus); + } + + @Override + public void setSelected(boolean selected) { + boolean wasSelected = isSelected(); + + super.setSelected(selected); + + if (selected != wasSelected && mEllipsize == TextUtils.TruncateAt.MARQUEE) { + if (selected) { + startMarquee(); + } else { + stopMarquee(); + } + } } @Override @@ -4421,7 +5316,18 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener if (mMovement != null && mText instanceof Spannable && mLayout != null) { - if (mMovement.onTouchEvent(this, (Spannable) mText, event)) { + boolean moved = mMovement.onTouchEvent(this, (Spannable) mText, event); + + if (mText instanceof Editable + && mInputType != EditorInfo.TYPE_NULL) { + if (event.getAction() == MotionEvent.ACTION_UP && isFocused()) { + InputMethodManager imm = (InputMethodManager) + getContext().getSystemService(Context.INPUT_METHOD_SERVICE); + imm.showSoftInput(this); + } + } + + if (moved) { return true; } } @@ -4489,6 +5395,52 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } } + @Override + protected float getLeftFadingEdgeStrength() { + if (mEllipsize == TextUtils.TruncateAt.MARQUEE) { + if (mMarquee != null && !mMarquee.isStopped()) { + final Marquee marquee = mMarquee; + return marquee.mScroll / getHorizontalFadingEdgeLength(); + } else if (getLineCount() == 1) { + switch (mGravity & Gravity.HORIZONTAL_GRAVITY_MASK) { + case Gravity.LEFT: + return 0.0f; + case Gravity.RIGHT: + return (mLayout.getLineRight(0) - (mRight - mLeft) - + getCompoundPaddingLeft() - getCompoundPaddingRight() - + mLayout.getLineLeft(0)) / getHorizontalFadingEdgeLength(); + case Gravity.CENTER_HORIZONTAL: + return 0.0f; + } + } + } + return super.getLeftFadingEdgeStrength(); + } + + @Override + protected float getRightFadingEdgeStrength() { + if (mEllipsize == TextUtils.TruncateAt.MARQUEE) { + if (mMarquee != null && !mMarquee.isStopped()) { + final Marquee marquee = mMarquee; + return (marquee.mMaxScroll - marquee.mScroll) / getHorizontalFadingEdgeLength(); + } else if (getLineCount() == 1) { + switch (mGravity & Gravity.HORIZONTAL_GRAVITY_MASK) { + case Gravity.LEFT: + return (mLayout.getLineRight(0) - mScrollX - (mRight - mLeft) - + getCompoundPaddingLeft() - getCompoundPaddingRight()) / + getHorizontalFadingEdgeLength(); + case Gravity.RIGHT: + return 0.0f; + case Gravity.CENTER_HORIZONTAL: + return (mLayout.getLineWidth(0) - ((mRight - mLeft) - + getCompoundPaddingLeft() - getCompoundPaddingRight())) / + getHorizontalFadingEdgeLength(); + } + } + } + return super.getRightFadingEdgeStrength(); + } + @Override protected int computeHorizontalScrollRange() { if (mLayout != null) @@ -4599,6 +5551,10 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } private boolean canCut() { + if (mTransformation instanceof PasswordTransformationMethod) { + return false; + } + if (mText.length() > 0 && getSelectionStart() >= 0) { if (mText instanceof Editable && mInput != null) { return true; @@ -4609,6 +5565,10 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } private boolean canCopy() { + if (mTransformation instanceof PasswordTransformationMethod) { + return false; + } + if (mText.length() > 0 && getSelectionStart() >= 0) { return true; } @@ -4632,8 +5592,22 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener @Override protected void onCreateContextMenu(ContextMenu menu) { super.onCreateContextMenu(menu); + boolean added = false; if (!isFocused()) { + if (isFocusable() && mInput != null) { + if (canCopy()) { + MenuHandler handler = new MenuHandler(); + int name = com.android.internal.R.string.copyAll; + + menu.add(0, ID_COPY, 0, name). + setOnMenuItemClickListener(handler). + setAlphabeticShortcut('c'); + menu.setHeaderTitle(com.android.internal.R.string. + editTextMenuTitle); + } + } + return; } @@ -4644,6 +5618,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener com.android.internal.R.string.selectAll). setOnMenuItemClickListener(handler). setAlphabeticShortcut('a'); + added = true; } boolean selection = getSelectionStart() != getSelectionEnd(); @@ -4659,6 +5634,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener menu.add(0, ID_CUT, 0, name). setOnMenuItemClickListener(handler). setAlphabeticShortcut('x'); + added = true; } if (canCopy()) { @@ -4672,12 +5648,14 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener menu.add(0, ID_COPY, 0, name). setOnMenuItemClickListener(handler). setAlphabeticShortcut('c'); + added = true; } if (canPaste()) { menu.add(0, ID_PASTE, 0, com.android.internal.R.string.paste). setOnMenuItemClickListener(handler). setAlphabeticShortcut('v'); + added = true; } if (mText instanceof Spanned) { @@ -4693,15 +5671,28 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener menu.add(0, ID_COPY_URL, 0, com.android.internal.R.string.copyUrl). setOnMenuItemClickListener(handler); + added = true; } } + + InputMethodManager imm = InputMethodManager.peekInstance(); + if (imm != null && imm.isActive(this)) { + menu.add(1, ID_SWITCH_IME, 0, com.android.internal.R.string.inputMethod). + setOnMenuItemClickListener(handler); + added = true; + } + + if (added) { + menu.setHeaderTitle(com.android.internal.R.string.editTextMenuTitle); + } } - private static final int ID_SELECT_ALL = 101; - private static final int ID_CUT = 102; - private static final int ID_COPY = 103; - private static final int ID_PASTE = 104; - private static final int ID_COPY_URL = 105; + private static final int ID_SELECT_ALL = com.android.internal.R.id.selectAll; + private static final int ID_CUT = com.android.internal.R.id.cut; + private static final int ID_COPY = com.android.internal.R.id.copy; + private static final int ID_PASTE = com.android.internal.R.id.paste; + private static final int ID_COPY_URL = com.android.internal.R.id.copyUrl; + private static final int ID_SWITCH_IME = com.android.internal.R.id.inputMethod; private class MenuHandler implements MenuItem.OnMenuItemClickListener { public boolean onMenuItemClick(MenuItem item) { @@ -4713,6 +5704,11 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener int selStart = getSelectionStart(); int selEnd = getSelectionEnd(); + if (!isFocused()) { + selStart = 0; + selEnd = mText.length(); + } + int min = Math.min(selStart, selEnd); int max = Math.max(selStart, selEnd); @@ -4769,7 +5765,14 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } return true; - } + + case ID_SWITCH_IME: + InputMethodManager imm = InputMethodManager.peekInstance(); + if (imm != null) { + imm.showInputMethodPicker(); + } + return true; + } return false; } @@ -4790,10 +5793,12 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener private CharSequence mTransformed; private BufferType mBufferType = BufferType.NORMAL; + private int mInputType = EditorInfo.TYPE_NULL; private CharSequence mHint; private Layout mHintLayout; private KeyListener mInput; + private MovementMethod mMovement; private TransformationMethod mTransformation; private ChangeWatcher mChangeWatcher; @@ -4842,7 +5847,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener // tmp primitives, so we don't alloc them on each draw private Path mHighlightPath; private boolean mHighlightPathBogus = true; - private static RectF sTempRect = new RectF(); + private static final RectF sTempRect = new RectF(); // XXX should be much larger private static final int VERY_WIDE = 16384; @@ -4858,8 +5863,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener private BoringLayout mSavedLayout, mSavedHintLayout; - - private static final InputFilter[] NO_FILTERS = new InputFilter[0]; private InputFilter[] mFilters = NO_FILTERS; private static final Spanned EMPTY_SPANNED = new SpannedString(""); diff --git a/core/java/android/widget/VideoView.java b/core/java/android/widget/VideoView.java index da3c2aa38f73844bcdb0cf9e43fb1abd37572ba4..df4015670bd6dceeee6554450edde33ea97f7b11 100644 --- a/core/java/android/widget/VideoView.java +++ b/core/java/android/widget/VideoView.java @@ -182,6 +182,7 @@ public class VideoView extends SurfaceView implements MediaPlayerControl { try { mMediaPlayer = new MediaPlayer(); mMediaPlayer.setOnPreparedListener(mPreparedListener); + mMediaPlayer.setOnVideoSizeChangedListener(mSizeChangedListener); mIsPrepared = false; mMediaPlayer.setOnCompletionListener(mCompletionListener); mMediaPlayer.setOnErrorListener(mErrorListener); @@ -220,6 +221,17 @@ public class VideoView extends SurfaceView implements MediaPlayerControl { } } + MediaPlayer.OnVideoSizeChangedListener mSizeChangedListener = + new MediaPlayer.OnVideoSizeChangedListener() { + public void onVideoSizeChanged(MediaPlayer mp, int width, int height) { + mVideoWidth = mp.getVideoWidth(); + mVideoHeight = mp.getVideoHeight(); + if (mVideoWidth != 0 && mVideoHeight != 0) { + getHolder().setFixedSize(mVideoWidth, mVideoHeight); + } + } + }; + MediaPlayer.OnPreparedListener mPreparedListener = new MediaPlayer.OnPreparedListener() { public void onPrepared(MediaPlayer mp) { // briefly show the mediacontroller @@ -241,26 +253,32 @@ public class VideoView extends SurfaceView implements MediaPlayerControl { // start the video here instead of in the callback. if (mSeekWhenPrepared != 0) { mMediaPlayer.seekTo(mSeekWhenPrepared); + mSeekWhenPrepared = 0; } if (mStartWhenPrepared) { mMediaPlayer.start(); + mStartWhenPrepared = false; if (mMediaController != null) { mMediaController.show(); } - } else if (!isPlaying() && (mSeekWhenPrepared != 0 || getCurrentPosition() > 0)) { + } else if (!isPlaying() && + (mSeekWhenPrepared != 0 || getCurrentPosition() > 0)) { if (mMediaController != null) { - mMediaController.show(0); // show the media controls when we're paused into a video and make 'em stick. + // Show the media controls when we're paused into a video and make 'em stick. + mMediaController.show(0); } } } } else { - Log.d("VideoView", "Couldn't get video size after prepare(): " + - mVideoWidth + "/" + mVideoHeight); - // The file was probably truncated or corrupt. Start anyway, so - // that we play whatever short snippet is there and then get - // the "playback completed" event. + // We don't know the video size yet, but should start anyway. + // The video size might be reported to us later. + if (mSeekWhenPrepared != 0) { + mMediaPlayer.seekTo(mSeekWhenPrepared); + mSeekWhenPrepared = 0; + } if (mStartWhenPrepared) { mMediaPlayer.start(); + mStartWhenPrepared = false; } } } @@ -370,9 +388,10 @@ public class VideoView extends SurfaceView implements MediaPlayerControl { { mSurfaceWidth = w; mSurfaceHeight = h; - if (mIsPrepared && mVideoWidth == w && mVideoHeight == h) { + if (mMediaPlayer != null && mIsPrepared && mVideoWidth == w && mVideoHeight == h) { if (mSeekWhenPrepared != 0) { mMediaPlayer.seekTo(mSeekWhenPrepared); + mSeekWhenPrepared = 0; } mMediaPlayer.start(); if (mMediaController != null) { diff --git a/core/java/com/android/internal/app/AlertController.java b/core/java/com/android/internal/app/AlertController.java index 53b9654901fdde64e0f6327737af304a27362552..989f97244543ff335bc7273c0847e1c87b1c46c6 100644 --- a/core/java/com/android/internal/app/AlertController.java +++ b/core/java/com/android/internal/app/AlertController.java @@ -34,6 +34,7 @@ import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.view.Window; +import android.view.WindowManager; import android.view.ViewGroup.LayoutParams; import android.widget.AdapterView; import android.widget.ArrayAdapter; @@ -68,23 +69,33 @@ public class AlertController { private View mView; - private Button mButton1; + private int mViewSpacingLeft; + + private int mViewSpacingTop; + + private int mViewSpacingRight; + + private int mViewSpacingBottom; + + private boolean mViewSpacingSpecified = false; + + private Button mButtonPositive; - private CharSequence mButton1Text; + private CharSequence mButtonPositiveText; - private Message mButton1Message; + private Message mButtonPositiveMessage; - private Button mButton2; + private Button mButtonNegative; - private CharSequence mButton2Text; + private CharSequence mButtonNegativeText; - private Message mButton2Message; + private Message mButtonNegativeMessage; - private Button mButton3; + private Button mButtonNeutral; - private CharSequence mButton3Text; + private CharSequence mButtonNeutralText; - private Message mButton3Message; + private Message mButtonNeutralMessage; private ScrollView mScrollView; @@ -111,12 +122,12 @@ public class AlertController { View.OnClickListener mButtonHandler = new View.OnClickListener() { public void onClick(View v) { Message m = null; - if (v == mButton1 && mButton1Message != null) { - m = Message.obtain(mButton1Message); - } else if (v == mButton2 && mButton2Message != null) { - m = Message.obtain(mButton2Message); - } else if (v == mButton3 && mButton3Message != null) { - m = Message.obtain(mButton3Message); + if (v == mButtonPositive && mButtonPositiveMessage != null) { + m = Message.obtain(mButtonPositiveMessage); + } else if (v == mButtonNegative && mButtonNegativeMessage != null) { + m = Message.obtain(mButtonNegativeMessage); + } else if (v == mButtonNeutral && mButtonNeutralMessage != null) { + m = Message.obtain(mButtonNeutralMessage); } if (m != null) { m.sendToTarget(); @@ -142,9 +153,9 @@ public class AlertController { public void handleMessage(Message msg) { switch (msg.what) { - case DialogInterface.BUTTON1: - case DialogInterface.BUTTON2: - case DialogInterface.BUTTON3: + case DialogInterface.BUTTON_POSITIVE: + case DialogInterface.BUTTON_NEGATIVE: + case DialogInterface.BUTTON_NEUTRAL: ((DialogInterface.OnClickListener) msg.obj).onClick(mDialog.get(), msg.what); break; @@ -165,6 +176,10 @@ public class AlertController { /* We use a custom title so never request a window title */ mWindow.requestFeature(Window.FEATURE_NO_TITLE); + if (mView == null) { + mWindow.setFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM, + WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM); + } mWindow.setContentView(com.android.internal.R.layout.alert_dialog); setupView(); } @@ -191,66 +206,64 @@ public class AlertController { } /** - * Set the view to display in that dialog. + * Set the view to display in the dialog. */ public void setView(View view) { mView = view; + mViewSpacingSpecified = false; } - - public void setButton(CharSequence text, Message msg) { - mButton1Text = text; - mButton1Message = msg; - } - - public void setButton2(CharSequence text, Message msg) { - mButton2Text = text; - mButton2Message = msg; - } - - public void setButton3(CharSequence text, Message msg) { - mButton3Text = text; - mButton3Message = msg; - } - + /** - * Set a listener to be invoked when button 1 of the dialog is pressed. - * @param text The text to display in button 1. - * @param listener The {@link DialogInterface.OnClickListener} to use. + * Set the view to display in the dialog along with the spacing around that view */ - public void setButton(CharSequence text, final DialogInterface.OnClickListener listener) { - mButton1Text = text; - if (listener != null) { - mButton1Message = mHandler.obtainMessage(DialogInterface.BUTTON1, listener); - } else { - mButton1Message = null; - } + public void setView(View view, int viewSpacingLeft, int viewSpacingTop, int viewSpacingRight, + int viewSpacingBottom) { + mView = view; + mViewSpacingSpecified = true; + mViewSpacingLeft = viewSpacingLeft; + mViewSpacingTop = viewSpacingTop; + mViewSpacingRight = viewSpacingRight; + mViewSpacingBottom = viewSpacingBottom; } /** - * Set a listener to be invoked when button 2 of the dialog is pressed. - * @param text The text to display in button 2. + * Sets a click listener or a message to be sent when the button is clicked. + * You only need to pass one of {@code listener} or {@code msg}. + * + * @param whichButton Which button, can be one of + * {@link DialogInterface#BUTTON_POSITIVE}, + * {@link DialogInterface#BUTTON_NEGATIVE}, or + * {@link DialogInterface#BUTTON_NEUTRAL} + * @param text The text to display in positive button. * @param listener The {@link DialogInterface.OnClickListener} to use. + * @param msg The {@link Message} to be sent when clicked. */ - public void setButton2(CharSequence text, final DialogInterface.OnClickListener listener) { - mButton2Text = text; - if (listener != null) { - mButton2Message = mHandler.obtainMessage(DialogInterface.BUTTON2, listener); - } else { - mButton2Message = null; + public void setButton(int whichButton, CharSequence text, + DialogInterface.OnClickListener listener, Message msg) { + + if (msg == null && listener != null) { + msg = mHandler.obtainMessage(whichButton, listener); } - } + + switch (whichButton) { - /** - * Set a listener to be invoked when button 3 of the dialog is pressed. - * @param text The text to display in button 3. - * @param listener The {@link DialogInterface.OnClickListener} to use. - */ - public void setButton3(CharSequence text, final DialogInterface.OnClickListener listener) { - mButton3Text = text; - if (listener != null) { - mButton3Message = mHandler.obtainMessage(DialogInterface.BUTTON3, listener); - } else { - mButton3Message = null; + case DialogInterface.BUTTON_POSITIVE: + mButtonPositiveText = text; + mButtonPositiveMessage = msg; + break; + + case DialogInterface.BUTTON_NEGATIVE: + mButtonNegativeText = text; + mButtonNegativeMessage = msg; + break; + + case DialogInterface.BUTTON_NEUTRAL: + mButtonNeutralText = text; + mButtonNeutralMessage = msg; + break; + + default: + throw new IllegalArgumentException("Button does not exist"); } } @@ -285,6 +298,19 @@ public class AlertController { return mListView; } + public Button getButton(int whichButton) { + switch (whichButton) { + case DialogInterface.BUTTON_POSITIVE: + return mButtonPositiveMessage != null ? mButtonPositive : null; + case DialogInterface.BUTTON_NEGATIVE: + return mButtonNegativeMessage != null ? mButtonNegative : null; + case DialogInterface.BUTTON_NEUTRAL: + return mButtonNeutralMessage != null ? mButtonNeutral : null; + default: + return null; + } + } + public boolean onKeyDown(int keyCode, KeyEvent event) { if (mScrollView != null && mScrollView.executeKeyEvent(event)) return true; return false; @@ -303,7 +329,7 @@ public class AlertController { LinearLayout topPanel = (LinearLayout) mWindow.findViewById(R.id.topPanel); TypedArray a = mContext.obtainStyledAttributes( null, com.android.internal.R.styleable.AlertDialog, com.android.internal.R.attr.alertDialogStyle, 0); - boolean hasTitle = setupTitle(topPanel, hasButtons); + boolean hasTitle = setupTitle(topPanel); View buttonPanel = mWindow.findViewById(R.id.buttonPanel); if (!hasButtons) { @@ -315,6 +341,10 @@ public class AlertController { customPanel = (FrameLayout) mWindow.findViewById(R.id.customPanel); FrameLayout custom = (FrameLayout) mWindow.findViewById(R.id.custom); custom.addView(mView, new LayoutParams(FILL_PARENT, WRAP_CONTENT)); + if (mViewSpacingSpecified) { + custom.setPadding(mViewSpacingLeft, mViewSpacingTop, mViewSpacingRight, + mViewSpacingBottom); + } } else { mWindow.findViewById(R.id.customPanel).setVisibility(View.GONE); } @@ -331,7 +361,7 @@ public class AlertController { a.recycle(); } - private boolean setupTitle(LinearLayout topPanel, boolean hasButtons) { + private boolean setupTitle(LinearLayout topPanel) { boolean hasTitle = true; if (mCustomTitleView != null) { @@ -352,40 +382,13 @@ public class AlertController { /* Display the title if a title is supplied, else hide it */ mTitleView = (TextView) mWindow.findViewById(R.id.alertTitle); - + mTitleView.setText(mTitle); - - /* The title font size and icon varies depending on - * what else is displayed within the dialog. - */ - if (mListView != null) { - - /* If a ListView is displayed then ensure the title - * is only 1 line and use a special icon. - */ - mTitleView.setSingleLine(); - mTitleView.setEllipsize(TruncateAt.END); - mIconView.setImageResource( - R.drawable.ic_dialog_menu_generic); - } else if ((mMessage != null) && hasButtons) { - - /* Has a message and buttons, we want the title to - * be a single line but large. - */ - mTitleView.setSingleLine(); - mTitleView.setEllipsize(TruncateAt.END); - mTitleView.setTextSize(getLargeTextSize()); - } else { - - /* We have a Title and buttons or we have title, - * and custom content. In either case the layout - * handles it so do nothing. - */ - } + mIconView.setImageResource(R.drawable.ic_dialog_menu_generic); /* Do this last so that if the user has supplied any * icons we use them instead of the default ones. If the - * user has specified 0 then make it dissapear. + * user has specified 0 then make it disappear. */ if (mIconId > 0) { mIconView.setImageResource(mIconId); @@ -414,17 +417,6 @@ public class AlertController { return hasTitle; } - private int getLargeTextSize() { - TypedArray a = - mContext.obtainStyledAttributes( - R.style.TextAppearance_Large, - R.styleable.TextAppearance); - int textSize = a.getDimensionPixelSize( - R.styleable.TextAppearance_textSize, 22); - a.recycle(); - return textSize; - } - private void setupContent(LinearLayout contentPanel) { mScrollView = (ScrollView) mWindow.findViewById(R.id.scrollView); mScrollView.setFocusable(false); @@ -452,65 +444,65 @@ public class AlertController { private boolean setupButtons() { View defaultButton = null; - int BUTTON1 = 1; - int BUTTON2 = 2; - int BUTTON3 = 4; - int whichButton = 0; - mButton1 = (Button) mWindow.findViewById(R.id.button1); - mButton1.setOnClickListener(mButtonHandler); - - if (TextUtils.isEmpty(mButton1Text)) { - mButton1.setVisibility(View.GONE); + int BIT_BUTTON_POSITIVE = 1; + int BIT_BUTTON_NEGATIVE = 2; + int BIT_BUTTON_NEUTRAL = 4; + int whichButtons = 0; + mButtonPositive = (Button) mWindow.findViewById(R.id.button1); + mButtonPositive.setOnClickListener(mButtonHandler); + + if (TextUtils.isEmpty(mButtonPositiveText)) { + mButtonPositive.setVisibility(View.GONE); } else { - mButton1.setText(mButton1Text); - mButton1.setVisibility(View.VISIBLE); - defaultButton = mButton1; - whichButton = whichButton | BUTTON1; + mButtonPositive.setText(mButtonPositiveText); + mButtonPositive.setVisibility(View.VISIBLE); + defaultButton = mButtonPositive; + whichButtons = whichButtons | BIT_BUTTON_POSITIVE; } - mButton2 = (Button) mWindow.findViewById(R.id.button2); - mButton2.setOnClickListener(mButtonHandler); + mButtonNegative = (Button) mWindow.findViewById(R.id.button2); + mButtonNegative.setOnClickListener(mButtonHandler); - if (TextUtils.isEmpty(mButton2Text)) { - mButton2.setVisibility(View.GONE); + if (TextUtils.isEmpty(mButtonNegativeText)) { + mButtonNegative.setVisibility(View.GONE); } else { - mButton2.setText(mButton2Text); - mButton2.setVisibility(View.VISIBLE); + mButtonNegative.setText(mButtonNegativeText); + mButtonNegative.setVisibility(View.VISIBLE); if (defaultButton == null) { - defaultButton = mButton2; + defaultButton = mButtonNegative; } - whichButton = whichButton | BUTTON2; + whichButtons = whichButtons | BIT_BUTTON_NEGATIVE; } - mButton3 = (Button) mWindow.findViewById(R.id.button3); - mButton3.setOnClickListener(mButtonHandler); + mButtonNeutral = (Button) mWindow.findViewById(R.id.button3); + mButtonNeutral.setOnClickListener(mButtonHandler); - if (TextUtils.isEmpty(mButton3Text)) { - mButton3.setVisibility(View.GONE); + if (TextUtils.isEmpty(mButtonNeutralText)) { + mButtonNeutral.setVisibility(View.GONE); } else { - mButton3.setText(mButton3Text); - mButton3.setVisibility(View.VISIBLE); + mButtonNeutral.setText(mButtonNeutralText); + mButtonNeutral.setVisibility(View.VISIBLE); if (defaultButton == null) { - defaultButton = mButton3; + defaultButton = mButtonNeutral; } - whichButton = whichButton | BUTTON3; + whichButtons = whichButtons | BIT_BUTTON_NEUTRAL; } /* * If we only have 1 button it should be centered on the layout and * expand to fill 50% of the available space. */ - if (whichButton == BUTTON1) { - centerButton(mButton1); - } else if (whichButton == BUTTON2) { - centerButton(mButton3); - } else if (whichButton == BUTTON3) { - centerButton(mButton3); + if (whichButtons == BIT_BUTTON_POSITIVE) { + centerButton(mButtonPositive); + } else if (whichButtons == BIT_BUTTON_NEGATIVE) { + centerButton(mButtonNeutral); + } else if (whichButtons == BIT_BUTTON_NEUTRAL) { + centerButton(mButtonNeutral); } - return whichButton != 0; + return whichButtons != 0; } private void centerButton(Button button) { @@ -677,6 +669,11 @@ public class AlertController { public ListAdapter mAdapter; public DialogInterface.OnClickListener mOnClickListener; public View mView; + public int mViewSpacingLeft; + public int mViewSpacingTop; + public int mViewSpacingRight; + public int mViewSpacingBottom; + public boolean mViewSpacingSpecified = false; public boolean[] mCheckedItems; public boolean mIsMultiChoice; public boolean mIsSingleChoice; @@ -726,13 +723,16 @@ public class AlertController { dialog.setMessage(mMessage); } if (mPositiveButtonText != null) { - dialog.setButton(mPositiveButtonText, mPositiveButtonListener); + dialog.setButton(DialogInterface.BUTTON_POSITIVE, mPositiveButtonText, + mPositiveButtonListener, null); } if (mNegativeButtonText != null) { - dialog.setButton2(mNegativeButtonText, mNegativeButtonListener); + dialog.setButton(DialogInterface.BUTTON_NEGATIVE, mNegativeButtonText, + mNegativeButtonListener, null); } if (mNeutralButtonText != null) { - dialog.setButton3(mNeutralButtonText, mNeutralButtonListener); + dialog.setButton(DialogInterface.BUTTON_NEUTRAL, mNeutralButtonText, + mNeutralButtonListener, null); } if (mForceInverseBackground) { dialog.setInverseBackgroundForced(true); @@ -743,7 +743,12 @@ public class AlertController { createListView(dialog); } if (mView != null) { - dialog.setView(mView); + if (mViewSpacingSpecified) { + dialog.setView(mView, mViewSpacingLeft, mViewSpacingTop, mViewSpacingRight, + mViewSpacingBottom); + } else { + dialog.setView(mView); + } } /* @@ -764,8 +769,7 @@ public class AlertController { adapter = new ArrayAdapter( mContext, R.layout.select_dialog_multichoice, R.id.text1, mItems) { @Override - public View getView(int position, View convertView, - ViewGroup parent) { + public View getView(int position, View convertView, ViewGroup parent) { View view = super.getView(position, convertView, parent); if (mCheckedItems != null) { boolean isItemChecked = mCheckedItems[position]; @@ -778,24 +782,27 @@ public class AlertController { }; } else { adapter = new CursorAdapter(mContext, mCursor, false) { - + private final int mLabelIndex; + private final int mIsCheckedIndex; + + { + final Cursor cursor = getCursor(); + mLabelIndex = cursor.getColumnIndexOrThrow(mLabelColumn); + mIsCheckedIndex = cursor.getColumnIndexOrThrow(mIsCheckedColumn); + } + @Override - public void bindView(View view, Context context, - Cursor cursor) { + public void bindView(View view, Context context, Cursor cursor) { CheckedTextView text = (CheckedTextView) view.findViewById(R.id.text1); - text.setText(cursor.getString(cursor.getColumnIndexOrThrow(mLabelColumn))); + text.setText(cursor.getString(mLabelIndex)); + listView.setItemChecked(cursor.getPosition(), + cursor.getInt(mIsCheckedIndex) == 1); } @Override - public View newView(Context context, Cursor cursor, - ViewGroup parent) { - View view = mInflater.inflate( - R.layout.select_dialog_multichoice, parent, false); - bindView(view, context, cursor); - if (cursor.getInt(cursor.getColumnIndexOrThrow(mIsCheckedColumn)) == 1) { - listView.setItemChecked(cursor.getPosition(), true); - } - return view; + public View newView(Context context, Cursor cursor, ViewGroup parent) { + return mInflater.inflate(R.layout.select_dialog_multichoice, + parent, false); } }; diff --git a/core/java/com/android/internal/app/IBatteryStats.aidl b/core/java/com/android/internal/app/IBatteryStats.aidl old mode 100755 new mode 100644 index bb9fa0b094e72490d7c40f051b5b84726f28b748..434850c439ba98abc643f32b5539df2b2d2c1636 --- a/core/java/com/android/internal/app/IBatteryStats.aidl +++ b/core/java/com/android/internal/app/IBatteryStats.aidl @@ -16,9 +16,14 @@ package com.android.internal.app; +import com.android.internal.os.BatteryStatsImpl; + interface IBatteryStats { + BatteryStatsImpl getStatistics(); void noteStartWakelock(int uid, String name, int type); void noteStopWakelock(int uid, String name, int type); + void noteStartSensor(int uid, int sensor); + void noteStopSensor(int uid, int sensor); void setOnBattery(boolean onBattery); long getAwakeTimeBattery(); long getAwakeTimePlugged(); diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java index d5a9f8c30addca6f20870f69992c375042ce6fd2..e907a04668777b5c2d9ba2540bdab2ad7a98619e 100644 --- a/core/java/com/android/internal/app/ResolverActivity.java +++ b/core/java/com/android/internal/app/ResolverActivity.java @@ -17,9 +17,6 @@ package com.android.internal.app; import com.android.internal.R; - -import android.app.Activity; -import android.app.ListActivity; import android.content.ComponentName; import android.content.Context; import android.content.DialogInterface; @@ -33,19 +30,17 @@ import android.os.Bundle; import android.os.PatternMatcher; import android.util.Config; import android.util.Log; -import android.view.KeyEvent; import android.view.View; import android.view.ViewGroup; import android.view.LayoutInflater; -import android.view.Window; import android.widget.BaseAdapter; import android.widget.CheckBox; import android.widget.CompoundButton; import android.widget.ImageView; -import android.widget.ListView; import android.widget.TextView; - +import java.util.ArrayList; import java.util.Collections; +import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Set; @@ -55,35 +50,37 @@ import java.util.Set; * which there is more than one matching activity, allowing the user to decide * which to go to. It is not normally used directly by application developers. */ -public class ResolverActivity extends AlertActivity implements +public class ResolverActivity extends AlertActivity implements DialogInterface.OnClickListener, CheckBox.OnCheckedChangeListener { private ResolveListAdapter mAdapter; private CheckBox mAlwaysCheck; private TextView mClearDefaultHint; - + private PackageManager mPm; + @Override protected void onCreate(Bundle savedInstanceState) { onCreate(savedInstanceState, new Intent(getIntent()), getResources().getText(com.android.internal.R.string.whichApplication), true); } - + protected void onCreate(Bundle savedInstanceState, Intent intent, CharSequence title, boolean alwaysUseOption) { super.onCreate(savedInstanceState); - + mPm = getPackageManager(); intent.setComponent(null); AlertController.AlertParams ap = mAlertParams; - + ap.mTitle = title; ap.mOnClickListener = this; - + if (alwaysUseOption) { LayoutInflater inflater = (LayoutInflater) getSystemService( Context.LAYOUT_INFLATER_SERVICE); ap.mView = inflater.inflate(R.layout.always_use_checkbox, null); mAlwaysCheck = (CheckBox)ap.mView.findViewById(com.android.internal.R.id.alwaysUse); + mAlwaysCheck.setText(R.string.alwaysUse); mAlwaysCheck.setOnCheckedChangeListener(this); mClearDefaultHint = (TextView)ap.mView.findViewById( com.android.internal.R.id.clearDefaultHint); @@ -99,10 +96,10 @@ public class ResolverActivity extends AlertActivity implements } else { ap.mMessage = getResources().getText(com.android.internal.R.string.noApplications); } - + setupAlert(); } - + public void onClick(DialogInterface dialog, int which) { ResolveInfo ri = mAdapter.resolveInfoForPosition(which); Intent intent = mAdapter.intentForPosition(which); @@ -110,7 +107,7 @@ public class ResolverActivity extends AlertActivity implements if ((mAlwaysCheck != null) && mAlwaysCheck.isChecked()) { // Build a reasonable intent filter, based on what matched. IntentFilter filter = new IntentFilter(); - + if (intent.getAction() != null) { filter.addAction(intent.getAction()); } @@ -121,7 +118,7 @@ public class ResolverActivity extends AlertActivity implements } } filter.addCategory(Intent.CATEGORY_DEFAULT); - + int cat = ri.match&IntentFilter.MATCH_CATEGORY_MASK; Uri data = intent.getData(); if (cat == IntentFilter.MATCH_CATEGORY_TYPE) { @@ -136,7 +133,7 @@ public class ResolverActivity extends AlertActivity implements } } else if (data != null && data.getScheme() != null) { filter.addDataScheme(data.getScheme()); - + // Look through the resolved filter to determine which part // of it matched the original Intent. Iterator aIt = ri.filter.authoritiesIterator(); @@ -163,13 +160,13 @@ public class ResolverActivity extends AlertActivity implements } } } - + if (filter != null) { final int N = mAdapter.mList.size(); ComponentName[] set = new ComponentName[N]; int bestMatch = 0; for (int i=0; i bestMatch) bestMatch = r.match; @@ -178,51 +175,135 @@ public class ResolverActivity extends AlertActivity implements intent.getComponent()); } } - + if (intent != null) { startActivity(intent); } finish(); } - + + private final class DisplayResolveInfo { + ResolveInfo ri; + CharSequence displayLabel; + CharSequence extendedInfo; + + DisplayResolveInfo(ResolveInfo pri, CharSequence pLabel, CharSequence pInfo) { + ri = pri; + displayLabel = pLabel; + extendedInfo = pInfo; + } + } + private final class ResolveListAdapter extends BaseAdapter { private final Intent mIntent; private final LayoutInflater mInflater; - private List mList; - + private List mList; + public ResolveListAdapter(Context context, Intent intent) { mIntent = new Intent(intent); mIntent.setComponent(null); mInflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); - PackageManager pm = context.getPackageManager(); - mList = pm.queryIntentActivities( + List rList = mPm.queryIntentActivities( intent, PackageManager.MATCH_DEFAULT_ONLY | (mAlwaysCheck != null ? PackageManager.GET_RESOLVED_FILTER : 0)); - if (mList != null) { - int N = mList.size(); + int N; + if ((rList != null) && ((N = rList.size()) > 0)) { + // Only display the first matches that are either of equal + // priority or have asked to be default options. + ResolveInfo r0 = rList.get(0); + for (int i=1; i 1) { - // Only display the first matches that are either of equal - // priority or have asked to be default options. - ResolveInfo r0 = mList.get(0); - for (int i=1; i(); + r0 = rList.get(0); + int start = 0; + CharSequence r0Label = r0.loadLabel(mPm); + for (int i = 1; i < N; i++) { + if (r0Label == null) { + r0Label = r0.activityInfo.packageName; + } + ResolveInfo ri = rList.get(i); + CharSequence riLabel = ri.loadLabel(mPm); + if (riLabel == null) { + riLabel = ri.activityInfo.packageName; + } + if (riLabel.equals(r0Label)) { + continue; + } + processGroup(rList, start, (i-1), r0, r0Label); + r0 = ri; + r0Label = riLabel; + start = i; + } + // Process last group + processGroup(rList, start, (N-1), r0, r0Label); + } + } + + private void processGroup(List rList, int start, int end, ResolveInfo ro, + CharSequence roLabel) { + // Process labels from start to i + int num = end - start+1; + if (num == 1) { + // No duplicate labels. Use label for entry at start + mList.add(new DisplayResolveInfo(ro, roLabel, null)); + } else { + boolean usePkg = false; + CharSequence startApp = ro.activityInfo.applicationInfo.loadLabel(mPm); + if (startApp == null) { + usePkg = true; + } + if (!usePkg) { + // Use HashSet to track duplicates + HashSet duplicates = + new HashSet(); + duplicates.add(startApp); + for (int j = start+1; j <= end ; j++) { + ResolveInfo jRi = rList.get(j); + CharSequence jApp = jRi.activityInfo.applicationInfo.loadLabel(mPm); + if ( (jApp == null) || (duplicates.contains(jApp))) { + usePkg = true; + break; + } else { + duplicates.add(jApp); } } - Collections.sort(mList, new ResolveInfo.DisplayNameComparator(pm)); + // Clear HashSet for later use + duplicates.clear(); + } + for (int k = start; k <= end; k++) { + ResolveInfo add = rList.get(k); + if (usePkg) { + // Use application name for all entries from start to end-1 + mList.add(new DisplayResolveInfo(add, roLabel, + add.activityInfo.packageName)); + } else { + // Use package name for all entries from start to end-1 + mList.add(new DisplayResolveInfo(add, roLabel, + add.activityInfo.applicationInfo.loadLabel(mPm))); + } } } } @@ -232,7 +313,7 @@ public class ResolverActivity extends AlertActivity implements return null; } - return mList.get(position); + return mList.get(position).ri; } public Intent intentForPosition(int position) { @@ -243,7 +324,7 @@ public class ResolverActivity extends AlertActivity implements Intent intent = new Intent(mIntent); intent.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT |Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP); - ActivityInfo ai = mList.get(position).activityInfo; + ActivityInfo ai = mList.get(position).ri.activityInfo; intent.setComponent(new ComponentName( ai.applicationInfo.packageName, ai.name)); return intent; @@ -273,22 +354,24 @@ public class ResolverActivity extends AlertActivity implements return view; } - private final void bindView(View view, ResolveInfo info) { + private final void bindView(View view, DisplayResolveInfo info) { TextView text = (TextView)view.findViewById(com.android.internal.R.id.text1); + TextView text2 = (TextView)view.findViewById(com.android.internal.R.id.text2); ImageView icon = (ImageView)view.findViewById(R.id.icon); - - PackageManager pm = getPackageManager(); - - CharSequence label = info.loadLabel(pm); - if (label == null) label = info.activityInfo.name; - text.setText(label); - icon.setImageDrawable(info.loadIcon(pm)); + text.setText(info.displayLabel); + if (info.extendedInfo != null) { + text2.setVisibility(View.VISIBLE); + text2.setText(info.extendedInfo); + } else { + text2.setVisibility(View.GONE); + } + icon.setImageDrawable(info.ri.loadIcon(mPm)); } } public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { if (mClearDefaultHint == null) return; - + if(isChecked) { mClearDefaultHint.setVisibility(View.VISIBLE); } else { diff --git a/core/java/com/android/internal/app/RingtonePickerActivity.java b/core/java/com/android/internal/app/RingtonePickerActivity.java index 63fe95261ce7e6e4b1d800ad0956be3ab0731f5f..9c83aa36f0f4cb830c3116542c7d0c610545a8af 100644 --- a/core/java/com/android/internal/app/RingtonePickerActivity.java +++ b/core/java/com/android/internal/app/RingtonePickerActivity.java @@ -139,6 +139,9 @@ public final class RingtonePickerActivity extends AlertActivity implements } mCursor = mRingtoneManager.getCursor(); + + // The volume keys will control the stream that we are choosing a ringtone for + setVolumeControlStream(mRingtoneManager.inferStreamType()); // Get the URI whose list item should have a checkmark mExistingUri = intent diff --git a/core/java/com/android/internal/app/UsbStorageActivity.java b/core/java/com/android/internal/app/UsbStorageActivity.java index 5b2bde07030c4e0fdbafacd1da9ef01852e07c4a..b8a2136cc9d003152a2796dca9eab69d4b2aaebb 100644 --- a/core/java/com/android/internal/app/UsbStorageActivity.java +++ b/core/java/com/android/internal/app/UsbStorageActivity.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2007 The Android Open Source Project + * Copyright (C) 2007 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -61,7 +61,7 @@ public class UsbStorageActivity extends AlertActivity implements DialogInterface p.mPositiveButtonText = getString(com.android.internal.R.string.usb_storage_button_mount); p.mPositiveButtonListener = this; p.mNegativeButtonText = getString(com.android.internal.R.string.usb_storage_button_unmount); - p.mPositiveButtonListener = this; + p.mNegativeButtonListener = this; setupAlert(); } diff --git a/core/java/com/android/internal/database/ArrayListCursor.java b/core/java/com/android/internal/database/ArrayListCursor.java index bcbcc41e38df04126e7ad448d3c68cb84fedd46f..2e1d8f12e758bb807ffdd68ad3a42b9517c24117 100644 --- a/core/java/com/android/internal/database/ArrayListCursor.java +++ b/core/java/com/android/internal/database/ArrayListCursor.java @@ -17,6 +17,7 @@ package com.android.internal.database; import android.database.AbstractCursor; +import android.database.CursorWindow; import java.lang.System; import java.util.ArrayList; @@ -25,105 +26,146 @@ import java.util.ArrayList; * A convenience class that presents a two-dimensional ArrayList * as a Cursor. */ -public class ArrayListCursor extends AbstractCursor -{ - public ArrayListCursor(String[] columnNames, ArrayList rows) - { +public class ArrayListCursor extends AbstractCursor { + private String[] mColumnNames; + private ArrayList[] mRows; + + @SuppressWarnings({"unchecked"}) + public ArrayListCursor(String[] columnNames, ArrayList rows) { int colCount = columnNames.length; boolean foundID = false; // Add an _id column if not in columnNames - for (int i=0; i getCount()) { + return; + } + + window.acquireReference(); + try { + int oldpos = mPos; + mPos = position - 1; + window.clear(); + window.setStartPosition(position); + int columnNum = getColumnCount(); + window.setNumColumns(columnNum); + while (moveToNext() && window.allocRow()) { + for (int i = 0; i < columnNum; i++) { + final Object data = mRows[mPos].get(i); + if (data != null) { + if (data instanceof byte[]) { + byte[] field = (byte[]) data; + if (!window.putBlob(field, mPos, i)) { + window.freeLastRow(); + break; + } + } else { + String field = data.toString(); + if (!window.putString(field, mPos, i)) { + window.freeLastRow(); + break; + } + } + } else { + if (!window.putNull(mPos, i)) { + window.freeLastRow(); + break; + } + } + } + } + + mPos = oldpos; + } catch (IllegalStateException e){ + // simply ignore it + } finally { + window.releaseReference(); + } + } @Override - public int getCount() - { + public int getCount() { return mRows.length; } @Override - public boolean deleteRow() - { + public boolean deleteRow() { return false; } @Override - public String[] getColumnNames() - { + public String[] getColumnNames() { return mColumnNames; } @Override - public String getString(int columnIndex) - { + public byte[] getBlob(int columnIndex) { + return (byte[]) mRows[mPos].get(columnIndex); + } + + @Override + public String getString(int columnIndex) { Object cell = mRows[mPos].get(columnIndex); return (cell == null) ? null : cell.toString(); } - + @Override - public short getShort(int columnIndex) - { - Number num = (Number)mRows[mPos].get(columnIndex); + public short getShort(int columnIndex) { + Number num = (Number) mRows[mPos].get(columnIndex); return num.shortValue(); } @Override - public int getInt(int columnIndex) - { - Number num = (Number)mRows[mPos].get(columnIndex); + public int getInt(int columnIndex) { + Number num = (Number) mRows[mPos].get(columnIndex); return num.intValue(); } @Override - public long getLong(int columnIndex) - { - Number num = (Number)mRows[mPos].get(columnIndex); + public long getLong(int columnIndex) { + Number num = (Number) mRows[mPos].get(columnIndex); return num.longValue(); } @Override - public float getFloat(int columnIndex) - { - Number num = (Number)mRows[mPos].get(columnIndex); + public float getFloat(int columnIndex) { + Number num = (Number) mRows[mPos].get(columnIndex); return num.floatValue(); } @Override - public double getDouble(int columnIndex) - { - Number num = (Number)mRows[mPos].get(columnIndex); + public double getDouble(int columnIndex) { + Number num = (Number) mRows[mPos].get(columnIndex); return num.doubleValue(); } @Override - public boolean isNull(int columnIndex) - { + public boolean isNull(int columnIndex) { return mRows[mPos].get(columnIndex) == null; } - - private String[] mColumnNames; - private ArrayList[] mRows; } diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.aidl b/core/java/com/android/internal/os/BatteryStatsImpl.aidl new file mode 100644 index 0000000000000000000000000000000000000000..0c26a3c411a706dcd093773d4ce411d884444261 --- /dev/null +++ b/core/java/com/android/internal/os/BatteryStatsImpl.aidl @@ -0,0 +1,19 @@ +/* + * 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.android.internal.os; + +parcelable BatteryStatsImpl; diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..8912960b0a479888cd96f53bae179f09d93141a1 --- /dev/null +++ b/core/java/com/android/internal/os/BatteryStatsImpl.java @@ -0,0 +1,1661 @@ +/* + * Copyright (C) 2006-2007 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.android.internal.os; + +import android.os.BatteryStats; +import android.os.Parcel; +import android.os.ParcelFormatException; +import android.os.Parcelable; +import android.os.SystemClock; +import android.util.Log; +import android.util.SparseArray; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.lang.ref.WeakReference; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; + +/** + * All information we are collecting about things that can happen that impact + * battery life. All times are represented in microseconds except where indicated + * otherwise. + */ +public final class BatteryStatsImpl extends BatteryStats implements Parcelable { + + // In-memory Parcel magic number, used to detect attempts to unmarshall bad data + private static final int MAGIC = 0xBA757475; // 'BATSTATS' + + // Current on-disk Parcel version + private static final int VERSION = 13; + + private final File mFile; + private final File mBackupFile; + + /** + * The statistics we have collected organized by uids. + */ + final SparseArray mUidStats = + new SparseArray(); + + // A set of pools of currently active timers. When a timer is queried, we will divide the + // elapsed time by the number of active timers to arrive at that timer's share of the time. + // In order to do this, we must refresh each timer whenever the number of active timers + // changes. + final ArrayList mPartialTimers = new ArrayList(); + final ArrayList mFullTimers = new ArrayList(); + final ArrayList mWindowTimers = new ArrayList(); + final ArrayList mSensorTimers = new ArrayList(); + + int mStartCount; + + long mBatteryUptime; + long mBatteryLastUptime; + long mBatteryRealtime; + long mBatteryLastRealtime; + + long mUptime; + long mUptimeStart; + long mLastUptime; + long mRealtime; + long mRealtimeStart; + long mLastRealtime; + + /** + * These provide time bases that discount the time the device is plugged + * in to power. + */ + boolean mOnBattery; + long mTrackBatteryPastUptime; + long mTrackBatteryUptimeStart; + long mTrackBatteryPastRealtime; + long mTrackBatteryRealtimeStart; + + long mLastWriteTime = 0; // Milliseconds + + // For debugging + public BatteryStatsImpl() { + mFile = mBackupFile = null; + } + + /** + * State for keeping track of timing information. + */ + public static final class Timer extends BatteryStats.Timer { + ArrayList mTimerPool; + + int mType; + int mNesting; + + int mCount; + int mLoadedCount; + int mLastCount; + + // Times are in microseconds for better accuracy when dividing by the lock count + + long mTotalTime; // Add mUnpluggedTotalTime to get true value + long mLoadedTotalTime; + long mLastTotalTime; + long mStartTime; + long mUpdateTime; + + /** + * The value of mTotalTime when unplug() was last called, initially 0. + */ + long mTotalTimeAtLastUnplug; + + /** Constructor used for unmarshalling only. */ + Timer() {} + + Timer(int type, ArrayList timerPool) { + mType = type; + mTimerPool = timerPool; + } + + public void writeToParcel(Parcel out) { + out.writeInt(mType); + out.writeInt(mNesting); + out.writeInt(mCount); + out.writeInt(mLoadedCount); + out.writeInt(mLastCount); + out.writeLong(mTotalTime); + out.writeLong(mLoadedTotalTime); + out.writeLong(mLastTotalTime); + out.writeLong(mStartTime); + out.writeLong(mUpdateTime); + out.writeLong(mTotalTimeAtLastUnplug); + } + + public void readFromParcel(Parcel in) { + mType = in.readInt(); + mNesting = in.readInt(); + mCount = in.readInt(); + mLoadedCount = in.readInt(); + mLastCount = in.readInt(); + mTotalTime = in.readLong(); + mLoadedTotalTime = in.readLong(); + mLastTotalTime = in.readLong(); + mStartTime = in.readLong(); + mUpdateTime = in.readLong(); + mTotalTimeAtLastUnplug = in.readLong(); + } + + private void unplug() { + mTotalTimeAtLastUnplug += mTotalTime; + mTotalTime = 0; + } + + /** + * Writes a possibly null Timer to a Parcel. + * + * @param out the Parcel to be written to. + * @param timer a Timer, or null. + */ + public static void writeTimerToParcel(Parcel out, Timer timer) { + if (timer == null) { + out.writeInt(0); // indicates null + return; + } + out.writeInt(1); // indicates non-null + + timer.writeToParcel(out); + } + + @Override + public long getTotalTime(long now, int which) { + long val; + if (which == STATS_LAST) { + val = mLastTotalTime; + } else { + val = computeRunTimeLocked(now); + if (which != STATS_UNPLUGGED) { + val += mTotalTimeAtLastUnplug; + } + if ((which == STATS_CURRENT) || (which == STATS_UNPLUGGED)) { + val -= mLoadedTotalTime; + } + } + + return val; + } + + @Override + public int getCount(int which) { + int val; + if (which == STATS_LAST) { + val = mLastCount; + } else { + val = mCount; + if ((which == STATS_CURRENT) || (which == STATS_UNPLUGGED)) { + val -= mLoadedCount; + } + } + + return val; + } + + void startRunningLocked(BatteryStatsImpl stats) { + if (mNesting++ == 0) { + mStartTime = mUpdateTime = + stats.getBatteryUptimeLocked(SystemClock.elapsedRealtime() * 1000); + // Accumulate time to all other active counters with the current value of mCount + refreshTimersLocked(stats); + // Add this timer to the active pool + mTimerPool.add(this); + // Increment the count + mCount++; + } + } + + void stopRunningLocked(BatteryStatsImpl stats) { + // Ignore attempt to stop a timer that isn't running + if (mNesting == 0) { + return; + } + if (--mNesting == 0) { + // Accumulate time to all active counters with the current value of mCount + refreshTimersLocked(stats); + // Remove this timer from the active pool + mTimerPool.remove(this); + // Decrement the count + mCount--; + } + } + + // Update the total time for all other running Timers with the same type as this Timer + // due to a change in timer count + private void refreshTimersLocked(BatteryStatsImpl stats) { + for (Timer t : mTimerPool) { + t.updateTimeLocked(stats); + } + } + + /** + * Update totalTime and reset updateTime + * @param stats + */ + private void updateTimeLocked(BatteryStatsImpl stats) { + long realtime = SystemClock.elapsedRealtime() * 1000; + long heldTime = stats.getBatteryUptimeLocked(realtime) - mUpdateTime; + if (heldTime > 0) { + mTotalTime += (heldTime * 1000) / mCount; + } + mUpdateTime = stats.getBatteryUptimeLocked(realtime); + } + + private long computeRunTimeLocked(long curBatteryUptime) { + return mTotalTime + + (mNesting > 0 ? ((curBatteryUptime * 1000) - mUpdateTime) / mCount : 0); + } + + void writeSummaryFromParcelLocked(Parcel out, long curBatteryUptime) { + long runTime = computeRunTimeLocked(curBatteryUptime); + // Divide by 1000 for backwards compatibility + out.writeLong((runTime + 500) / 1000); + out.writeLong(((runTime - mLoadedTotalTime) + 500) / 1000); + out.writeInt(mCount); + out.writeInt(mCount - mLoadedCount); + } + + void readSummaryFromParcelLocked(Parcel in) { + // Multiply by 1000 for backwards compatibility + mTotalTime = mLoadedTotalTime = in.readLong() * 1000; + mLastTotalTime = in.readLong(); + mCount = mLoadedCount = in.readInt(); + mLastCount = in.readInt(); + mNesting = 0; + } + } + + public void unplugTimers() { + ArrayList timers; + + timers = mPartialTimers; + for (int i = timers.size() - 1; i >= 0; i--) { + timers.get(i).unplug(); + } + timers = mFullTimers; + for (int i = timers.size() - 1; i >= 0; i--) { + timers.get(i).unplug(); + } + timers = mWindowTimers; + for (int i = timers.size() - 1; i >= 0; i--) { + timers.get(i).unplug(); + } + timers = mSensorTimers; + for (int i = timers.size() - 1; i >= 0; i--) { + timers.get(i).unplug(); + } + } + + @Override + public SparseArray getUidStats() { + return mUidStats; + } + + /** + * The statistics associated with a particular uid. + */ + public final class Uid extends BatteryStats.Uid { + + /** + * The statistics we have collected for this uid's wake locks. + */ + final HashMap mWakelockStats = new HashMap(); + + /** + * The statistics we have collected for this uid's sensor activations. + */ + final HashMap mSensorStats = new HashMap(); + + /** + * The statistics we have collected for this uid's processes. + */ + final HashMap mProcessStats = new HashMap(); + + /** + * The statistics we have collected for this uid's processes. + */ + final HashMap mPackageStats = new HashMap(); + + @Override + public Map getWakelockStats() { + return mWakelockStats; + } + + @Override + public Map getSensorStats() { + return mSensorStats; + } + + @Override + public Map getProcessStats() { + return mProcessStats; + } + + @Override + public Map getPackageStats() { + return mPackageStats; + } + + void writeToParcelLocked(Parcel out) { + out.writeInt(mWakelockStats.size()); + for (Map.Entry wakelockEntry : mWakelockStats.entrySet()) { + out.writeString(wakelockEntry.getKey()); + Uid.Wakelock wakelock = wakelockEntry.getValue(); + wakelock.writeToParcelLocked(out); + } + + out.writeInt(mSensorStats.size()); + for (Map.Entry sensorEntry : mSensorStats.entrySet()) { + out.writeInt(sensorEntry.getKey()); + Uid.Sensor sensor = sensorEntry.getValue(); + sensor.writeToParcelLocked(out); + } + + out.writeInt(mProcessStats.size()); + for (Map.Entry procEntry : mProcessStats.entrySet()) { + out.writeString(procEntry.getKey()); + Uid.Proc proc = procEntry.getValue(); + proc.writeToParcelLocked(out); + } + + out.writeInt(mPackageStats.size()); + for (Map.Entry pkgEntry : mPackageStats.entrySet()) { + out.writeString(pkgEntry.getKey()); + Uid.Pkg pkg = pkgEntry.getValue(); + pkg.writeToParcelLocked(out); + } + } + + void readFromParcelLocked(Parcel in) { + int numWakelocks = in.readInt(); + mWakelockStats.clear(); + for (int j = 0; j < numWakelocks; j++) { + String wakelockName = in.readString(); + Uid.Wakelock wakelock = new Wakelock(); + wakelock.readFromParcelLocked(in); + mWakelockStats.put(wakelockName, wakelock); + } + + int numSensors = in.readInt(); + mSensorStats.clear(); + for (int k = 0; k < numSensors; k++) { + int sensorNumber = in.readInt(); + Uid.Sensor sensor = new Sensor(); + sensor.readFromParcelLocked(in); + mSensorStats.put(sensorNumber, sensor); + } + + int numProcs = in.readInt(); + mProcessStats.clear(); + for (int k = 0; k < numProcs; k++) { + String processName = in.readString(); + Uid.Proc proc = new Proc(); + proc.readFromParcelLocked(in); + mProcessStats.put(processName, proc); + } + + int numPkgs = in.readInt(); + mPackageStats.clear(); + for (int l = 0; l < numPkgs; l++) { + String packageName = in.readString(); + Uid.Pkg pkg = new Pkg(); + pkg.readFromParcelLocked(in); + mPackageStats.put(packageName, pkg); + } + } + + /** + * The statistics associated with a particular wake lock. + */ + public final class Wakelock extends BatteryStats.Uid.Wakelock { + /** + * How long (in ms) this uid has been keeping the device partially awake. + */ + Timer wakeTimePartial; + + /** + * How long (in ms) this uid has been keeping the device fully awake. + */ + Timer wakeTimeFull; + + /** + * How long (in ms) this uid has had a window keeping the device awake. + */ + Timer wakeTimeWindow; + + /** + * Reads a possibly null Timer from a Parcel. The timer is associated with the + * proper timer pool from the given BatteryStatsImpl object. + * + * @param in the Parcel to be read from. + * return a new Timer, or null. + */ + private Timer readTimerFromParcel(Parcel in) { + if (in.readInt() == 0) { + return null; + } + + Timer timer = new Timer(); + timer.readFromParcel(in); + // Set the timer pool for the timer according to its type + switch (timer.mType) { + case WAKE_TYPE_PARTIAL: + timer.mTimerPool = mPartialTimers; + break; + case WAKE_TYPE_FULL: + timer.mTimerPool = mFullTimers; + break; + case WAKE_TYPE_WINDOW: + timer.mTimerPool = mWindowTimers; + break; + } + // If the timer is active, add it to the pool + if (timer.mNesting > 0) { + timer.mTimerPool.add(timer); + } + return timer; + } + + void readFromParcelLocked(Parcel in) { + wakeTimePartial = readTimerFromParcel(in); + wakeTimeFull = readTimerFromParcel(in); + wakeTimeWindow = readTimerFromParcel(in); + } + + void writeToParcelLocked(Parcel out) { + Timer.writeTimerToParcel(out, wakeTimePartial); + Timer.writeTimerToParcel(out, wakeTimeFull); + Timer.writeTimerToParcel(out, wakeTimeWindow); + } + + @Override + public Timer getWakeTime(int type) { + switch (type) { + case WAKE_TYPE_FULL: return wakeTimeFull; + case WAKE_TYPE_PARTIAL: return wakeTimePartial; + case WAKE_TYPE_WINDOW: return wakeTimeWindow; + default: throw new IllegalArgumentException("type = " + type); + } + } + } + + public final class Sensor extends BatteryStats.Uid.Sensor { + Timer sensorTime; + + private Timer readTimerFromParcel(Parcel in) { + if (in.readInt() == 0) { + return null; + } + + Timer timer = new Timer(); + timer.readFromParcel(in); + // Set the timer pool for the timer + timer.mTimerPool = mSensorTimers; + + // If the timer is active, add it to the pool + if (timer.mNesting > 0) { + timer.mTimerPool.add(timer); + } + return timer; + } + + void readFromParcelLocked(Parcel in) { + sensorTime = readTimerFromParcel(in); + } + + void writeToParcelLocked(Parcel out) { + Timer.writeTimerToParcel(out, sensorTime); + } + + @Override + public Timer getSensorTime() { + return sensorTime; + } + } + + /** + * The statistics associated with a particular process. + */ + public final class Proc extends BatteryStats.Uid.Proc { + /** + * Total time (in 1/100 sec) spent executing in user code. + */ + long mUserTime; + + /** + * Total time (in 1/100 sec) spent executing in kernel code. + */ + long mSystemTime; + + /** + * Number of times the process has been started. + */ + int mStarts; + + /** + * The amount of user time loaded from a previous save. + */ + long mLoadedUserTime; + + /** + * The amount of system time loaded from a previous save. + */ + long mLoadedSystemTime; + + /** + * The number of times the process has started from a previous save. + */ + int mLoadedStarts; + + /** + * The amount of user time loaded from the previous run. + */ + long mLastUserTime; + + /** + * The amount of system time loaded from the previous run. + */ + long mLastSystemTime; + + /** + * The number of times the process has started from the previous run. + */ + int mLastStarts; + + void writeToParcelLocked(Parcel out) { + out.writeLong(mUserTime); + out.writeLong(mSystemTime); + out.writeInt(mStarts); + out.writeLong(mLoadedUserTime); + out.writeLong(mLoadedSystemTime); + out.writeInt(mLoadedStarts); + out.writeLong(mLastUserTime); + out.writeLong(mLastSystemTime); + out.writeInt(mLastStarts); + } + + void readFromParcelLocked(Parcel in) { + mUserTime = in.readLong(); + mSystemTime = in.readLong(); + mStarts = in.readInt(); + mLoadedUserTime = in.readLong(); + mLoadedSystemTime = in.readLong(); + mLoadedStarts = in.readInt(); + mLastUserTime = in.readLong(); + mLastSystemTime = in.readLong(); + mLastStarts = in.readInt(); + } + + public BatteryStatsImpl getBatteryStats() { + return BatteryStatsImpl.this; + } + + public void addCpuTimeLocked(int utime, int stime) { + mUserTime += utime; + mSystemTime += stime; + } + + public void incStartsLocked() { + mStarts++; + } + + @Override + public long getUserTime(int which) { + long val; + if (which == STATS_LAST) { + val = mLastUserTime; + } else { + val = mUserTime; + if (which == STATS_CURRENT) { + val -= mLoadedUserTime; + } + } + return val; + } + + @Override + public long getSystemTime(int which) { + long val; + if (which == STATS_LAST) { + val = mLastSystemTime; + } else { + val = mSystemTime; + if (which == STATS_CURRENT) { + val -= mLoadedSystemTime; + } + } + return val; + } + + @Override + public int getStarts(int which) { + int val; + if (which == STATS_LAST) { + val = mLastStarts; + } else { + val = mStarts; + if (which == STATS_CURRENT) { + val -= mLoadedStarts; + } + } + return val; + } + } + + /** + * The statistics associated with a particular package. + */ + public final class Pkg extends BatteryStats.Uid.Pkg { + /** + * Number of times this package has done something that could wake up the + * device from sleep. + */ + int mWakeups; + + /** + * Number of things that could wake up the device loaded from a + * previous save. + */ + int mLoadedWakeups; + + /** + * Number of things that could wake up the device as of the + * last run. + */ + int mLastWakeups; + + /** + * The statics we have collected for this package's services. + */ + final HashMap mServiceStats = new HashMap(); + + void readFromParcelLocked(Parcel in) { + mWakeups = in.readInt(); + mLoadedWakeups = in.readInt(); + mLastWakeups = in.readInt(); + + int numServs = in.readInt(); + mServiceStats.clear(); + for (int m = 0; m < numServs; m++) { + String serviceName = in.readString(); + Uid.Pkg.Serv serv = new Serv(); + mServiceStats.put(serviceName, serv); + + serv.readFromParcelLocked(in); + } + } + + void writeToParcelLocked(Parcel out) { + out.writeInt(mWakeups); + out.writeInt(mLoadedWakeups); + out.writeInt(mLastWakeups); + + out.writeInt(mServiceStats.size()); + for (Map.Entry servEntry : mServiceStats.entrySet()) { + out.writeString(servEntry.getKey()); + Uid.Pkg.Serv serv = servEntry.getValue(); + + serv.writeToParcelLocked(out); + } + } + + @Override + public Map getServiceStats() { + return mServiceStats; + } + + @Override + public int getWakeups(int which) { + int val; + if (which == STATS_LAST) { + val = mLastWakeups; + } else { + val = mWakeups; + if (which == STATS_CURRENT) { + val -= mLoadedWakeups; + } + } + + return val; + } + + /** + * The statistics associated with a particular service. + */ + public final class Serv extends BatteryStats.Uid.Pkg.Serv { + /** + * Total time (ms) the service has been left started. + */ + long mStartTime; + + /** + * If service has been started and not yet stopped, this is + * when it was started. + */ + long mRunningSince; + + /** + * True if we are currently running. + */ + boolean mRunning; + + /** + * Total number of times startService() has been called. + */ + int mStarts; + + /** + * Total time (ms) the service has been left launched. + */ + long mLaunchedTime; + + /** + * If service has been launched and not yet exited, this is + * when it was launched. + */ + long mLaunchedSince; + + /** + * True if we are currently launched. + */ + boolean mLaunched; + + /** + * Total number times the service has been launched. + */ + int mLaunches; + + /** + * The amount of time spent started loaded from a previous save. + */ + long mLoadedStartTime; + + /** + * The number of starts loaded from a previous save. + */ + int mLoadedStarts; + + /** + * The number of launches loaded from a previous save. + */ + int mLoadedLaunches; + + /** + * The amount of time spent started as of the last run. + */ + long mLastStartTime; + + /** + * The number of starts as of the last run. + */ + int mLastStarts; + + /** + * The number of launches as of the last run. + */ + int mLastLaunches; + + void readFromParcelLocked(Parcel in) { + mStartTime = in.readLong(); + mRunningSince = in.readLong(); + mRunning = in.readInt() != 0; + mStarts = in.readInt(); + mLaunchedTime = in.readLong(); + mLaunchedSince = in.readLong(); + mLaunched = in.readInt() != 0; + mLaunches = in.readInt(); + mLoadedStartTime = in.readLong(); + mLoadedStarts = in.readInt(); + mLoadedLaunches = in.readInt(); + mLastStartTime = in.readLong(); + mLastStarts = in.readInt(); + mLastLaunches = in.readInt(); + } + + void writeToParcelLocked(Parcel out) { + out.writeLong(mStartTime); + out.writeLong(mRunningSince); + out.writeInt(mRunning ? 1 : 0); + out.writeInt(mStarts); + out.writeLong(mLaunchedTime); + out.writeLong(mLaunchedSince); + out.writeInt(mLaunched ? 1 : 0); + out.writeInt(mLaunches); + out.writeLong(mLoadedStartTime); + out.writeInt(mLoadedStarts); + out.writeInt(mLoadedLaunches); + out.writeLong(mLastStartTime); + out.writeInt(mLastStarts); + out.writeInt(mLastLaunches); + } + + long getLaunchTimeToNowLocked(long batteryUptime) { + if (!mLaunched) return mLaunchedTime; + return mLaunchedTime + batteryUptime - mLaunchedSince; + } + + long getStartTimeToNowLocked(long batteryUptime) { + if (!mRunning) return mStartTime; + return mStartTime + batteryUptime - mRunningSince; + } + + public void startLaunchedLocked() { + if (!mLaunched) { + mLaunches++; + mLaunchedSince = getBatteryUptimeLocked(); + mLaunched = true; + } + } + + public void stopLaunchedLocked() { + if (mLaunched) { + long time = getBatteryUptimeLocked() - mLaunchedSince; + if (time > 0) { + mLaunchedTime += time; + } else { + mLaunches--; + } + mLaunched = false; + } + } + + public void startRunningLocked() { + if (!mRunning) { + mStarts++; + mRunningSince = getBatteryUptimeLocked(); + mRunning = true; + } + } + + public void stopRunningLocked() { + if (mRunning) { + long time = getBatteryUptimeLocked() - mRunningSince; + if (time > 0) { + mStartTime += time; + } else { + mStarts--; + } + mRunning = false; + } + } + + public BatteryStatsImpl getBatteryStats() { + return BatteryStatsImpl.this; + } + + @Override + public int getLaunches(int which) { + int val; + + if (which == STATS_LAST) { + val = mLastLaunches; + } else { + val = mLaunches; + if (which == STATS_CURRENT) { + val -= mLoadedLaunches; + } + } + + return val; + } + + @Override + public long getStartTime(long now, int which) { + long val; + if (which == STATS_LAST) { + val = mLastStartTime; + } else { + val = getStartTimeToNowLocked(now); + if (which == STATS_CURRENT) { + val -= mLoadedStartTime; + } + } + + return val; + } + + @Override + public int getStarts(int which) { + int val; + if (which == STATS_LAST) { + val = mLastStarts; + } else { + val = mStarts; + if (which == STATS_CURRENT) { + val -= mLoadedStarts; + } + } + + return val; + } + } + + public BatteryStatsImpl getBatteryStats() { + return BatteryStatsImpl.this; + } + + public void incWakeupsLocked() { + mWakeups++; + } + + final Serv newServiceStatsLocked() { + return new Serv(); + } + } + + /** + * Retrieve the statistics object for a particular process, creating + * if needed. + */ + public Proc getProcessStatsLocked(String name) { + Proc ps = mProcessStats.get(name); + if (ps == null) { + ps = new Proc(); + mProcessStats.put(name, ps); + } + + return ps; + } + + /** + * Retrieve the statistics object for a particular service, creating + * if needed. + */ + public Pkg getPackageStatsLocked(String name) { + Pkg ps = mPackageStats.get(name); + if (ps == null) { + ps = new Pkg(); + mPackageStats.put(name, ps); + } + + return ps; + } + + /** + * Retrieve the statistics object for a particular service, creating + * if needed. + */ + public Pkg.Serv getServiceStatsLocked(String pkg, String serv) { + Pkg ps = getPackageStatsLocked(pkg); + Pkg.Serv ss = ps.mServiceStats.get(serv); + if (ss == null) { + ss = ps.newServiceStatsLocked(); + ps.mServiceStats.put(serv, ss); + } + + return ss; + } + + public Timer getWakeTimerLocked(String name, int type) { + Wakelock wl = mWakelockStats.get(name); + if (wl == null) { + wl = new Wakelock(); + mWakelockStats.put(name, wl); + } + Timer t = null; + switch (type) { + case WAKE_TYPE_PARTIAL: + t = wl.wakeTimePartial; + if (t == null) { + t = new Timer(WAKE_TYPE_PARTIAL, mPartialTimers); + wl.wakeTimePartial = t; + } + return t; + case WAKE_TYPE_FULL: + t = wl.wakeTimeFull; + if (t == null) { + t = new Timer(WAKE_TYPE_FULL, mFullTimers); + wl.wakeTimeFull = t; + } + return t; + case WAKE_TYPE_WINDOW: + t = wl.wakeTimeWindow; + if (t == null) { + t = new Timer(WAKE_TYPE_WINDOW, mWindowTimers); + wl.wakeTimeWindow = t; + } + return t; + default: + throw new IllegalArgumentException("type=" + type); + } + } + + public Timer getSensorTimerLocked(int sensor, boolean create) { + Integer sId = Integer.valueOf(sensor); + Sensor se = mSensorStats.get(sId); + if (se == null) { + if (!create) { + return null; + } + se = new Sensor(); + mSensorStats.put(sId, se); + } + Timer t = se.sensorTime; + if (t == null) { + t = new Timer(0, mSensorTimers); + se.sensorTime = t; + } + return t; + } + + public void noteStartWakeLocked(String name, int type) { + Timer t = getWakeTimerLocked(name, type); + if (t != null) { + t.startRunningLocked(BatteryStatsImpl.this); + } + } + + public void noteStopWakeLocked(String name, int type) { + Timer t = getWakeTimerLocked(name, type); + if (t != null) { + t.stopRunningLocked(BatteryStatsImpl.this); + } + } + + public void noteStartSensor(int sensor) { + Timer t = getSensorTimerLocked(sensor, true); + if (t != null) { + t.startRunningLocked(BatteryStatsImpl.this); + } + } + + public void noteStopSensor(int sensor) { + // Don't create a timer if one doesn't already exist + Timer t = getSensorTimerLocked(sensor, false); + if (t != null) { + t.stopRunningLocked(BatteryStatsImpl.this); + } + } + + public BatteryStatsImpl getBatteryStats() { + return BatteryStatsImpl.this; + } + } + + public BatteryStatsImpl(String filename) { + mFile = new File(filename); + mBackupFile = new File(filename + ".bak"); + mStartCount++; + mOnBattery = true; + mTrackBatteryPastUptime = 0; + mTrackBatteryPastRealtime = 0; + mUptimeStart = mTrackBatteryUptimeStart = SystemClock.uptimeMillis() * 1000; + mRealtimeStart = mTrackBatteryRealtimeStart = SystemClock.elapsedRealtime() * 1000; + } + + public BatteryStatsImpl(Parcel p) { + mFile = mBackupFile = null; + readFromParcel(p); + } + + @Override + public int getStartCount() { + return mStartCount; + } + + public boolean isOnBattery() { + return mOnBattery; + } + + public void setOnBattery(boolean onBattery) { + synchronized(this) { + if (mOnBattery != onBattery) { + long uptime = SystemClock.uptimeMillis() * 1000; + long mSecRealtime = SystemClock.elapsedRealtime(); + long realtime = mSecRealtime * 1000; + if (onBattery) { + mTrackBatteryUptimeStart = uptime; + mTrackBatteryRealtimeStart = realtime; + unplugTimers(); + } else { + mTrackBatteryPastUptime += uptime - mTrackBatteryUptimeStart; + mTrackBatteryPastRealtime += realtime - mTrackBatteryRealtimeStart; + } + mOnBattery = onBattery; + if ((mLastWriteTime + (60 * 1000)) < mSecRealtime) { + if (mFile != null) { + writeLocked(); + } + } + } + } + } + + public long getAwakeTimeBattery() { + return computeBatteryUptime(getBatteryUptimeLocked(), STATS_CURRENT); + } + + public long getAwakeTimePlugged() { + return (SystemClock.uptimeMillis() * 1000) - getAwakeTimeBattery(); + } + + @Override + public long computeUptime(long curTime, int which) { + switch (which) { + case STATS_TOTAL: return mUptime + (curTime-mUptimeStart); + case STATS_LAST: return mLastUptime; + case STATS_CURRENT: return (curTime-mUptimeStart); + case STATS_UNPLUGGED: return (curTime-mTrackBatteryUptimeStart); + } + return 0; + } + + @Override + public long computeRealtime(long curTime, int which) { + switch (which) { + case STATS_TOTAL: return mRealtime + (curTime-mRealtimeStart); + case STATS_LAST: return mLastRealtime; + case STATS_CURRENT: return (curTime-mRealtimeStart); + case STATS_UNPLUGGED: return (curTime-mTrackBatteryRealtimeStart); + } + return 0; + } + + @Override + public long computeBatteryUptime(long curTime, int which) { + switch (which) { + case STATS_TOTAL: + return mBatteryUptime + getBatteryUptime(curTime); + case STATS_LAST: + return mBatteryLastUptime; + case STATS_CURRENT: + case STATS_UNPLUGGED: + return getBatteryUptime(curTime); + } + return 0; + } + + @Override + public long computeBatteryRealtime(long curTime, int which) { + switch (which) { + case STATS_TOTAL: + return mBatteryRealtime + getBatteryRealtimeLocked(curTime); + case STATS_LAST: + return mBatteryLastRealtime; + case STATS_CURRENT: + case STATS_UNPLUGGED: + return getBatteryRealtimeLocked(curTime); + } + return 0; + } + + long getBatteryUptimeLocked(long curTime) { + long time = mTrackBatteryPastUptime; + if (mOnBattery) { + time += curTime - mTrackBatteryUptimeStart; + } + return time; + } + + long getBatteryUptimeLocked() { + return getBatteryUptime(SystemClock.uptimeMillis() * 1000); + } + + @Override + public long getBatteryUptime(long curTime) { + return getBatteryUptimeLocked(curTime); + } + + long getBatteryRealtimeLocked(long curTime) { + long time = mTrackBatteryPastRealtime; + if (mOnBattery) { + time += curTime - mTrackBatteryRealtimeStart; + } + return time; + } + + @Override + public long getBatteryRealtime(long curTime) { + return getBatteryRealtimeLocked(curTime); + } + + /** + * Retrieve the statistics object for a particular uid, creating if needed. + */ + public Uid getUidStatsLocked(int uid) { + Uid u = mUidStats.get(uid); + if (u == null) { + u = new Uid(); + mUidStats.put(uid, u); + } + return u; + } + + /** + * Remove the statistics object for a particular uid. + */ + public void removeUidStatsLocked(int uid) { + mUidStats.remove(uid); + } + + /** + * Retrieve the statistics object for a particular process, creating + * if needed. + */ + public Uid.Proc getProcessStatsLocked(int uid, String name) { + Uid u = getUidStatsLocked(uid); + return u.getProcessStatsLocked(name); + } + + /** + * Retrieve the statistics object for a particular process, creating + * if needed. + */ + public Uid.Pkg getPackageStatsLocked(int uid, String pkg) { + Uid u = getUidStatsLocked(uid); + return u.getPackageStatsLocked(pkg); + } + + /** + * Retrieve the statistics object for a particular service, creating + * if needed. + */ + public Uid.Pkg.Serv getServiceStatsLocked(int uid, String pkg, String name) { + Uid u = getUidStatsLocked(uid); + return u.getServiceStatsLocked(pkg, name); + } + + public void writeLocked() { + if ((mFile == null) || (mBackupFile == null)) { + Log.w("BatteryStats", "writeLocked: no file associated with this instance"); + return; + } + + // Keep the old file around until we know the new one has + // been successfully written. + if (mFile.exists()) { + if (mBackupFile.exists()) { + mBackupFile.delete(); + } + mFile.renameTo(mBackupFile); + } + + try { + FileOutputStream stream = new FileOutputStream(mFile); + Parcel out = Parcel.obtain(); + writeSummaryToParcel(out); + stream.write(out.marshall()); + out.recycle(); + + stream.flush(); + stream.close(); + mBackupFile.delete(); + + mLastWriteTime = SystemClock.elapsedRealtime(); + } catch (IOException e) { + Log.e("BatteryStats", "Error writing battery statistics", e); + } + } + + static byte[] readFully(FileInputStream stream) throws java.io.IOException { + int pos = 0; + int avail = stream.available(); + byte[] data = new byte[avail]; + while (true) { + int amt = stream.read(data, pos, data.length-pos); + //Log.i("foo", "Read " + amt + " bytes at " + pos + // + " of avail " + data.length); + if (amt <= 0) { + //Log.i("foo", "**** FINISHED READING: pos=" + pos + // + " len=" + data.length); + return data; + } + pos += amt; + avail = stream.available(); + if (avail > data.length-pos) { + byte[] newData = new byte[pos+avail]; + System.arraycopy(data, 0, newData, 0, pos); + data = newData; + } + } + } + + public void readLocked() { + if ((mFile == null) || (mBackupFile == null)) { + Log.w("BatteryStats", "readLocked: no file associated with this instance"); + return; + } + + mUidStats.clear(); + + FileInputStream stream = null; + if (mBackupFile.exists()) { + try { + stream = new FileInputStream(mBackupFile); + } catch (java.io.IOException e) { + // We'll try for the normal settings file. + } + } + + try { + if (stream == null) { + if (!mFile.exists()) { + return; + } + stream = new FileInputStream(mFile); + } + + byte[] raw = readFully(stream); + Parcel in = Parcel.obtain(); + in.unmarshall(raw, 0, raw.length); + in.setDataPosition(0); + stream.close(); + + readSummaryFromParcel(in); + } catch(java.io.IOException e) { + Log.e("BatteryStats", "Error reading battery statistics", e); + } + } + + public int describeContents() { + return 0; + } + + private void readSummaryFromParcel(Parcel in) { + final int version = in.readInt(); + if (version != VERSION) { + Log.e("BatteryStats", "readFromParcel: version got " + version + + ", expected " + VERSION); + return; + } + + mStartCount = in.readInt(); + mBatteryUptime = in.readLong(); + mBatteryLastUptime = in.readLong(); + mBatteryRealtime = in.readLong(); + mBatteryLastRealtime = in.readLong(); + mUptime = in.readLong(); + mLastUptime = in.readLong(); + mRealtime = in.readLong(); + mLastRealtime = in.readLong(); + mStartCount++; + + final int NU = in.readInt(); + for (int iu=0; iu= 12) { + int NSE = in.readInt(); + for (int is=0; is 0) { + for (Map.Entry ent + : u.mWakelockStats.entrySet()) { + out.writeString(ent.getKey()); + Uid.Wakelock wl = ent.getValue(); + if (wl.wakeTimeFull != null) { + out.writeInt(1); + wl.wakeTimeFull.writeSummaryFromParcelLocked(out, NOW); + } else { + out.writeInt(0); + } + if (wl.wakeTimePartial != null) { + out.writeInt(1); + wl.wakeTimePartial.writeSummaryFromParcelLocked(out, NOW); + } else { + out.writeInt(0); + } + if (wl.wakeTimeWindow != null) { + out.writeInt(1); + wl.wakeTimeWindow.writeSummaryFromParcelLocked(out, NOW); + } else { + out.writeInt(0); + } + } + } + + int NSE = u.mSensorStats.size(); + out.writeInt(NSE); + if (NSE > 0) { + for (Map.Entry ent + : u.mSensorStats.entrySet()) { + out.writeInt(ent.getKey()); + Uid.Sensor se = ent.getValue(); + if (se.sensorTime != null) { + out.writeInt(1); + se.sensorTime.writeSummaryFromParcelLocked(out, NOW); + } else { + out.writeInt(0); + } + } + } + + int NP = u.mProcessStats.size(); + out.writeInt(NP); + if (NP > 0) { + for (Map.Entry ent + : u.mProcessStats.entrySet()) { + out.writeString(ent.getKey()); + Uid.Proc ps = ent.getValue(); + out.writeLong(ps.mUserTime); + out.writeLong(ps.mUserTime - ps.mLoadedUserTime); + out.writeLong(ps.mSystemTime); + out.writeLong(ps.mSystemTime - ps.mLoadedSystemTime); + out.writeInt(ps.mStarts); + out.writeInt(ps.mStarts - ps.mLoadedStarts); + } + } + + NP = u.mPackageStats.size(); + out.writeInt(NP); + if (NP > 0) { + for (Map.Entry ent + : u.mPackageStats.entrySet()) { + out.writeString(ent.getKey()); + Uid.Pkg ps = ent.getValue(); + out.writeInt(ps.mWakeups); + out.writeInt(ps.mWakeups - ps.mLoadedWakeups); + final int NS = ps.mServiceStats.size(); + out.writeInt(NS); + if (NS > 0) { + for (Map.Entry sent + : ps.mServiceStats.entrySet()) { + out.writeString(sent.getKey()); + BatteryStatsImpl.Uid.Pkg.Serv ss = sent.getValue(); + long time = ss.getStartTimeToNowLocked(NOW); + out.writeLong(time); + out.writeLong(time - ss.mLoadedStartTime); + out.writeInt(ss.mStarts); + out.writeInt(ss.mStarts - ss.mLoadedStarts); + out.writeInt(ss.mLaunches); + out.writeInt(ss.mLaunches - ss.mLoadedLaunches); + } + } + } + } + } + } + + public void readFromParcel(Parcel in) { + readFromParcelLocked(in); + } + + void readFromParcelLocked(Parcel in) { + int magic = in.readInt(); + if (magic != MAGIC) { + throw new ParcelFormatException("Bad magic number"); + } + + mStartCount = in.readInt(); + mBatteryUptime = in.readLong(); + mBatteryLastUptime = in.readLong(); + mBatteryRealtime = in.readLong(); + mBatteryLastRealtime = in.readLong(); + mUptime = in.readLong(); + mUptimeStart = in.readLong(); + mLastUptime = in.readLong(); + mRealtime = in.readLong(); + mRealtimeStart = in.readLong(); + mLastRealtime = in.readLong(); + mOnBattery = in.readInt() != 0; + mTrackBatteryPastUptime = in.readLong(); + mTrackBatteryUptimeStart = in.readLong(); + mTrackBatteryPastRealtime = in.readLong(); + mTrackBatteryRealtimeStart = in.readLong(); + mLastWriteTime = in.readLong(); + + mPartialTimers.clear(); + mFullTimers.clear(); + mWindowTimers.clear(); + + int numUids = in.readInt(); + mUidStats.clear(); + for (int i = 0; i < numUids; i++) { + int key = in.readInt(); + Uid uid = new Uid(); + uid.readFromParcelLocked(in); + mUidStats.append(key, uid); + } + } + + public void writeToParcel(Parcel out, int flags) { + writeToParcelLocked(out, flags); + } + + @SuppressWarnings("unused") + void writeToParcelLocked(Parcel out, int flags) { + out.writeInt(MAGIC); + out.writeInt(mStartCount); + out.writeLong(mBatteryUptime); + out.writeLong(mBatteryLastUptime); + out.writeLong(mBatteryRealtime); + out.writeLong(mBatteryLastRealtime); + out.writeLong(mUptime); + out.writeLong(mUptimeStart); + out.writeLong(mLastUptime); + out.writeLong(mRealtime); + out.writeLong(mRealtimeStart); + out.writeLong(mLastRealtime); + out.writeInt(mOnBattery ? 1 : 0); + out.writeLong(mTrackBatteryPastUptime); + out.writeLong(mTrackBatteryUptimeStart); + out.writeLong(mTrackBatteryPastRealtime); + out.writeLong(mTrackBatteryRealtimeStart); + out.writeLong(mLastWriteTime); + + int size = mUidStats.size(); + out.writeInt(size); + for (int i = 0; i < size; i++) { + out.writeInt(mUidStats.keyAt(i)); + Uid uid = mUidStats.valueAt(i); + + uid.writeToParcelLocked(out); + } + } + + public static final Parcelable.Creator CREATOR = + new Parcelable.Creator() { + public BatteryStatsImpl createFromParcel(Parcel in) { + return new BatteryStatsImpl(in); + } + + public BatteryStatsImpl[] newArray(int size) { + return new BatteryStatsImpl[size]; + } + }; +} diff --git a/core/java/com/android/internal/os/HandlerCaller.java b/core/java/com/android/internal/os/HandlerCaller.java new file mode 100644 index 0000000000000000000000000000000000000000..fd8fd5ab5c5b1c23ba64e2c9785365778dd623a7 --- /dev/null +++ b/core/java/com/android/internal/os/HandlerCaller.java @@ -0,0 +1,166 @@ +package com.android.internal.os; + +import android.content.Context; +import android.os.Handler; +import android.os.Looper; +import android.os.Message; + +public class HandlerCaller { + private static final String TAG = "HandlerCaller"; + private static final boolean DEBUG = false; + + public final Context mContext; + + final Looper mMainLooper; + final Handler mH; + + final Callback mCallback; + + public static class SomeArgs { + SomeArgs next; + + public Object arg1; + public Object arg2; + Object arg3; + public int argi1; + public int argi2; + public int argi3; + public int argi4; + } + + static final int ARGS_POOL_MAX_SIZE = 10; + int mArgsPoolSize; + SomeArgs mArgsPool; + + class MyHandler extends Handler { + MyHandler(Looper looper) { + super(looper); + } + + @Override + public void handleMessage(Message msg) { + mCallback.executeMessage(msg); + } + } + + public interface Callback { + public void executeMessage(Message msg); + } + + public HandlerCaller(Context context, Callback callback) { + mContext = context; + mMainLooper = context.getMainLooper(); + mH = new MyHandler(mMainLooper); + mCallback = callback; + } + + public SomeArgs obtainArgs() { + synchronized (mH) { + SomeArgs args = mArgsPool; + if (args != null) { + mArgsPool = args.next; + args.next = null; + mArgsPoolSize--; + return args; + } + } + return new SomeArgs(); + } + + public void recycleArgs(SomeArgs args) { + synchronized (mH) { + if (mArgsPoolSize < ARGS_POOL_MAX_SIZE) { + args.next = mArgsPool; + mArgsPool = args; + mArgsPoolSize++; + } + } + } + + public void executeOrSendMessage(Message msg) { + // If we are calling this from the main thread, then we can call + // right through. Otherwise, we need to send the message to the + // main thread. + if (Looper.myLooper() == mMainLooper) { + mCallback.executeMessage(msg); + msg.recycle(); + return; + } + + mH.sendMessage(msg); + } + + public void sendMessage(Message msg) { + mH.sendMessage(msg); + } + + public Message obtainMessage(int what) { + return mH.obtainMessage(what); + } + + public Message obtainMessageBO(int what, boolean arg1, Object arg2) { + return mH.obtainMessage(what, arg1 ? 1 : 0, 0, arg2); + } + + public Message obtainMessageBOO(int what, boolean arg1, Object arg2, Object arg3) { + SomeArgs args = obtainArgs(); + args.arg1 = arg2; + args.arg2 = arg3; + return mH.obtainMessage(what, arg1 ? 1 : 0, 0, args); + } + + public Message obtainMessageO(int what, Object arg1) { + return mH.obtainMessage(what, 0, 0, arg1); + } + + public Message obtainMessageIO(int what, int arg1, Object arg2) { + return mH.obtainMessage(what, arg1, 0, arg2); + } + + public Message obtainMessageIO(int what, int arg1, int arg2, Object arg3) { + return mH.obtainMessage(what, arg1, arg2, arg3); + } + + public Message obtainMessageIOO(int what, int arg1, Object arg2, Object arg3) { + SomeArgs args = obtainArgs(); + args.arg1 = arg2; + args.arg2 = arg3; + return mH.obtainMessage(what, arg1, 0, args); + } + + public Message obtainMessageOO(int what, Object arg1, Object arg2) { + SomeArgs args = obtainArgs(); + args.arg1 = arg1; + args.arg2 = arg2; + return mH.obtainMessage(what, 0, 0, args); + } + + public Message obtainMessageOOO(int what, Object arg1, Object arg2, Object arg3) { + SomeArgs args = obtainArgs(); + args.arg1 = arg1; + args.arg2 = arg2; + args.arg3 = arg3; + return mH.obtainMessage(what, 0, 0, args); + } + + public Message obtainMessageIIII(int what, int arg1, int arg2, + int arg3, int arg4) { + SomeArgs args = obtainArgs(); + args.argi1 = arg1; + args.argi2 = arg2; + args.argi3 = arg3; + args.argi4 = arg4; + return mH.obtainMessage(what, 0, 0, args); + } + + public Message obtainMessageIIIIO(int what, int arg1, int arg2, + int arg3, int arg4, Object arg5) { + SomeArgs args = obtainArgs(); + args.arg1 = arg5; + args.argi1 = arg1; + args.argi2 = arg2; + args.argi3 = arg3; + args.argi4 = arg4; + return mH.obtainMessage(what, 0, 0, args); + } +} diff --git a/core/java/com/android/internal/os/ZygoteConnection.java b/core/java/com/android/internal/os/ZygoteConnection.java index 566332b2ddb14cf6150037268cbd41136f3ac6a5..631e7d8f1cf0eb14001c66fbdf79487c7a472a89 100644 --- a/core/java/com/android/internal/os/ZygoteConnection.java +++ b/core/java/com/android/internal/os/ZygoteConnection.java @@ -210,7 +210,7 @@ class ZygoteConnection { } pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, - parsedArgs.gids, parsedArgs.enableDebugger, rlimits); + parsedArgs.gids, parsedArgs.debugFlags, rlimits); } catch (IllegalArgumentException ex) { logAndPrintError (newStderr, "Invalid zygote arguments", ex); pid = -1; @@ -295,8 +295,8 @@ class ZygoteConnection { /** from --peer-wait */ boolean peerWait; - /** from --enable-debugger */ - boolean enableDebugger; + /** from --enable-debugger, --enable-checkjni, --enable-assert */ + int debugFlags; /** from --classpath */ String classpath; @@ -362,7 +362,11 @@ class ZygoteConnection { gid = Integer.parseInt( arg.substring(arg.indexOf('=') + 1)); } else if (arg.equals("--enable-debugger")) { - enableDebugger = true; + debugFlags |= Zygote.DEBUG_ENABLE_DEBUGGER; + } else if (arg.equals("--enable-checkjni")) { + debugFlags |= Zygote.DEBUG_ENABLE_CHECKJNI; + } else if (arg.equals("--enable-assert")) { + debugFlags |= Zygote.DEBUG_ENABLE_ASSERT; } else if (arg.equals("--peer-wait")) { peerWait = true; } else if (arg.equals("--runtime-init")) { @@ -567,7 +571,7 @@ class ZygoteConnection { */ private static void applyDebuggerSecurityPolicy(Arguments args) { if ("1".equals(SystemProperties.get("ro.debuggable"))) { - args.enableDebugger = true; + args.debugFlags |= Zygote.DEBUG_ENABLE_DEBUGGER; } } diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java index 5714b99e91c5fe0d373cb947fcefbcd5ab1f6443..f21b62f32c862b149cca8663cd3ef4ffbec9a611 100644 --- a/core/java/com/android/internal/os/ZygoteInit.java +++ b/core/java/com/android/internal/os/ZygoteInit.java @@ -260,7 +260,7 @@ public class ZygoteInit { int count = 0; String line; - boolean gotMissingClass = false; + String missingClasses = null; while ((line = br.readLine()) != null) { // Skip comments and blank lines. line = line.trim(); @@ -285,14 +285,19 @@ public class ZygoteInit { count++; } catch (ClassNotFoundException e) { Log.e(TAG, "Class not found for preloading: " + line); - gotMissingClass = true; + if (missingClasses == null) { + missingClasses = line; + } else { + missingClasses += " " + line; + } } } - if (gotMissingClass && + if (missingClasses != null && "1".equals(SystemProperties.get("persist.service.adb.enable"))) { throw new IllegalStateException( - "Missing class(es) for preloading, update preloaded-classes"); + "Missing class(es) for preloading, update preloaded-classes [" + + missingClasses + "]"); } Log.i(TAG, "...preloaded " + count + " classes in " @@ -425,7 +430,7 @@ public class ZygoteInit { "--setuid=1000", "--setgid=1000", "--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,3001,3002,3003", - "--capabilities=88161312,88161312", + "--capabilities=121715744,121715744", "--runtime-init", "--nice-name=system_server", "com.android.server.SystemServer", @@ -442,13 +447,14 @@ public class ZygoteInit { * indicate it should be debuggable or the ro.debuggable system property * is set to "1" */ - boolean debuggableBuild = "1".equals(SystemProperties.get("ro.debuggable")); - boolean enableDebugger = parsedArgs.enableDebugger || debuggableBuild; + int debugFlags = parsedArgs.debugFlags; + if ("1".equals(SystemProperties.get("ro.debuggable"))) + debugFlags |= Zygote.DEBUG_ENABLE_DEBUGGER; /* Request to fork the system server process */ pid = Zygote.forkSystemServer( parsedArgs.uid, parsedArgs.gid, - parsedArgs.gids, enableDebugger, null); + parsedArgs.gids, debugFlags, null); } catch (IllegalArgumentException ex) { throw new RuntimeException(ex); } diff --git a/core/java/com/android/internal/provider/Settings.java b/core/java/com/android/internal/provider/Settings.java deleted file mode 100644 index 85ef17e0243ba5377a1b1a71f988781459165460..0000000000000000000000000000000000000000 --- a/core/java/com/android/internal/provider/Settings.java +++ /dev/null @@ -1,199 +0,0 @@ -/* - * 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.android.internal.provider; - -import android.provider.BaseColumns; -import android.net.Uri; - -/** - * Settings related utilities. - */ -public class Settings { - /** - * Favorite intents - */ - public static final class Favorites implements BaseColumns { - /** - * The content:// style URL for this table - */ - public static final Uri CONTENT_URI = Uri.parse("content://" + - android.provider.Settings.AUTHORITY + "/favorites?notify=true"); - - /** - * The content:// style URL for this table. When this Uri is used, no notification is - * sent if the content changes. - */ - public static final Uri CONTENT_URI_NO_NOTIFICATION = - Uri.parse("content://" + android.provider.Settings.AUTHORITY + - "/favorites?notify=false"); - - /** - * The content:// style URL for a given row, identified by its id. - * - * @param id The row id. - * @param notify True to send a notification is the content changes. - * - * @return The unique content URL for the specified row. - */ - public static Uri getContentUri(long id, boolean notify) { - return Uri.parse("content://" + android.provider.Settings.AUTHORITY + - "/favorites/" + id + "?notify=" + notify); - } - - /** - * The row ID. - *

              Type: INTEGER

              - */ - public static final String ID = "_id"; - - /** - * Descriptive name of the favorite that can be displayed to the user. - *

              Type: TEXT

              - */ - public static final String TITLE = "title"; - - /** - * The Intent URL of the favorite, describing what it points to. This - * value is given to {@link android.content.Intent#getIntent} to create - * an Intent that can be launched. - *

              Type: TEXT

              - */ - public static final String INTENT = "intent"; - - /** - * The container holding the favorite - *

              Type: INTEGER

              - */ - public static final String CONTAINER = "container"; - - /** - * The icon is a resource identified by a package name and an integer id. - */ - public static final int CONTAINER_DESKTOP = -100; - - /** - * The screen holding the favorite (if container is CONTAINER_DESKTOP) - *

              Type: INTEGER

              - */ - public static final String SCREEN = "screen"; - - /** - * The X coordinate of the cell holding the favorite - * (if container is CONTAINER_DESKTOP or CONTAINER_DOCK) - *

              Type: INTEGER

              - */ - public static final String CELLX = "cellX"; - - /** - * The Y coordinate of the cell holding the favorite - * (if container is CONTAINER_DESKTOP) - *

              Type: INTEGER

              - */ - public static final String CELLY = "cellY"; - - /** - * The X span of the cell holding the favorite - *

              Type: INTEGER

              - */ - public static final String SPANX = "spanX"; - - /** - * The Y span of the cell holding the favorite - *

              Type: INTEGER

              - */ - public static final String SPANY = "spanY"; - - /** - * The type of the favorite - * - *

              Type: INTEGER

              - */ - public static final String ITEM_TYPE = "itemType"; - - /** - * The favorite is an application - */ - public static final int ITEM_TYPE_APPLICATION = 0; - - /** - * The favorite is an application created shortcut - */ - public static final int ITEM_TYPE_SHORTCUT = 1; - - /** - * The favorite is a user created folder - */ - public static final int ITEM_TYPE_USER_FOLDER = 2; - - /** - * The favorite is a clock - */ - public static final int ITEM_TYPE_WIDGET_CLOCK = 1000; - - /** - * The favorite is a search widget - */ - public static final int ITEM_TYPE_WIDGET_SEARCH = 1001; - - /** - * The favorite is a photo frame - */ - public static final int ITEM_TYPE_WIDGET_PHOTO_FRAME = 1002; - - /** - * Indicates whether this favorite is an application-created shortcut or not. - * If the value is 0, the favorite is not an application-created shortcut, if the - * value is 1, it is an application-created shortcut. - *

              Type: INTEGER

              - */ - public static final String IS_SHORTCUT = "isShortcut"; - - /** - * The icon type. - *

              Type: INTEGER

              - */ - public static final String ICON_TYPE = "iconType"; - - /** - * The icon is a resource identified by a package name and an integer id. - */ - public static final int ICON_TYPE_RESOURCE = 0; - - /** - * The icon is a bitmap. - */ - public static final int ICON_TYPE_BITMAP = 1; - - /** - * The icon package name, if icon type is ICON_TYPE_RESOURCE. - *

              Type: TEXT

              - */ - public static final String ICON_PACKAGE = "iconPackage"; - - /** - * The icon resource id, if icon type is ICON_TYPE_RESOURCE. - *

              Type: TEXT

              - */ - public static final String ICON_RESOURCE = "iconResource"; - - /** - * The custom icon bitmap, if icon type is ICON_TYPE_BITMAP. - *

              Type: BLOB

              - */ - public static final String ICON = "icon"; - } -} diff --git a/core/java/com/android/internal/util/FastXmlSerializer.java b/core/java/com/android/internal/util/FastXmlSerializer.java index b4dae9418e22669e2d4685a0140692481ce7e9e3..592a8facc7fd18ad2f51f70d8430754cb4c4c658 100644 --- a/core/java/com/android/internal/util/FastXmlSerializer.java +++ b/core/java/com/android/internal/util/FastXmlSerializer.java @@ -125,7 +125,7 @@ public class FastXmlSerializer implements XmlSerializer { String escape = escapes[c]; if (escape == null) continue; if (lastPos < pos) append(string, lastPos, pos-lastPos); - lastPos = pos; + lastPos = pos + 1; append(escape); } if (lastPos < pos) append(string, lastPos, pos-lastPos); @@ -143,7 +143,7 @@ public class FastXmlSerializer implements XmlSerializer { String escape = escapes[c]; if (escape == null) continue; if (lastPos < pos) append(buf, lastPos, pos-lastPos); - lastPos = pos; + lastPos = pos + 1; append(escape); } if (lastPos < pos) append(buf, lastPos, pos-lastPos); diff --git a/core/java/com/android/internal/view/IInputConnectionCallback.aidl b/core/java/com/android/internal/view/IInputConnectionCallback.aidl new file mode 100644 index 0000000000000000000000000000000000000000..5b5b3dfbb4a5c2e19582d7bb6d4b702692d17ca5 --- /dev/null +++ b/core/java/com/android/internal/view/IInputConnectionCallback.aidl @@ -0,0 +1,31 @@ +/* + * 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.android.internal.view; + +import android.graphics.Rect; +import android.view.KeyEvent; +import android.view.MotionEvent; +import android.view.inputmethod.TextBoxAttribute; +import com.android.internal.view.IInputContext; +import android.os.IBinder; + +/** + * {@hide} + */ +oneway interface IInputMethodCallback { + void finishedEvent(int seq, boolean handled); +} diff --git a/core/java/com/android/internal/view/IInputConnectionWrapper.java b/core/java/com/android/internal/view/IInputConnectionWrapper.java new file mode 100644 index 0000000000000000000000000000000000000000..c5966ee46350c7275f0da229a5853343efb9195c --- /dev/null +++ b/core/java/com/android/internal/view/IInputConnectionWrapper.java @@ -0,0 +1,252 @@ +package com.android.internal.view; + +import com.android.internal.view.IInputContext; + +import android.os.Bundle; +import android.os.Handler; +import android.os.Looper; +import android.os.Message; +import android.os.RemoteException; +import android.util.Log; +import android.view.KeyEvent; +import android.view.inputmethod.CompletionInfo; +import android.view.inputmethod.ExtractedTextRequest; +import android.view.inputmethod.InputConnection; + +public class IInputConnectionWrapper extends IInputContext.Stub { + static final String TAG = "IInputConnectionWrapper"; + + private static final int DO_GET_TEXT_AFTER_CURSOR = 10; + private static final int DO_GET_TEXT_BEFORE_CURSOR = 20; + private static final int DO_GET_CURSOR_CAPS_MODE = 30; + private static final int DO_GET_EXTRACTED_TEXT = 40; + private static final int DO_COMMIT_TEXT = 50; + private static final int DO_COMMIT_COMPLETION = 55; + private static final int DO_SET_COMPOSING_TEXT = 60; + private static final int DO_SEND_KEY_EVENT = 70; + private static final int DO_DELETE_SURROUNDING_TEXT = 80; + private static final int DO_HIDE_STATUS_ICON = 100; + private static final int DO_SHOW_STATUS_ICON = 110; + private static final int DO_PERFORM_PRIVATE_COMMAND = 120; + private static final int DO_CLEAR_META_KEY_STATES = 130; + + private InputConnection mInputConnection; + + private Looper mMainLooper; + private Handler mH; + + static class SomeArgs { + Object arg1; + Object arg2; + IInputContextCallback callback; + int seq; + } + + class MyHandler extends Handler { + MyHandler(Looper looper) { + super(looper); + } + + @Override + public void handleMessage(Message msg) { + executeMessage(msg); + } + } + + public IInputConnectionWrapper(Looper mainLooper, InputConnection conn) { + mInputConnection = conn; + mMainLooper = mainLooper; + mH = new MyHandler(mMainLooper); + } + + public void getTextAfterCursor(int length, int seq, IInputContextCallback callback) { + dispatchMessage(obtainMessageISC(DO_GET_TEXT_AFTER_CURSOR, length, seq, callback)); + } + + public void getTextBeforeCursor(int length, int seq, IInputContextCallback callback) { + dispatchMessage(obtainMessageISC(DO_GET_TEXT_BEFORE_CURSOR, length, seq, callback)); + } + + public void getCursorCapsMode(int reqModes, int seq, IInputContextCallback callback) { + dispatchMessage(obtainMessageISC(DO_GET_CURSOR_CAPS_MODE, reqModes, seq, callback)); + } + + public void getExtractedText(ExtractedTextRequest request, + int flags, int seq, IInputContextCallback callback) { + dispatchMessage(obtainMessageIOSC(DO_GET_EXTRACTED_TEXT, flags, + request, seq, callback)); + } + + public void commitText(CharSequence text, int newCursorPosition) { + dispatchMessage(obtainMessageIO(DO_COMMIT_TEXT, newCursorPosition, text)); + } + + public void commitCompletion(CompletionInfo text) { + dispatchMessage(obtainMessageO(DO_COMMIT_COMPLETION, text)); + } + + public void setComposingText(CharSequence text, int newCursorPosition) { + dispatchMessage(obtainMessageIO(DO_SET_COMPOSING_TEXT, newCursorPosition, text)); + } + + public void sendKeyEvent(KeyEvent event) { + dispatchMessage(obtainMessageO(DO_SEND_KEY_EVENT, event)); + } + + public void clearMetaKeyStates(int states) { + dispatchMessage(obtainMessageII(DO_CLEAR_META_KEY_STATES, states, 0)); + } + + public void deleteSurroundingText(int leftLength, int rightLength) { + dispatchMessage(obtainMessageII(DO_DELETE_SURROUNDING_TEXT, + leftLength, rightLength)); + } + + public void hideStatusIcon() { + dispatchMessage(obtainMessage(DO_HIDE_STATUS_ICON)); + } + + public void showStatusIcon(String packageName, int resId) { + dispatchMessage(obtainMessageIO(DO_SHOW_STATUS_ICON, resId, packageName)); + } + + public void performPrivateCommand(String action, Bundle data) { + dispatchMessage(obtainMessageOO(DO_PERFORM_PRIVATE_COMMAND, action, data)); + } + + void dispatchMessage(Message msg) { + // If we are calling this from the main thread, then we can call + // right through. Otherwise, we need to send the message to the + // main thread. + if (Looper.myLooper() == mMainLooper) { + executeMessage(msg); + msg.recycle(); + return; + } + + mH.sendMessage(msg); + } + + void executeMessage(Message msg) { + switch (msg.what) { + case DO_GET_TEXT_AFTER_CURSOR: { + SomeArgs args = (SomeArgs)msg.obj; + try { + args.callback.setTextAfterCursor(mInputConnection.getTextAfterCursor(msg.arg1), + args.seq); + } catch (RemoteException e) { + Log.w(TAG, "Got RemoteException calling setTextAfterCursor", e); + } + return; + } + case DO_GET_TEXT_BEFORE_CURSOR: { + SomeArgs args = (SomeArgs)msg.obj; + try { + args.callback.setTextBeforeCursor(mInputConnection.getTextBeforeCursor(msg.arg1), + args.seq); + } catch (RemoteException e) { + Log.w(TAG, "Got RemoteException calling setTextBeforeCursor", e); + } + return; + } + case DO_GET_CURSOR_CAPS_MODE: { + SomeArgs args = (SomeArgs)msg.obj; + try { + args.callback.setCursorCapsMode(mInputConnection.getCursorCapsMode(msg.arg1), + args.seq); + } catch (RemoteException e) { + Log.w(TAG, "Got RemoteException calling setCursorCapsMode", e); + } + return; + } + case DO_GET_EXTRACTED_TEXT: { + SomeArgs args = (SomeArgs)msg.obj; + try { + args.callback.setExtractedText(mInputConnection.getExtractedText( + (ExtractedTextRequest)args.arg1, msg.arg1), args.seq); + } catch (RemoteException e) { + Log.w(TAG, "Got RemoteException calling setExtractedText", e); + } + return; + } + case DO_COMMIT_TEXT: { + mInputConnection.commitText((CharSequence)msg.obj, msg.arg1); + return; + } + case DO_COMMIT_COMPLETION: { + mInputConnection.commitCompletion((CompletionInfo)msg.obj); + return; + } + case DO_SET_COMPOSING_TEXT: { + mInputConnection.setComposingText((CharSequence)msg.obj, msg.arg1); + return; + } + case DO_SEND_KEY_EVENT: { + mInputConnection.sendKeyEvent((KeyEvent)msg.obj); + return; + } + case DO_CLEAR_META_KEY_STATES: { + mInputConnection.clearMetaKeyStates(msg.arg1); + return; + } + case DO_DELETE_SURROUNDING_TEXT: { + mInputConnection.deleteSurroundingText(msg.arg1, msg.arg2); + return; + } + case DO_HIDE_STATUS_ICON: { + mInputConnection.hideStatusIcon(); + return; + } + case DO_SHOW_STATUS_ICON: { + mInputConnection.showStatusIcon((String)msg.obj, msg.arg1); + return; + } + case DO_PERFORM_PRIVATE_COMMAND: { + SomeArgs args = (SomeArgs)msg.obj; + mInputConnection.performPrivateCommand((String)args.arg1, + (Bundle)args.arg2); + return; + } + } + Log.w(TAG, "Unhandled message code: " + msg.what); + } + + Message obtainMessage(int what) { + return mH.obtainMessage(what); + } + + Message obtainMessageII(int what, int arg1, int arg2) { + return mH.obtainMessage(what, arg1, arg2); + } + + Message obtainMessageO(int what, Object arg1) { + return mH.obtainMessage(what, 0, 0, arg1); + } + + Message obtainMessageISC(int what, int arg1, int seq, IInputContextCallback callback) { + SomeArgs args = new SomeArgs(); + args.callback = callback; + args.seq = seq; + return mH.obtainMessage(what, arg1, 0, args); + } + + Message obtainMessageIOSC(int what, int arg1, Object arg2, int seq, + IInputContextCallback callback) { + SomeArgs args = new SomeArgs(); + args.arg1 = arg2; + args.callback = callback; + args.seq = seq; + return mH.obtainMessage(what, arg1, 0, args); + } + + Message obtainMessageIO(int what, int arg1, Object arg2) { + return mH.obtainMessage(what, arg1, 0, arg2); + } + + Message obtainMessageOO(int what, Object arg1, Object arg2) { + SomeArgs args = new SomeArgs(); + args.arg1 = arg1; + args.arg2 = arg2; + return mH.obtainMessage(what, 0, 0, args); + } +} diff --git a/core/java/com/android/internal/view/IInputContext.aidl b/core/java/com/android/internal/view/IInputContext.aidl new file mode 100644 index 0000000000000000000000000000000000000000..7ea65a054209a0dc6d7c08fe77a4842d3331e84c --- /dev/null +++ b/core/java/com/android/internal/view/IInputContext.aidl @@ -0,0 +1,58 @@ +/* + * 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.android.internal.view; + +import android.os.Bundle; +import android.view.KeyEvent; +import android.view.inputmethod.CompletionInfo; +import android.view.inputmethod.ExtractedTextRequest; + +import com.android.internal.view.IInputContextCallback; + +/** + * Interface from an input method to the application, allowing it to perform + * edits on the current input field and other interactions with the application. + * {@hide} + */ + oneway interface IInputContext { + void getTextBeforeCursor(int length, int seq, IInputContextCallback callback); + + void getTextAfterCursor(int length, int seq, IInputContextCallback callback); + + void getCursorCapsMode(int reqModes, int seq, IInputContextCallback callback); + + void getExtractedText(in ExtractedTextRequest request, int flags, int seq, + IInputContextCallback callback); + + void deleteSurroundingText(int leftLength, int rightLength); + + void setComposingText(CharSequence text, int newCursorPosition); + + void commitText(CharSequence text, int newCursorPosition); + + void commitCompletion(in CompletionInfo completion); + + void sendKeyEvent(in KeyEvent event); + + void clearMetaKeyStates(int states); + + void performPrivateCommand(String action, in Bundle data); + + void showStatusIcon(String packageName, int resId); + + void hideStatusIcon(); +} diff --git a/core/java/com/android/internal/view/IInputContextCallback.aidl b/core/java/com/android/internal/view/IInputContextCallback.aidl new file mode 100644 index 0000000000000000000000000000000000000000..9b8c43c6ff72fb255043bba86faf91f4a71ff786 --- /dev/null +++ b/core/java/com/android/internal/view/IInputContextCallback.aidl @@ -0,0 +1,29 @@ +/* + * 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.android.internal.view; + +import android.view.inputmethod.ExtractedText; + +/** + * {@hide} + */ +oneway interface IInputContextCallback { + void setTextBeforeCursor(CharSequence textBeforeCursor, int seq); + void setTextAfterCursor(CharSequence textAfterCursor, int seq); + void setCursorCapsMode(int capsMode, int seq); + void setExtractedText(in ExtractedText extractedText, int seq); +} diff --git a/core/java/com/android/internal/view/IInputMethod.aidl b/core/java/com/android/internal/view/IInputMethod.aidl new file mode 100644 index 0000000000000000000000000000000000000000..87bf473f550c86927b54007c2f750fe94c84b3d6 --- /dev/null +++ b/core/java/com/android/internal/view/IInputMethod.aidl @@ -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. + */ + +package com.android.internal.view; + +import android.graphics.Rect; +import android.os.IBinder; +import android.view.KeyEvent; +import android.view.MotionEvent; +import android.view.inputmethod.EditorInfo; +import android.view.inputmethod.InputBinding; +import com.android.internal.view.IInputContext; +import com.android.internal.view.IInputMethodCallback; +import com.android.internal.view.IInputMethodSession; + +/** + * Top-level interface to an input method component (implemented in a + * Service). + * {@hide} + */ +oneway interface IInputMethod { + void attachToken(IBinder token); + + void bindInput(in InputBinding binding); + + void unbindInput(); + + void startInput(in EditorInfo attribute); + + void restartInput(in EditorInfo attribute); + + void createSession(IInputMethodCallback callback); + + void setSessionEnabled(IInputMethodSession session, boolean enabled); + + void revokeSession(IInputMethodSession session); + + void showSoftInput(); + + void hideSoftInput(); +} diff --git a/core/java/com/android/internal/view/IInputMethodCallback.aidl b/core/java/com/android/internal/view/IInputMethodCallback.aidl new file mode 100644 index 0000000000000000000000000000000000000000..480cc0e5cd59d04f05040920d5cc084f1d33ccdd --- /dev/null +++ b/core/java/com/android/internal/view/IInputMethodCallback.aidl @@ -0,0 +1,34 @@ +/* + * 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.android.internal.view; + +import android.graphics.Rect; +import android.view.KeyEvent; +import android.view.MotionEvent; +import com.android.internal.view.IInputContext; +import com.android.internal.view.IInputMethodSession; +import android.os.IBinder; + +/** + * Helper interface for IInputMethod to allow the input method to call back + * to its client with results from incoming calls. + * {@hide} + */ +oneway interface IInputMethodCallback { + void finishedEvent(int seq, boolean handled); + void sessionCreated(IInputMethodSession session); +} diff --git a/core/java/com/android/internal/view/IInputMethodClient.aidl b/core/java/com/android/internal/view/IInputMethodClient.aidl new file mode 100644 index 0000000000000000000000000000000000000000..ce4312dafee3241a879e9195fb94f4f795d3c50f --- /dev/null +++ b/core/java/com/android/internal/view/IInputMethodClient.aidl @@ -0,0 +1,30 @@ +/* + * 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.android.internal.view; + +import com.android.internal.view.InputBindResult; + +/** + * Interface a client of the IInputMethodManager implements, to identify + * itself and receive information about changes to the global manager state. + */ +oneway interface IInputMethodClient { + void setUsingInputMethod(boolean state); + void onBindMethod(in InputBindResult res); + void onUnbindMethod(int sequence); + void setActive(boolean active); +} diff --git a/core/java/com/android/internal/view/IInputMethodManager.aidl b/core/java/com/android/internal/view/IInputMethodManager.aidl new file mode 100644 index 0000000000000000000000000000000000000000..b4cfe26330c8367ff4473e8b8e5ee6d33937db96 --- /dev/null +++ b/core/java/com/android/internal/view/IInputMethodManager.aidl @@ -0,0 +1,51 @@ +/* + * 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.android.internal.view; + +import android.view.inputmethod.InputMethodInfo; +import android.view.inputmethod.EditorInfo; +import com.android.internal.view.InputBindResult; +import com.android.internal.view.IInputContext; +import com.android.internal.view.IInputMethodClient; + +/** + * Public interface to the global input method manager, used by all client + * applications. + */ +interface IInputMethodManager { + List getInputMethodList(); + List getEnabledInputMethodList(); + + void addClient(in IInputMethodClient client, + in IInputContext inputContext, int uid, int pid); + void removeClient(in IInputMethodClient client); + + InputBindResult startInput(in IInputMethodClient client, + in EditorInfo attribute, boolean initial, boolean needResult); + void finishInput(in IInputMethodClient client); + void showSoftInput(in IInputMethodClient client); + void hideSoftInput(in IInputMethodClient client); + void windowGainedFocus(in IInputMethodClient client, + boolean viewHasFocus, int softInputMode, boolean first, + int windowFlags); + + void showInputMethodPickerFromClient(in IInputMethodClient client); + void setInputMethod(in IBinder token, String id); + void hideMySoftInput(in IBinder token); + void updateStatusIcon(int iconId, String iconPackage); +} + diff --git a/core/java/com/android/internal/view/IInputMethodSession.aidl b/core/java/com/android/internal/view/IInputMethodSession.aidl new file mode 100644 index 0000000000000000000000000000000000000000..4f285933dec7d1c15ae2d23a34ea83190d00f487 --- /dev/null +++ b/core/java/com/android/internal/view/IInputMethodSession.aidl @@ -0,0 +1,48 @@ +/* + * 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.android.internal.view; + +import android.graphics.Rect; +import android.os.Bundle; +import android.view.KeyEvent; +import android.view.MotionEvent; +import android.view.inputmethod.CompletionInfo; +import android.view.inputmethod.ExtractedText; +import com.android.internal.view.IInputMethodCallback; + +/** + * Sub-interface of IInputMethod which is safe to give to client applications. + * {@hide} + */ +oneway interface IInputMethodSession { + void finishInput(); + + void updateExtractedText(int token, in ExtractedText text); + + void updateSelection(int oldSelStart, int oldSelEnd, + int newSelStart, int newSelEnd); + + void updateCursor(in Rect newCursor); + + void displayCompletions(in CompletionInfo[] completions); + + void dispatchKeyEvent(int seq, in KeyEvent event, IInputMethodCallback callback); + + void dispatchTrackballEvent(int seq, in MotionEvent event, IInputMethodCallback callback); + + void appPrivateCommand(String action, in Bundle data); +} diff --git a/core/java/com/android/internal/view/InputBindResult.aidl b/core/java/com/android/internal/view/InputBindResult.aidl new file mode 100644 index 0000000000000000000000000000000000000000..7ff5c4eac75e8f0827a2a772e9a9314de64e7fe4 --- /dev/null +++ b/core/java/com/android/internal/view/InputBindResult.aidl @@ -0,0 +1,19 @@ +/* + * 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.android.internal.view; + +parcelable InputBindResult; diff --git a/core/java/com/android/internal/view/InputBindResult.java b/core/java/com/android/internal/view/InputBindResult.java new file mode 100644 index 0000000000000000000000000000000000000000..658f098bdaefd33af00dd68438ac79d0c3de0c41 --- /dev/null +++ b/core/java/com/android/internal/view/InputBindResult.java @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2007-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.android.internal.view; + +import android.os.Parcel; +import android.os.Parcelable; + +/** + * Bundle of information returned by input method manager about a successful + * binding to an input method. + */ +public final class InputBindResult implements Parcelable { + static final String TAG = "InputBindResult"; + + /** + * The input method service. + */ + public final IInputMethodSession method; + + /** + * The ID for this input method, as found in InputMethodInfo; null if + * no input method will be bound. + */ + public final String id; + + /** + * Sequence number of this binding. + */ + public final int sequence; + + public InputBindResult(IInputMethodSession _method, String _id, int _sequence) { + method = _method; + id = _id; + sequence = _sequence; + } + + InputBindResult(Parcel source) { + method = IInputMethodSession.Stub.asInterface(source.readStrongBinder()); + id = source.readString(); + sequence = source.readInt(); + } + + @Override + public String toString() { + return "InputBindResult{" + method + " " + id + + " #" + sequence + "}"; + } + + /** + * Used to package this object into a {@link Parcel}. + * + * @param dest The {@link Parcel} to be written. + * @param flags The flags used for parceling. + */ + public void writeToParcel(Parcel dest, int flags) { + dest.writeStrongInterface(method); + dest.writeString(id); + dest.writeInt(sequence); + } + + /** + * Used to make this class parcelable. + */ + public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { + public InputBindResult createFromParcel(Parcel source) { + return new InputBindResult(source); + } + + public InputBindResult[] newArray(int size) { + return new InputBindResult[size]; + } + }; + + public int describeContents() { + return 0; + } +} diff --git a/core/java/com/android/internal/view/InputConnectionWrapper.java b/core/java/com/android/internal/view/InputConnectionWrapper.java new file mode 100644 index 0000000000000000000000000000000000000000..5bfcfe9598b214ad978f6d6b92f756f3d20a28c9 --- /dev/null +++ b/core/java/com/android/internal/view/InputConnectionWrapper.java @@ -0,0 +1,306 @@ +package com.android.internal.view; + +import com.android.internal.view.IInputContext; + +import android.os.Bundle; +import android.os.RemoteException; +import android.os.SystemClock; +import android.util.Log; +import android.view.KeyEvent; +import android.view.inputmethod.CompletionInfo; +import android.view.inputmethod.ExtractedText; +import android.view.inputmethod.ExtractedTextRequest; +import android.view.inputmethod.InputConnection; + +public class InputConnectionWrapper implements InputConnection { + private static final int MAX_WAIT_TIME_MILLIS = 2000; + private final IInputContext mIInputContext; + + static class InputContextCallback extends IInputContextCallback.Stub { + private static final String TAG = "InputConnectionWrapper.ICC"; + public int mSeq; + public boolean mHaveValue; + public CharSequence mTextBeforeCursor; + public CharSequence mTextAfterCursor; + public ExtractedText mExtractedText; + public int mCursorCapsMode; + + // A 'pool' of one InputContextCallback. Each ICW request will attempt to gain + // exclusive access to this object. + private static InputContextCallback sInstance = new InputContextCallback(); + private static int sSequenceNumber = 1; + + /** + * Returns an InputContextCallback object that is guaranteed not to be in use by + * any other thread. The returned object's 'have value' flag is cleared and its expected + * sequence number is set to a new integer. We use a sequence number so that replies that + * occur after a timeout has expired are not interpreted as replies to a later request. + */ + private static InputContextCallback getInstance() { + synchronized (InputContextCallback.class) { + // Return sInstance if it's non-null, otherwise construct a new callback + InputContextCallback callback; + if (sInstance != null) { + callback = sInstance; + sInstance = null; + + // Reset the callback + callback.mHaveValue = false; + } else { + callback = new InputContextCallback(); + } + + // Set the sequence number + callback.mSeq = sSequenceNumber++; + return callback; + } + } + + /** + * Makes the given InputContextCallback available for use in the future. + */ + private void dispose() { + synchronized (InputContextCallback.class) { + // If sInstance is non-null, just let this object be garbage-collected + if (sInstance == null) { + // Allow any objects being held to be gc'ed + mTextAfterCursor = null; + mTextBeforeCursor = null; + mExtractedText = null; + sInstance = this; + } + } + } + + public void setTextBeforeCursor(CharSequence textBeforeCursor, int seq) { + synchronized (this) { + if (seq == mSeq) { + mTextBeforeCursor = textBeforeCursor; + mHaveValue = true; + notifyAll(); + } else { + Log.i(TAG, "Got out-of-sequence callback " + seq + " (expected " + mSeq + + ") in setTextBeforeCursor, ignoring."); + } + } + } + + public void setTextAfterCursor(CharSequence textAfterCursor, int seq) { + synchronized (this) { + if (seq == mSeq) { + mTextAfterCursor = textAfterCursor; + mHaveValue = true; + notifyAll(); + } else { + Log.i(TAG, "Got out-of-sequence callback " + seq + " (expected " + mSeq + + ") in setTextAfterCursor, ignoring."); + } + } + } + + public void setCursorCapsMode(int capsMode, int seq) { + synchronized (this) { + if (seq == mSeq) { + mCursorCapsMode = capsMode; + mHaveValue = true; + notifyAll(); + } else { + Log.i(TAG, "Got out-of-sequence callback " + seq + " (expected " + mSeq + + ") in setCursorCapsMode, ignoring."); + } + } + } + + public void setExtractedText(ExtractedText extractedText, int seq) { + synchronized (this) { + if (seq == mSeq) { + mExtractedText = extractedText; + mHaveValue = true; + notifyAll(); + } else { + Log.i(TAG, "Got out-of-sequence callback " + seq + " (expected " + mSeq + + ") in setExtractedText, ignoring."); + } + } + } + + /** + * Waits for a result for up to {@link #MAX_WAIT_TIME_MILLIS} milliseconds. + * + *

              The caller must be synchronized on this callback object. + */ + void waitForResultLocked() { + long startTime = SystemClock.uptimeMillis(); + long endTime = startTime + MAX_WAIT_TIME_MILLIS; + + while (!mHaveValue) { + long remainingTime = endTime - SystemClock.uptimeMillis(); + if (remainingTime <= 0) { + Log.w(TAG, "Timed out waiting on IInputContextCallback"); + return; + } + try { + wait(remainingTime); + } catch (InterruptedException e) { + } + } + } + } + + public InputConnectionWrapper(IInputContext inputContext) { + mIInputContext = inputContext; + } + + public CharSequence getTextAfterCursor(int length) { + CharSequence value = null; + try { + InputContextCallback callback = InputContextCallback.getInstance(); + mIInputContext.getTextAfterCursor(length, callback.mSeq, callback); + synchronized (callback) { + callback.waitForResultLocked(); + if (callback.mHaveValue) { + value = callback.mTextAfterCursor; + } + } + callback.dispose(); + } catch (RemoteException e) { + return null; + } + return value; + } + + public CharSequence getTextBeforeCursor(int length) { + CharSequence value = null; + try { + InputContextCallback callback = InputContextCallback.getInstance(); + mIInputContext.getTextBeforeCursor(length, callback.mSeq, callback); + synchronized (callback) { + callback.waitForResultLocked(); + if (callback.mHaveValue) { + value = callback.mTextBeforeCursor; + } + } + callback.dispose(); + } catch (RemoteException e) { + return null; + } + return value; + } + + public int getCursorCapsMode(int reqModes) { + int value = 0; + try { + InputContextCallback callback = InputContextCallback.getInstance(); + mIInputContext.getCursorCapsMode(reqModes, callback.mSeq, callback); + synchronized (callback) { + callback.waitForResultLocked(); + if (callback.mHaveValue) { + value = callback.mCursorCapsMode; + } + } + callback.dispose(); + } catch (RemoteException e) { + return 0; + } + return value; + } + + public ExtractedText getExtractedText(ExtractedTextRequest request, int flags) { + ExtractedText value = null; + try { + InputContextCallback callback = InputContextCallback.getInstance(); + mIInputContext.getExtractedText(request, flags, callback.mSeq, callback); + synchronized (callback) { + callback.waitForResultLocked(); + if (callback.mHaveValue) { + value = callback.mExtractedText; + } + } + callback.dispose(); + } catch (RemoteException e) { + return null; + } + return value; + } + + public boolean commitText(CharSequence text, int newCursorPosition) { + try { + mIInputContext.commitText(text, newCursorPosition); + return true; + } catch (RemoteException e) { + return false; + } + } + + public boolean commitCompletion(CompletionInfo text) { + try { + mIInputContext.commitCompletion(text); + return true; + } catch (RemoteException e) { + return false; + } + } + + public boolean setComposingText(CharSequence text, int newCursorPosition) { + try { + mIInputContext.setComposingText(text, newCursorPosition); + return true; + } catch (RemoteException e) { + return false; + } + } + + public boolean sendKeyEvent(KeyEvent event) { + try { + mIInputContext.sendKeyEvent(event); + return true; + } catch (RemoteException e) { + return false; + } + } + + public boolean clearMetaKeyStates(int states) { + try { + mIInputContext.clearMetaKeyStates(states); + return true; + } catch (RemoteException e) { + return false; + } + } + + public boolean deleteSurroundingText(int leftLength, int rightLength) { + try { + mIInputContext.deleteSurroundingText(leftLength, rightLength); + return true; + } catch (RemoteException e) { + return false; + } + } + + public boolean hideStatusIcon() { + try { + mIInputContext.showStatusIcon(null, 0); + return true; + } catch (RemoteException e) { + return false; + } + } + + public boolean showStatusIcon(String packageName, int resId) { + try { + mIInputContext.showStatusIcon(packageName, resId); + return true; + } catch (RemoteException e) { + return false; + } + } + + public boolean performPrivateCommand(String action, Bundle data) { + try { + mIInputContext.performPrivateCommand(action, data); + return true; + } catch (RemoteException e) { + return false; + } + } +} diff --git a/core/java/com/android/internal/view/menu/IconMenuItemView.java b/core/java/com/android/internal/view/menu/IconMenuItemView.java index 156e20ae7ba192981e7ea8c6f66d1bf4036ee111..3b11a649e31137ade68213284a8659672fb8d747 100644 --- a/core/java/com/android/internal/view/menu/IconMenuItemView.java +++ b/core/java/com/android/internal/view/menu/IconMenuItemView.java @@ -26,6 +26,7 @@ import android.util.AttributeSet; import android.view.Gravity; import android.view.SoundEffectConstants; import android.view.View; +import android.view.ViewDebug; import android.widget.TextView; /** @@ -176,6 +177,9 @@ public final class IconMenuItemView extends TextView implements MenuView.ItemVie // Set the compound drawables setCompoundDrawables(null, icon, null, null); + + // When there is an icon, make sure the text is at the bottom + setGravity(Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL); /* * Request a layout to reposition the icon. The positioning of icon @@ -185,13 +189,17 @@ public final class IconMenuItemView extends TextView implements MenuView.ItemVie requestLayout(); } else { setCompoundDrawables(null, null, null, null); + + // When there is no icon, make sure the text is centered vertically + setGravity(Gravity.CENTER_VERTICAL | Gravity.CENTER_HORIZONTAL); } } public void setItemInvoker(ItemInvoker itemInvoker) { mItemInvoker = itemInvoker; } - + + @ViewDebug.CapturedViewProperty(retrieveReturn = true) public MenuItemImpl getItemData() { return mItemData; } diff --git a/core/java/com/android/internal/view/menu/IconMenuView.java b/core/java/com/android/internal/view/menu/IconMenuView.java index fc76a0426be9f914843fdba0dde3381acdb4425f..781c608aaebb723002fafb8cd259f7d1c1ae59f9 100644 --- a/core/java/com/android/internal/view/menu/IconMenuView.java +++ b/core/java/com/android/internal/view/menu/IconMenuView.java @@ -26,6 +26,7 @@ import android.graphics.Rect; import android.graphics.drawable.Drawable; import android.os.Parcel; import android.os.Parcelable; +import android.text.Layout; import android.util.AttributeSet; import android.view.KeyEvent; import android.view.View; @@ -57,6 +58,8 @@ public final class IconMenuView extends ViewGroup implements ItemInvoker, MenuVi private int mRowHeight; /** Maximum number of rows to be shown */ private int mMaxRows; + /** Maximum number of items to show in the icon menu. */ + private int mMaxItems; /** Maximum number of items per row */ private int mMaxItemsPerRow; /** Actual number of items (the 'More' view does not count as an item) shown */ @@ -76,15 +79,15 @@ public final class IconMenuView extends ViewGroup implements ItemInvoker, MenuVi /** Set of vertical divider positions where the vertical divider will be drawn */ private ArrayList mVerticalDividerRects; + /** Icon for the 'More' button */ + private Drawable mMoreIcon; + /** Item view for the 'More' button */ private IconMenuItemView mMoreItemView; /** Background of each item (should contain the selected and focused states) */ private Drawable mItemBackground; - /** Icon for the 'More' button */ - private Drawable mMoreIcon; - /** Default animations for this menu */ private int mAnimations; @@ -108,6 +111,20 @@ public final class IconMenuView extends ViewGroup implements ItemInvoker, MenuVi * we broadcasted to children. */ private boolean mLastChildrenCaptionMode; + + /** + * The layout to use for menu items. Each index is the row number (0 is the + * top-most). Each value contains the number of items in that row. + *

              + * The length of this array should not be used to get the number of rows in + * the current layout, instead use {@link #mLayoutNumRows}. + */ + private int[] mLayout; + + /** + * The number of rows in the current layout. + */ + private int mLayoutNumRows; /** * Instantiates the IconMenuView that is linked with the provided MenuBuilder. @@ -119,6 +136,7 @@ public final class IconMenuView extends ViewGroup implements ItemInvoker, MenuVi context.obtainStyledAttributes(attrs, com.android.internal.R.styleable.IconMenuView, 0, 0); mRowHeight = a.getDimensionPixelSize(com.android.internal.R.styleable.IconMenuView_rowHeight, 64); mMaxRows = a.getInt(com.android.internal.R.styleable.IconMenuView_maxRows, 2); + mMaxItems = a.getInt(com.android.internal.R.styleable.IconMenuView_maxItems, 6); mMaxItemsPerRow = a.getInt(com.android.internal.R.styleable.IconMenuView_maxItemsPerRow, 3); mMoreIcon = a.getDrawable(com.android.internal.R.styleable.IconMenuView_moreIcon); a.recycle(); @@ -144,6 +162,8 @@ public final class IconMenuView extends ViewGroup implements ItemInvoker, MenuVi if (mVerticalDividerWidth == -1) mVerticalDividerWidth = 1; } + mLayout = new int[mMaxRows]; + // This view will be drawing the dividers setWillNotDraw(false); @@ -152,13 +172,106 @@ public final class IconMenuView extends ViewGroup implements ItemInvoker, MenuVi // This is so our children can still be arrow-key focused setDescendantFocusability(FOCUS_AFTER_DESCENDANTS); } - + + /** + * Figures out the layout for the menu items. + * + * @param width The available width for the icon menu. + */ + private void layoutItems(int width) { + int numItems = getChildCount(); + + // Start with the least possible number of rows + int curNumRows = + Math.min((int) Math.ceil(numItems / (float) mMaxItemsPerRow), mMaxRows); + + /* + * Increase the number of rows until we find a configuration that fits + * all of the items' titles. Worst case, we use mMaxRows. + */ + for (; curNumRows <= mMaxRows; curNumRows++) { + layoutItemsUsingGravity(curNumRows, numItems); + + if (curNumRows >= numItems) { + // Can't have more rows than items + break; + } + + if (doItemsFit()) { + // All the items fit, so this is a good configuration + break; + } + } + } + /** - * Calculates the minimum number of rows needed to the items to be shown. - * @return the minimum number of rows + * Figures out the layout for the menu items by equally distributing, and + * adding any excess items equally to lower rows. + * + * @param numRows The total number of rows for the menu view + * @param numItems The total number of items (across all rows) contained in + * the menu view + * @return int[] Where the value of index i contains the number of items for row i */ - private int calculateNumberOfRows() { - return Math.min((int) Math.ceil(getChildCount() / (double) mMaxItemsPerRow), mMaxRows); + private void layoutItemsUsingGravity(int numRows, int numItems) { + int numBaseItemsPerRow = numItems / numRows; + int numLeftoverItems = numItems % numRows; + /** + * The bottom rows will each get a leftover item. Rows (indexed at 0) + * that are >= this get a leftover item. Note: if there are 0 leftover + * items, no rows will get them since this value will be greater than + * the last row. + */ + int rowsThatGetALeftoverItem = numRows - numLeftoverItems; + + int[] layout = mLayout; + for (int i = 0; i < numRows; i++) { + layout[i] = numBaseItemsPerRow; + + // Fill the bottom rows with a leftover item each + if (i >= rowsThatGetALeftoverItem) { + layout[i]++; + } + } + + mLayoutNumRows = numRows; + } + + /** + * Checks whether each item's title is fully visible using the current + * layout. + * + * @return True if the items fit (each item's text is fully visible), false + * otherwise. + */ + private boolean doItemsFit() { + int itemPos = 0; + + int[] layout = mLayout; + int numRows = mLayoutNumRows; + for (int row = 0; row < numRows; row++) { + int numItemsOnRow = layout[row]; + + /* + * If there is only one item on this row, increasing the + * number of rows won't help. + */ + if (numItemsOnRow == 1) { + itemPos++; + continue; + } + + for (int itemsOnRowCounter = numItemsOnRow; itemsOnRowCounter > 0; + itemsOnRowCounter--) { + View child = getChildAt(itemPos++); + LayoutParams lp = (LayoutParams) child.getLayoutParams(); + if (lp.maxNumItemsOnRow < numItemsOnRow) { + return false; + } + } + } + + return true; } /** @@ -166,7 +279,7 @@ public final class IconMenuView extends ViewGroup implements ItemInvoker, MenuVi * @param itemView The item's view to add */ private void addItemView(IconMenuItemView itemView) { - ViewGroup.LayoutParams lp = itemView.getLayoutParams(); + LayoutParams lp = (LayoutParams) itemView.getLayoutParams(); if (lp == null) { // Default layout parameters @@ -182,6 +295,9 @@ public final class IconMenuView extends ViewGroup implements ItemInvoker, MenuVi // This class is the invoker for all its item views itemView.setItemInvoker(this); + // Set the desired width of item + lp.desiredWidth = (int) Layout.getDesiredWidth(itemView.getText(), itemView.getPaint()); + addView(itemView, lp); } @@ -228,7 +344,7 @@ public final class IconMenuView extends ViewGroup implements ItemInvoker, MenuVi final ArrayList itemsToShow = mMenu.getVisibleItems(); final int numItems = itemsToShow.size(); - final int numItemsThatCanFit = mMaxItemsPerRow * mMaxRows; + final int numItemsThatCanFit = mMaxItems; // Minimum of the num that can fit and the num that we have final int minFitMinus1AndNumItems = Math.min(numItemsThatCanFit - 1, numItems); @@ -262,30 +378,6 @@ public final class IconMenuView extends ViewGroup implements ItemInvoker, MenuVi } } - /** - * Calculates the number of items that should go on each row of this menu view. - * @param numRows the total number of rows for the menu view - * @param numItems the total number of items (across all rows) contained in the menu view - * @return int[] where index i contains the number of items for row i - */ - private int[] calculateNumberOfItemsPerRow(final int numRows, final int numItems) { - // TODO: get from theme? or write a best-fit algorithm? either way, this hard-coding needs - // to be dropped (946635). Right now, this is according to UI spec. - final int numItemsForRow[] = new int[numRows]; - if (numRows == 2) { - if (numItems <= 5) { - numItemsForRow[0] = 2; - numItemsForRow[1] = numItems - 2; - } else { - numItemsForRow[0] = numItemsForRow[1] = mMaxItemsPerRow; - } - } else if (numRows == 1) { - numItemsForRow[0] = numItems; - } - - return numItemsForRow; - } - /** * The positioning algorithm that gets called from onMeasure. It * just computes positions for each child, and then stores them in the child's layout params. @@ -298,10 +390,9 @@ public final class IconMenuView extends ViewGroup implements ItemInvoker, MenuVi if (mVerticalDivider != null) mVerticalDividerRects.clear(); // Get the minimum number of rows needed - final int numRows = calculateNumberOfRows(); + final int numRows = mLayoutNumRows; final int numRowsMinus1 = numRows - 1; - final int numItems = getChildCount(); - final int numItemsForRow[] = calculateNumberOfItemsPerRow(numRows, numItems); + final int numItemsForRow[] = mLayout; // The item position across all rows int itemPos = 0; @@ -382,13 +473,17 @@ public final class IconMenuView extends ViewGroup implements ItemInvoker, MenuVi updateChildren(false); } + int measuredWidth = resolveSize(Integer.MAX_VALUE, widthMeasureSpec); + calculateItemFittingMetadata(measuredWidth); + layoutItems(measuredWidth); + // Get the desired height of the icon menu view (last row of items does // not have a divider below) - final int desiredHeight = (mRowHeight + mHorizontalDividerHeight) * calculateNumberOfRows() - - mHorizontalDividerHeight; + final int desiredHeight = (mRowHeight + mHorizontalDividerHeight) * + mLayoutNumRows - mHorizontalDividerHeight; // Maximum possible width and desired height - setMeasuredDimension(resolveSize(Integer.MAX_VALUE, widthMeasureSpec), + setMeasuredDimension(measuredWidth, resolveSize(desiredHeight, heightMeasureSpec)); // Position the children @@ -472,6 +567,32 @@ public final class IconMenuView extends ViewGroup implements ItemInvoker, MenuVi return mAnimations; } + /** + * Returns the number of items per row. + *

              + * This should only be used for testing. + * + * @return The length of the array is the number of rows. A value at a + * position is the number of items in that row. + * @hide + */ + public int[] getLayout() { + return mLayout; + } + + /** + * Returns the number of rows in the layout. + *

              + * This should only be used for testing. + * + * @return The length of the array is the number of rows. A value at a + * position is the number of items in that row. + * @hide + */ + public int getLayoutNumRows() { + return mLayoutNumRows; + } + @Override public boolean dispatchKeyEvent(KeyEvent event) { @@ -498,6 +619,13 @@ public final class IconMenuView extends ViewGroup implements ItemInvoker, MenuVi return super.dispatchKeyEvent(event); } + @Override + protected void onAttachedToWindow() { + super.onAttachedToWindow(); + + requestFocus(); + } + @Override protected void onDetachedFromWindow() { setCycleShortcutCaptionMode(false); @@ -580,6 +708,31 @@ public final class IconMenuView extends ViewGroup implements ItemInvoker, MenuVi ((IconMenuItemView) getChildAt(i)).setCaptionMode(shortcut); } } + + /** + * For each item, calculates the most dense row that fully shows the item's + * title. + * + * @param width The available width of the icon menu. + */ + private void calculateItemFittingMetadata(int width) { + int maxNumItemsPerRow = mMaxItemsPerRow; + int numItems = getChildCount(); + for (int i = 0; i < numItems; i++) { + LayoutParams lp = (LayoutParams) getChildAt(i).getLayoutParams(); + // Start with 1, since that case does not get covered in the loop below + lp.maxNumItemsOnRow = 1; + for (int curNumItemsPerRow = maxNumItemsPerRow; curNumItemsPerRow > 0; + curNumItemsPerRow--) { + // Check whether this item can fit into a row containing curNumItemsPerRow + if (lp.desiredWidth < width / curNumItemsPerRow) { + // It can, mark this value as the most dense row it can fit into + lp.maxNumItemsOnRow = curNumItemsPerRow; + break; + } + } + } + } @Override protected Parcelable onSaveInstanceState() { @@ -655,6 +808,8 @@ public final class IconMenuView extends ViewGroup implements ItemInvoker, MenuVi public static class LayoutParams extends ViewGroup.MarginLayoutParams { int left, top, right, bottom; + int desiredWidth; + int maxNumItemsOnRow; public LayoutParams(Context c, AttributeSet attrs) { super(c, attrs); diff --git a/core/java/com/android/internal/view/menu/MenuBuilder.java b/core/java/com/android/internal/view/menu/MenuBuilder.java index 835e4a93628774cce4bf1b9539213ec88799bd22..298760265141eb5f247cca74d47b654337b21515 100644 --- a/core/java/com/android/internal/view/menu/MenuBuilder.java +++ b/core/java/com/android/internal/view/menu/MenuBuilder.java @@ -432,8 +432,9 @@ public class MenuBuilder implements Menu { rintent.setComponent(new ComponentName( ri.activityInfo.applicationInfo.packageName, ri.activityInfo.name)); - final MenuItem item = add(group, id, categoryOrder, ri.loadLabel(pm)); - item.setIntent(rintent); + final MenuItem item = add(group, id, categoryOrder, ri.loadLabel(pm)) + .setIcon(ri.loadIcon(pm)) + .setIntent(rintent); if (outSpecificItems != null && ri.specificIndex >= 0) { outSpecificItems[ri.specificIndex] = item; } @@ -624,7 +625,8 @@ public class MenuBuilder implements Menu { return mItems.size(); } - public MenuItem get(int index) { + /** {@inheritDoc} */ + public MenuItem getItem(int index) { return mItems.get(index); } @@ -773,7 +775,8 @@ public class MenuBuilder implements Menu { (shortcutAlphaChar != 0) && (shortcutAlphaChar == possibleChars.meta[0] || shortcutAlphaChar == possibleChars.meta[2] - || (shortcutAlphaChar == '\b' && keyCode == KeyEvent.KEYCODE_DEL))) { + || (shortcutAlphaChar == '\b' && keyCode == KeyEvent.KEYCODE_DEL)) && + item.isEnabled()) { return item; } } else { @@ -781,7 +784,8 @@ public class MenuBuilder implements Menu { if (((metaState & (KeyEvent.META_SHIFT_ON | KeyEvent.META_SYM_ON)) == 0) && (shortcutNumericChar != 0) && (shortcutNumericChar == possibleChars.meta[0] - || shortcutNumericChar == possibleChars.meta[2])) { + || shortcutNumericChar == possibleChars.meta[2]) && + item.isEnabled()) { return item; } } @@ -829,13 +833,18 @@ public class MenuBuilder implements Menu { * sub menu is about to be shown, allMenusAreClosing * is false. */ - public final void close(boolean allMenusAreClosing) { + final void close(boolean allMenusAreClosing) { Callback callback = getCallback(); if (callback != null) { callback.onCloseMenu(this, allMenusAreClosing); } } + /** {@inheritDoc} */ + public void close() { + close(true); + } + /** * Called when an item is added or removed. * diff --git a/core/java/com/android/internal/view/menu/MenuDialogHelper.java b/core/java/com/android/internal/view/menu/MenuDialogHelper.java index 6dfc7a2e27494196ff3142c0646de20359f948a9..bc51cf3a385f95349aa25def498ae5217e5e2f3e 100644 --- a/core/java/com/android/internal/view/menu/MenuDialogHelper.java +++ b/core/java/com/android/internal/view/menu/MenuDialogHelper.java @@ -72,10 +72,11 @@ public class MenuDialogHelper implements DialogInterface.OnKeyListener, DialogIn mDialog = builder.create(); WindowManager.LayoutParams lp = mDialog.getWindow().getAttributes(); - lp.type = WindowManager.LayoutParams.TYPE_APPLICATION_PANEL; + lp.type = WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG; if (windowToken != null) { lp.token = windowToken; } + lp.flags |= WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM; mDialog.show(); } diff --git a/core/java/com/android/internal/view/menu/MenuItemImpl.java b/core/java/com/android/internal/view/menu/MenuItemImpl.java index c89f2e9892d472a8926c95fe9179c2f9410af6d4..43dba6f3e465c9a436301205a313af71d70adbc1 100644 --- a/core/java/com/android/internal/view/menu/MenuItemImpl.java +++ b/core/java/com/android/internal/view/menu/MenuItemImpl.java @@ -24,6 +24,7 @@ import android.view.LayoutInflater; import android.view.MenuItem; import android.view.SubMenu; import android.view.View; +import android.view.ViewDebug; import android.view.ViewGroup; import android.view.ContextMenu.ContextMenuInfo; @@ -183,6 +184,7 @@ public final class MenuItemImpl implements MenuItem { return mGroup; } + @ViewDebug.CapturedViewProperty public int getItemId() { return mId; } @@ -353,6 +355,7 @@ public final class MenuItemImpl implements MenuItem { subMenu.setHeaderTitle(getTitle()); } + @ViewDebug.CapturedViewProperty public CharSequence getTitle() { return mTitle; } diff --git a/core/java/com/android/internal/view/package.html b/core/java/com/android/internal/view/package.html new file mode 100644 index 0000000000000000000000000000000000000000..783d0a1b54d5275fc99f1e9673978c4fda3c8a9a --- /dev/null +++ b/core/java/com/android/internal/view/package.html @@ -0,0 +1,3 @@ + +{@hide} + diff --git a/core/java/com/android/internal/widget/DialogTitle.java b/core/java/com/android/internal/widget/DialogTitle.java new file mode 100644 index 0000000000000000000000000000000000000000..2eef0b6638513f1c4ef04fb684738f0bba37cfa1 --- /dev/null +++ b/core/java/com/android/internal/widget/DialogTitle.java @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2008 Google Inc. + * + * 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.android.internal.widget; + +import android.content.Context; +import android.content.res.TypedArray; +import android.text.Layout; +import android.util.AttributeSet; +import android.util.TypedValue; +import android.widget.TextView; + +/** + * Used by dialogs to change the font size and number of lines to try to fit + * the text to the available space. + */ +public class DialogTitle extends TextView { + + public DialogTitle(Context context, AttributeSet attrs, + int defStyle) { + super(context, attrs, defStyle); + } + + public DialogTitle(Context context, AttributeSet attrs) { + super(context, attrs); + } + + public DialogTitle(Context context) { + super(context); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + + final Layout layout = getLayout(); + if (layout != null) { + final int lineCount = layout.getLineCount(); + if (lineCount > 0) { + final int ellipsisCount = layout.getEllipsisCount(lineCount - 1); + if (ellipsisCount > 0) { + setSingleLine(false); + + TypedArray a = mContext.obtainStyledAttributes( + android.R.style.TextAppearance_Medium, + android.R.styleable.TextAppearance); + final int textSize = a.getDimensionPixelSize( + android.R.styleable.TextAppearance_textSize, 20); + + setTextSize(TypedValue.COMPLEX_UNIT_SP, textSize); + setMaxLines(2); + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + } + } + } + } + +} \ No newline at end of file diff --git a/core/java/com/android/internal/widget/EditableInputConnection.java b/core/java/com/android/internal/widget/EditableInputConnection.java new file mode 100644 index 0000000000000000000000000000000000000000..efe15f3b57917f6a9cc36f5c340520083f704fca --- /dev/null +++ b/core/java/com/android/internal/widget/EditableInputConnection.java @@ -0,0 +1,338 @@ +/* + * Copyright (C) 2007-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.android.internal.widget; + +import android.content.res.TypedArray; +import android.os.Bundle; +import android.os.Handler; +import android.text.Editable; +import android.text.Selection; +import android.text.Spannable; +import android.text.SpannableStringBuilder; +import android.text.Spanned; +import android.text.TextUtils; +import android.text.method.KeyListener; +import android.util.Log; +import android.util.LogPrinter; +import android.view.inputmethod.BaseInputConnection; +import android.view.inputmethod.CompletionInfo; +import android.view.inputmethod.ExtractedText; +import android.view.inputmethod.ExtractedTextRequest; +import android.widget.TextView; + +class ComposingText { +} + +public class EditableInputConnection extends BaseInputConnection { + private static final boolean DEBUG = false; + private static final String TAG = "EditableInputConnection"; + + public static final Object COMPOSING = new ComposingText(); + + private final TextView mTextView; + private final Handler mUiHandler; + + private Object[] mDefaultComposingSpans; + + public EditableInputConnection(TextView textview) { + super(textview); + mTextView = textview; + mUiHandler = textview.getHandler(); + } + + public boolean setComposingText(CharSequence text, int newCursorPosition) { + if (DEBUG) Log.v(TAG, "setComposingText " + text); + replaceText(text, newCursorPosition, true); + return true; + } + + public boolean commitText(CharSequence text, int newCursorPosition) { + if (DEBUG) Log.v(TAG, "commitText " + text); + replaceText(text, newCursorPosition, false); + return true; + } + + public boolean commitCompletion(CompletionInfo text) { + if (DEBUG) Log.v(TAG, "commitCompletion " + text); + mTextView.onCommitCompletion(text); + return true; + } + + public CharSequence getTextBeforeCursor(int length) { + final Editable content = getEditable(); + if (content == null) return null; + + int a = Selection.getSelectionStart(content); + int b = Selection.getSelectionEnd(content); + + if (a > b) { + int tmp = a; + a = b; + b = tmp; + } + + if (length > a) { + length = a; + } + + return content.subSequence(a - length, a); + } + + public CharSequence getTextAfterCursor(int length) { + final Editable content = getEditable(); + if (content == null) return null; + + int a = Selection.getSelectionStart(content); + int b = Selection.getSelectionEnd(content); + + if (a > b) { + int tmp = a; + a = b; + b = tmp; + } + + if (b + length > content.length()) { + length = content.length() - b; + } + + return content.subSequence(b, b + length); + } + + public int getCursorCapsMode(int reqModes) { + final Editable content = getEditable(); + if (content == null) return 0; + + int a = Selection.getSelectionStart(content); + int b = Selection.getSelectionEnd(content); + + if (a > b) { + int tmp = a; + a = b; + b = tmp; + } + + return TextUtils.getCapsMode(content, a, reqModes); + } + + public ExtractedText getExtractedText(ExtractedTextRequest request, int flags) { + if (mTextView != null) { + ExtractedText et = new ExtractedText(); + if (mTextView.extractText(request, et)) { + if ((flags&EXTRACTED_TEXT_MONITOR) != 0) { + mTextView.setExtracting(request); + } + return et; + } + } + return null; + } + + public boolean deleteSurroundingText(int leftLength, int rightLength) { + if (DEBUG) Log.v(TAG, "deleteSurroundingText " + leftLength + + " / " + rightLength); + final Editable content = getEditable(); + if (content == null) return false; + + int a = Selection.getSelectionStart(content); + int b = Selection.getSelectionEnd(content); + + if (a > b) { + int tmp = a; + a = b; + b = tmp; + } + + // ignore the composing text. + int ca = content.getSpanStart(COMPOSING); + int cb = content.getSpanEnd(COMPOSING); + if (cb < ca) { + int tmp = ca; + ca = cb; + cb = tmp; + } + if (ca != -1 && cb != -1) { + if (ca < a) a = ca; + if (cb > b) b = cb; + } + + int deleted = 0; + + if (leftLength > 0) { + int start = a - leftLength; + if (start < 0) start = 0; + content.delete(start, a); + deleted = a - start; + } + + if (rightLength > 0) { + b = b - deleted; + + int end = b + rightLength; + if (end > content.length()) end = content.length(); + + content.delete(b, end); + } + + return true; + } + + public boolean clearMetaKeyStates(int states) { + final Editable content = getEditable(); + if (content == null) return false; + KeyListener kl = mTextView.getKeyListener(); + if (kl != null) kl.clearMetaKeyState(mTextView, content, states); + return true; + } + + public boolean performPrivateCommand(String action, Bundle data) { + if (mTextView == null) return false; + mTextView.onPrivateIMECommand(action, data); + return true; + } + + private Editable getEditable() { + TextView tv = mTextView; + if (tv != null) { + return tv.getEditableText(); + } + return null; + } + + public static void setComposingSpans(Spannable text) { + final Object[] sps = text.getSpans(0, text.length(), Object.class); + if (sps != null) { + for (int i=sps.length-1; i>=0; i--) { + final Object o = sps[i]; + if (o == COMPOSING) { + text.removeSpan(o); + continue; + } + final int fl = text.getSpanFlags(o); + if ((fl&(Spanned.SPAN_COMPOSING|Spanned.SPAN_POINT_MARK_MASK)) + != (Spanned.SPAN_COMPOSING|Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)) { + text.setSpan(o, text.getSpanStart(o), text.getSpanEnd(o), + (fl&Spanned.SPAN_POINT_MARK_MASK) + | Spanned.SPAN_COMPOSING + | Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + } + } + } + + text.setSpan(COMPOSING, 0, text.length(), + Spanned.SPAN_EXCLUSIVE_EXCLUSIVE | Spanned.SPAN_COMPOSING); + } + + public static final void removeComposingSpans(Spannable text) { + text.removeSpan(COMPOSING); + Object[] sps = text.getSpans(0, text.length(), Object.class); + if (sps != null) { + for (int i=sps.length-1; i>=0; i--) { + Object o = sps[i]; + if ((text.getSpanFlags(o)&Spanned.SPAN_COMPOSING) != 0) { + text.removeSpan(o); + } + } + } + } + + private void replaceText(CharSequence text, int newCursorPosition, + boolean composing) { + final Editable content = getEditable(); + + // delete composing text set previously. + int a = content.getSpanStart(COMPOSING); + int b = content.getSpanEnd(COMPOSING); + + if (DEBUG) Log.v(TAG, "Composing span: " + a + " to " + b); + + if (b < a) { + int tmp = a; + a = b; + b = tmp; + } + + if (a != -1 && b != -1) { + removeComposingSpans(content); + } else { + a = Selection.getSelectionStart(content); + b = Selection.getSelectionEnd(content); + if (a >=0 && b>= 0 && a != b) { + if (b < a) { + int tmp = a; + a = b; + b = tmp; + } + } + } + + if (composing) { + Spannable sp = null; + if (!(text instanceof Spannable)) { + sp = new SpannableStringBuilder(text); + text = sp; + if (mDefaultComposingSpans == null) { + TypedArray ta = mTextView.getContext().getTheme() + .obtainStyledAttributes(new int[] { + com.android.internal.R.attr.candidatesTextStyleSpans + }); + CharSequence style = ta.getText(0); + ta.recycle(); + if (style != null && style instanceof Spanned) { + mDefaultComposingSpans = ((Spanned)style).getSpans( + 0, style.length(), Object.class); + } + } + if (mDefaultComposingSpans != null) { + for (int i = 0; i < mDefaultComposingSpans.length; ++i) { + sp.setSpan(mDefaultComposingSpans[i], 0, sp.length(), + Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + } + } + } else { + sp = (Spannable)text; + } + setComposingSpans(sp); + } + + // Adjust newCursorPosition to be relative the start of the text. + newCursorPosition += a; + + if (DEBUG) Log.v(TAG, "Replacing from " + a + " to " + b + " with \"" + + text + "\", composing=" + composing + + ", type=" + text.getClass().getCanonicalName()); + + if (DEBUG) { + LogPrinter lp = new LogPrinter(Log.VERBOSE, TAG); + lp.println("Current text:"); + TextUtils.dumpSpans(content, lp, " "); + lp.println("Composing text:"); + TextUtils.dumpSpans(text, lp, " "); + } + + content.replace(a, b, text); + if (newCursorPosition < 0) newCursorPosition = 0; + if (newCursorPosition > content.length()) + newCursorPosition = content.length(); + Selection.setSelection(content, newCursorPosition); + + if (DEBUG) { + LogPrinter lp = new LogPrinter(Log.VERBOSE, TAG); + lp.println("Final text:"); + TextUtils.dumpSpans(content, lp, " "); + } + } +} diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java index 1c75daa9eda40cfa8b643801656fc3632982405c..ed1cd58c73850dff7a1c56f59fe42f082c1a5b88 100644 --- a/core/java/com/android/internal/widget/LockPatternUtils.java +++ b/core/java/com/android/internal/widget/LockPatternUtils.java @@ -255,6 +255,20 @@ public class LockPatternUtils { setBoolean(Settings.System.LOCK_PATTERN_VISIBLE, enabled); } + /** + * @return Whether tactile feedback for the pattern is enabled. + */ + public boolean isTactileFeedbackEnabled() { + return getBoolean(Settings.System.LOCK_PATTERN_TACTILE_FEEDBACK_ENABLED); + } + + /** + * Set whether tactile feedback for the pattern is enabled. + */ + public void setTactileFeedbackEnabled(boolean enabled) { + setBoolean(Settings.System.LOCK_PATTERN_TACTILE_FEEDBACK_ENABLED, enabled); + } + /** * Store the lockout deadline, meaning the user can't attempt his/her unlock * pattern until the deadline has passed. Does not persist across reboots. diff --git a/core/java/com/android/internal/widget/LockPatternView.java b/core/java/com/android/internal/widget/LockPatternView.java index bf00eff5d93756cba658b12104aafcee4d9f0457..7f99ac84eb493426b449344e03561cf8e4f5bd82 100644 --- a/core/java/com/android/internal/widget/LockPatternView.java +++ b/core/java/com/android/internal/widget/LockPatternView.java @@ -32,6 +32,7 @@ import android.os.Parcel; import android.os.Parcelable; import android.os.SystemClock; import android.os.Debug; +import android.os.Vibrator; import android.util.AttributeSet; import android.view.MotionEvent; import android.view.View; @@ -48,6 +49,9 @@ import java.util.List; * "correct" states. */ public class LockPatternView extends View { + // Vibrator pattern for creating a tactile bump + private static final long[] VIBE_PATTERN = {0, 1, 40, 41}; + private static final boolean PROFILE_DRAWING = false; private boolean mDrawingProfilingStarted = false; @@ -88,6 +92,7 @@ public class LockPatternView extends View { private DisplayMode mPatternDisplayMode = DisplayMode.Correct; private boolean mInputEnabled = true; private boolean mInStealthMode = false; + private boolean mTactileFeedbackEnabled = true; private boolean mPatternInProgress = false; private float mDiameterFactor = 0.5f; @@ -112,6 +117,8 @@ public class LockPatternView extends View { private int mBitmapHeight; + private Vibrator vibe; // Vibrator for creating tactile feedback + /** * Represents a cell in the 3 X 3 matrix of the unlock pattern view. */ @@ -219,6 +226,7 @@ public class LockPatternView extends View { public LockPatternView(Context context, AttributeSet attrs) { super(context, attrs); + vibe = new Vibrator(); setClickable(true); @@ -256,6 +264,13 @@ public class LockPatternView extends View { return mInStealthMode; } + /** + * @return Whether the view has tactile feedback enabled. + */ + public boolean isTactileFeedbackEnabled() { + return mTactileFeedbackEnabled; + } + /** * Set whether the view is in stealth mode. If true, there will be no * visible feedback as the user enters the pattern. @@ -266,6 +281,16 @@ public class LockPatternView extends View { mInStealthMode = inStealthMode; } + /** + * Set whether the view will use tactile feedback. If true, there will be + * tactile feedback as the user enters the pattern. + * + * @param tactileFeedbackEnabled Whether tactile feedback is enabled + */ + public void setTactileFeedbackEnabled(boolean tactileFeedbackEnabled) { + mTactileFeedbackEnabled = tactileFeedbackEnabled; + } + /** * Set the call back for pattern detection. * @param onPatternListener The call back. @@ -420,6 +445,9 @@ public class LockPatternView extends View { addCellToPattern(fillInGapCell); } addCellToPattern(cell); + if (mTactileFeedbackEnabled){ + vibe.vibrate(VIBE_PATTERN, -1); // Generate tactile feedback + } return cell; } return null; @@ -900,7 +928,7 @@ public class LockPatternView extends View { return new SavedState(superState, LockPatternUtils.patternToString(mPattern), mPatternDisplayMode.ordinal(), - mInputEnabled, mInStealthMode); + mInputEnabled, mInStealthMode, mTactileFeedbackEnabled); } @Override @@ -913,6 +941,7 @@ public class LockPatternView extends View { mPatternDisplayMode = DisplayMode.values()[ss.getDisplayMode()]; mInputEnabled = ss.isInputEnabled(); mInStealthMode = ss.isInStealthMode(); + mTactileFeedbackEnabled = ss.isTactileFeedbackEnabled(); } /** @@ -924,17 +953,19 @@ public class LockPatternView extends View { private final int mDisplayMode; private final boolean mInputEnabled; private final boolean mInStealthMode; + private final boolean mTactileFeedbackEnabled; /** * Constructor called from {@link LockPatternView#onSaveInstanceState()} */ private SavedState(Parcelable superState, String serializedPattern, int displayMode, - boolean inputEnabled, boolean inStealthMode) { + boolean inputEnabled, boolean inStealthMode, boolean tactileFeedbackEnabled) { super(superState); mSerializedPattern = serializedPattern; mDisplayMode = displayMode; mInputEnabled = inputEnabled; mInStealthMode = inStealthMode; + mTactileFeedbackEnabled = tactileFeedbackEnabled; } /** @@ -946,6 +977,7 @@ public class LockPatternView extends View { mDisplayMode = in.readInt(); mInputEnabled = (Boolean) in.readValue(null); mInStealthMode = (Boolean) in.readValue(null); + mTactileFeedbackEnabled = (Boolean) in.readValue(null); } public String getSerializedPattern() { @@ -964,6 +996,10 @@ public class LockPatternView extends View { return mInStealthMode; } + public boolean isTactileFeedbackEnabled(){ + return mTactileFeedbackEnabled; + } + @Override public void writeToParcel(Parcel dest, int flags) { super.writeToParcel(dest, flags); @@ -971,6 +1007,7 @@ public class LockPatternView extends View { dest.writeInt(mDisplayMode); dest.writeValue(mInputEnabled); dest.writeValue(mInStealthMode); + dest.writeValue(mTactileFeedbackEnabled); } public static final Parcelable.Creator CREATOR = diff --git a/core/java/com/android/internal/widget/NumberPicker.java b/core/java/com/android/internal/widget/NumberPicker.java index 5a7ddcb72f9975b649706570b03ab1786493a46e..5590f1a2c4e36bf61ae379b38bc494ed04aa0e2d 100644 --- a/core/java/com/android/internal/widget/NumberPicker.java +++ b/core/java/com/android/internal/widget/NumberPicker.java @@ -19,6 +19,7 @@ package com.android.internal.widget; import android.content.Context; import android.os.Handler; import android.text.InputFilter; +import android.text.InputType; import android.text.Spanned; import android.text.method.NumberKeyListener; import android.util.AttributeSet; @@ -359,6 +360,12 @@ public class NumberPicker extends LinearLayout implements OnClickListener, private class NumberRangeKeyListener extends NumberKeyListener { + // XXX This doesn't allow for range limits when controlled by a + // soft input method! + public int getInputType() { + return InputType.TYPE_CLASS_NUMBER; + } + @Override protected char[] getAcceptedChars() { return DIGIT_CHARACTERS; @@ -421,4 +428,10 @@ public class NumberPicker extends LinearLayout implements OnClickListener, return mStart; } -} + /** + * @return the current value. + */ + public int getCurrent() { + return mCurrent; + } +} \ No newline at end of file diff --git a/core/java/com/android/internal/widget/SlidingDrawer.java b/core/java/com/android/internal/widget/SlidingDrawer.java index 90a548a7a1a20ed7d9ac1e66876139cce27fa443..a4045d553a024472c3a17e0dc3e7c8a0cdb2b054 100644 --- a/core/java/com/android/internal/widget/SlidingDrawer.java +++ b/core/java/com/android/internal/widget/SlidingDrawer.java @@ -74,6 +74,7 @@ import com.android.internal.R; * @attr ref com.android.internal.R.styleable#SlidingDrawer_topOffset * @attr ref com.android.internal.R.styleable#SlidingDrawer_bottomOffset * @attr ref com.android.internal.R.styleable#SlidingDrawer_orientation + * @attr ref com.android.internal.R.styleable#SlidingDrawer_allowSingleTap * @attr ref com.android.internal.R.styleable#SlidingDrawer_animateOnClick */ public class SlidingDrawer extends ViewGroup { @@ -124,6 +125,7 @@ public class SlidingDrawer extends ViewGroup { private long mCurrentAnimationTime; private int mTouchDelta; private boolean mAnimating; + private boolean mAllowSingleTap; private boolean mAnimateOnClick; /** @@ -186,6 +188,7 @@ public class SlidingDrawer extends ViewGroup { mVertical = orientation == ORIENTATION_VERTICAL; mBottomOffset = (int) a.getDimension(R.styleable.SlidingDrawer_bottomOffset, 0.0f); mTopOffset = (int) a.getDimension(R.styleable.SlidingDrawer_topOffset, 0.0f); + mAllowSingleTap = a.getBoolean(R.styleable.SlidingDrawer_allowSingleTap, true); mAnimateOnClick = a.getBoolean(R.styleable.SlidingDrawer_animateOnClick, true); int handleId = a.getResourceId(R.styleable.SlidingDrawer_handle, 0); @@ -241,11 +244,11 @@ public class SlidingDrawer extends ViewGroup { measureChild(handle, widthMeasureSpec, heightMeasureSpec); if (mVertical) { - int height = heightSpecSize - handle.getMeasuredHeight(); + int height = heightSpecSize - handle.getMeasuredHeight() - mTopOffset; mContent.measure(MeasureSpec.makeMeasureSpec(widthSpecSize, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY)); } else { - int width = widthSpecSize - handle.getMeasuredWidth(); + int width = widthSpecSize - handle.getMeasuredWidth() - mTopOffset; mContent.measure(MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(heightSpecSize, MeasureSpec.EXACTLY)); } @@ -269,6 +272,12 @@ public class SlidingDrawer extends ViewGroup { } else { canvas.drawBitmap(cache, handle.getRight(), 0, null); } + } else { + canvas.save(); + canvas.translate(isVertical ? 0 : handle.getLeft() - mTopOffset, + isVertical ? handle.getTop() - mTopOffset : 0); + drawChild(canvas, mContent, drawingTime); + canvas.restore(); } } else if (mExpanded) { drawChild(canvas, mContent, drawingTime); @@ -415,12 +424,14 @@ public class SlidingDrawer extends ViewGroup { (!mExpanded && left > mBottomOffset + mRight - mLeft - mHandleWidth - TAP_THRESHOLD)) { - playSoundEffect(SoundEffectConstants.CLICK); + if (mAllowSingleTap) { + playSoundEffect(SoundEffectConstants.CLICK); - if (mExpanded) { - animateClose(vertical ? top : left); - } else { - animateOpen(vertical ? top : left); + if (mExpanded) { + animateClose(vertical ? top : left); + } else { + animateOpen(vertical ? top : left); + } } } else { @@ -889,6 +900,9 @@ public class SlidingDrawer extends ViewGroup { if (mLocked) { return; } + // mAllowSingleTap isn't relevant here; you're *always* + // allowed to open/close the drawer by clicking with the + // trackball. if (mAnimateOnClick) { animateToggle(); diff --git a/core/java/com/google/android/mms/pdu/PduComposer.java b/core/java/com/google/android/mms/pdu/PduComposer.java index acece474c971c16ac8438623d911130d75df7b0e..094e992e64dac47218e9e33e84de4042bbb3a478 100644 --- a/core/java/com/google/android/mms/pdu/PduComposer.java +++ b/core/java/com/google/android/mms/pdu/PduComposer.java @@ -24,7 +24,6 @@ import java.io.ByteArrayOutputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; -import java.io.UnsupportedEncodingException; import java.util.Arrays; import java.util.HashMap; @@ -461,7 +460,7 @@ public class PduComposer { int version = mPduHeader.getOctet(field); if (0 == version) { - appendShortInteger(PduHeaders.MMS_VERSION_1_3); + appendShortInteger(PduHeaders.CURRENT_MMS_VERSION); } else { appendShortInteger(version); } @@ -952,7 +951,7 @@ public class PduComposer { appendQuotedString("<" + new String(contentId) + ">"); } } - + // content-location byte[] contentLocation = part.getContentLocation(); if (null != contentLocation) { diff --git a/core/java/com/google/android/mms/pdu/PduHeaders.java b/core/java/com/google/android/mms/pdu/PduHeaders.java index 37693491b84e2d5d800c019a16ffb831c10f69b7..43138150f80452d1dfe3d6b428e6101cf82ada05 100644 --- a/core/java/com/google/android/mms/pdu/PduHeaders.java +++ b/core/java/com/google/android/mms/pdu/PduHeaders.java @@ -150,13 +150,14 @@ public class PduHeaders { /** * X-Mms-MMS-Version field types. */ - // Current version is 1.3. public static final int MMS_VERSION_1_3 = ((1 << 4) | 3); - public static final int MMS_VERSION_1_2 = ((1 << 4) | 2); public static final int MMS_VERSION_1_1 = ((1 << 4) | 1); public static final int MMS_VERSION_1_0 = ((1 << 4) | 0); + // Current version is 1.2. + public static final int CURRENT_MMS_VERSION = MMS_VERSION_1_2; + /** * From field type components. */ @@ -475,7 +476,7 @@ public class PduHeaders { break; case MMS_VERSION: if ((value < MMS_VERSION_1_0)|| (value > MMS_VERSION_1_3)) { - value = MMS_VERSION_1_3; //1.3 is the default version. + value = CURRENT_MMS_VERSION; // Current version is the default value. } break; case MESSAGE_TYPE: diff --git a/core/java/com/google/android/mms/pdu/PduPersister.java b/core/java/com/google/android/mms/pdu/PduPersister.java index 4089c584420c97d52b6bf09a8c36a1976a8fceea..d2a41f1ce960555041622568c2a0daa7628eff1f 100644 --- a/core/java/com/google/android/mms/pdu/PduPersister.java +++ b/core/java/com/google/android/mms/pdu/PduPersister.java @@ -729,36 +729,13 @@ public class PduPersister { } is = mContentResolver.openInputStream(dataUri); - boolean fakeRawAmr = contentType.equals("audio/amr"); - if (LOCAL_LOGV) { Log.v(TAG, "Saving data to: " + uri); } byte[] buffer = new byte[256]; for (int len = 0; (len = is.read(buffer)) != -1; ) { - if (fakeRawAmr && len > 32) { - // This is a Gross Hack. We can only record audio to amr format in a 3gpp container. - // Millions of handsets out there only support what is essentially raw AMR. - // We work around this issue by extracting the AMR data out of the 3gpp container - // (in a really stupid and non-portable way), prepending a little header, and then - // using that as the attachment. - // This also requires some cooperation from the SoundRecorder, which ends up saving - // a "recording.amr" file with mime type audio/amr, even though it's a 3gpp file. - if (buffer[4] == 0x66 && // f - buffer[5] == 0x74 && // t - buffer[6] == 0x79 && // y - buffer[7] == 0x70) { // p - byte [] amrHeader = new byte [] { 0x23, 0x21, 0x41, 0x4d, 0x52, 0x0a }; - os.write(amrHeader); - os.write(buffer, 32, len - 32); - } else { - os.write(buffer, 0, len); - } - fakeRawAmr = false; - } else { - os.write(buffer, 0, len); - } + os.write(buffer, 0, len); } } else { if (LOCAL_LOGV) { diff --git a/core/java/com/google/android/mms/pdu/SendReq.java b/core/java/com/google/android/mms/pdu/SendReq.java index e2f110101bf31a49053392752bc98b08bc0f9802..9081b0c233bcd0a460b4562e6fa2685576efb428 100644 --- a/core/java/com/google/android/mms/pdu/SendReq.java +++ b/core/java/com/google/android/mms/pdu/SendReq.java @@ -29,7 +29,7 @@ public class SendReq extends MultimediaMessagePdu { try { setMessageType(PduHeaders.MESSAGE_TYPE_SEND_REQ); - setMmsVersion(PduHeaders.MMS_VERSION_1_3); + setMmsVersion(PduHeaders.CURRENT_MMS_VERSION); // FIXME: Content-type must be decided according to whether // SMIL part present. setContentType("application/vnd.wap.multipart.related".getBytes()); diff --git a/core/java/com/google/android/net/ParentalControl.java b/core/java/com/google/android/net/ParentalControl.java index 368b885ab0d2adadc136fb125ff0ab30ccaff0e2..71a3958ef52fee6b7d2017cf3fef9a1702c7d42d 100644 --- a/core/java/com/google/android/net/ParentalControl.java +++ b/core/java/com/google/android/net/ParentalControl.java @@ -23,7 +23,13 @@ import android.os.ServiceManager; import android.util.Log; public class ParentalControl { - + /** + * Strings to identify your app. To enable parental control checking for + * new apps, please add it here, and configure GServices accordingly. + */ + public static final String VENDING = "vending"; + public static final String YOUTUBE = "youtube"; + /** * This interface is supplied to getParentalControlState and is callback upon with * the state of parental control. @@ -36,28 +42,29 @@ public class ParentalControl { */ void onResult(ParentalControlState state); } - + private static class RemoteCallback extends IParentalControlCallback.Stub { private Callback mCallback; - + public RemoteCallback(Callback callback) { mCallback = callback; } - + public void onResult(ParentalControlState state) { if (mCallback != null) { mCallback.onResult(state); } } }; - - public static void getParentalControlState(Callback callback) { + + public static void getParentalControlState(Callback callback, + String requestingApp) { ICheckinService service = ICheckinService.Stub.asInterface(ServiceManager.getService("checkin")); - + RemoteCallback remoteCallback = new RemoteCallback(callback); try { - service.getParentalControlState(remoteCallback); + service.getParentalControlState(remoteCallback, requestingApp); } catch (RemoteException e) { // This should never happen. Log.e("ParentalControl", "Failed to talk to the checkin service."); diff --git a/core/java/com/google/android/util/GoogleWebContentHelper.java b/core/java/com/google/android/util/GoogleWebContentHelper.java index 57095222a2ad7f34dfb8d2741fef2b7cd3503b25..7500ec3b0db9eabca5b584b48356ad97844ee8bf 100644 --- a/core/java/com/google/android/util/GoogleWebContentHelper.java +++ b/core/java/com/google/android/util/GoogleWebContentHelper.java @@ -22,6 +22,7 @@ import android.net.http.SslError; import android.os.Message; import android.provider.Settings; import android.text.TextUtils; +import android.view.KeyEvent; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -81,10 +82,26 @@ public class GoogleWebContentHelper { */ public GoogleWebContentHelper setUrlsFromGservices(String secureSetting, String prettySetting) { ContentResolver contentResolver = mContext.getContentResolver(); - mSecureUrl = fillUrl(Settings.Gservices.getString(contentResolver, secureSetting)); - mPrettyUrl = fillUrl(Settings.Gservices.getString(contentResolver, prettySetting)); + mSecureUrl = fillUrl(Settings.Gservices.getString(contentResolver, secureSetting), + mContext); + mPrettyUrl = fillUrl(Settings.Gservices.getString(contentResolver, prettySetting), + mContext); return this; } + + /** + * Fetch directly from provided urls. + * + * @param secureUrl The HTTPS URL. + * @param prettyUrl The pretty URL. + * @return This {@link GoogleWebContentHelper} so methods can be chained. + */ + public GoogleWebContentHelper setUrls(String secureUrl, String prettyUrl) { + mSecureUrl = fillUrl(secureUrl, mContext); + mPrettyUrl = fillUrl(prettyUrl, mContext); + return this; + } + /** * Sets the message that will be shown if we are unable to load the page. @@ -113,6 +130,22 @@ public class GoogleWebContentHelper { mWebView.loadUrl(mSecureUrl); return this; } + + /** + * Helper to handle the back key. Returns true if the back key was handled, + * otherwise returns false. + * @param event the key event sent to {@link Activity#dispatchKeyEvent()} + */ + public boolean handleKey(KeyEvent event) { + if (event.getKeyCode() == KeyEvent.KEYCODE_BACK + && event.getAction() == KeyEvent.ACTION_DOWN) { + if (mWebView.canGoBack()) { + mWebView.goBack(); + return true; + } + } + return false; + } /** * Returns the layout containing the web view, progress bar, and text view. @@ -138,12 +171,23 @@ public class GoogleWebContentHelper { * @param url The URL in Formatter style for the extra info to be filled in. * @return The filled URL. */ - private static String fillUrl(String url) { + private static String fillUrl(String url, Context context) { if (TextUtils.isEmpty(url)) { return ""; } - + + /* We add another layer of indirection here to allow mcc's to fill + * in Locales for TOS. TODO - REMOVE when needed locales supported + * natively (when not shipping devices to country X without support + * for their locale). + */ + String localeReplacement = context. + getString(com.android.internal.R.string.locale_replacement); + if (localeReplacement != null && localeReplacement.length() != 0) { + url = String.format(url, localeReplacement); + } + Locale locale = Locale.getDefault(); String tmp = locale.getLanguage() + "_" + locale.getCountry().toLowerCase(); return String.format(url, tmp); diff --git a/core/java/jarjar-rules.txt b/core/java/jarjar-rules.txt new file mode 100644 index 0000000000000000000000000000000000000000..5fdb022251b3bb7a136fe296c82650bfbb4a9257 --- /dev/null +++ b/core/java/jarjar-rules.txt @@ -0,0 +1,2 @@ +rule org.apache.commons com.android.internal.apache.commons + diff --git a/core/jni/Android.mk b/core/jni/Android.mk index e9009e6865b030e03a7e66b9abc9c2bbe2abea03..2c74ab78e5a07c99cf20523e821a1ecb7cb2dd61 100644 --- a/core/jni/Android.mk +++ b/core/jni/Android.mk @@ -11,6 +11,10 @@ else LOCAL_CFLAGS += -DPACKED="" endif +ifneq ($(USE_CUSTOM_RUNTIME_HEAP_MAX),) + LOCAL_CFLAGS += -DCUSTOM_RUNTIME_HEAP_MAX=$(USE_CUSTOM_RUNTIME_HEAP_MAX) +endif + LOCAL_SRC_FILES:= \ ActivityManager.cpp \ AndroidRuntime.cpp \ @@ -45,7 +49,7 @@ LOCAL_SRC_FILES:= \ android_net_wifi_Wifi.cpp \ android_nio_utils.cpp \ android_pim_EventRecurrence.cpp \ - android_pim_Time.cpp \ + android_text_format_Time.cpp \ android_security_Md5MessageDigest.cpp \ android_util_AssetManager.cpp \ android_util_Binder.cpp \ @@ -84,7 +88,9 @@ LOCAL_SRC_FILES:= \ android/graphics/Shader.cpp \ android/graphics/Typeface.cpp \ android/graphics/Xfermode.cpp \ + android_media_AudioRecord.cpp \ android_media_AudioSystem.cpp \ + android_media_AudioTrack.cpp \ android_media_ToneGenerator.cpp \ android_hardware_Camera.cpp \ android_hardware_SensorManager.cpp \ @@ -100,6 +106,7 @@ LOCAL_SRC_FILES:= \ android_bluetooth_ScoSocket.cpp \ android_server_BluetoothDeviceService.cpp \ android_server_BluetoothEventLoop.cpp \ + android_server_BluetoothA2dpService.cpp \ android_message_digest_sha1.cpp \ android_ddm_DdmHandleNativeHeap.cpp \ android_location_GpsLocationProvider.cpp \ @@ -109,7 +116,7 @@ LOCAL_SRC_FILES:= \ LOCAL_C_INCLUDES += \ $(JNI_H_INCLUDE) \ $(LOCAL_PATH)/android/graphics \ - $(call include-path-for, corecg graphics) \ + $(call include-path-for, bluedroid corecg graphics) \ $(call include-path-for, libhardware)/hardware \ $(LOCAL_PATH)/../../include/ui \ $(LOCAL_PATH)/../../include/utils \ @@ -128,6 +135,7 @@ LOCAL_SHARED_LIBRARIES := \ libutils \ libnetutils \ libui \ + libskiagl \ libsgl \ libcorecg \ libsqlite \ @@ -151,15 +159,15 @@ LOCAL_CFLAGS += -DHAVE_BLUETOOTH LOCAL_SHARED_LIBRARIES += libbluedroid libdbus endif -ifeq ($(TARGET_ARCH),arm) +ifneq ($(TARGET_SIMULATOR),true) LOCAL_SHARED_LIBRARIES += \ libdl endif LOCAL_LDLIBS += -lpthread -ldl -ifeq ($(TARGET_OS),linux) -ifeq ($(TARGET_ARCH),x86) +ifeq ($(TARGET_SIMULATOR),true) +ifeq ($(TARGET_OS)-$(TARGET_ARCH),linux-x86) LOCAL_LDLIBS += -lrt endif endif diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp index 2a1184f8bf0980c149ae4be79092b72b7fc03bde..f85f7d54abe2a31ecccc70a597bd5590df5e1cc3 100644 --- a/core/jni/AndroidRuntime.cpp +++ b/core/jni/AndroidRuntime.cpp @@ -71,7 +71,9 @@ extern int register_android_hardware_Camera(JNIEnv *env); extern int register_android_hardware_SensorManager(JNIEnv *env); +extern int register_android_media_AudioRecord(JNIEnv *env); extern int register_android_media_AudioSystem(JNIEnv *env); +extern int register_android_media_AudioTrack(JNIEnv *env); extern int register_android_media_ToneGenerator(JNIEnv *env); extern int register_android_message_digest_sha1(JNIEnv *env); @@ -114,7 +116,7 @@ extern int register_android_database_SQLiteStatement(JNIEnv* env); extern int register_android_debug_JNITest(JNIEnv* env); extern int register_android_nio_utils(JNIEnv* env); extern int register_android_pim_EventRecurrence(JNIEnv* env); -extern int register_android_pim_Time(JNIEnv* env); +extern int register_android_text_format_Time(JNIEnv* env); extern int register_android_os_Debug(JNIEnv* env); extern int register_android_os_ParcelFileDescriptor(JNIEnv *env); extern int register_android_os_Power(JNIEnv *env); @@ -142,6 +144,7 @@ extern int register_android_bluetooth_RfcommSocket(JNIEnv *env); extern int register_android_bluetooth_ScoSocket(JNIEnv *env); extern int register_android_server_BluetoothDeviceService(JNIEnv* env); extern int register_android_server_BluetoothEventLoop(JNIEnv *env); +extern int register_android_server_BluetoothA2dpService(JNIEnv* env); extern int register_android_ddm_DdmHandleNativeHeap(JNIEnv *env); extern int register_com_android_internal_os_ZygoteInit(JNIEnv* env); extern int register_android_util_Base64(JNIEnv* env); @@ -471,42 +474,21 @@ static void blockSigpipe() } /* - * Read the persistent locale from file. + * Read the persistent locale. */ static void readLocale(char* language, char* region) { - char path[512]; char propLang[PROPERTY_VALUE_MAX], propRegn[PROPERTY_VALUE_MAX]; - char *dataDir = getenv("ANDROID_DATA"); - bool found = false; - if (dataDir && strlen(dataDir) < 500) { - strcpy(path, dataDir); - } else { - strcpy(path, "/data"); - } - strcat(path, "/locale"); - FILE* localeFile = fopen(path, "r"); - if (localeFile) { - char line[10]; - char *got = fgets(line, 10, localeFile); - /* Locale code is ll_rr */ - if (got != NULL && strlen(line) >= 5) { - strncat(language, line, 2); - strncat(region, line + 3, 2); - found = true; - } - fclose(localeFile); - } - - if (!found) { + property_get("persist.sys.language", propLang, ""); + property_get("persist.sys.country", propRegn, ""); + if (*propLang == 0 && *propRegn == 0) { /* Set to ro properties, default is en_US */ property_get("ro.product.locale.language", propLang, "en"); property_get("ro.product.locale.region", propRegn, "US"); - strncat(language, propLang, 2); - strncat(region, propRegn, 2); } - + strncat(language, propLang, 2); + strncat(region, propRegn, 2); //LOGD("language=%s region=%s\n", language, region); } @@ -518,8 +500,9 @@ void AndroidRuntime::start(const char* className, const bool startSystemServer) JavaVMInitArgs initArgs; JavaVMOption opt; char propBuf[PROPERTY_VALUE_MAX]; - char enableAssertBuf[4 + PROPERTY_VALUE_MAX]; char stackTraceFileBuf[PROPERTY_VALUE_MAX]; + char enableAssertBuf[sizeof("-ea:")-1 + PROPERTY_VALUE_MAX]; + char jniOptsBuf[sizeof("-Xjniopts:")-1 + PROPERTY_VALUE_MAX]; char* stackTraceFile = NULL; char* slashClassName = NULL; char* cp; @@ -578,6 +561,9 @@ void AndroidRuntime::start(const char* className, const bool startSystemServer) strcpy(enableAssertBuf, "-ea:"); property_get("dalvik.vm.enableassertions", enableAssertBuf+4, ""); + strcpy(jniOptsBuf, "-Xjniopts:"); + property_get("dalvik.vm.jniopts", jniOptsBuf+10, ""); + const char* rootDir = getenv("ANDROID_ROOT"); if (rootDir == NULL) { rootDir = "/system"; @@ -609,20 +595,23 @@ void AndroidRuntime::start(const char* className, const bool startSystemServer) mOptions.add(opt); //options[curOpt++].optionString = "-verbose:class"; +#ifdef CUSTOM_RUNTIME_HEAP_MAX +#define __make_max_heap_opt(val) #val +#define _make_max_heap_opt(val) "-Xmx" __make_max_heap_opt(val) + opt.optionString = _make_max_heap_opt(CUSTOM_RUNTIME_HEAP_MAX); +#undef __make_max_heap_opt +#undef _make_max_heap_opt +#else /* limit memory use to 16MB */ opt.optionString = "-Xmx16m"; +#endif mOptions.add(opt); - /* enable Java "assert" statements in all non-system code */ - //options[curOpt++].optionString = "-ea"; - /* - * Enable or disable bytecode verification. We currently force optimization - * to be enabled when the verifier is off; this is a bad idea, but - * useful while we fiddle with the verifier. + * Enable or disable bytecode verification. * - * This should be coordinated with: - * //device/dalvik/libcore/android/src/main/native/dalvik_system_TouchDex.cpp + * We don't optimize classes that haven't been verified, but that only + * matters if we do "just-in-time" DEX optimization. */ if (verifyJava) { opt.optionString = "-Xverify:all"; @@ -632,7 +621,6 @@ void AndroidRuntime::start(const char* className, const bool startSystemServer) } else { opt.optionString = "-Xverify:none"; mOptions.add(opt); - //opt.optionString = "-Xdexopt:all"; opt.optionString = "-Xdexopt:verified"; mOptions.add(opt); } @@ -697,6 +685,12 @@ void AndroidRuntime::start(const char* className, const bool startSystemServer) LOGV("Assertions disabled\n"); } + if (jniOptsBuf[10] != '\0') { + LOGI("JNI options: '%s'\n", jniOptsBuf); + opt.optionString = jniOptsBuf; + mOptions.add(opt); + } + if (stackTraceFileBuf[0] != '\0') { static const char* stfOptName = "-Xstacktracefile:"; @@ -1008,7 +1002,7 @@ static const RegJNIRec gRegJNI[] = { REG_JNI(register_android_util_EventLog), REG_JNI(register_android_util_Log), REG_JNI(register_android_util_FloatMath), - REG_JNI(register_android_pim_Time), + REG_JNI(register_android_text_format_Time), REG_JNI(register_android_pim_EventRecurrence), REG_JNI(register_android_content_AssetManager), REG_JNI(register_android_content_StringBlock), @@ -1076,7 +1070,9 @@ static const RegJNIRec gRegJNI[] = { REG_JNI(register_com_android_internal_os_ZygoteInit), REG_JNI(register_android_hardware_Camera), REG_JNI(register_android_hardware_SensorManager), + REG_JNI(register_android_media_AudioRecord), REG_JNI(register_android_media_AudioSystem), + REG_JNI(register_android_media_AudioTrack), REG_JNI(register_android_media_ToneGenerator), REG_JNI(register_android_opengl_classes), @@ -1087,6 +1083,7 @@ static const RegJNIRec gRegJNI[] = { REG_JNI(register_android_bluetooth_ScoSocket), REG_JNI(register_android_server_BluetoothDeviceService), REG_JNI(register_android_server_BluetoothEventLoop), + REG_JNI(register_android_server_BluetoothA2dpService), REG_JNI(register_android_message_digest_sha1), REG_JNI(register_android_ddm_DdmHandleNativeHeap), REG_JNI(register_android_util_Base64), diff --git a/core/jni/android/graphics/Bitmap.cpp b/core/jni/android/graphics/Bitmap.cpp index 8628ec0b71cb89bf367dd16c5f10ba2a1e5a6be0..27a63493b660b6849eefc57b580341fb37f785af 100644 --- a/core/jni/android/graphics/Bitmap.cpp +++ b/core/jni/android/graphics/Bitmap.cpp @@ -1,573 +1,561 @@ -#include "SkBitmap.h" -#include "SkImageDecoder.h" -#include "SkColorPriv.h" -#include "GraphicsJNI.h" -#include "SkDither.h" - -#include "Parcel.h" -#include "android_util_Binder.h" -#include "android_nio_utils.h" -#include "CreateJavaOutputStreamAdaptor.h" - -#include - -#if 0 - #define TRACE_BITMAP(code) code -#else - #define TRACE_BITMAP(code) -#endif - -/////////////////////////////////////////////////////////////////////////////// -// Conversions to/from SkColor, for get/setPixels, and the create method, which -// is basically like setPixels - -typedef void (*FromColorProc)(void* dst, const SkColor src[], int width, - int x, int y); - -static void FromColor_D32(void* dst, const SkColor src[], int width, - int, int) { - SkPMColor* d = (SkPMColor*)dst; - - for (int i = 0; i < width; i++) { - *d++ = SkPreMultiplyColor(*src++); - } -} - -static void FromColor_D565(void* dst, const SkColor src[], int width, - int x, int y) { - uint16_t* d = (uint16_t*)dst; - - DITHER_565_SCAN(y); - for (int stop = x + width; x < stop; x++) { - SkColor c = *src++; - *d++ = SkDitherRGBTo565(SkColorGetR(c), SkColorGetG(c), SkColorGetB(c), - DITHER_VALUE(x)); - } -} - -static void FromColor_D4444(void* dst, const SkColor src[], int width, - int x, int y) { - SkPMColor16* d = (SkPMColor16*)dst; - - DITHER_4444_SCAN(y); - for (int stop = x + width; x < stop; x++) { - SkPMColor c = SkPreMultiplyColor(*src++); - *d++ = SkDitherARGB32To4444(c, DITHER_VALUE(x)); -// *d++ = SkPixel32ToPixel4444(c); - } -} - -// can return NULL -static FromColorProc ChooseFromColorProc(SkBitmap::Config config) { - switch (config) { - case SkBitmap::kARGB_8888_Config: - return FromColor_D32; - case SkBitmap::kARGB_4444_Config: - return FromColor_D4444; - case SkBitmap::kRGB_565_Config: - return FromColor_D565; - default: - break; - } - return NULL; -} - -bool GraphicsJNI::SetPixels(JNIEnv* env, jintArray srcColors, - int srcOffset, int srcStride, - int x, int y, int width, int height, - const SkBitmap& dstBitmap) { - SkAutoLockPixels alp(dstBitmap); - void* dst = dstBitmap.getPixels(); - FromColorProc proc = ChooseFromColorProc(dstBitmap.config()); - - if (NULL == dst || NULL == proc) { - return false; - } - - jint* array = env->GetIntArrayElements(srcColors, NULL); - const SkColor* src = (const SkColor*)array + srcOffset; - - // reset to to actual choice from caller - dst = dstBitmap.getAddr(x, y); - // now copy/convert each scanline - for (int y = 0; y < height; y++) { - proc(dst, src, width, x, y); - src += srcStride; - dst = (char*)dst + dstBitmap.rowBytes(); - } - - env->ReleaseIntArrayElements(srcColors, array, 0); - return true; -} - -//////////////////// ToColor procs - -typedef void (*ToColorProc)(SkColor dst[], const void* src, int width, - SkColorTable*); - -static inline SkColor pmcolorToColor(SkPMColor c) { - if (0 == c) { - return 0; - } - - unsigned a = SkGetPackedA32(c); - unsigned r = SkGetPackedR32(c); - unsigned g = SkGetPackedG32(c); - unsigned b = SkGetPackedB32(c); - - if (a < 255) { - SkFixed scale = SK_Fixed1 / a; - r = SkFixedRound(r * scale); - g = SkFixedRound(g * scale); - b = SkFixedRound(b * scale); - SkASSERT(r <= 0xFF); - SkASSERT(g <= 0xFF); - SkASSERT(b <= 0xFF); - } - - return SkColorSetARGB(a, r, g, b); -} - -static void ToColor_S32_Alpha(SkColor dst[], const void* src, int width, - SkColorTable*) { - SkASSERT(width > 0); - const SkPMColor* s = (const SkPMColor*)src; - do { - *dst++ = pmcolorToColor(*s++); - } while (--width != 0); -} - -static void ToColor_S32_Opaque(SkColor dst[], const void* src, int width, - SkColorTable*) { - SkASSERT(width > 0); - const SkPMColor* s = (const SkPMColor*)src; - do { - SkPMColor c = *s++; - *dst++ = SkColorSetRGB(SkGetPackedR32(c), SkGetPackedG32(c), - SkGetPackedB32(c)); - } while (--width != 0); -} - -static void ToColor_S4444_Alpha(SkColor dst[], const void* src, int width, - SkColorTable*) { - SkASSERT(width > 0); - const SkPMColor16* s = (const SkPMColor16*)src; - do { - *dst++ = pmcolorToColor(SkPixel4444ToPixel32(*s++)); - } while (--width != 0); -} - -static void ToColor_S4444_Opaque(SkColor dst[], const void* src, int width, - SkColorTable*) { - SkASSERT(width > 0); - const SkPMColor* s = (const SkPMColor*)src; - do { - SkPMColor c = SkPixel4444ToPixel32(*s++); - *dst++ = SkColorSetRGB(SkGetPackedR32(c), SkGetPackedG32(c), - SkGetPackedB32(c)); - } while (--width != 0); -} - -static void ToColor_S565(SkColor dst[], const void* src, int width, - SkColorTable*) { - SkASSERT(width > 0); - const uint16_t* s = (const uint16_t*)src; - do { - uint16_t c = *s++; - *dst++ = SkColorSetRGB(SkPacked16ToR32(c), SkPacked16ToG32(c), - SkPacked16ToB32(c)); - } while (--width != 0); -} - -static void ToColor_SI8_Alpha(SkColor dst[], const void* src, int width, - SkColorTable* ctable) { - SkASSERT(width > 0); - const uint8_t* s = (const uint8_t*)src; - const SkPMColor* colors = ctable->lockColors(); - do { - *dst++ = pmcolorToColor(colors[*s++]); - } while (--width != 0); - ctable->unlockColors(false); -} - -static void ToColor_SI8_Opaque(SkColor dst[], const void* src, int width, - SkColorTable* ctable) { - SkASSERT(width > 0); - const uint8_t* s = (const uint8_t*)src; - const SkPMColor* colors = ctable->lockColors(); - do { - SkPMColor c = colors[*s++]; - *dst++ = SkColorSetRGB(SkGetPackedR32(c), SkGetPackedG32(c), - SkGetPackedB32(c)); - } while (--width != 0); - ctable->unlockColors(false); -} - -// can return NULL -static ToColorProc ChooseToColorProc(const SkBitmap& src) { - switch (src.config()) { - case SkBitmap::kARGB_8888_Config: - return src.isOpaque() ? ToColor_S32_Opaque : ToColor_S32_Alpha; - case SkBitmap::kARGB_4444_Config: - return src.isOpaque() ? ToColor_S4444_Opaque : ToColor_S4444_Alpha; - case SkBitmap::kRGB_565_Config: - return ToColor_S565; - case SkBitmap::kIndex8_Config: - if (src.getColorTable() == NULL) { - return NULL; - } - return src.isOpaque() ? ToColor_SI8_Opaque : ToColor_SI8_Alpha; - default: - break; - } - return NULL; -} - -/////////////////////////////////////////////////////////////////////////////// -/////////////////////////////////////////////////////////////////////////////// - -static jobject Bitmap_creator(JNIEnv* env, jobject, jintArray jColors, - int offset, int stride, int width, int height, - SkBitmap::Config config, jboolean isMutable) { - if (width <= 0 || height <= 0) { - doThrowIAE(env, "width and height must be > 0"); - return NULL; - } - - if (NULL != jColors) { - size_t n = env->GetArrayLength(jColors); - if (n < SkAbs32(stride) * (size_t)height) { - doThrowAIOOBE(env); - return NULL; - } - } - - SkBitmap bitmap; - - bitmap.setConfig(config, width, height); - if (!GraphicsJNI::setJavaPixelRef(env, &bitmap, NULL)) { - return NULL; - } - - if (jColors != NULL) { - GraphicsJNI::SetPixels(env, jColors, offset, stride, - 0, 0, width, height, bitmap); - } - - return GraphicsJNI::createBitmap(env, new SkBitmap(bitmap), isMutable, - NULL); -} - -static jobject Bitmap_copy(JNIEnv* env, jobject, const SkBitmap* src, - SkBitmap::Config dstConfig, jboolean isMutable) { - SkBitmap result; - JavaPixelAllocator allocator(env); - - if (!src->copyTo(&result, dstConfig, &allocator)) { - return NULL; - } - - return GraphicsJNI::createBitmap(env, new SkBitmap(result), isMutable, - NULL); -} - -static void Bitmap_destructor(JNIEnv* env, jobject, SkBitmap* bitmap) { - delete bitmap; -} - -static void Bitmap_recycle(JNIEnv* env, jobject, SkBitmap* bitmap) { - bitmap->setPixels(NULL, NULL); -} - -// These must match the int values in Bitmap.java -enum JavaEncodeFormat { - kJPEG_JavaEncodeFormat = 0, - kPNG_JavaEncodeFormat = 1 -}; - -static bool Bitmap_compress(JNIEnv* env, jobject clazz, SkBitmap* bitmap, - int format, int quality, - jobject jstream, jbyteArray jstorage) { - SkImageEncoder::Type fm; - - switch (format) { - case kJPEG_JavaEncodeFormat: - fm = SkImageEncoder::kJPEG_Type; - break; - case kPNG_JavaEncodeFormat: - fm = SkImageEncoder::kPNG_Type; - break; - default: - return false; - } - - bool success = false; - SkWStream* strm = CreateJavaOutputStreamAdaptor(env, jstream, jstorage); - if (NULL != strm) { - SkImageEncoder* encoder = SkImageEncoder::Create(fm); - if (NULL != encoder) { - success = encoder->encodeStream(strm, *bitmap, quality); - delete encoder; - } - delete strm; - } - return success; -} - -static void Bitmap_erase(JNIEnv* env, jobject, SkBitmap* bitmap, jint color) { - bitmap->eraseColor(color); -} - -static int Bitmap_width(JNIEnv* env, jobject, SkBitmap* bitmap) { - return bitmap->width(); -} - -static int Bitmap_height(JNIEnv* env, jobject, SkBitmap* bitmap) { - return bitmap->height(); -} - -static int Bitmap_rowBytes(JNIEnv* env, jobject, SkBitmap* bitmap) { - return bitmap->rowBytes(); -} - -static int Bitmap_config(JNIEnv* env, jobject, SkBitmap* bitmap) { - return bitmap->config(); -} - -static jboolean Bitmap_hasAlpha(JNIEnv* env, jobject, SkBitmap* bitmap) { - return !bitmap->isOpaque(); -} - -/////////////////////////////////////////////////////////////////////////////// - -static jobject Bitmap_createFromParcel(JNIEnv* env, jobject, jobject parcel) { - if (parcel == NULL) { - SkDebugf("-------- unparcel parcel is NULL\n"); - return NULL; - } - - android::Parcel* p = android::parcelForJavaObject(env, parcel); - - const bool isMutable = p->readInt32() != 0; - const SkBitmap::Config config = (SkBitmap::Config)p->readInt32(); - const int width = p->readInt32(); - const int height = p->readInt32(); - const int rowBytes = p->readInt32(); - - if (SkBitmap::kARGB_8888_Config != config && - SkBitmap::kRGB_565_Config != config && - SkBitmap::kARGB_4444_Config != config && - SkBitmap::kIndex8_Config != config && - SkBitmap::kA8_Config != config) { - SkDebugf("Bitmap_createFromParcel unknown config: %d\n", config); - return NULL; - } - - SkBitmap* bitmap = new SkBitmap; - - bitmap->setConfig(config, width, height, rowBytes); - - SkColorTable* ctable = NULL; - if (config == SkBitmap::kIndex8_Config) { - int count = p->readInt32(); - if (count > 0) { - size_t size = count * sizeof(SkPMColor); - const SkPMColor* src = (const SkPMColor*)p->readInplace(size); - ctable = new SkColorTable(src, count); - } - } - - if (!GraphicsJNI::setJavaPixelRef(env, bitmap, ctable)) { - ctable->safeUnref(); - delete bitmap; - return NULL; - } - - ctable->safeUnref(); - - size_t size = bitmap->getSize(); - bitmap->lockPixels(); - memcpy(bitmap->getPixels(), p->readInplace(size), size); - bitmap->unlockPixels(); - - return GraphicsJNI::createBitmap(env, bitmap, isMutable, NULL); -} - -static jboolean Bitmap_writeToParcel(JNIEnv* env, jobject, - const SkBitmap* bitmap, - jboolean isMutable, jobject parcel) { - if (parcel == NULL) { - SkDebugf("------- writeToParcel null parcel\n"); - return false; - } - - android::Parcel* p = android::parcelForJavaObject(env, parcel); - - p->writeInt32(isMutable); - p->writeInt32(bitmap->config()); - p->writeInt32(bitmap->width()); - p->writeInt32(bitmap->height()); - p->writeInt32(bitmap->rowBytes()); - - if (bitmap->getConfig() == SkBitmap::kIndex8_Config) { - SkColorTable* ctable = bitmap->getColorTable(); - if (ctable != NULL) { - int count = ctable->count(); - p->writeInt32(count); - memcpy(p->writeInplace(count * sizeof(SkPMColor)), - ctable->lockColors(), count * sizeof(SkPMColor)); - ctable->unlockColors(false); - } else { - p->writeInt32(0); // indicate no ctable - } - } - - size_t size = bitmap->getSize(); - bitmap->lockPixels(); - memcpy(p->writeInplace(size), bitmap->getPixels(), size); - bitmap->unlockPixels(); - return true; -} - -static jobject Bitmap_extractAlpha(JNIEnv* env, jobject clazz, - const SkBitmap* src, const SkPaint* paint, - jintArray offsetXY) { - SkIPoint offset; - SkBitmap* dst = new SkBitmap; - - src->extractAlpha(dst, paint, &offset); - if (offsetXY != 0 && env->GetArrayLength(offsetXY) >= 2) { - int* array = env->GetIntArrayElements(offsetXY, NULL); - array[0] = offset.fX; - array[1] = offset.fY; - env->ReleaseIntArrayElements(offsetXY, array, 0); - } - - return GraphicsJNI::createBitmap(env, dst, true, NULL); -} - -/////////////////////////////////////////////////////////////////////////////// - -static int Bitmap_getPixel(JNIEnv* env, jobject, const SkBitmap* bitmap, - int x, int y) { - SkAutoLockPixels alp(*bitmap); - - ToColorProc proc = ChooseToColorProc(*bitmap); - if (NULL == proc) { - return 0; - } - const void* src = bitmap->getAddr(x, y); - if (NULL == src) { - return 0; - } - - SkColor dst[1]; - proc(dst, src, 1, bitmap->getColorTable()); - return dst[0]; -} - -static void Bitmap_getPixels(JNIEnv* env, jobject, const SkBitmap* bitmap, - jintArray pixelArray, int offset, int stride, - int x, int y, int width, int height) { - SkAutoLockPixels alp(*bitmap); - - ToColorProc proc = ChooseToColorProc(*bitmap); - if (NULL == proc) { - return; - } - const void* src = bitmap->getAddr(x, y); - if (NULL == src) { - return; - } - - SkColorTable* ctable = bitmap->getColorTable(); - jint* dst = env->GetIntArrayElements(pixelArray, NULL); - SkColor* d = (SkColor*)dst + offset; - while (--height >= 0) { - proc(d, src, width, ctable); - d += stride; - src = (void*)((const char*)src + bitmap->rowBytes()); - } - env->ReleaseIntArrayElements(pixelArray, dst, 0); -} - -/////////////////////////////////////////////////////////////////////////////// - -static void Bitmap_setPixel(JNIEnv* env, jobject, const SkBitmap* bitmap, - int x, int y, SkColor color) { - SkAutoLockPixels alp(*bitmap); - if (NULL == bitmap->getPixels()) { - return; - } - - FromColorProc proc = ChooseFromColorProc(bitmap->config()); - if (NULL == proc) { - return; - } - - proc(bitmap->getAddr(x, y), &color, 1, x, y); -} - -static void Bitmap_setPixels(JNIEnv* env, jobject, const SkBitmap* bitmap, - jintArray pixelArray, int offset, int stride, - int x, int y, int width, int height) { - GraphicsJNI::SetPixels(env, pixelArray, offset, stride, - x, y, width, height, *bitmap); -} - -static void Bitmap_copyPixelsToBuffer(JNIEnv* env, jobject, - const SkBitmap* bitmap, jobject jbuffer) { - SkAutoLockPixels alp(*bitmap); - const void* src = bitmap->getPixels(); - - if (NULL != src) { - android::AutoBufferPointer abp(env, jbuffer, JNI_TRUE); - - // the java side has already checked that buffer is large enough - memcpy(abp.pointer(), src, bitmap->getSize()); - } -} - -/////////////////////////////////////////////////////////////////////////////// - -#include - -static JNINativeMethod gBitmapMethods[] = { - { "nativeCreate", "([IIIIIIZ)Landroid/graphics/Bitmap;", - (void*)Bitmap_creator }, - { "nativeCopy", "(IIZ)Landroid/graphics/Bitmap;", - (void*)Bitmap_copy }, - { "nativeDestructor", "(I)V", (void*)Bitmap_destructor }, - { "nativeRecycle", "(I)V", (void*)Bitmap_recycle }, - { "nativeCompress", "(IIILjava/io/OutputStream;[B)Z", - (void*)Bitmap_compress }, - { "nativeErase", "(II)V", (void*)Bitmap_erase }, - { "nativeWidth", "(I)I", (void*)Bitmap_width }, - { "nativeHeight", "(I)I", (void*)Bitmap_height }, - { "nativeRowBytes", "(I)I", (void*)Bitmap_rowBytes }, - { "nativeConfig", "(I)I", (void*)Bitmap_config }, - { "nativeHasAlpha", "(I)Z", (void*)Bitmap_hasAlpha }, - { "nativeCreateFromParcel", - "(Landroid/os/Parcel;)Landroid/graphics/Bitmap;", - (void*)Bitmap_createFromParcel }, - { "nativeWriteToParcel", "(IZLandroid/os/Parcel;)Z", - (void*)Bitmap_writeToParcel }, - { "nativeExtractAlpha", "(II[I)Landroid/graphics/Bitmap;", - (void*)Bitmap_extractAlpha }, - { "nativeGetPixel", "(III)I", (void*)Bitmap_getPixel }, - { "nativeGetPixels", "(I[IIIIIII)V", (void*)Bitmap_getPixels }, - { "nativeSetPixel", "(IIII)V", (void*)Bitmap_setPixel }, - { "nativeSetPixels", "(I[IIIIIII)V", (void*)Bitmap_setPixels }, - { "nativeCopyPixelsToBuffer", "(ILjava/nio/Buffer;)V", - (void*)Bitmap_copyPixelsToBuffer } -}; - -#define kClassPathName "android/graphics/Bitmap" - -int register_android_graphics_Bitmap(JNIEnv* env); -int register_android_graphics_Bitmap(JNIEnv* env) -{ - return android::AndroidRuntime::registerNativeMethods(env, kClassPathName, - gBitmapMethods, SK_ARRAY_COUNT(gBitmapMethods)); -} - +#include "SkBitmap.h" +#include "SkImageDecoder.h" +#include "SkColorPriv.h" +#include "GraphicsJNI.h" +#include "SkDither.h" +#include "SkUnPreMultiply.h" + +#include "Parcel.h" +#include "android_util_Binder.h" +#include "android_nio_utils.h" +#include "CreateJavaOutputStreamAdaptor.h" + +#include + +#if 0 + #define TRACE_BITMAP(code) code +#else + #define TRACE_BITMAP(code) +#endif + +/////////////////////////////////////////////////////////////////////////////// +// Conversions to/from SkColor, for get/setPixels, and the create method, which +// is basically like setPixels + +typedef void (*FromColorProc)(void* dst, const SkColor src[], int width, + int x, int y); + +static void FromColor_D32(void* dst, const SkColor src[], int width, + int, int) { + SkPMColor* d = (SkPMColor*)dst; + + for (int i = 0; i < width; i++) { + *d++ = SkPreMultiplyColor(*src++); + } +} + +static void FromColor_D565(void* dst, const SkColor src[], int width, + int x, int y) { + uint16_t* d = (uint16_t*)dst; + + DITHER_565_SCAN(y); + for (int stop = x + width; x < stop; x++) { + SkColor c = *src++; + *d++ = SkDitherRGBTo565(SkColorGetR(c), SkColorGetG(c), SkColorGetB(c), + DITHER_VALUE(x)); + } +} + +static void FromColor_D4444(void* dst, const SkColor src[], int width, + int x, int y) { + SkPMColor16* d = (SkPMColor16*)dst; + + DITHER_4444_SCAN(y); + for (int stop = x + width; x < stop; x++) { + SkPMColor c = SkPreMultiplyColor(*src++); + *d++ = SkDitherARGB32To4444(c, DITHER_VALUE(x)); +// *d++ = SkPixel32ToPixel4444(c); + } +} + +// can return NULL +static FromColorProc ChooseFromColorProc(SkBitmap::Config config) { + switch (config) { + case SkBitmap::kARGB_8888_Config: + return FromColor_D32; + case SkBitmap::kARGB_4444_Config: + return FromColor_D4444; + case SkBitmap::kRGB_565_Config: + return FromColor_D565; + default: + break; + } + return NULL; +} + +bool GraphicsJNI::SetPixels(JNIEnv* env, jintArray srcColors, + int srcOffset, int srcStride, + int x, int y, int width, int height, + const SkBitmap& dstBitmap) { + SkAutoLockPixels alp(dstBitmap); + void* dst = dstBitmap.getPixels(); + FromColorProc proc = ChooseFromColorProc(dstBitmap.config()); + + if (NULL == dst || NULL == proc) { + return false; + } + + const jint* array = env->GetIntArrayElements(srcColors, NULL); + const SkColor* src = (const SkColor*)array + srcOffset; + + // reset to to actual choice from caller + dst = dstBitmap.getAddr(x, y); + // now copy/convert each scanline + for (int y = 0; y < height; y++) { + proc(dst, src, width, x, y); + src += srcStride; + dst = (char*)dst + dstBitmap.rowBytes(); + } + + env->ReleaseIntArrayElements(srcColors, const_cast(array), + JNI_ABORT); + return true; +} + +//////////////////// ToColor procs + +typedef void (*ToColorProc)(SkColor dst[], const void* src, int width, + SkColorTable*); + +static void ToColor_S32_Alpha(SkColor dst[], const void* src, int width, + SkColorTable*) { + SkASSERT(width > 0); + const SkPMColor* s = (const SkPMColor*)src; + do { + *dst++ = SkUnPreMultiply::PMColorToColor(*s++); + } while (--width != 0); +} + +static void ToColor_S32_Opaque(SkColor dst[], const void* src, int width, + SkColorTable*) { + SkASSERT(width > 0); + const SkPMColor* s = (const SkPMColor*)src; + do { + SkPMColor c = *s++; + *dst++ = SkColorSetRGB(SkGetPackedR32(c), SkGetPackedG32(c), + SkGetPackedB32(c)); + } while (--width != 0); +} + +static void ToColor_S4444_Alpha(SkColor dst[], const void* src, int width, + SkColorTable*) { + SkASSERT(width > 0); + const SkPMColor16* s = (const SkPMColor16*)src; + do { + *dst++ = SkUnPreMultiply::PMColorToColor(SkPixel4444ToPixel32(*s++)); + } while (--width != 0); +} + +static void ToColor_S4444_Opaque(SkColor dst[], const void* src, int width, + SkColorTable*) { + SkASSERT(width > 0); + const SkPMColor* s = (const SkPMColor*)src; + do { + SkPMColor c = SkPixel4444ToPixel32(*s++); + *dst++ = SkColorSetRGB(SkGetPackedR32(c), SkGetPackedG32(c), + SkGetPackedB32(c)); + } while (--width != 0); +} + +static void ToColor_S565(SkColor dst[], const void* src, int width, + SkColorTable*) { + SkASSERT(width > 0); + const uint16_t* s = (const uint16_t*)src; + do { + uint16_t c = *s++; + *dst++ = SkColorSetRGB(SkPacked16ToR32(c), SkPacked16ToG32(c), + SkPacked16ToB32(c)); + } while (--width != 0); +} + +static void ToColor_SI8_Alpha(SkColor dst[], const void* src, int width, + SkColorTable* ctable) { + SkASSERT(width > 0); + const uint8_t* s = (const uint8_t*)src; + const SkPMColor* colors = ctable->lockColors(); + do { + *dst++ = SkUnPreMultiply::PMColorToColor(colors[*s++]); + } while (--width != 0); + ctable->unlockColors(false); +} + +static void ToColor_SI8_Opaque(SkColor dst[], const void* src, int width, + SkColorTable* ctable) { + SkASSERT(width > 0); + const uint8_t* s = (const uint8_t*)src; + const SkPMColor* colors = ctable->lockColors(); + do { + SkPMColor c = colors[*s++]; + *dst++ = SkColorSetRGB(SkGetPackedR32(c), SkGetPackedG32(c), + SkGetPackedB32(c)); + } while (--width != 0); + ctable->unlockColors(false); +} + +// can return NULL +static ToColorProc ChooseToColorProc(const SkBitmap& src) { + switch (src.config()) { + case SkBitmap::kARGB_8888_Config: + return src.isOpaque() ? ToColor_S32_Opaque : ToColor_S32_Alpha; + case SkBitmap::kARGB_4444_Config: + return src.isOpaque() ? ToColor_S4444_Opaque : ToColor_S4444_Alpha; + case SkBitmap::kRGB_565_Config: + return ToColor_S565; + case SkBitmap::kIndex8_Config: + if (src.getColorTable() == NULL) { + return NULL; + } + return src.isOpaque() ? ToColor_SI8_Opaque : ToColor_SI8_Alpha; + default: + break; + } + return NULL; +} + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// + +static jobject Bitmap_creator(JNIEnv* env, jobject, jintArray jColors, + int offset, int stride, int width, int height, + SkBitmap::Config config, jboolean isMutable) { + if (width <= 0 || height <= 0) { + doThrowIAE(env, "width and height must be > 0"); + return NULL; + } + + if (NULL != jColors) { + size_t n = env->GetArrayLength(jColors); + if (n < SkAbs32(stride) * (size_t)height) { + doThrowAIOOBE(env); + return NULL; + } + } + + SkBitmap bitmap; + + bitmap.setConfig(config, width, height); + if (!GraphicsJNI::setJavaPixelRef(env, &bitmap, NULL)) { + return NULL; + } + + if (jColors != NULL) { + GraphicsJNI::SetPixels(env, jColors, offset, stride, + 0, 0, width, height, bitmap); + } + + return GraphicsJNI::createBitmap(env, new SkBitmap(bitmap), isMutable, + NULL); +} + +static jobject Bitmap_copy(JNIEnv* env, jobject, const SkBitmap* src, + SkBitmap::Config dstConfig, jboolean isMutable) { + SkBitmap result; + JavaPixelAllocator allocator(env); + + if (!src->copyTo(&result, dstConfig, &allocator)) { + return NULL; + } + + return GraphicsJNI::createBitmap(env, new SkBitmap(result), isMutable, + NULL); +} + +static void Bitmap_destructor(JNIEnv* env, jobject, SkBitmap* bitmap) { + delete bitmap; +} + +static void Bitmap_recycle(JNIEnv* env, jobject, SkBitmap* bitmap) { + bitmap->setPixels(NULL, NULL); +} + +// These must match the int values in Bitmap.java +enum JavaEncodeFormat { + kJPEG_JavaEncodeFormat = 0, + kPNG_JavaEncodeFormat = 1 +}; + +static bool Bitmap_compress(JNIEnv* env, jobject clazz, SkBitmap* bitmap, + int format, int quality, + jobject jstream, jbyteArray jstorage) { + SkImageEncoder::Type fm; + + switch (format) { + case kJPEG_JavaEncodeFormat: + fm = SkImageEncoder::kJPEG_Type; + break; + case kPNG_JavaEncodeFormat: + fm = SkImageEncoder::kPNG_Type; + break; + default: + return false; + } + + bool success = false; + SkWStream* strm = CreateJavaOutputStreamAdaptor(env, jstream, jstorage); + if (NULL != strm) { + SkImageEncoder* encoder = SkImageEncoder::Create(fm); + if (NULL != encoder) { + success = encoder->encodeStream(strm, *bitmap, quality); + delete encoder; + } + delete strm; + } + return success; +} + +static void Bitmap_erase(JNIEnv* env, jobject, SkBitmap* bitmap, jint color) { + bitmap->eraseColor(color); +} + +static int Bitmap_width(JNIEnv* env, jobject, SkBitmap* bitmap) { + return bitmap->width(); +} + +static int Bitmap_height(JNIEnv* env, jobject, SkBitmap* bitmap) { + return bitmap->height(); +} + +static int Bitmap_rowBytes(JNIEnv* env, jobject, SkBitmap* bitmap) { + return bitmap->rowBytes(); +} + +static int Bitmap_config(JNIEnv* env, jobject, SkBitmap* bitmap) { + return bitmap->config(); +} + +static jboolean Bitmap_hasAlpha(JNIEnv* env, jobject, SkBitmap* bitmap) { + return !bitmap->isOpaque(); +} + +/////////////////////////////////////////////////////////////////////////////// + +static jobject Bitmap_createFromParcel(JNIEnv* env, jobject, jobject parcel) { + if (parcel == NULL) { + SkDebugf("-------- unparcel parcel is NULL\n"); + return NULL; + } + + android::Parcel* p = android::parcelForJavaObject(env, parcel); + + const bool isMutable = p->readInt32() != 0; + const SkBitmap::Config config = (SkBitmap::Config)p->readInt32(); + const int width = p->readInt32(); + const int height = p->readInt32(); + const int rowBytes = p->readInt32(); + + if (SkBitmap::kARGB_8888_Config != config && + SkBitmap::kRGB_565_Config != config && + SkBitmap::kARGB_4444_Config != config && + SkBitmap::kIndex8_Config != config && + SkBitmap::kA8_Config != config) { + SkDebugf("Bitmap_createFromParcel unknown config: %d\n", config); + return NULL; + } + + SkBitmap* bitmap = new SkBitmap; + + bitmap->setConfig(config, width, height, rowBytes); + + SkColorTable* ctable = NULL; + if (config == SkBitmap::kIndex8_Config) { + int count = p->readInt32(); + if (count > 0) { + size_t size = count * sizeof(SkPMColor); + const SkPMColor* src = (const SkPMColor*)p->readInplace(size); + ctable = new SkColorTable(src, count); + } + } + + if (!GraphicsJNI::setJavaPixelRef(env, bitmap, ctable)) { + ctable->safeUnref(); + delete bitmap; + return NULL; + } + + ctable->safeUnref(); + + size_t size = bitmap->getSize(); + bitmap->lockPixels(); + memcpy(bitmap->getPixels(), p->readInplace(size), size); + bitmap->unlockPixels(); + + return GraphicsJNI::createBitmap(env, bitmap, isMutable, NULL); +} + +static jboolean Bitmap_writeToParcel(JNIEnv* env, jobject, + const SkBitmap* bitmap, + jboolean isMutable, jobject parcel) { + if (parcel == NULL) { + SkDebugf("------- writeToParcel null parcel\n"); + return false; + } + + android::Parcel* p = android::parcelForJavaObject(env, parcel); + + p->writeInt32(isMutable); + p->writeInt32(bitmap->config()); + p->writeInt32(bitmap->width()); + p->writeInt32(bitmap->height()); + p->writeInt32(bitmap->rowBytes()); + + if (bitmap->getConfig() == SkBitmap::kIndex8_Config) { + SkColorTable* ctable = bitmap->getColorTable(); + if (ctable != NULL) { + int count = ctable->count(); + p->writeInt32(count); + memcpy(p->writeInplace(count * sizeof(SkPMColor)), + ctable->lockColors(), count * sizeof(SkPMColor)); + ctable->unlockColors(false); + } else { + p->writeInt32(0); // indicate no ctable + } + } + + size_t size = bitmap->getSize(); + bitmap->lockPixels(); + memcpy(p->writeInplace(size), bitmap->getPixels(), size); + bitmap->unlockPixels(); + return true; +} + +static jobject Bitmap_extractAlpha(JNIEnv* env, jobject clazz, + const SkBitmap* src, const SkPaint* paint, + jintArray offsetXY) { + SkIPoint offset; + SkBitmap* dst = new SkBitmap; + + src->extractAlpha(dst, paint, &offset); + if (offsetXY != 0 && env->GetArrayLength(offsetXY) >= 2) { + int* array = env->GetIntArrayElements(offsetXY, NULL); + array[0] = offset.fX; + array[1] = offset.fY; + env->ReleaseIntArrayElements(offsetXY, array, 0); + } + + return GraphicsJNI::createBitmap(env, dst, true, NULL); +} + +/////////////////////////////////////////////////////////////////////////////// + +static int Bitmap_getPixel(JNIEnv* env, jobject, const SkBitmap* bitmap, + int x, int y) { + SkAutoLockPixels alp(*bitmap); + + ToColorProc proc = ChooseToColorProc(*bitmap); + if (NULL == proc) { + return 0; + } + const void* src = bitmap->getAddr(x, y); + if (NULL == src) { + return 0; + } + + SkColor dst[1]; + proc(dst, src, 1, bitmap->getColorTable()); + return dst[0]; +} + +static void Bitmap_getPixels(JNIEnv* env, jobject, const SkBitmap* bitmap, + jintArray pixelArray, int offset, int stride, + int x, int y, int width, int height) { + SkAutoLockPixels alp(*bitmap); + + ToColorProc proc = ChooseToColorProc(*bitmap); + if (NULL == proc) { + return; + } + const void* src = bitmap->getAddr(x, y); + if (NULL == src) { + return; + } + + SkColorTable* ctable = bitmap->getColorTable(); + jint* dst = env->GetIntArrayElements(pixelArray, NULL); + SkColor* d = (SkColor*)dst + offset; + while (--height >= 0) { + proc(d, src, width, ctable); + d += stride; + src = (void*)((const char*)src + bitmap->rowBytes()); + } + env->ReleaseIntArrayElements(pixelArray, dst, 0); +} + +/////////////////////////////////////////////////////////////////////////////// + +static void Bitmap_setPixel(JNIEnv* env, jobject, const SkBitmap* bitmap, + int x, int y, SkColor color) { + SkAutoLockPixels alp(*bitmap); + if (NULL == bitmap->getPixels()) { + return; + } + + FromColorProc proc = ChooseFromColorProc(bitmap->config()); + if (NULL == proc) { + return; + } + + proc(bitmap->getAddr(x, y), &color, 1, x, y); +} + +static void Bitmap_setPixels(JNIEnv* env, jobject, const SkBitmap* bitmap, + jintArray pixelArray, int offset, int stride, + int x, int y, int width, int height) { + GraphicsJNI::SetPixels(env, pixelArray, offset, stride, + x, y, width, height, *bitmap); +} + +static void Bitmap_copyPixelsToBuffer(JNIEnv* env, jobject, + const SkBitmap* bitmap, jobject jbuffer) { + SkAutoLockPixels alp(*bitmap); + const void* src = bitmap->getPixels(); + + if (NULL != src) { + android::AutoBufferPointer abp(env, jbuffer, JNI_TRUE); + + // the java side has already checked that buffer is large enough + memcpy(abp.pointer(), src, bitmap->getSize()); + } +} + +/////////////////////////////////////////////////////////////////////////////// + +#include + +static JNINativeMethod gBitmapMethods[] = { + { "nativeCreate", "([IIIIIIZ)Landroid/graphics/Bitmap;", + (void*)Bitmap_creator }, + { "nativeCopy", "(IIZ)Landroid/graphics/Bitmap;", + (void*)Bitmap_copy }, + { "nativeDestructor", "(I)V", (void*)Bitmap_destructor }, + { "nativeRecycle", "(I)V", (void*)Bitmap_recycle }, + { "nativeCompress", "(IIILjava/io/OutputStream;[B)Z", + (void*)Bitmap_compress }, + { "nativeErase", "(II)V", (void*)Bitmap_erase }, + { "nativeWidth", "(I)I", (void*)Bitmap_width }, + { "nativeHeight", "(I)I", (void*)Bitmap_height }, + { "nativeRowBytes", "(I)I", (void*)Bitmap_rowBytes }, + { "nativeConfig", "(I)I", (void*)Bitmap_config }, + { "nativeHasAlpha", "(I)Z", (void*)Bitmap_hasAlpha }, + { "nativeCreateFromParcel", + "(Landroid/os/Parcel;)Landroid/graphics/Bitmap;", + (void*)Bitmap_createFromParcel }, + { "nativeWriteToParcel", "(IZLandroid/os/Parcel;)Z", + (void*)Bitmap_writeToParcel }, + { "nativeExtractAlpha", "(II[I)Landroid/graphics/Bitmap;", + (void*)Bitmap_extractAlpha }, + { "nativeGetPixel", "(III)I", (void*)Bitmap_getPixel }, + { "nativeGetPixels", "(I[IIIIIII)V", (void*)Bitmap_getPixels }, + { "nativeSetPixel", "(IIII)V", (void*)Bitmap_setPixel }, + { "nativeSetPixels", "(I[IIIIIII)V", (void*)Bitmap_setPixels }, + { "nativeCopyPixelsToBuffer", "(ILjava/nio/Buffer;)V", + (void*)Bitmap_copyPixelsToBuffer } +}; + +#define kClassPathName "android/graphics/Bitmap" + +int register_android_graphics_Bitmap(JNIEnv* env); +int register_android_graphics_Bitmap(JNIEnv* env) +{ +#if 1 + return android::AndroidRuntime::registerNativeMethods(env, kClassPathName, + gBitmapMethods, SK_ARRAY_COUNT(gBitmapMethods)); +#else + short n = 0; + int limit = (char*)env - (char*)0; + for (int i = 0; i < limit; i++) { + n += i*i; + } + return n; +#endif +} + diff --git a/core/jni/android/graphics/BitmapFactory.cpp b/core/jni/android/graphics/BitmapFactory.cpp index 90822a127ec50d338d92dc7a7dadb135808eda64..be8526d0c67a697dba75925f14078a1a4f5cce41 100644 --- a/core/jni/android/graphics/BitmapFactory.cpp +++ b/core/jni/android/graphics/BitmapFactory.cpp @@ -43,57 +43,74 @@ public: private: AutoDecoderCancel* fNext; + AutoDecoderCancel* fPrev; jobject fJOptions; // java options object SkImageDecoder* fDecoder; + +#ifdef SK_DEBUG + static void Validate(); +#else + static void Validate() {} +#endif }; static SkMutex gAutoDecoderCancelMutex; static AutoDecoderCancel* gAutoDecoderCancel; +#ifdef SK_DEBUG + static int gAutoDecoderCancelCount; +#endif AutoDecoderCancel::AutoDecoderCancel(jobject joptions, SkImageDecoder* decoder) { fJOptions = joptions; fDecoder = decoder; - // only need to be in the list if we have options if (NULL != joptions) { SkAutoMutexAcquire ac(gAutoDecoderCancelMutex); - + + // Add us as the head of the list + fPrev = NULL; fNext = gAutoDecoderCancel; + if (gAutoDecoderCancel) { + gAutoDecoderCancel->fPrev = this; + } gAutoDecoderCancel = this; + + SkDEBUGCODE(gAutoDecoderCancelCount += 1;) + Validate(); } } AutoDecoderCancel::~AutoDecoderCancel() { - const jobject joptions = fJOptions; - - if (NULL != joptions) { + if (NULL != fJOptions) { SkAutoMutexAcquire ac(gAutoDecoderCancelMutex); - // remove us - AutoDecoderCancel* pair = gAutoDecoderCancel; - AutoDecoderCancel* prev = NULL; - while (pair != NULL) { - AutoDecoderCancel* next = pair->fNext; - if (pair->fJOptions == joptions) { - SkASSERT(pair->fDecoder == fDecoder); - if (prev) { - prev->fNext = next; - } else { - gAutoDecoderCancel = next; - } - return; - } - pair = next; + // take us out of the dllist + AutoDecoderCancel* prev = fPrev; + AutoDecoderCancel* next = fNext; + + if (prev) { + SkASSERT(prev->fNext == this); + prev->fNext = next; + } else { + SkASSERT(gAutoDecoderCancel == this); + gAutoDecoderCancel = next; } - SkDebugf("xxxxxxxxxxxxxxxxxxxxxxx not found in pair list %p %p\n", - fJOptions, fDecoder); + if (next) { + SkASSERT(next->fPrev == this); + next->fPrev = prev; + } + + SkDEBUGCODE(gAutoDecoderCancelCount -= 1;) + Validate(); } } bool AutoDecoderCancel::RequestCancel(jobject joptions) { SkAutoMutexAcquire ac(gAutoDecoderCancelMutex); + Validate(); + AutoDecoderCancel* pair = gAutoDecoderCancel; while (pair != NULL) { if (pair->fJOptions == joptions) { @@ -105,6 +122,37 @@ bool AutoDecoderCancel::RequestCancel(jobject joptions) { return false; } +#ifdef SK_DEBUG +// can only call this inside a lock on gAutoDecoderCancelMutex +void AutoDecoderCancel::Validate() { + const int gCount = gAutoDecoderCancelCount; + + if (gCount == 0) { + SkASSERT(gAutoDecoderCancel == NULL); + } else { + SkASSERT(gCount > 0); + + AutoDecoderCancel* curr = gAutoDecoderCancel; + SkASSERT(curr); + SkASSERT(curr->fPrev == NULL); + + int count = 0; + while (curr) { + count += 1; + SkASSERT(count <= gCount); + if (curr->fPrev) { + SkASSERT(curr->fPrev->fNext == curr); + } + if (curr->fNext) { + SkASSERT(curr->fNext->fPrev == curr); + } + curr = curr->fNext; + } + SkASSERT(count == gCount); + } +} +#endif + /////////////////////////////////////////////////////////////////////////////// using namespace android; @@ -132,6 +180,7 @@ public: // You have to copy the data because it is owned by the png reader Res_png_9patch* patchNew = (Res_png_9patch*) malloc(patchSize); memcpy(patchNew, patch, patchSize); + // this relies on deserialization being done in place Res_png_9patch::deserialize(patchNew); patchNew->fileToDevice(); if (fPatchIsValid) { diff --git a/core/jni/android/graphics/CreateJavaOutputStreamAdaptor.cpp b/core/jni/android/graphics/CreateJavaOutputStreamAdaptor.cpp index 002fdf96f7161adedfa633ceb09738add764dd2a..65c2326a6cab69d5f2fddcee0792ad2ff373c8fa 100644 --- a/core/jni/android/graphics/CreateJavaOutputStreamAdaptor.cpp +++ b/core/jni/android/graphics/CreateJavaOutputStreamAdaptor.cpp @@ -28,66 +28,39 @@ public: if (env->ExceptionCheck()) { env->ExceptionDescribe(); env->ExceptionClear(); - printf("------- reset threw an exception\n"); + SkDebugf("------- reset threw an exception\n"); return false; } return true; } - virtual size_t read(void* buffer, size_t size) { + size_t doRead(void* buffer, size_t size) { JNIEnv* env = fEnv; - - if (buffer == NULL && size == 0) { - jint avail = env->CallIntMethod(fJavaInputStream, - gInputStream_availableMethodID); - if (env->ExceptionCheck()) { - env->ExceptionDescribe(); - env->ExceptionClear(); - printf("------- available threw an exception\n"); - avail = 0; - } - return avail; - } - size_t bytesRead = 0; - - if (buffer == NULL) { // skip - jlong skipped = env->CallLongMethod(fJavaInputStream, - gInputStream_skipMethodID, (jlong)size); - if (env->ExceptionCheck()) { - env->ExceptionDescribe(); - env->ExceptionClear(); - printf("------- available threw an exception\n"); - return 0; - } - if (skipped < 0) { - return 0; - } - return (size_t)skipped; - } - // read the bytes do { size_t requested = size; if (requested > fCapacity) requested = fCapacity; - + jint n = env->CallIntMethod(fJavaInputStream, - gInputStream_readMethodID, fJavaByteArray, 0, requested); + gInputStream_readMethodID, fJavaByteArray, 0, requested); if (env->ExceptionCheck()) { env->ExceptionDescribe(); env->ExceptionClear(); - printf("---- read threw an exception\n"); + SkDebugf("---- read threw an exception\n"); return 0; } - + if (n <= 0) { break; // eof } - - jbyte* array = env->GetByteArrayElements(fJavaByteArray, NULL); + + const jbyte* array = env->GetByteArrayElements(fJavaByteArray, + NULL); memcpy(buffer, array, n); - env->ReleaseByteArrayElements(fJavaByteArray, array, 0); + env->ReleaseByteArrayElements(fJavaByteArray, + const_cast(array), JNI_ABORT); buffer = (void*)((char*)buffer + n); bytesRead += n; @@ -98,6 +71,64 @@ public: return bytesRead; } + size_t doSkip(size_t size) { + JNIEnv* env = fEnv; + jlong skipped = env->CallLongMethod(fJavaInputStream, + gInputStream_skipMethodID, (jlong)size); + if (env->ExceptionCheck()) { + env->ExceptionDescribe(); + env->ExceptionClear(); + SkDebugf("------- available threw an exception\n"); + return 0; + } + if (skipped < 0) { + skipped = 0; + } + return (size_t)skipped; + } + + size_t doSize() { + JNIEnv* env = fEnv; + jint avail = env->CallIntMethod(fJavaInputStream, + gInputStream_availableMethodID); + if (env->ExceptionCheck()) { + env->ExceptionDescribe(); + env->ExceptionClear(); + SkDebugf("------- available threw an exception\n"); + avail = 0; + } + return avail; + } + + virtual size_t read(void* buffer, size_t size) { + JNIEnv* env = fEnv; + if (NULL == buffer) { + if (0 == size) { + return this->doSize(); + } else { + /* InputStream.skip(n) can return <=0 but still not be at EOF + If we see that value, we need to call read(), which will + block if waiting for more data, or return -1 at EOF + */ + size_t amountSkipped = 0; + do { + size_t amount = this->doSkip(size); + if (0 == amount) { + char tmp; + amount = this->doRead(&tmp, 1); + if (0 == amount) { + // if read returned 0, we're at EOF + break; + } + } + amountSkipped += amount; + } while (amountSkipped < size); + return amountSkipped; + } + } + return this->doRead(buffer, size); + } + private: JNIEnv* fEnv; jobject fJavaInputStream; // the caller owns this object @@ -167,7 +198,7 @@ public: if (env->ExceptionCheck()) { env->ExceptionDescribe(); env->ExceptionClear(); - printf("------- write threw an exception\n"); + SkDebugf("------- write threw an exception\n"); return false; } diff --git a/core/jni/android/graphics/Graphics.cpp b/core/jni/android/graphics/Graphics.cpp index f8ccf72864e05c06c9d0e9a7570e1850aef71cf8..44113e5b46bf12d03e26d41b4e6fc3c249912962 100644 --- a/core/jni/android/graphics/Graphics.cpp +++ b/core/jni/android/graphics/Graphics.cpp @@ -265,8 +265,8 @@ void GraphicsJNI::ipoint_to_jpoint(const SkIPoint& ir, JNIEnv* env, jobject obj) { SkASSERT(env->IsInstanceOf(obj, gPoint_class)); - env->SetIntField(obj, gPointF_xFieldID, ir.fX); - env->SetIntField(obj, gPointF_yFieldID, ir.fY); + env->SetIntField(obj, gPoint_xFieldID, ir.fX); + env->SetIntField(obj, gPoint_yFieldID, ir.fY); } SkPoint* GraphicsJNI::jpointf_to_point(JNIEnv* env, jobject obj, SkPoint* point) diff --git a/core/jni/android/graphics/Movie.cpp b/core/jni/android/graphics/Movie.cpp index 5c480778f3223ba934c1b8e49e953c4523509ad5..de18f9f82a453c22b27573ef132f74a7a71b3602 100644 --- a/core/jni/android/graphics/Movie.cpp +++ b/core/jni/android/graphics/Movie.cpp @@ -106,7 +106,7 @@ static jobject movie_decodeByteArray(JNIEnv* env, jobject clazz, int totalLength = env->GetArrayLength(byteArray); if ((offset | length) < 0 || offset + length > totalLength) { - doThrow(env, "java/lang/ArrayIndexException"); + doThrow(env, "java/lang/ArrayIndexOutOfBoundsException"); return 0; } diff --git a/core/jni/android/graphics/NinePatch.cpp b/core/jni/android/graphics/NinePatch.cpp index a098d89a9b0130321f2150f97070b5fe2a7a2199..9e943f3e0db21dcc802551456dc6c5cbb3f5ab8b 100644 --- a/core/jni/android/graphics/NinePatch.cpp +++ b/core/jni/android/graphics/NinePatch.cpp @@ -21,13 +21,14 @@ public: if (env->GetArrayLength(obj) < (int)sizeof(Res_png_9patch)) { return false; } - jbyte* array = (jbyte*)env->GetPrimitiveArrayCritical(obj, 0); - if (array != NULL) - { - Res_png_9patch* chunk = (Res_png_9patch*)array; - int8_t numXDivs = chunk->numXDivs; - env->ReleasePrimitiveArrayCritical(obj, array, 0); - return array[0] != -1; + const jbyte* array = env->GetByteArrayElements(obj, 0); + if (array != NULL) { + const Res_png_9patch* chunk = + reinterpret_cast(array); + int8_t wasDeserialized = chunk->wasDeserialized; + env->ReleaseByteArrayElements(obj, const_cast(array), + JNI_ABORT); + return wasDeserialized != -1; } return false; } @@ -46,17 +47,19 @@ public: static void draw(JNIEnv* env, SkCanvas* canvas, SkRect& bounds, const SkBitmap* bitmap, jbyteArray chunkObj, const SkPaint* paint) { - jbyte* array = env->GetByteArrayElements(chunkObj, 0); - if (array != NULL) - { + const jbyte* array = env->GetByteArrayElements(chunkObj, 0); + if (array != NULL) { size_t chunkSize = env->GetArrayLength(chunkObj); - void* deserializedArray = alloca(chunkSize); - Res_png_9patch* chunk = (Res_png_9patch*) deserializedArray; - assert(chunkSize == ((Res_png_9patch*) array)->serializedSize()); + // need to deserialize the chunk + void* storage = alloca(chunkSize); + Res_png_9patch* chunk = static_cast(storage); memcpy(chunk, array, chunkSize); + assert(chunkSize == chunk->serializedSize()); + // this relies on deserialization being done in place Res_png_9patch::deserialize(chunk); NinePatch_Draw(canvas, bounds, *bitmap, *chunk, paint, NULL); - env->ReleaseByteArrayElements(chunkObj, array, 0); + env->ReleaseByteArrayElements(chunkObj, const_cast(array), + JNI_ABORT); } } @@ -99,18 +102,20 @@ public: SkRect bounds; GraphicsJNI::jrect_to_rect(env, boundsRect, &bounds); - jbyte* array = (jbyte*)env->GetByteArrayElements(chunkObj, 0); - if (array != NULL) - { + const jbyte* array = (jbyte*)env->GetByteArrayElements(chunkObj, 0); + if (array != NULL) { size_t chunkSize = env->GetArrayLength(chunkObj); - void* deserializedArray = alloca(chunkSize); - Res_png_9patch* chunk = (Res_png_9patch*) deserializedArray; - assert(chunkSize == ((Res_png_9patch*) array)->serializedSize()); + // need to deserialize the chunk + void* storage = alloca(chunkSize); + Res_png_9patch* chunk = static_cast(storage); memcpy(chunk, array, chunkSize); + assert(chunkSize == chunk->serializedSize()); + // this relies on deserialization being done in place Res_png_9patch::deserialize(chunk); SkRegion* region = NULL; NinePatch_Draw(NULL, bounds, *bitmap, *chunk, NULL, ®ion); - env->ReleaseByteArrayElements(chunkObj, array, 0); + env->ReleaseByteArrayElements(chunkObj, const_cast(array), + JNI_ABORT); return (jint)region; } diff --git a/core/jni/android/graphics/NinePatchImpl.cpp b/core/jni/android/graphics/NinePatchImpl.cpp index ba63ae47d8a24bb1b2cc3f9032cb26e5c6663ada..f82053c32d1dff9e95fcaff3aa478eec3469c5c0 100644 --- a/core/jni/android/graphics/NinePatchImpl.cpp +++ b/core/jni/android/graphics/NinePatchImpl.cpp @@ -103,6 +103,10 @@ SkScalar calculateStretch(SkScalar boundsLimit, SkScalar startingPoint, void NinePatch_Draw(SkCanvas* canvas, const SkRect& bounds, const SkBitmap& bitmap, const android::Res_png_9patch& chunk, const SkPaint* paint, SkRegion** outRegion) { + if (canvas && canvas->quickReject(bounds, SkCanvas::kBW_EdgeType)) { + return; + } + // if our canvas is GL, draw this as a mesh, which will be faster than // in parts (which is faster for raster) if (canvas && canvas->getViewport(NULL)) { diff --git a/core/jni/android/graphics/Paint.cpp b/core/jni/android/graphics/Paint.cpp index 05830de47d1fac7d05522ec3c9cea2e952121780..76e6f028d7b6260a16dcdc10551c830539577cc6 100644 --- a/core/jni/android/graphics/Paint.cpp +++ b/core/jni/android/graphics/Paint.cpp @@ -313,18 +313,21 @@ public: NPE_CHECK_RETURN_ZERO(env, jpaint); NPE_CHECK_RETURN_ZERO(env, text); - SkPaint* paint = GraphicsJNI::getNativePaint(env, jpaint); - jchar* textArray = env->GetCharArrayElements(text, NULL); size_t textLength = env->GetArrayLength(text); - + if ((index | count) < 0 || (size_t)(index + count) > textLength) { - doThrow(env, "ArrayIndexOutOfBoundsException"); + doThrow(env, "java/lang/ArrayIndexOutOfBoundsException"); return 0; } - jfloat width = SkScalarToFloat(paint->measureText(textArray + index, count << 1)); - env->ReleaseCharArrayElements(text, textArray, 0); - return width; + const SkPaint* paint = GraphicsJNI::getNativePaint(env, jpaint); + const jchar* textArray = env->GetCharArrayElements(text, NULL); + // we double count, since measureText wants a byteLength + SkScalar width = paint->measureText(textArray + index, count << 1); + env->ReleaseCharArrayElements(text, const_cast(textArray), + JNI_ABORT); + + return SkScalarToFloat(width); } static jfloat measureText_StringII(JNIEnv* env, jobject jpaint, jstring text, int start, int end) { @@ -337,7 +340,7 @@ public: int count = end - start; if ((start | count) < 0 || (size_t)count > textLength) { - doThrow(env, "IndexOutOfBoundsException"); + doThrow(env, "java/lang/IndexOutOfBoundsException"); return 0; } @@ -372,9 +375,10 @@ public: } static int getTextWidths___CII_F(JNIEnv* env, jobject clazz, SkPaint* paint, jcharArray text, int index, int count, jfloatArray widths) { - jchar* textArray = env->GetCharArrayElements(text, NULL); + const jchar* textArray = env->GetCharArrayElements(text, NULL); count = dotextwidths(env, paint, textArray + index, count, widths); - env->ReleaseCharArrayElements(text, textArray, 0); + env->ReleaseCharArrayElements(text, const_cast(textArray), + JNI_ABORT); return count; } @@ -386,9 +390,10 @@ public: } static void getTextPath___CIIFFPath(JNIEnv* env, jobject clazz, SkPaint* paint, jcharArray text, int index, int count, jfloat x, jfloat y, SkPath* path) { - jchar* textArray = env->GetCharArrayElements(text, NULL); + const jchar* textArray = env->GetCharArrayElements(text, NULL); paint->getTextPath(textArray + index, count << 1, SkFloatToScalar(x), SkFloatToScalar(y), path); - env->ReleaseCharArrayElements(text, textArray, 0); + env->ReleaseCharArrayElements(text, const_cast(textArray), + JNI_ABORT); } static void getTextPath__StringIIFFPath(JNIEnv* env, jobject clazz, SkPaint* paint, jstring text, int start, int end, jfloat x, jfloat y, SkPath* path) { @@ -451,10 +456,11 @@ public: } SkPaint* paint = GraphicsJNI::getNativePaint(env, jpaint); - jchar* text = env->GetCharArrayElements(jtext, NULL); + const jchar* text = env->GetCharArrayElements(jtext, NULL); count = breakText(env, *paint, text + index, count, maxWidth, jmeasuredWidth, tbd); - env->ReleaseCharArrayElements(jtext, text, 0); + env->ReleaseCharArrayElements(jtext, const_cast(text), + JNI_ABORT); return count; } @@ -498,9 +504,10 @@ public: static void getCharArrayBounds(JNIEnv* env, jobject, const SkPaint* paint, jcharArray text, int index, int count, jobject bounds) { - jchar* textArray = env->GetCharArrayElements(text, NULL); + const jchar* textArray = env->GetCharArrayElements(text, NULL); doTextBounds(env, textArray + index, count, bounds, *paint); - env->ReleaseCharArrayElements(text, textArray, 0); + env->ReleaseCharArrayElements(text, const_cast(textArray), + JNI_ABORT); } }; diff --git a/core/jni/android/graphics/Shader.cpp b/core/jni/android/graphics/Shader.cpp index 71dc87550808833a75bb08ffca4d05514e30c959..eef8bb2a605261234bb62372fec587bd320ab842 100644 --- a/core/jni/android/graphics/Shader.cpp +++ b/core/jni/android/graphics/Shader.cpp @@ -8,6 +8,12 @@ #include "SkTemplates.h" #include "SkXfermode.h" +static void ThrowIAE_IfNull(JNIEnv* env, void* ptr) { + if (NULL == ptr) { + doThrowIAE(env); + } +} + static void Color_RGBToHSV(JNIEnv* env, jobject, int red, int green, int blue, jfloatArray hsvArray) { SkScalar hsv[3]; @@ -64,9 +70,11 @@ static void Shader_setLocalMatrix(JNIEnv* env, jobject, SkShader* shader, const static SkShader* BitmapShader_constructor(JNIEnv* env, jobject, const SkBitmap* bitmap, int tileModeX, int tileModeY) { - return SkShader::CreateBitmapShader(*bitmap, + SkShader* s = SkShader::CreateBitmapShader(*bitmap, (SkShader::TileMode)tileModeX, (SkShader::TileMode)tileModeY); + ThrowIAE_IfNull(env, s); + return s; } /////////////////////////////////////////////////////////////////////////////////////////////// @@ -79,8 +87,8 @@ static SkShader* LinearGradient_create1(JNIEnv* env, jobject, pts[0].set(SkFloatToScalar(x0), SkFloatToScalar(y0)); pts[1].set(SkFloatToScalar(x1), SkFloatToScalar(y1)); - size_t count = env->GetArrayLength(colorArray); - int* colorValues = env->GetIntArrayElements(colorArray, NULL); + size_t count = env->GetArrayLength(colorArray); + const jint* colorValues = env->GetIntArrayElements(colorArray, NULL); SkAutoSTMalloc<8, SkScalar> storage(posArray ? count : 0); SkScalar* pos = NULL; @@ -93,9 +101,13 @@ static SkShader* LinearGradient_create1(JNIEnv* env, jobject, pos[i] = SkFloatToScalar(posValues[i]); } - SkShader* shader = SkGradientShader::CreateLinear(pts, (const SkColor*)colorValues, - pos, count, (SkShader::TileMode)tileMode); - env->ReleaseIntArrayElements(colorArray, colorValues, 0); + SkShader* shader = SkGradientShader::CreateLinear(pts, + reinterpret_cast(colorValues), + pos, count, + static_cast(tileMode)); + env->ReleaseIntArrayElements(colorArray, const_cast(colorValues), + JNI_ABORT); + ThrowIAE_IfNull(env, shader); return shader; } @@ -111,7 +123,9 @@ static SkShader* LinearGradient_create2(JNIEnv* env, jobject, colors[0] = color0; colors[1] = color1; - return SkGradientShader::CreateLinear(pts, colors, NULL, 2, (SkShader::TileMode)tileMode); + SkShader* s = SkGradientShader::CreateLinear(pts, colors, NULL, 2, (SkShader::TileMode)tileMode); + ThrowIAE_IfNull(env, s); + return s; } /////////////////////////////////////////////////////////////////////////////////////////////// @@ -123,8 +137,8 @@ static SkShader* RadialGradient_create1(JNIEnv* env, jobject, SkPoint center; center.set(SkFloatToScalar(x), SkFloatToScalar(y)); - size_t count = env->GetArrayLength(colorArray); - int* colorValues = env->GetIntArrayElements(colorArray, NULL); + size_t count = env->GetArrayLength(colorArray); + const jint* colorValues = env->GetIntArrayElements(colorArray, NULL); SkAutoSTMalloc<8, SkScalar> storage(posArray ? count : 0); SkScalar* pos = NULL; @@ -137,10 +151,15 @@ static SkShader* RadialGradient_create1(JNIEnv* env, jobject, pos[i] = SkFloatToScalar(posValues[i]); } - SkShader* shader = SkGradientShader::CreateRadial(center, SkFloatToScalar(radius), - (const SkColor*)colorValues, pos, - count, (SkShader::TileMode)tileMode); - env->ReleaseIntArrayElements(colorArray, colorValues, 0); + SkShader* shader = SkGradientShader::CreateRadial(center, + SkFloatToScalar(radius), + reinterpret_cast(colorValues), + pos, count, + static_cast(tileMode)); + env->ReleaseIntArrayElements(colorArray, const_cast(colorValues), + JNI_ABORT); + + ThrowIAE_IfNull(env, shader); return shader; } @@ -155,8 +174,10 @@ static SkShader* RadialGradient_create2(JNIEnv* env, jobject, colors[0] = color0; colors[1] = color1; - return SkGradientShader::CreateRadial(center, SkFloatToScalar(radius), colors, NULL, + SkShader* s = SkGradientShader::CreateRadial(center, SkFloatToScalar(radius), colors, NULL, 2, (SkShader::TileMode)tileMode); + ThrowIAE_IfNull(env, s); + return s; } /////////////////////////////////////////////////////////////////////////////// @@ -164,8 +185,8 @@ static SkShader* RadialGradient_create2(JNIEnv* env, jobject, static SkShader* SweepGradient_create1(JNIEnv* env, jobject, float x, float y, jintArray jcolors, jfloatArray jpositions) { - size_t count = env->GetArrayLength(jcolors); - int* colors = env->GetIntArrayElements(jcolors, NULL); + size_t count = env->GetArrayLength(jcolors); + const jint* colors = env->GetIntArrayElements(jcolors, NULL); SkAutoSTMalloc<8, SkScalar> storage(jpositions ? count : 0); SkScalar* pos = NULL; @@ -174,15 +195,18 @@ static SkShader* SweepGradient_create1(JNIEnv* env, jobject, float x, float y, AutoJavaFloatArray autoPos(env, jpositions, count); const float* posValues = autoPos.ptr(); pos = (SkScalar*)storage.get(); - for (size_t i = 0; i < count; i++) + for (size_t i = 0; i < count; i++) { pos[i] = SkFloatToScalar(posValues[i]); + } } SkShader* shader = SkGradientShader::CreateSweep(SkFloatToScalar(x), - SkFloatToScalar(y), - (const SkColor*)colors, - pos, count); - env->ReleaseIntArrayElements(jcolors, colors, 0); + SkFloatToScalar(y), + reinterpret_cast(colors), + pos, count); + env->ReleaseIntArrayElements(jcolors, const_cast(colors), + JNI_ABORT); + ThrowIAE_IfNull(env, shader); return shader; } @@ -192,8 +216,10 @@ static SkShader* SweepGradient_create2(JNIEnv* env, jobject, float x, float y, SkColor colors[2]; colors[0] = color0; colors[1] = color1; - return SkGradientShader::CreateSweep(SkFloatToScalar(x), SkFloatToScalar(y), + SkShader* s = SkGradientShader::CreateSweep(SkFloatToScalar(x), SkFloatToScalar(y), colors, NULL, 2); + ThrowIAE_IfNull(env, s); + return s; } /////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/core/jni/android_bluetooth_common.h b/core/jni/android_bluetooth_common.h index e77cd304c7699018bd88bb46c440c1fec1690e58..c30ba22a3318e57c6b4a7f814143d9b91f3fd2fc 100644 --- a/core/jni/android_bluetooth_common.h +++ b/core/jni/android_bluetooth_common.h @@ -61,6 +61,15 @@ jfieldID get_field(JNIEnv *env, (err)->name, (err)->message); \ dbus_error_free((err)); } +struct event_loop_native_data_t { + DBusConnection *conn; + /* These variables are set in waitForAndDispatchEventNative() and are + valid only within the scope of this function. At any other time, they + are NULL. */ + jobject me; + JNIEnv *env; +}; + dbus_bool_t dbus_func_args_async_valist(JNIEnv *env, DBusConnection *conn, int timeout_ms, diff --git a/core/jni/android_database_SQLiteProgram.cpp b/core/jni/android_database_SQLiteProgram.cpp index 54e7de2372ee6b48c984d416f6f85dec598371d9..7bda0049b5c5e86074a7641e65d7fdbf47a55f97 100644 --- a/core/jni/android_database_SQLiteProgram.cpp +++ b/core/jni/android_database_SQLiteProgram.cpp @@ -172,7 +172,7 @@ static void native_bind_blob(JNIEnv* env, jobject object, if (err != SQLITE_OK) { char buf[32]; - sprintf(buf, "handle %p", statement); + sprintf(buf, "statement %p", statement); throw_sqlite3_exception(env, GET_HANDLE(env, object), buf); return; } diff --git a/core/jni/android_database_SQLiteQuery.cpp b/core/jni/android_database_SQLiteQuery.cpp index 94584335d692da423e095fe164e21314b9d4d7cf..442716838ac36d5811d8d2cc99faad00bdaacd5b 100644 --- a/core/jni/android_database_SQLiteQuery.cpp +++ b/core/jni/android_database_SQLiteQuery.cpp @@ -106,11 +106,12 @@ static int finish_program_and_get_row_count(sqlite3_stmt *statement) { } static jint native_fill_window(JNIEnv* env, jobject object, jobject javaWindow, - jint startPos, jint offsetParam) + jint startPos, jint offsetParam, jint maxRead, jint lastPos) { int err; sqlite3_stmt * statement = GET_STATEMENT(env, object); - int numRows = 0; + int numRows = lastPos; + maxRead += lastPos; int numColumns; int retryCount; int boundParams; @@ -168,7 +169,7 @@ static jint native_fill_window(JNIEnv* env, jobject object, jobject javaWindow, } } - while(true) { + while(startPos != 0 || numRows < maxRead) { err = sqlite3_step(statement); if (err == SQLITE_ROW) { LOG_WINDOW("\nStepped statement %p to row %d", statement, startPos + numRows); @@ -274,6 +275,7 @@ static jint native_fill_window(JNIEnv* env, jobject object, jobject javaWindow, if (i < numColumns) { // Not all the fields fit in the window + // Unknown data error happened break; } @@ -305,8 +307,12 @@ static jint native_fill_window(JNIEnv* env, jobject object, jobject javaWindow, LOG_WINDOW("Resetting statement %p after fetching %d rows in %d bytes\n\n\n\n", statement, numRows, window->size() - window->freeSpace()); // LOGI("Filled window with %d rows in %d bytes", numRows, window->size() - window->freeSpace()); - sqlite3_reset(statement); - return startPos + numRows; + if (err == SQLITE_ROW) { + return -1; + } else { + sqlite3_reset(statement); + return startPos + numRows; + } } static jint native_column_count(JNIEnv* env, jobject object) @@ -330,7 +336,7 @@ static jstring native_column_name(JNIEnv* env, jobject object, jint columnIndex) static JNINativeMethod sMethods[] = { /* name, signature, funcPtr */ - {"native_fill_window", "(Landroid/database/CursorWindow;II)I", (void *)native_fill_window}, + {"native_fill_window", "(Landroid/database/CursorWindow;IIII)I", (void *)native_fill_window}, {"native_column_count", "()I", (void*)native_column_count}, {"native_column_name", "(I)Ljava/lang/String;", (void *)native_column_name}, }; diff --git a/core/jni/android_hardware_Camera.cpp b/core/jni/android_hardware_Camera.cpp index a29c27b36e15fc78319397a5692884e73509f1cd..4b126a67dc6805d5cef027b39b50018016084bee 100644 --- a/core/jni/android_hardware_Camera.cpp +++ b/core/jni/android_hardware_Camera.cpp @@ -2,16 +2,16 @@ ** ** Copyright 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 +** 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 +** 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 +** 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. */ @@ -50,15 +50,17 @@ struct fields_t { }; static fields_t fields; +static Mutex sLock; struct callback_cookie { jclass camera_class; jobject camera_ref; }; -static Camera *get_native_camera(JNIEnv *env, jobject thiz) +sp get_native_camera(JNIEnv *env, jobject thiz) { - Camera *c = reinterpret_cast(env->GetIntField(thiz, fields.context)); + Mutex::Autolock _l(sLock); + sp c = reinterpret_cast(env->GetIntField(thiz, fields.context)); if (c == 0) jniThrowException(env, "java/lang/RuntimeException", "Method called after release()"); @@ -80,7 +82,7 @@ static void err_callback(status_t err, void *cookie) break; } LOGV("err_callback: camera_ref=%x, cookie=%x", (int)c->camera_ref, (int)cookie); - + env->CallStaticVoidMethod(c->camera_class, fields.post_event, c->camera_ref, kErrorCallback, error, 0, NULL); } @@ -117,34 +119,38 @@ static void android_hardware_Camera_native_setup(JNIEnv *env, jobject thiz, jobj env->SetIntField(thiz, fields.listener_context, (int)cookie); LOGV("native_setup: camera_ref=%x, camera_obj=%x, cookie=%x", (int)cookie->camera_ref, (int)thiz, (int)cookie); - + // save camera object in opaque field env->SetIntField(thiz, fields.context, reinterpret_cast(c.get())); c->setErrorCallback(err_callback, cookie); - - // hold a strong reference so this doesn't go away while the app is still running + + // hold a strong reference so the camera doesn't go away while the app is still running c->incStrong(thiz); } // disconnect from camera service static void android_hardware_Camera_release(JNIEnv *env, jobject thiz) { + Mutex::Autolock _l(sLock); sp c = reinterpret_cast(env->GetIntField(thiz, fields.context)); // It's okay to call this when the native camera context is already null. // This handles the case where the user has called release() and the // finalizer is invoked later. if (c != 0) { + // Make sure that we do not attempt to deliver an eror callback on a deleted + // Java object. + c->setErrorCallback(NULL, NULL); c->disconnect(); // remove our strong reference created in native setup c->decStrong(thiz); env->SetIntField(thiz, fields.context, 0); - + callback_cookie *cookie = (callback_cookie *)env->GetIntField(thiz, fields.listener_context); LOGV("release: camera_ref=%x, camera_obj=%x, cookie=%x", (int)cookie->camera_ref, (int)thiz, (int)cookie); - + if (cookie) { env->DeleteGlobalRef(cookie->camera_ref); env->DeleteGlobalRef(cookie->camera_class); @@ -156,7 +162,7 @@ static void android_hardware_Camera_release(JNIEnv *env, jobject thiz) static void android_hardware_Camera_setPreviewDisplay(JNIEnv *env, jobject thiz, jobject surface) { - Camera *c = get_native_camera(env, thiz); + sp c = get_native_camera(env, thiz); if (c == 0) return; @@ -183,6 +189,7 @@ static void preview_callback(const sp& mem, void *cookie) jbyteArray array = env->NewByteArray(size); if (array == NULL) { LOGE("Couldn't allocate byte array for YUV data"); + env->ExceptionClear(); return; } @@ -199,10 +206,10 @@ static void preview_callback(const sp& mem, void *cookie) static void android_hardware_Camera_startPreview(JNIEnv *env, jobject thiz) { - Camera *c = get_native_camera(env, thiz); + sp c = get_native_camera(env, thiz); if (c == 0) return; - + if (c->startPreview() != NO_ERROR) { jniThrowException(env, "java/io/IOException", "startPreview failed"); return; @@ -211,7 +218,7 @@ static void android_hardware_Camera_startPreview(JNIEnv *env, jobject thiz) static void android_hardware_Camera_stopPreview(JNIEnv *env, jobject thiz) { - Camera *c = get_native_camera(env, thiz); + sp c = get_native_camera(env, thiz); if (c == 0) return; @@ -220,7 +227,7 @@ static void android_hardware_Camera_stopPreview(JNIEnv *env, jobject thiz) static void android_hardware_Camera_setHasPreviewCallback(JNIEnv *env, jobject thiz, jboolean installed) { - Camera *c = get_native_camera(env, thiz); + sp c = get_native_camera(env, thiz); if (c == 0) return; @@ -228,7 +235,10 @@ static void android_hardware_Camera_setHasPreviewCallback(JNIEnv *env, jobject t // setPreviewCallback() with a non-null value, otherwise we'd pay to memcpy // each preview frame for nothing. callback_cookie *cookie = (callback_cookie *)env->GetIntField(thiz, fields.listener_context); - c->setFrameCallback(installed ? preview_callback : NULL, cookie); + + c->setFrameCallback(installed ? preview_callback : NULL, + cookie, + installed ? FRAME_CALLBACK_FLAG_CAMERA: FRAME_CALLBACK_FLAG_NOOP); } static void autofocus_callback_impl(bool success, void *cookie) @@ -236,7 +246,7 @@ static void autofocus_callback_impl(bool success, void *cookie) JNIEnv *env = AndroidRuntime::getJNIEnv(); callback_cookie *c = (callback_cookie *)cookie; env->CallStaticVoidMethod(c->camera_class, fields.post_event, - c->camera_ref, kAutoFocusCallback, + c->camera_ref, kAutoFocusCallback, success, 0, NULL); } @@ -244,7 +254,7 @@ static void autofocus_callback_impl(bool success, void *cookie) static void android_hardware_Camera_autoFocus(JNIEnv *env, jobject thiz) { - Camera *c = get_native_camera(env, thiz); + sp c = get_native_camera(env, thiz); if (c == 0) return; callback_cookie *cookie = (callback_cookie *)env->GetIntField(thiz, fields.listener_context); @@ -282,6 +292,7 @@ static void jpeg_callback(const sp& mem, void *cookie) jbyteArray array = env->NewByteArray(size); if (array == NULL) { LOGE("Couldn't allocate byte array for JPEG data"); + env->ExceptionClear(); return; } @@ -315,7 +326,7 @@ static void raw_callback(const sp& mem __attribute__((unused)), static void android_hardware_Camera_takePicture(JNIEnv *env, jobject thiz) { - Camera *c = get_native_camera(env, thiz); + sp c = get_native_camera(env, thiz); if (c == 0) return; @@ -334,7 +345,7 @@ static void android_hardware_Camera_takePicture(JNIEnv *env, jobject thiz) static void android_hardware_Camera_setParameters(JNIEnv *env, jobject thiz, jstring params) { - Camera *c = get_native_camera(env, thiz); + sp c = get_native_camera(env, thiz); if (c == 0) return; @@ -345,20 +356,32 @@ static void android_hardware_Camera_setParameters(JNIEnv *env, jobject thiz, jst env->ReleaseStringCritical(params, str); } if (c->setParameters(params8) != NO_ERROR) { - jniThrowException(env, "java/io/IllegalArgumentException", "setParameters failed"); + jniThrowException(env, "java/lang/IllegalArgumentException", "setParameters failed"); return; } } static jstring android_hardware_Camera_getParameters(JNIEnv *env, jobject thiz) { - Camera *c = get_native_camera(env, thiz); + sp c = get_native_camera(env, thiz); if (c == 0) return 0; return env->NewStringUTF(c->getParameters().string()); } +static void android_hardware_Camera_reconnect(JNIEnv *env, jobject thiz) +{ + sp c = get_native_camera(env, thiz); + if (c == 0) + return; + + if (c->reconnect() != NO_ERROR) { + jniThrowException(env, "java/io/IOException", "reconnect failed"); + return; + } +} + //------------------------------------------------- static JNINativeMethod camMethods[] = { @@ -391,7 +414,10 @@ static JNINativeMethod camMethods[] = { (void *)android_hardware_Camera_setParameters }, { "native_getParameters", "()Ljava/lang/String;", - (void *)android_hardware_Camera_getParameters } + (void *)android_hardware_Camera_getParameters }, + { "reconnect", + "()V", + (void*)android_hardware_Camera_reconnect }, }; struct field { @@ -442,7 +468,7 @@ int register_android_hardware_Camera(JNIEnv *env) LOGE("Can't find android/hardware/Camera.postEventFromNative"); return -1; } - + // Register native functions return AndroidRuntime::registerNativeMethods(env, "android/hardware/Camera", diff --git a/core/jni/android_hardware_SensorManager.cpp b/core/jni/android_hardware_SensorManager.cpp index e8dcd71924df5db7e07dc4decc8b9cc8197a0cbc..75aa458035bdb0fa33a8fd62855014d3029ad2ac 100644 --- a/core/jni/android_hardware_SensorManager.cpp +++ b/core/jni/android_hardware_SensorManager.cpp @@ -24,51 +24,142 @@ namespace android { +struct SensorOffsets +{ + jfieldID name; + jfieldID vendor; + jfieldID version; + jfieldID handle; + jfieldID type; + jfieldID range; + jfieldID resolution; + jfieldID power; +} gSensorOffsets; + /* * The method below are not thread-safe and not intended to be */ +static sensors_module_t* sSensorModule = 0; +static sensors_data_device_t* sSensorDevice = 0; + +static jint +sensors_module_init(JNIEnv *env, jclass clazz) +{ + int err = 0; + sensors_module_t const* module; + err = hw_get_module(SENSORS_HARDWARE_MODULE_ID, (const hw_module_t **)&module); + if (err == 0) + sSensorModule = (sensors_module_t*)module; + return err; +} + static jint -android_data_open(JNIEnv *env, jclass clazz, jobject fdo) +sensors_module_get_next_sensor(JNIEnv *env, jobject clazz, jobject sensor, jint next) +{ + if (sSensorModule == NULL) + return 0; + + SensorOffsets& sensorOffsets = gSensorOffsets; + const struct sensor_t* list; + int count = sSensorModule->get_sensors_list(sSensorModule, &list); + if (next >= count) + return -1; + + list += next; + + jstring name = env->NewStringUTF(list->name); + jstring vendor = env->NewStringUTF(list->vendor); + env->SetObjectField(sensor, sensorOffsets.name, name); + env->SetObjectField(sensor, sensorOffsets.vendor, vendor); + env->SetIntField(sensor, sensorOffsets.version, list->version); + env->SetIntField(sensor, sensorOffsets.handle, list->handle); + env->SetIntField(sensor, sensorOffsets.type, list->type); + env->SetFloatField(sensor, sensorOffsets.range, list->maxRange); + env->SetFloatField(sensor, sensorOffsets.resolution, list->resolution); + env->SetFloatField(sensor, sensorOffsets.power, list->power); + + next++; + return nextcommon, &sSensorDevice); + return err; +} + +static jint +sensors_data_uninit(JNIEnv *env, jclass clazz) +{ + int err = 0; + if (sSensorDevice) { + err = sensors_data_close(sSensorDevice); + if (err == 0) + sSensorDevice = 0; + } + return err; +} + +static jint +sensors_data_open(JNIEnv *env, jclass clazz, jobject fdo) { jclass FileDescriptor = env->FindClass("java/io/FileDescriptor"); jfieldID offset = env->GetFieldID(FileDescriptor, "descriptor", "I"); int fd = env->GetIntField(fdo, offset); - return sensors_data_open(fd); // doesn't take ownership of fd + return sSensorDevice->data_open(sSensorDevice, fd); // doesn't take ownership of fd } static jint -android_data_close(JNIEnv *env, jclass clazz) +sensors_data_close(JNIEnv *env, jclass clazz) { - return sensors_data_close(); + return sSensorDevice->data_close(sSensorDevice); } static jint -android_data_poll(JNIEnv *env, jclass clazz, jfloatArray values, jint sensors) +sensors_data_poll(JNIEnv *env, jclass clazz, + jfloatArray values, jintArray status, jlongArray timestamp) { sensors_data_t data; - int res = sensors_data_poll(&data, sensors); - if (res) { + int res = sSensorDevice->poll(sSensorDevice, &data); + if (res >= 0) { + jint accuracy = data.vector.status; env->SetFloatArrayRegion(values, 0, 3, data.vector.v); - // return the sensor's number - res = 31 - __builtin_clz(res); - // and its status in the top 4 bits - res |= data.vector.status << 28; + env->SetIntArrayRegion(status, 0, 1, &accuracy); + env->SetLongArrayRegion(timestamp, 0, 1, &data.time); } return res; } -static jint -android_data_get_sensors(JNIEnv *env, jclass clazz) +static void +nativeClassInit (JNIEnv *_env, jclass _this) { - return sensors_data_get_sensors(); + jclass sensorClass = _env->FindClass("android/hardware/Sensor"); + SensorOffsets& sensorOffsets = gSensorOffsets; + sensorOffsets.name = _env->GetFieldID(sensorClass, "mName", "Ljava/lang/String;"); + sensorOffsets.vendor = _env->GetFieldID(sensorClass, "mVendor", "Ljava/lang/String;"); + sensorOffsets.version = _env->GetFieldID(sensorClass, "mVersion", "I"); + sensorOffsets.handle = _env->GetFieldID(sensorClass, "mHandle", "I"); + sensorOffsets.type = _env->GetFieldID(sensorClass, "mType", "I"); + sensorOffsets.range = _env->GetFieldID(sensorClass, "mMaxRange", "F"); + sensorOffsets.resolution = _env->GetFieldID(sensorClass, "mResolution","F"); + sensorOffsets.power = _env->GetFieldID(sensorClass, "mPower", "F"); } static JNINativeMethod gMethods[] = { - {"_sensors_data_open", "(Ljava/io/FileDescriptor;)I", (void*) android_data_open }, - {"_sensors_data_close", "()I", (void*) android_data_close }, - {"_sensors_data_poll", "([FI)I", (void*) android_data_poll }, - {"_sensors_data_get_sensors","()I", (void*) android_data_get_sensors }, + {"nativeClassInit", "()V", (void*)nativeClassInit }, + {"sensors_module_init","()I", (void*)sensors_module_init }, + {"sensors_module_get_next_sensor","(Landroid/hardware/Sensor;I)I", + (void*)sensors_module_get_next_sensor }, + {"sensors_data_init", "()I", (void*)sensors_data_init }, + {"sensors_data_uninit", "()I", (void*)sensors_data_uninit }, + {"sensors_data_open", "(Ljava/io/FileDescriptor;)I", (void*)sensors_data_open }, + {"sensors_data_close", "()I", (void*)sensors_data_close }, + {"sensors_data_poll", "([F[I[J)I", (void*)sensors_data_poll }, }; }; // namespace android diff --git a/core/jni/android_media_AudioRecord.cpp b/core/jni/android_media_AudioRecord.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e4586d9238e7a8e02843546f72c443e31423ad5e --- /dev/null +++ b/core/jni/android_media_AudioRecord.cpp @@ -0,0 +1,566 @@ +/* + * 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_NDEBUG 0 + +#define LOG_TAG "AudioRecord-JNI" + +#include +#include +#include +#include + +#include "jni.h" +#include "JNIHelp.h" +#include "android_runtime/AndroidRuntime.h" + +#include "utils/Log.h" +#include "media/AudioSystem.h" +#include "media/AudioRecord.h" + + +// ---------------------------------------------------------------------------- + +using namespace android; + +// ---------------------------------------------------------------------------- +static const char* const kClassPathName = "android/media/AudioRecord"; + +struct fields_t { + // these fields provide access from C++ to the... + jclass audioRecordClass; //... AudioRecord class + jmethodID postNativeEventInJava; //... event post callback method + int PCM16; //... format constants + int PCM8; //... format constants + int SOURCE_DEFAULT; //... record source constants + int SOURCE_MIC; //... record source constants + jfieldID nativeRecorderInJavaObj; // provides access to the C++ AudioRecord object + jfieldID nativeCallbackCookie; // provides access to the AudioRecord callback data +}; +static fields_t javaAudioRecordFields; + +struct audiorecord_callback_cookie { + jclass audioRecord_class; + jobject audioRecord_ref; + }; + +// ---------------------------------------------------------------------------- + +#define AUDIORECORD_SUCCESS 0 +#define AUDIORECORD_ERROR -1 +#define AUDIORECORD_ERROR_BAD_VALUE -2 +#define AUDIORECORD_ERROR_INVALID_OPERATION -3 +#define AUDIORECORD_ERROR_SETUP_ZEROFRAMECOUNT -4 +#define AUDIORECORD_ERROR_SETUP_INVALIDCHANNELCOUNT -5 +#define AUDIORECORD_ERROR_SETUP_INVALIDFORMAT -6 +#define AUDIORECORD_ERROR_SETUP_INVALIDSTREAMTYPE -7 +#define AUDIORECORD_ERROR_SETUP_NATIVEINITFAILED -8 + +jint android_media_translateRecorderErrorCode(int code) { + switch(code) { + case NO_ERROR: + return AUDIORECORD_SUCCESS; + case BAD_VALUE: + return AUDIORECORD_ERROR_BAD_VALUE; + case INVALID_OPERATION: + return AUDIORECORD_ERROR_INVALID_OPERATION; + default: + return AUDIORECORD_ERROR; + } +} + + +// ---------------------------------------------------------------------------- +static void recorderCallback(int event, void* user, void *info) { + if (event == AudioRecord::EVENT_MORE_DATA) { + // set size to 0 to signal we're not using the callback to read more data + AudioRecord::Buffer* pBuff = (AudioRecord::Buffer*)info; + pBuff->size = 0; + + } else if (event == AudioRecord::EVENT_MARKER) { + audiorecord_callback_cookie *callbackInfo = (audiorecord_callback_cookie *)user; + JNIEnv *env = AndroidRuntime::getJNIEnv(); + if (user && env) { + env->CallStaticVoidMethod( + callbackInfo->audioRecord_class, + javaAudioRecordFields.postNativeEventInJava, + callbackInfo->audioRecord_ref, event, 0,0, NULL); + if (env->ExceptionCheck()) { + env->ExceptionDescribe(); + env->ExceptionClear(); + } + } + + } else if (event == AudioRecord::EVENT_NEW_POS) { + audiorecord_callback_cookie *callbackInfo = (audiorecord_callback_cookie *)user; + JNIEnv *env = AndroidRuntime::getJNIEnv(); + if (user && env) { + env->CallStaticVoidMethod( + callbackInfo->audioRecord_class, + javaAudioRecordFields.postNativeEventInJava, + callbackInfo->audioRecord_ref, event, 0,0, NULL); + if (env->ExceptionCheck()) { + env->ExceptionDescribe(); + env->ExceptionClear(); + } + } + } +} + + +// ---------------------------------------------------------------------------- +static int +android_media_AudioRecord_setup(JNIEnv *env, jobject thiz, jobject weak_this, + jint source, jint sampleRateInHertz, jint nbChannels, + jint audioFormat, jint buffSizeInBytes) +{ + //LOGV(">> Entering android_media_AudioRecord_setup"); + //LOGV("sampleRate=%d, audioFormat=%d, nbChannels=%d, buffSizeInBytes=%d", + // sampleRateInHertz, audioFormat, nbChannels, buffSizeInBytes); + + if ((nbChannels == 0) || (nbChannels > 2)) { + LOGE("Error creating AudioRecord: channel count is not 1 or 2."); + return AUDIORECORD_ERROR_SETUP_INVALIDCHANNELCOUNT; + } + + // compare the format against the Java constants + if ((audioFormat != javaAudioRecordFields.PCM16) + && (audioFormat != javaAudioRecordFields.PCM8)) { + LOGE("Error creating AudioRecord: unsupported audio format."); + return AUDIORECORD_ERROR_SETUP_INVALIDFORMAT; + } + + int bytesPerSample = audioFormat==javaAudioRecordFields.PCM16 ? 2 : 1; + int format = audioFormat==javaAudioRecordFields.PCM16 ? + AudioSystem::PCM_16_BIT : AudioSystem::PCM_8_BIT; + + if (buffSizeInBytes == 0) { + LOGE("Error creating AudioRecord: frameCount is 0."); + return AUDIORECORD_ERROR_SETUP_ZEROFRAMECOUNT; + } + int frameSize = nbChannels * bytesPerSample; + size_t frameCount = buffSizeInBytes / frameSize; + + // compare the source against the Java constants + AudioRecord::stream_type arSource; + if (source == javaAudioRecordFields.SOURCE_DEFAULT) { + arSource = AudioRecord::DEFAULT_INPUT; + } else if (source == javaAudioRecordFields.SOURCE_MIC) { + arSource = AudioRecord::MIC_INPUT; + } else { + LOGE("Error creating AudioRecord: unknown source."); + return AUDIORECORD_ERROR_SETUP_INVALIDSTREAMTYPE; + } + + audiorecord_callback_cookie *lpCallbackData = NULL; + AudioRecord* lpRecorder = NULL; + + // create an uninitialized AudioRecord object + lpRecorder = new AudioRecord(); + if(lpRecorder == NULL) { + LOGE("Error creating AudioRecord instance."); + return AUDIORECORD_ERROR_SETUP_NATIVEINITFAILED; + } + + // create the callback information: + // this data will be passed with every AudioRecord callback + jclass clazz = env->GetObjectClass(thiz); + if (clazz == NULL) { + LOGE("Can't find %s when setting up callback.", kClassPathName); + goto native_track_failure; + } + lpCallbackData = new audiorecord_callback_cookie; + lpCallbackData->audioRecord_class = (jclass)env->NewGlobalRef(clazz); + // we use a weak reference so the AudioRecord object can be garbage collected. + lpCallbackData->audioRecord_ref = env->NewGlobalRef(weak_this); + + lpRecorder->set(arSource, + sampleRateInHertz, + format, // word length, PCM + nbChannels, + frameCount, + 0, // flags + recorderCallback,// callback_t + lpCallbackData,// void* user + 0, // notificationFrames, + true); // threadCanCallJava) + + if(lpRecorder->initCheck() != NO_ERROR) { + LOGE("Error creating AudioRecord instance: initialization check failed."); + goto native_init_failure; + } + + // save our newly created C++ AudioRecord in the "nativeRecorderInJavaObj" field + // of the Java object + env->SetIntField(thiz, javaAudioRecordFields.nativeRecorderInJavaObj, (int)lpRecorder); + + // save our newly created callback information in the "nativeCallbackCookie" field + // of the Java object (in mNativeCallbackCookie) so we can free the memory in finalize() + env->SetIntField(thiz, javaAudioRecordFields.nativeCallbackCookie, (int)lpCallbackData); + + return AUDIORECORD_SUCCESS; + + // failure: +native_init_failure: + delete lpCallbackData; + +native_track_failure: + delete lpRecorder; + + env->SetIntField(thiz, javaAudioRecordFields.nativeRecorderInJavaObj, 0); + env->SetIntField(thiz, javaAudioRecordFields.nativeCallbackCookie, 0); + + return AUDIORECORD_ERROR_SETUP_NATIVEINITFAILED; +} + + + +// ---------------------------------------------------------------------------- +static void +android_media_AudioRecord_start(JNIEnv *env, jobject thiz) +{ + AudioRecord *lpRecorder = + (AudioRecord *)env->GetIntField(thiz, javaAudioRecordFields.nativeRecorderInJavaObj); + if (lpRecorder == NULL ) { + jniThrowException(env, "java/lang/IllegalStateException", NULL); + return; + } + + lpRecorder->start(); +} + + +// ---------------------------------------------------------------------------- +static void +android_media_AudioRecord_stop(JNIEnv *env, jobject thiz) +{ + AudioRecord *lpRecorder = + (AudioRecord *)env->GetIntField(thiz, javaAudioRecordFields.nativeRecorderInJavaObj); + if (lpRecorder == NULL ) { + jniThrowException(env, "java/lang/IllegalStateException", NULL); + return; + } + + lpRecorder->stop(); + //LOGV("Called lpRecorder->stop()"); +} + + +// ---------------------------------------------------------------------------- +static void android_media_AudioRecord_finalize(JNIEnv *env, jobject thiz) { + + // delete the AudioRecord object + AudioRecord *lpRecorder = + (AudioRecord *)env->GetIntField(thiz, javaAudioRecordFields.nativeRecorderInJavaObj); + + if (lpRecorder) { + //LOGV("About to delete lpRecorder: %x\n", (int)lpRecorder); + lpRecorder->stop(); + delete lpRecorder; + } + + // delete the callback information + audiorecord_callback_cookie *lpCookie = (audiorecord_callback_cookie *)env->GetIntField( + thiz, javaAudioRecordFields.nativeCallbackCookie); + if (lpCookie) { + LOGV("deleting lpCookie: %x\n", (int)lpCookie); + delete lpCookie; + } + +} + + +// ---------------------------------------------------------------------------- +static void android_media_AudioRecord_release(JNIEnv *env, jobject thiz) { + + // do everything a call to finalize would + android_media_AudioRecord_finalize(env, thiz); + // + reset the native resources in the Java object so any attempt to access + // them after a call to release fails. + env->SetIntField(thiz, javaAudioRecordFields.nativeRecorderInJavaObj, 0); + env->SetIntField(thiz, javaAudioRecordFields.nativeCallbackCookie, 0); +} + + +// ---------------------------------------------------------------------------- +static jint android_media_AudioRecord_readInByteArray(JNIEnv *env, jobject thiz, + jbyteArray javaAudioData, + jint offsetInBytes, jint sizeInBytes) { + jbyte* recordBuff = NULL; + AudioRecord *lpRecorder = NULL; + + // get the audio recorder from which we'll read new audio samples + lpRecorder = + (AudioRecord *)env->GetIntField(thiz, javaAudioRecordFields.nativeRecorderInJavaObj); + if (lpRecorder == NULL) { + LOGE("Unable to retrieve AudioRecord object, can't record"); + return 0; + } + + if (!javaAudioData) { + LOGE("Invalid Java array to store recorded audio, can't record"); + return 0; + } + + // get the pointer to where we'll record the audio + recordBuff = (jbyte *)env->GetPrimitiveArrayCritical(javaAudioData, NULL); + + if (recordBuff == NULL) { + LOGE("Error retrieving destination for recorded audio data, can't record"); + return 0; + } + + // read the new audio data from the native AudioRecord object + ssize_t recorderBuffSize = lpRecorder->frameCount()*lpRecorder->frameSize(); + ssize_t readSize = lpRecorder->read(recordBuff + offsetInBytes, + sizeInBytes > (jint)recorderBuffSize ? + (jint)recorderBuffSize : sizeInBytes ); + env->ReleasePrimitiveArrayCritical(javaAudioData, recordBuff, 0); + + return (jint) readSize; +} + +// ---------------------------------------------------------------------------- +static jint android_media_AudioRecord_readInShortArray(JNIEnv *env, jobject thiz, + jshortArray javaAudioData, + jint offsetInShorts, jint sizeInShorts) { + + return (android_media_AudioRecord_readInByteArray(env, thiz, + (jbyteArray) javaAudioData, + offsetInShorts*2, sizeInShorts*2) + / 2); +} + +// ---------------------------------------------------------------------------- +static jint android_media_AudioRecord_readInDirectBuffer(JNIEnv *env, jobject thiz, + jobject jBuffer, jint sizeInBytes) { + AudioRecord *lpRecorder = NULL; + //LOGV("Entering android_media_AudioRecord_readInBuffer"); + + // get the audio recorder from which we'll read new audio samples + lpRecorder = + (AudioRecord *)env->GetIntField(thiz, javaAudioRecordFields.nativeRecorderInJavaObj); + if(lpRecorder==NULL) + return 0; + + // direct buffer and direct access supported? + long capacity = env->GetDirectBufferCapacity(jBuffer); + if(capacity == -1) { + // buffer direct access is not supported + LOGE("Buffer direct access is not supported, can't record"); + return 0; + } + //LOGV("capacity = %ld", capacity); + jbyte* nativeFromJavaBuf = (jbyte*) env->GetDirectBufferAddress(jBuffer); + if(nativeFromJavaBuf==NULL) { + LOGE("Buffer direct access is not supported, can't record"); + return 0; + } + + // read new data from the recorder + return (jint) lpRecorder->read(nativeFromJavaBuf, + capacity < sizeInBytes ? capacity : sizeInBytes); +} + + +// ---------------------------------------------------------------------------- +static jint android_media_AudioRecord_set_marker_pos(JNIEnv *env, jobject thiz, + jint markerPos) { + + AudioRecord *lpRecorder = (AudioRecord *)env->GetIntField( + thiz, javaAudioRecordFields.nativeRecorderInJavaObj); + + if (lpRecorder) { + return + android_media_translateRecorderErrorCode( lpRecorder->setMarkerPosition(markerPos) ); + } else { + jniThrowException(env, "java/lang/IllegalStateException", + "Unable to retrieve AudioRecord pointer for setMarkerPosition()"); + return AUDIORECORD_ERROR; + } +} + + +// ---------------------------------------------------------------------------- +static jint android_media_AudioRecord_get_marker_pos(JNIEnv *env, jobject thiz) { + + AudioRecord *lpRecorder = (AudioRecord *)env->GetIntField( + thiz, javaAudioRecordFields.nativeRecorderInJavaObj); + uint32_t markerPos = 0; + + if (lpRecorder) { + lpRecorder->getMarkerPosition(&markerPos); + return (jint)markerPos; + } else { + jniThrowException(env, "java/lang/IllegalStateException", + "Unable to retrieve AudioRecord pointer for getMarkerPosition()"); + return AUDIORECORD_ERROR; + } +} + + +// ---------------------------------------------------------------------------- +static jint android_media_AudioRecord_set_pos_update_period(JNIEnv *env, jobject thiz, + jint period) { + + AudioRecord *lpRecorder = (AudioRecord *)env->GetIntField( + thiz, javaAudioRecordFields.nativeRecorderInJavaObj); + + if (lpRecorder) { + return + android_media_translateRecorderErrorCode( lpRecorder->setPositionUpdatePeriod(period) ); + } else { + jniThrowException(env, "java/lang/IllegalStateException", + "Unable to retrieve AudioRecord pointer for setPositionUpdatePeriod()"); + return AUDIORECORD_ERROR; + } +} + + +// ---------------------------------------------------------------------------- +static jint android_media_AudioRecord_get_pos_update_period(JNIEnv *env, jobject thiz) { + + AudioRecord *lpRecorder = (AudioRecord *)env->GetIntField( + thiz, javaAudioRecordFields.nativeRecorderInJavaObj); + uint32_t period = 0; + + if (lpRecorder) { + lpRecorder->getPositionUpdatePeriod(&period); + return (jint)period; + } else { + jniThrowException(env, "java/lang/IllegalStateException", + "Unable to retrieve AudioRecord pointer for getPositionUpdatePeriod()"); + return AUDIORECORD_ERROR; + } +} + + +// ---------------------------------------------------------------------------- +// ---------------------------------------------------------------------------- +static JNINativeMethod gMethods[] = { + // name, signature, funcPtr + {"native_start", "()V", (void *)android_media_AudioRecord_start}, + {"native_stop", "()V", (void *)android_media_AudioRecord_stop}, + {"native_setup", "(Ljava/lang/Object;IIIII)I", + (void *)android_media_AudioRecord_setup}, + {"native_finalize", "()V", (void *)android_media_AudioRecord_finalize}, + {"native_release", "()V", (void *)android_media_AudioRecord_release}, + {"native_read_in_byte_array", + "([BII)I", (void *)android_media_AudioRecord_readInByteArray}, + {"native_read_in_short_array", + "([SII)I", (void *)android_media_AudioRecord_readInShortArray}, + {"native_read_in_direct_buffer","(Ljava/lang/Object;I)I", + (void *)android_media_AudioRecord_readInDirectBuffer}, + {"native_set_marker_pos","(I)I", (void *)android_media_AudioRecord_set_marker_pos}, + {"native_get_marker_pos","()I", (void *)android_media_AudioRecord_get_marker_pos}, + {"native_set_pos_update_period", + "(I)I", (void *)android_media_AudioRecord_set_pos_update_period}, + {"native_get_pos_update_period", + "()I", (void *)android_media_AudioRecord_get_pos_update_period}, +}; + +// field names found in android/media/AudioRecord.java +#define JAVA_POSTEVENT_CALLBACK_NAME "postEventFromNative" +#define JAVA_CONST_PCM16_NAME "ENCODING_PCM_16BIT" +#define JAVA_CONST_PCM8_NAME "ENCODING_PCM_8BIT" +#define JAVA_CONST_SOURCEDEFAULT_NAME "SOURCE_DEFAULT" +#define JAVA_CONST_SOURCEMIC_NAME "SOURCE_MIC" +#define JAVA_NATIVERECORDERINJAVAOBJ_FIELD_NAME "mNativeRecorderInJavaObj" +#define JAVA_NATIVECALLBACKINFO_FIELD_NAME "mNativeCallbackCookie" + +#define JAVA_AUDIOFORMAT_CLASS_NAME "android/media/AudioFormat" + +// ---------------------------------------------------------------------------- + +extern bool android_media_getIntConstantFromClass(JNIEnv* pEnv, + jclass theClass, const char* className, const char* constName, int* constVal); + +// ---------------------------------------------------------------------------- +int register_android_media_AudioRecord(JNIEnv *env) +{ + javaAudioRecordFields.audioRecordClass = NULL; + javaAudioRecordFields.postNativeEventInJava = NULL; + javaAudioRecordFields.nativeRecorderInJavaObj = NULL; + javaAudioRecordFields.nativeCallbackCookie = NULL; + + + // Get the AudioRecord class + javaAudioRecordFields.audioRecordClass = env->FindClass(kClassPathName); + if (javaAudioRecordFields.audioRecordClass == NULL) { + LOGE("Can't find %s", kClassPathName); + return -1; + } + + // Get the postEvent method + javaAudioRecordFields.postNativeEventInJava = env->GetStaticMethodID( + javaAudioRecordFields.audioRecordClass, + JAVA_POSTEVENT_CALLBACK_NAME, "(Ljava/lang/Object;IIILjava/lang/Object;)V"); + if (javaAudioRecordFields.postNativeEventInJava == NULL) { + LOGE("Can't find AudioRecord.%s", JAVA_POSTEVENT_CALLBACK_NAME); + return -1; + } + + // Get the variables + // mNativeRecorderInJavaObj + javaAudioRecordFields.nativeRecorderInJavaObj = + env->GetFieldID(javaAudioRecordFields.audioRecordClass, + JAVA_NATIVERECORDERINJAVAOBJ_FIELD_NAME, "I"); + if (javaAudioRecordFields.nativeRecorderInJavaObj == NULL) { + LOGE("Can't find AudioRecord.%s", JAVA_NATIVERECORDERINJAVAOBJ_FIELD_NAME); + return -1; + } + // mNativeCallbackCookie + javaAudioRecordFields.nativeCallbackCookie = env->GetFieldID( + javaAudioRecordFields.audioRecordClass, + JAVA_NATIVECALLBACKINFO_FIELD_NAME, "I"); + if (javaAudioRecordFields.nativeCallbackCookie == NULL) { + LOGE("Can't find AudioRecord.%s", JAVA_NATIVECALLBACKINFO_FIELD_NAME); + return -1; + } + + // Get the format constants from the AudioFormat class + jclass audioFormatClass = NULL; + audioFormatClass = env->FindClass(JAVA_AUDIOFORMAT_CLASS_NAME); + if (audioFormatClass == NULL) { + LOGE("Can't find %s", JAVA_AUDIOFORMAT_CLASS_NAME); + return -1; + } + if ( !android_media_getIntConstantFromClass(env, audioFormatClass, + JAVA_AUDIOFORMAT_CLASS_NAME, + JAVA_CONST_PCM16_NAME, &(javaAudioRecordFields.PCM16)) + || !android_media_getIntConstantFromClass(env, audioFormatClass, + JAVA_AUDIOFORMAT_CLASS_NAME, + JAVA_CONST_PCM8_NAME, &(javaAudioRecordFields.PCM8)) ) { + // error log performed in getIntConstantFromClass() + return -1; + } + + // Get the recording source constants from the AudioRecord class + if ( !android_media_getIntConstantFromClass(env, javaAudioRecordFields.audioRecordClass, + kClassPathName, + JAVA_CONST_SOURCEDEFAULT_NAME, &(javaAudioRecordFields.SOURCE_DEFAULT)) + || !android_media_getIntConstantFromClass(env, javaAudioRecordFields.audioRecordClass, + kClassPathName, + JAVA_CONST_SOURCEMIC_NAME, &(javaAudioRecordFields.SOURCE_MIC)) ) { + // error log performed in getIntConstantFromClass() + return -1; + } + + return AndroidRuntime::registerNativeMethods(env, + kClassPathName, gMethods, NELEM(gMethods)); +} + +// ---------------------------------------------------------------------------- diff --git a/core/jni/android_media_AudioTrack.cpp b/core/jni/android_media_AudioTrack.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4a98fcc22489a7ef5ae8f315687c05a71aaf8daf --- /dev/null +++ b/core/jni/android_media_AudioTrack.cpp @@ -0,0 +1,832 @@ +/* + * 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_NDEBUG 0 + +#define LOG_TAG "AudioTrack-JNI" + +#include +#include +#include +#include + +#include "jni.h" +#include "JNIHelp.h" +#include "android_runtime/AndroidRuntime.h" + +#include "utils/Log.h" +#include "media/AudioSystem.h" +#include "media/AudioTrack.h" + +#include +#include + + +// ---------------------------------------------------------------------------- + +using namespace android; + +// ---------------------------------------------------------------------------- +static const char* const kClassPathName = "android/media/AudioTrack"; + +struct fields_t { + // these fields provide access from C++ to the... + jclass audioTrackClass; //... AudioTrack class + jmethodID postNativeEventInJava; //... event post callback method + int PCM16; //... format constants + int PCM8; //... format constants + int STREAM_VOICE_CALL; //... stream type constants + int STREAM_SYSTEM; //... stream type constants + int STREAM_RING; //... stream type constants + int STREAM_MUSIC; //... stream type constants + int STREAM_ALARM; //... stream type constants + int MODE_STREAM; //... memory mode + int MODE_STATIC; //... memory mode + jfieldID nativeTrackInJavaObj; // stores in Java the native AudioTrack object + jfieldID jniData; // stores in Java additional resources used by the native AudioTrack +}; +static fields_t javaAudioTrackFields; + +struct audiotrack_callback_cookie { + jclass audioTrack_class; + jobject audioTrack_ref; + }; + +// ---------------------------------------------------------------------------- +class AudioTrackJniStorage { + public: + sp mMemHeap; + sp mMemBase; + audiotrack_callback_cookie mCallbackData; + + AudioTrackJniStorage() { + } + + ~AudioTrackJniStorage() { + mMemBase.clear(); + mMemHeap.clear(); + } + + bool allocSharedMem(int sizeInBytes) { + mMemHeap = new MemoryHeapBase(sizeInBytes, 0, "AudioTrack Heap Base"); + if (mMemHeap->getHeapID() < 0) { + return false; + } + mMemBase = new MemoryBase(mMemHeap, 0, sizeInBytes); + return true; + } +}; + +// ---------------------------------------------------------------------------- +#define DEFAULT_OUTPUT_SAMPLE_RATE 44100 + +#define AUDIOTRACK_SUCCESS 0 +#define AUDIOTRACK_ERROR -1 +#define AUDIOTRACK_ERROR_SETUP_AUDIOSYSTEM -2 +#define AUDIOTRACK_ERROR_SETUP_INVALIDCHANNELCOUNT -3 +#define AUDIOTRACK_ERROR_SETUP_INVALIDFORMAT -4 +#define AUDIOTRACK_ERROR_SETUP_INVALIDSTREAMTYPE -5 +#define AUDIOTRACK_ERROR_SETUP_NATIVEINITFAILED -6 +#define AUDIOTRACK_ERROR_BAD_VALUE -7 +#define AUDIOTRACK_ERROR_INVALID_OPERATION -8 + + +jint android_media_translateErrorCode(int code) { + switch(code) { + case NO_ERROR: + return AUDIOTRACK_SUCCESS; + case BAD_VALUE: + return AUDIOTRACK_ERROR_BAD_VALUE; + case INVALID_OPERATION: + return AUDIOTRACK_ERROR_INVALID_OPERATION; + default: + return AUDIOTRACK_ERROR; + } +} + + +// ---------------------------------------------------------------------------- +static void audioCallback(int event, void* user, void *info) { + if (event == AudioTrack::EVENT_MORE_DATA) { + // set size to 0 to signal we're not using the callback to write more data + AudioTrack::Buffer* pBuff = (AudioTrack::Buffer*)info; + pBuff->size = 0; + + } else if (event == AudioTrack::EVENT_MARKER) { + audiotrack_callback_cookie *callbackInfo = (audiotrack_callback_cookie *)user; + JNIEnv *env = AndroidRuntime::getJNIEnv(); + if (user && env) { + env->CallStaticVoidMethod( + callbackInfo->audioTrack_class, + javaAudioTrackFields.postNativeEventInJava, + callbackInfo->audioTrack_ref, event, 0,0, NULL); + if (env->ExceptionCheck()) { + env->ExceptionDescribe(); + env->ExceptionClear(); + } + } + + } else if (event == AudioTrack::EVENT_NEW_POS) { + audiotrack_callback_cookie *callbackInfo = (audiotrack_callback_cookie *)user; + JNIEnv *env = AndroidRuntime::getJNIEnv(); + if (user && env) { + env->CallStaticVoidMethod( + callbackInfo->audioTrack_class, + javaAudioTrackFields.postNativeEventInJava, + callbackInfo->audioTrack_ref, event, 0,0, NULL); + if (env->ExceptionCheck()) { + env->ExceptionDescribe(); + env->ExceptionClear(); + } + } + } +} + + +// ---------------------------------------------------------------------------- +static int +android_media_AudioTrack_native_setup(JNIEnv *env, jobject thiz, jobject weak_this, + jint streamType, jint sampleRateInHertz, jint nbChannels, + jint audioFormat, jint buffSizeInBytes, jint memoryMode) +{ + //LOGV("sampleRate=%d, audioFormat(from Java)=%d, nbChannels=%d, buffSize=%d", + // sampleRateInHertz, audioFormat, nbChannels, buffSizeInBytes); + int afSampleRate; + int afFrameCount; + + if (AudioSystem::getOutputFrameCount(&afFrameCount) != NO_ERROR) { + LOGE("Error creating AudioTrack: Could not get AudioSystem frame count."); + return AUDIOTRACK_ERROR_SETUP_AUDIOSYSTEM; + } + if (AudioSystem::getOutputSamplingRate(&afSampleRate) != NO_ERROR) { + LOGE("Error creating AudioTrack: Could not get AudioSystem sampling rate."); + return AUDIOTRACK_ERROR_SETUP_AUDIOSYSTEM; + } + + if ((nbChannels == 0) || (nbChannels > 2)) { + LOGE("Error creating AudioTrack: channel count is not 1 or 2."); + return AUDIOTRACK_ERROR_SETUP_INVALIDCHANNELCOUNT; + } + + // check the stream type + AudioTrack::stream_type atStreamType; + if (streamType == javaAudioTrackFields.STREAM_VOICE_CALL) { + atStreamType = AudioTrack::VOICE_CALL; + } else if (streamType == javaAudioTrackFields.STREAM_SYSTEM) { + atStreamType = AudioTrack::SYSTEM; + } else if (streamType == javaAudioTrackFields.STREAM_RING) { + atStreamType = AudioTrack::RING; + } else if (streamType == javaAudioTrackFields.STREAM_MUSIC) { + atStreamType = AudioTrack::MUSIC; + } else if (streamType == javaAudioTrackFields.STREAM_ALARM) { + atStreamType = AudioTrack::ALARM; + } else { + LOGE("Error creating AudioTrack: unknown stream type."); + return AUDIOTRACK_ERROR_SETUP_INVALIDSTREAMTYPE; + } + + // check the format. + // This function was called from Java, so we compare the format against the Java constants + if ((audioFormat != javaAudioTrackFields.PCM16) && (audioFormat != javaAudioTrackFields.PCM8)) { + LOGE("Error creating AudioTrack: unsupported audio format."); + return AUDIOTRACK_ERROR_SETUP_INVALIDFORMAT; + } + + // compute the frame count + int bytesPerSample = audioFormat == javaAudioTrackFields.PCM16 ? 2 : 1; + int format = audioFormat == javaAudioTrackFields.PCM16 ? + AudioSystem::PCM_16_BIT : AudioSystem::PCM_8_BIT; + int frameCount; + if (buffSizeInBytes == -1) { + // compute the frame count based on the system's output frame count + // and the native sample rate + frameCount = (sampleRateInHertz*afFrameCount)/afSampleRate; + } else { + // compute the frame count based on the specified buffer size + frameCount = buffSizeInBytes / (nbChannels * bytesPerSample); + } + + AudioTrackJniStorage* lpJniStorage = new AudioTrackJniStorage(); + + // initialize the callback information: + // this data will be passed with every AudioTrack callback + jclass clazz = env->GetObjectClass(thiz); + if (clazz == NULL) { + LOGE("Can't find %s when setting up callback.", kClassPathName); + delete lpJniStorage; + return AUDIOTRACK_ERROR_SETUP_NATIVEINITFAILED; + } + lpJniStorage->mCallbackData.audioTrack_class = (jclass)env->NewGlobalRef(clazz); + // we use a weak reference so the AudioTrack object can be garbage collected. + lpJniStorage->mCallbackData.audioTrack_ref = env->NewGlobalRef(weak_this); + + // create the native AudioTrack object + AudioTrack* lpTrack = new AudioTrack(); + if (lpTrack == NULL) { + LOGE("Error creating uninitialized AudioTrack"); + goto native_track_failure; + } + + // initialize the native AudioTrack object + if (memoryMode == javaAudioTrackFields.MODE_STREAM) { + + lpTrack->set( + atStreamType,// stream type + sampleRateInHertz, + format,// word length, PCM + nbChannels, + frameCount, + 0,// flags + audioCallback, &(lpJniStorage->mCallbackData),//callback, callback data (user) + 0,// notificationFrames == 0 since not using EVENT_MORE_DATA to feed the AudioTrack + 0,// shared mem + true);// thread can call Java + + } else if (memoryMode == javaAudioTrackFields.MODE_STATIC) { + // AudioTrack is using shared memory + + if (!lpJniStorage->allocSharedMem(buffSizeInBytes)) { + LOGE("Error creating AudioTrack in static mode: error creating mem heap base"); + goto native_init_failure; + } + + lpTrack->set( + atStreamType,// stream type + sampleRateInHertz, + format,// word length, PCM + nbChannels, + frameCount, + 0,// flags + audioCallback, &(lpJniStorage->mCallbackData),//callback, callback data (user)); + 0,// notificationFrames == 0 since not using EVENT_MORE_DATA to feed the AudioTrack + lpJniStorage->mMemBase,// shared mem + true);// thread can call Java + } + + if (lpTrack->initCheck() != NO_ERROR) { + LOGE("Error initializing AudioTrack"); + goto native_init_failure; + } + + // save our newly created C++ AudioTrack in the "nativeTrackInJavaObj" field + // of the Java object (in mNativeTrackInJavaObj) + env->SetIntField(thiz, javaAudioTrackFields.nativeTrackInJavaObj, (int)lpTrack); + + // save the JNI resources so we can free them later + //LOGV("storing lpJniStorage: %x\n", (int)lpJniStorage); + env->SetIntField(thiz, javaAudioTrackFields.jniData, (int)lpJniStorage); + + return AUDIOTRACK_SUCCESS; + + // failures: +native_init_failure: + delete lpTrack; + env->SetIntField(thiz, javaAudioTrackFields.nativeTrackInJavaObj, 0); + +native_track_failure: + delete lpJniStorage; + env->SetIntField(thiz, javaAudioTrackFields.jniData, 0); + return AUDIOTRACK_ERROR_SETUP_NATIVEINITFAILED; + +} + + +// ---------------------------------------------------------------------------- +static void +android_media_AudioTrack_start(JNIEnv *env, jobject thiz) +{ + AudioTrack *lpTrack = (AudioTrack *)env->GetIntField( + thiz, javaAudioTrackFields.nativeTrackInJavaObj); + if (lpTrack == NULL ) { + jniThrowException(env, "java/lang/IllegalStateException", + "Unable to retrieve AudioTrack pointer for start()"); + } + + lpTrack->start(); +} + + +// ---------------------------------------------------------------------------- +static void +android_media_AudioTrack_stop(JNIEnv *env, jobject thiz) +{ + AudioTrack *lpTrack = (AudioTrack *)env->GetIntField( + thiz, javaAudioTrackFields.nativeTrackInJavaObj); + if (lpTrack == NULL ) { + jniThrowException(env, "java/lang/IllegalStateException", + "Unable to retrieve AudioTrack pointer for stop()"); + } + + lpTrack->stop(); +} + + +// ---------------------------------------------------------------------------- +static void +android_media_AudioTrack_pause(JNIEnv *env, jobject thiz) +{ + AudioTrack *lpTrack = (AudioTrack *)env->GetIntField( + thiz, javaAudioTrackFields.nativeTrackInJavaObj); + if (lpTrack == NULL ) { + jniThrowException(env, "java/lang/IllegalStateException", + "Unable to retrieve AudioTrack pointer for pause()"); + } + + lpTrack->pause(); +} + + +// ---------------------------------------------------------------------------- +static void +android_media_AudioTrack_flush(JNIEnv *env, jobject thiz) +{ + AudioTrack *lpTrack = (AudioTrack *)env->GetIntField( + thiz, javaAudioTrackFields.nativeTrackInJavaObj); + if (lpTrack == NULL ) { + jniThrowException(env, "java/lang/IllegalStateException", + "Unable to retrieve AudioTrack pointer for flush()"); + } + + lpTrack->flush(); +} + +// ---------------------------------------------------------------------------- +static void +android_media_AudioTrack_set_volume(JNIEnv *env, jobject thiz, jfloat leftVol, jfloat rightVol ) +{ + AudioTrack *lpTrack = (AudioTrack *)env->GetIntField( + thiz, javaAudioTrackFields.nativeTrackInJavaObj); + if (lpTrack == NULL ) { + jniThrowException(env, "java/lang/IllegalStateException", + "Unable to retrieve AudioTrack pointer for setVolume()"); + } + + lpTrack->setVolume(leftVol, rightVol); +} + +// ---------------------------------------------------------------------------- +static void android_media_AudioTrack_native_finalize(JNIEnv *env, jobject thiz) { + LOGV("android_media_AudioTrack_native_finalize jobject: %x\n", (int)thiz); + + // delete the AudioTrack object + AudioTrack *lpTrack = (AudioTrack *)env->GetIntField( + thiz, javaAudioTrackFields.nativeTrackInJavaObj); + if (lpTrack) { + LOGV("deleting lpTrack: %x\n", (int)lpTrack); + lpTrack->stop(); + delete lpTrack; + } + + // delete the JNI data + AudioTrackJniStorage* pJniStorage = (AudioTrackJniStorage *)env->GetIntField( + thiz, javaAudioTrackFields.jniData); + if (pJniStorage) { + LOGV("deleting pJniStorage: %x\n", (int)pJniStorage); + delete pJniStorage; + } +} + +// ---------------------------------------------------------------------------- +static void android_media_AudioTrack_native_release(JNIEnv *env, jobject thiz) { + + // do everything a call to finalize would + android_media_AudioTrack_native_finalize(env, thiz); + // + reset the native resources in the Java object so any attempt to access + // them after a call to release fails. + env->SetIntField(thiz, javaAudioTrackFields.nativeTrackInJavaObj, 0); + env->SetIntField(thiz, javaAudioTrackFields.jniData, 0); +} + + +// ---------------------------------------------------------------------------- +static jint android_media_AudioTrack_native_write(JNIEnv *env, jobject thiz, + jbyteArray javaAudioData, + jint offsetInBytes, jint sizeInBytes) { + jbyte* cAudioData = NULL; + AudioTrack *lpTrack = NULL; + //LOGV("android_media_AudioTrack_native_write(offset=%d, sizeInBytes=%d) called", + // offsetInBytes, sizeInBytes); + + // get the audio track to load with samples + lpTrack = (AudioTrack *)env->GetIntField(thiz, javaAudioTrackFields.nativeTrackInJavaObj); + if (lpTrack == NULL) { + jniThrowException(env, "java/lang/IllegalStateException", + "Unable to retrieve AudioTrack pointer for write()"); + } + + // get the pointer for the audio data from the java array + if (javaAudioData) { + cAudioData = (jbyte *)env->GetPrimitiveArrayCritical(javaAudioData, NULL); + if (cAudioData == NULL) { + LOGE("Error retrieving source of audio data to play, can't play"); + return 0; // out of memory or no data to load + } + } else { + LOGE("NULL java array of audio data to play, can't play"); + return 0; + } + + // give the data to the native AudioTrack object (the data starts at the offset) + ssize_t written = 0; + // regular write() or copy the data to the AudioTrack's shared memory? + if (lpTrack->sharedBuffer() == 0) { + written = lpTrack->write(cAudioData + offsetInBytes, sizeInBytes); + } else { + memcpy(lpTrack->sharedBuffer()->pointer(), cAudioData + offsetInBytes, sizeInBytes); + written = sizeInBytes; + } + + env->ReleasePrimitiveArrayCritical(javaAudioData, cAudioData, 0); + + //LOGV("write wrote %d (tried %d) bytes in the native AudioTrack with offset %d", + // (int)written, (int)(sizeInBytes), (int)offsetInBytes); + return (int)written; +} + + +// ---------------------------------------------------------------------------- +static jint android_media_AudioTrack_native_write_short(JNIEnv *env, jobject thiz, + jshortArray javaAudioData, + jint offsetInShorts, jint sizeInShorts) { + return (android_media_AudioTrack_native_write(env, thiz, + (jbyteArray) javaAudioData, + offsetInShorts*2, sizeInShorts*2) + / 2); +} + + +// ---------------------------------------------------------------------------- +static jint android_media_AudioTrack_get_native_frame_count(JNIEnv *env, jobject thiz) { + AudioTrack *lpTrack = (AudioTrack *)env->GetIntField( + thiz, javaAudioTrackFields.nativeTrackInJavaObj); + + if (lpTrack) { + return lpTrack->frameCount(); + } else { + jniThrowException(env, "java/lang/IllegalStateException", + "Unable to retrieve AudioTrack pointer for frameCount()"); + return AUDIOTRACK_ERROR; + } +} + + +// ---------------------------------------------------------------------------- +static void android_media_AudioTrack_set_playback_rate(JNIEnv *env, jobject thiz, + jint sampleRateInHz) { + AudioTrack *lpTrack = (AudioTrack *)env->GetIntField( + thiz, javaAudioTrackFields.nativeTrackInJavaObj); + + if (lpTrack) { + lpTrack->setSampleRate(sampleRateInHz); + } else { + jniThrowException(env, "java/lang/IllegalStateException", + "Unable to retrieve AudioTrack pointer for setSampleRate()"); + } +} + + +// ---------------------------------------------------------------------------- +static jint android_media_AudioTrack_get_playback_rate(JNIEnv *env, jobject thiz) { + AudioTrack *lpTrack = (AudioTrack *)env->GetIntField( + thiz, javaAudioTrackFields.nativeTrackInJavaObj); + + if (lpTrack) { + return (jint) lpTrack->getSampleRate(); + } else { + jniThrowException(env, "java/lang/IllegalStateException", + "Unable to retrieve AudioTrack pointer for getSampleRate()"); + return AUDIOTRACK_ERROR; + } +} + + +// ---------------------------------------------------------------------------- +static jint android_media_AudioTrack_set_marker_pos(JNIEnv *env, jobject thiz, + jint markerPos) { + + AudioTrack *lpTrack = (AudioTrack *)env->GetIntField( + thiz, javaAudioTrackFields.nativeTrackInJavaObj); + + if (lpTrack) { + return android_media_translateErrorCode( lpTrack->setMarkerPosition(markerPos) ); + } else { + jniThrowException(env, "java/lang/IllegalStateException", + "Unable to retrieve AudioTrack pointer for setMarkerPosition()"); + return AUDIOTRACK_ERROR; + } +} + + +// ---------------------------------------------------------------------------- +static jint android_media_AudioTrack_get_marker_pos(JNIEnv *env, jobject thiz) { + + AudioTrack *lpTrack = (AudioTrack *)env->GetIntField( + thiz, javaAudioTrackFields.nativeTrackInJavaObj); + uint32_t markerPos = 0; + + if (lpTrack) { + lpTrack->getMarkerPosition(&markerPos); + return (jint)markerPos; + } else { + jniThrowException(env, "java/lang/IllegalStateException", + "Unable to retrieve AudioTrack pointer for getMarkerPosition()"); + return AUDIOTRACK_ERROR; + } +} + + +// ---------------------------------------------------------------------------- +static jint android_media_AudioTrack_set_pos_update_period(JNIEnv *env, jobject thiz, + jint period) { + + AudioTrack *lpTrack = (AudioTrack *)env->GetIntField( + thiz, javaAudioTrackFields.nativeTrackInJavaObj); + + if (lpTrack) { + return android_media_translateErrorCode( lpTrack->setPositionUpdatePeriod(period) ); + } else { + jniThrowException(env, "java/lang/IllegalStateException", + "Unable to retrieve AudioTrack pointer for setPositionUpdatePeriod()"); + return AUDIOTRACK_ERROR; + } +} + + +// ---------------------------------------------------------------------------- +static jint android_media_AudioTrack_get_pos_update_period(JNIEnv *env, jobject thiz) { + + AudioTrack *lpTrack = (AudioTrack *)env->GetIntField( + thiz, javaAudioTrackFields.nativeTrackInJavaObj); + uint32_t period = 0; + + if (lpTrack) { + lpTrack->getPositionUpdatePeriod(&period); + return (jint)period; + } else { + jniThrowException(env, "java/lang/IllegalStateException", + "Unable to retrieve AudioTrack pointer for getPositionUpdatePeriod()"); + return AUDIOTRACK_ERROR; + } +} + + +// ---------------------------------------------------------------------------- +static jint android_media_AudioTrack_set_position(JNIEnv *env, jobject thiz, + jint position) { + + AudioTrack *lpTrack = (AudioTrack *)env->GetIntField( + thiz, javaAudioTrackFields.nativeTrackInJavaObj); + + if (lpTrack) { + return android_media_translateErrorCode( lpTrack->setPosition(position) ); + } else { + jniThrowException(env, "java/lang/IllegalStateException", + "Unable to retrieve AudioTrack pointer for setPosition()"); + return AUDIOTRACK_ERROR; + } +} + + +// ---------------------------------------------------------------------------- +static jint android_media_AudioTrack_get_position(JNIEnv *env, jobject thiz) { + + AudioTrack *lpTrack = (AudioTrack *)env->GetIntField( + thiz, javaAudioTrackFields.nativeTrackInJavaObj); + uint32_t position = 0; + + if (lpTrack) { + lpTrack->getPosition(&position); + return (jint)position; + } else { + jniThrowException(env, "java/lang/IllegalStateException", + "Unable to retrieve AudioTrack pointer for getPosition()"); + return AUDIOTRACK_ERROR; + } +} + + +// ---------------------------------------------------------------------------- +static jint android_media_AudioTrack_set_loop(JNIEnv *env, jobject thiz, + jint loopStart, jint loopEnd, jint loopCount) { + + AudioTrack *lpTrack = (AudioTrack *)env->GetIntField( + thiz, javaAudioTrackFields.nativeTrackInJavaObj); + if (lpTrack) { + return android_media_translateErrorCode( lpTrack->setLoop(loopStart, loopEnd, loopCount) ); + } else { + jniThrowException(env, "java/lang/IllegalStateException", + "Unable to retrieve AudioTrack pointer for setLoop()"); + return AUDIOTRACK_ERROR; + } +} + + +// ---------------------------------------------------------------------------- +static jint android_media_AudioTrack_reload(JNIEnv *env, jobject thiz) { + + AudioTrack *lpTrack = (AudioTrack *)env->GetIntField( + thiz, javaAudioTrackFields.nativeTrackInJavaObj); + if (lpTrack) { + return android_media_translateErrorCode( lpTrack->reload() ); + } else { + jniThrowException(env, "java/lang/IllegalStateException", + "Unable to retrieve AudioTrack pointer for reload()"); + return AUDIOTRACK_ERROR; + } +} + + +// ---------------------------------------------------------------------------- +static jint android_media_AudioTrack_get_output_sample_rate(JNIEnv *env, jobject thiz) { + int afSamplingRate; + if (AudioSystem::getOutputSamplingRate(&afSamplingRate) != NO_ERROR) { + return DEFAULT_OUTPUT_SAMPLE_RATE; + } else { + return afSamplingRate; + } +} + + +// ---------------------------------------------------------------------------- +// ---------------------------------------------------------------------------- +static JNINativeMethod gMethods[] = { + // name, signature, funcPtr + {"native_start", "()V", (void *)android_media_AudioTrack_start}, + {"native_stop", "()V", (void *)android_media_AudioTrack_stop}, + {"native_pause", "()V", (void *)android_media_AudioTrack_pause}, + {"native_flush", "()V", (void *)android_media_AudioTrack_flush}, + {"native_setup", "(Ljava/lang/Object;IIIIII)I", + (void *)android_media_AudioTrack_native_setup}, + {"native_finalize", "()V", (void *)android_media_AudioTrack_native_finalize}, + {"native_release", "()V", (void *)android_media_AudioTrack_native_release}, + {"native_write_byte", "([BII)I", (void *)android_media_AudioTrack_native_write}, + {"native_write_short", "([SII)I", (void *)android_media_AudioTrack_native_write_short}, + {"native_setVolume", "(FF)V", (void *)android_media_AudioTrack_set_volume}, + {"native_get_native_frame_count", + "()I", (void *)android_media_AudioTrack_get_native_frame_count}, + {"native_set_playback_rate", + "(I)V", (void *)android_media_AudioTrack_set_playback_rate}, + {"native_get_playback_rate", + "()I", (void *)android_media_AudioTrack_get_playback_rate}, + {"native_set_marker_pos","(I)I", (void *)android_media_AudioTrack_set_marker_pos}, + {"native_get_marker_pos","()I", (void *)android_media_AudioTrack_get_marker_pos}, + {"native_set_pos_update_period", + "(I)I", (void *)android_media_AudioTrack_set_pos_update_period}, + {"native_get_pos_update_period", + "()I", (void *)android_media_AudioTrack_get_pos_update_period}, + {"native_set_position", "(I)I", (void *)android_media_AudioTrack_set_position}, + {"native_get_position", "()I", (void *)android_media_AudioTrack_get_position}, + {"native_set_loop", "(III)I", (void *)android_media_AudioTrack_set_loop}, + {"native_reload_static", "()I", (void *)android_media_AudioTrack_reload}, + {"native_get_output_sample_rate", + "()I", (void *)android_media_AudioTrack_get_output_sample_rate}, +}; + + +// field names found in android/media/AudioTrack.java +#define JAVA_POSTEVENT_CALLBACK_NAME "postEventFromNative" +#define JAVA_CONST_PCM16_NAME "ENCODING_PCM_16BIT" +#define JAVA_CONST_PCM8_NAME "ENCODING_PCM_8BIT" +#define JAVA_CONST_BUFFER_COUNT_NAME "BUFFER_COUNT" +#define JAVA_CONST_STREAM_VOICE_CALL_NAME "STREAM_VOICE_CALL" +#define JAVA_CONST_STREAM_SYSTEM_NAME "STREAM_SYSTEM" +#define JAVA_CONST_STREAM_RING_NAME "STREAM_RING" +#define JAVA_CONST_STREAM_MUSIC_NAME "STREAM_MUSIC" +#define JAVA_CONST_STREAM_ALARM_NAME "STREAM_ALARM" +#define JAVA_CONST_MODE_STREAM_NAME "MODE_STREAM" +#define JAVA_CONST_MODE_STATIC_NAME "MODE_STATIC" +#define JAVA_NATIVETRACKINJAVAOBJ_FIELD_NAME "mNativeTrackInJavaObj" +#define JAVA_JNIDATA_FIELD_NAME "mJniData" + +#define JAVA_AUDIOFORMAT_CLASS_NAME "android/media/AudioFormat" +#define JAVA_AUDIOMANAGER_CLASS_NAME "android/media/AudioManager" + +// ---------------------------------------------------------------------------- +// preconditions: +// theClass is valid +bool android_media_getIntConstantFromClass(JNIEnv* pEnv, jclass theClass, const char* className, + const char* constName, int* constVal) { + jfieldID javaConst = NULL; + javaConst = pEnv->GetStaticFieldID(theClass, constName, "I"); + if (javaConst != NULL) { + *constVal = pEnv->GetStaticIntField(theClass, javaConst); + return true; + } else { + LOGE("Can't find %s.%s", className, constName); + return false; + } +} + + +// ---------------------------------------------------------------------------- +int register_android_media_AudioTrack(JNIEnv *env) +{ + javaAudioTrackFields.audioTrackClass = NULL; + javaAudioTrackFields.nativeTrackInJavaObj = NULL; + javaAudioTrackFields.postNativeEventInJava = NULL; + + // Get the AudioTrack class + javaAudioTrackFields.audioTrackClass = env->FindClass(kClassPathName); + if (javaAudioTrackFields.audioTrackClass == NULL) { + LOGE("Can't find %s", kClassPathName); + return -1; + } + + // Get the postEvent method + javaAudioTrackFields.postNativeEventInJava = env->GetStaticMethodID( + javaAudioTrackFields.audioTrackClass, + JAVA_POSTEVENT_CALLBACK_NAME, "(Ljava/lang/Object;IIILjava/lang/Object;)V"); + if (javaAudioTrackFields.postNativeEventInJava == NULL) { + LOGE("Can't find AudioTrack.%s", JAVA_POSTEVENT_CALLBACK_NAME); + return -1; + } + + // Get the variables fields + // nativeTrackInJavaObj + javaAudioTrackFields.nativeTrackInJavaObj = env->GetFieldID( + javaAudioTrackFields.audioTrackClass, + JAVA_NATIVETRACKINJAVAOBJ_FIELD_NAME, "I"); + if (javaAudioTrackFields.nativeTrackInJavaObj == NULL) { + LOGE("Can't find AudioTrack.%s", JAVA_NATIVETRACKINJAVAOBJ_FIELD_NAME); + return -1; + } + // jniData; + javaAudioTrackFields.jniData = env->GetFieldID( + javaAudioTrackFields.audioTrackClass, + JAVA_JNIDATA_FIELD_NAME, "I"); + if (javaAudioTrackFields.jniData == NULL) { + LOGE("Can't find AudioTrack.%s", JAVA_JNIDATA_FIELD_NAME); + return -1; + } + + // Get the memory mode constants + if ( !android_media_getIntConstantFromClass(env, javaAudioTrackFields.audioTrackClass, + kClassPathName, + JAVA_CONST_MODE_STATIC_NAME, &(javaAudioTrackFields.MODE_STATIC)) + || !android_media_getIntConstantFromClass(env, javaAudioTrackFields.audioTrackClass, + kClassPathName, + JAVA_CONST_MODE_STREAM_NAME, &(javaAudioTrackFields.MODE_STREAM)) ) { + // error log performed in android_media_getIntConstantFromClass() + return -1; + } + + // Get the format constants from the AudioFormat class + jclass audioFormatClass = NULL; + audioFormatClass = env->FindClass(JAVA_AUDIOFORMAT_CLASS_NAME); + if (audioFormatClass == NULL) { + LOGE("Can't find %s", JAVA_AUDIOFORMAT_CLASS_NAME); + return -1; + } + if ( !android_media_getIntConstantFromClass(env, audioFormatClass, + JAVA_AUDIOFORMAT_CLASS_NAME, + JAVA_CONST_PCM16_NAME, &(javaAudioTrackFields.PCM16)) + || !android_media_getIntConstantFromClass(env, audioFormatClass, + JAVA_AUDIOFORMAT_CLASS_NAME, + JAVA_CONST_PCM8_NAME, &(javaAudioTrackFields.PCM8)) ) { + // error log performed in android_media_getIntConstantFromClass() + return -1; + } + + // Get the stream types from the AudioManager class + jclass audioManagerClass = NULL; + audioManagerClass = env->FindClass(JAVA_AUDIOMANAGER_CLASS_NAME); + if (audioManagerClass == NULL) { + LOGE("Can't find %s", JAVA_AUDIOMANAGER_CLASS_NAME); + return -1; + } + if ( !android_media_getIntConstantFromClass(env, audioManagerClass, + JAVA_AUDIOMANAGER_CLASS_NAME, + JAVA_CONST_STREAM_VOICE_CALL_NAME, &(javaAudioTrackFields.STREAM_VOICE_CALL)) + || !android_media_getIntConstantFromClass(env, audioManagerClass, + JAVA_AUDIOMANAGER_CLASS_NAME, + JAVA_CONST_STREAM_MUSIC_NAME, &(javaAudioTrackFields.STREAM_MUSIC)) + || !android_media_getIntConstantFromClass(env, audioManagerClass, + JAVA_AUDIOMANAGER_CLASS_NAME, + JAVA_CONST_STREAM_SYSTEM_NAME, &(javaAudioTrackFields.STREAM_SYSTEM)) + || !android_media_getIntConstantFromClass(env, audioManagerClass, + JAVA_AUDIOMANAGER_CLASS_NAME, + JAVA_CONST_STREAM_RING_NAME, &(javaAudioTrackFields.STREAM_RING)) + || !android_media_getIntConstantFromClass(env, audioManagerClass, + JAVA_AUDIOMANAGER_CLASS_NAME, + JAVA_CONST_STREAM_ALARM_NAME, &(javaAudioTrackFields.STREAM_ALARM)) ) { + // error log performed in android_media_getIntConstantFromClass() + return -1; + } + + return AndroidRuntime::registerNativeMethods(env, kClassPathName, gMethods, NELEM(gMethods)); +} + + +// ---------------------------------------------------------------------------- diff --git a/core/jni/android_media_ToneGenerator.cpp b/core/jni/android_media_ToneGenerator.cpp index 73c128345af023dd028bef58ac4e06d7bb049743..a4388de82409c8d9cd121bb943ac01248bae7cda 100644 --- a/core/jni/android_media_ToneGenerator.cpp +++ b/core/jni/android_media_ToneGenerator.cpp @@ -87,7 +87,7 @@ static void android_media_ToneGenerator_native_setup(JNIEnv *env, jobject thiz, if (lpToneGen == NULL) { LOGE("ToneGenerator creation failed \n"); - jniThrowException(env, "java/lang/OutOfMemoryException", NULL); + jniThrowException(env, "java/lang/OutOfMemoryError", NULL); return; } LOGV("ToneGenerator lpToneGen: %x\n", (unsigned int)lpToneGen); diff --git a/core/jni/android_net_LocalSocketImpl.cpp b/core/jni/android_net_LocalSocketImpl.cpp index abd0961a23f4939fb6036a63b370492a258dd242..f14b9fa05b20cd83e2845b3fa9059bb4db3cd9a3 100644 --- a/core/jni/android_net_LocalSocketImpl.cpp +++ b/core/jni/android_net_LocalSocketImpl.cpp @@ -700,7 +700,7 @@ static jint socket_readba (JNIEnv *env, jobject object, } if (off < 0 || len < 0 || (off + len) > env->GetArrayLength(buffer)) { - jniThrowException(env, "java/lang/ArrayIndexOutOfBounds", NULL); + jniThrowException(env, "java/lang/ArrayIndexOutOfBoundsException", NULL); return (jint)-1; } @@ -767,7 +767,7 @@ static void socket_writeba (JNIEnv *env, jobject object, } if (off < 0 || len < 0 || (off + len) > env->GetArrayLength(buffer)) { - jniThrowException(env, "java/lang/ArrayIndexOutOfBounds", NULL); + jniThrowException(env, "java/lang/ArrayIndexOutOfBoundsException", NULL); return; } diff --git a/core/jni/android_net_NetUtils.cpp b/core/jni/android_net_NetUtils.cpp index 417ce541e4a3432f3925f1d367447cee146f1c89..8383deb59a725159d9a620681c9d912d095786d6 100644 --- a/core/jni/android_net_NetUtils.cpp +++ b/core/jni/android_net_NetUtils.cpp @@ -41,6 +41,7 @@ int dhcp_do_request(const char *ifname, in_addr_t *server, uint32_t *lease); int dhcp_stop(const char *ifname); +int dhcp_release_lease(const char *ifname); char *dhcp_get_errmsg(); } @@ -157,7 +158,7 @@ static jboolean android_net_utils_runDhcp(JNIEnv* env, jobject clazz, jstring if return (jboolean)(result == 0); } -static jboolean android_net_utils_stopDhcp(JNIEnv* env, jobject clazz, jstring ifname, jobject info) +static jboolean android_net_utils_stopDhcp(JNIEnv* env, jobject clazz, jstring ifname) { int result; @@ -167,6 +168,16 @@ static jboolean android_net_utils_stopDhcp(JNIEnv* env, jobject clazz, jstring i return (jboolean)(result == 0); } +static jboolean android_net_utils_releaseDhcpLease(JNIEnv* env, jobject clazz, jstring ifname) +{ + int result; + + const char *nameStr = env->GetStringUTFChars(ifname, NULL); + result = ::dhcp_release_lease(nameStr); + env->ReleaseStringUTFChars(ifname, nameStr); + return (jboolean)(result == 0); +} + static jstring android_net_utils_getDhcpError(JNIEnv* env, jobject clazz) { return env->NewStringUTF(::dhcp_get_errmsg()); @@ -207,6 +218,7 @@ static JNINativeMethod gNetworkUtilMethods[] = { { "resetConnections", "(Ljava/lang/String;)I", (void *)android_net_utils_resetConnections }, { "runDhcp", "(Ljava/lang/String;Landroid/net/DhcpInfo;)Z", (void *)android_net_utils_runDhcp }, { "stopDhcp", "(Ljava/lang/String;)Z", (void *)android_net_utils_stopDhcp }, + { "releaseDhcpLease", "(Ljava/lang/String;)Z", (void *)android_net_utils_releaseDhcpLease }, { "configureNative", "(Ljava/lang/String;IIIII)Z", (void *)android_net_utils_configureInterface }, { "getDhcpError", "()Ljava/lang/String;", (void*) android_net_utils_getDhcpError }, }; diff --git a/core/jni/android_net_wifi_Wifi.cpp b/core/jni/android_net_wifi_Wifi.cpp index 48af99eef19a7714e92c9a41b93381c4886b0e5d..722b5b8165ab33c53d5c80c3cfe67ad8ac669818 100644 --- a/core/jni/android_net_wifi_Wifi.cpp +++ b/core/jni/android_net_wifi_Wifi.cpp @@ -343,6 +343,32 @@ static jboolean android_net_wifi_setPowerModeCommand(JNIEnv* env, jobject clazz, return (jboolean)!cmdTooLong && doBooleanCommand(cmdstr, "OK"); } +static jboolean android_net_wifi_setNumAllowedChannelsCommand(JNIEnv* env, jobject clazz, jint numChannels) +{ + char cmdstr[256]; + + int numWritten = snprintf(cmdstr, sizeof(cmdstr), "DRIVER SCAN-CHANNELS %u", numChannels); + int cmdTooLong = numWritten >= (int)sizeof(cmdstr); + + return (jboolean)!cmdTooLong && doBooleanCommand(cmdstr, "OK"); +} + +static jint android_net_wifi_getNumAllowedChannelsCommand(JNIEnv* env, jobject clazz) +{ + char reply[256]; + int numChannels; + + if (doCommand("DRIVER SCAN-CHANNELS", reply, sizeof(reply)) != 0) { + return -1; + } + // reply comes back in the form "Scan-Channels = X" where X is the + // number of channels + if (sscanf(reply, "%*s = %u", &numChannels) == 1) + return numChannels; + else + return -1; +} + static jboolean android_net_wifi_setBluetoothCoexistenceModeCommand(JNIEnv* env, jobject clazz, jint mode) { char cmdstr[256]; @@ -382,7 +408,7 @@ static jboolean android_net_wifi_addToBlacklistCommand(JNIEnv* env, jobject claz const char *bssidStr = env->GetStringUTFChars(bssid, &isCopy); - int cmdTooLong = snprintf(cmdstr, sizeof(cmdstr), "BLACKLIST %s", bssidStr) >= sizeof(cmdstr); + int cmdTooLong = snprintf(cmdstr, sizeof(cmdstr), "BLACKLIST %s", bssidStr) >= (int)sizeof(cmdstr); env->ReleaseStringUTFChars(bssid, bssidStr); @@ -453,6 +479,8 @@ static JNINativeMethod gWifiMethods[] = { { "startDriverCommand", "()Z", (void*) android_net_wifi_startDriverCommand }, { "stopDriverCommand", "()Z", (void*) android_net_wifi_stopDriverCommand }, { "setPowerModeCommand", "(I)Z", (void*) android_net_wifi_setPowerModeCommand }, + { "setNumAllowedChannelsCommand", "(I)Z", (void*) android_net_wifi_setNumAllowedChannelsCommand }, + { "getNumAllowedChannelsCommand", "()I", (void*) android_net_wifi_getNumAllowedChannelsCommand }, { "setBluetoothCoexistenceModeCommand", "(I)Z", (void*) android_net_wifi_setBluetoothCoexistenceModeCommand }, { "getRssiCommand", "()I", (void*) android_net_wifi_getRssiCommand }, diff --git a/core/jni/android_server_BluetoothA2dpService.cpp b/core/jni/android_server_BluetoothA2dpService.cpp new file mode 100644 index 0000000000000000000000000000000000000000..19ed39f8d2ded07ec1a1c5f461279a99e091462f --- /dev/null +++ b/core/jni/android_server_BluetoothA2dpService.cpp @@ -0,0 +1,417 @@ +/* +** Copyright 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 "BluetoothA2dpService.cpp" + +#include "android_bluetooth_common.h" +#include "android_runtime/AndroidRuntime.h" +#include "JNIHelp.h" +#include "jni.h" +#include "utils/Log.h" +#include "utils/misc.h" + +#include +#include +#include +#include +#include +#include + +#ifdef HAVE_BLUETOOTH +#include +#endif + +namespace android { + +#ifdef HAVE_BLUETOOTH +static jmethodID method_onHeadsetCreated; +static jmethodID method_onHeadsetRemoved; +static jmethodID method_onSinkConnected; +static jmethodID method_onSinkDisconnected; +static jmethodID method_onSinkPlaying; +static jmethodID method_onSinkStopped; + +typedef struct { + JNIEnv *env; + DBusConnection *conn; + jobject me; // for callbacks to java +} native_data_t; + +static native_data_t *nat = NULL; // global native data + +extern event_loop_native_data_t *event_loop_nat; // for the event loop JNIEnv +#endif + +#ifdef HAVE_BLUETOOTH +static void onConnectSinkResult(DBusMessage *msg, void *user); +static void onDisconnectSinkResult(DBusMessage *msg, void *user); +#endif + +/* Returns true on success (even if adapter is present but disabled). + * Return false if dbus is down, or another serious error (out of memory) +*/ +static bool initNative(JNIEnv* env, jobject object) { + LOGV(__FUNCTION__); +#ifdef HAVE_BLUETOOTH + nat = (native_data_t *)calloc(1, sizeof(native_data_t)); + if (NULL == nat) { + LOGE("%s: out of memory!", __FUNCTION__); + return false; + } + nat->env = env; + nat->me = env->NewGlobalRef(object); + + DBusError err; + dbus_error_init(&err); + dbus_threads_init_default(); + nat->conn = dbus_bus_get(DBUS_BUS_SYSTEM, &err); + if (dbus_error_is_set(&err)) { + LOGE("Could not get onto the system bus: %s", err.message); + dbus_error_free(&err); + return false; + } +#endif /*HAVE_BLUETOOTH*/ + return true; +} + +static void cleanupNative(JNIEnv* env, jobject object) { +#ifdef HAVE_BLUETOOTH + LOGV(__FUNCTION__); + if (nat) { + dbus_connection_close(nat->conn); + env->DeleteGlobalRef(nat->me); + free(nat); + nat = NULL; + } +#endif +} +static jobjectArray listHeadsetsNative(JNIEnv *env, jobject object) { +#ifdef HAVE_BLUETOOTH + LOGV(__FUNCTION__); + if (nat) { + DBusMessage *reply = + dbus_func_args(env, nat->conn, "/org/bluez/audio", + "org.bluez.audio.Manager", "ListHeadsets", + DBUS_TYPE_INVALID); + return reply ? dbus_returns_array_of_strings(env, reply) : NULL; + } +#endif + return NULL; +} + +static jstring createHeadsetNative(JNIEnv *env, jobject object, + jstring address) { +#ifdef HAVE_BLUETOOTH + LOGV(__FUNCTION__); + if (nat) { + const char *c_address = env->GetStringUTFChars(address, NULL); + LOGV("... address = %s\n", c_address); + DBusMessage *reply = + dbus_func_args(env, nat->conn, "/org/bluez/audio", + "org.bluez.audio.Manager", "CreateHeadset", + DBUS_TYPE_STRING, &c_address, + DBUS_TYPE_INVALID); + env->ReleaseStringUTFChars(address, c_address); + return reply ? dbus_returns_string(env, reply) : NULL; + } +#endif + return NULL; +} + +static jstring removeHeadsetNative(JNIEnv *env, jobject object, jstring path) { +#ifdef HAVE_BLUETOOTH + LOGV(__FUNCTION__); + if (nat) { + const char *c_path = env->GetStringUTFChars(path, NULL); + DBusMessage *reply = + dbus_func_args(env, nat->conn, "/org/bluez/audio", + "org.bluez.audio.Manager", "RemoveHeadset", + DBUS_TYPE_STRING, &c_path, + DBUS_TYPE_INVALID); + env->ReleaseStringUTFChars(path, c_path); + return reply ? dbus_returns_string(env, reply) : NULL; + } +#endif + return NULL; +} + +static jstring getAddressNative(JNIEnv *env, jobject object, jstring path) { +#ifdef HAVE_BLUETOOTH + LOGV(__FUNCTION__); + if (nat) { + const char *c_path = env->GetStringUTFChars(path, NULL); + DBusMessage *reply = + dbus_func_args(env, nat->conn, c_path, + "org.bluez.audio.Device", "GetAddress", + DBUS_TYPE_INVALID); + env->ReleaseStringUTFChars(path, c_path); + return reply ? dbus_returns_string(env, reply) : NULL; + } +#endif + return NULL; +} + +static jboolean connectSinkNative(JNIEnv *env, jobject object, jstring path) { +#ifdef HAVE_BLUETOOTH + LOGV(__FUNCTION__); + if (nat) { + const char *c_path = env->GetStringUTFChars(path, NULL); + size_t path_sz = env->GetStringUTFLength(path) + 1; + char *c_path_copy = (char *)malloc(path_sz); // callback data + strncpy(c_path_copy, c_path, path_sz); + + bool ret = + dbus_func_args_async(env, nat->conn, -1, + onConnectSinkResult, (void *)c_path_copy, c_path, + "org.bluez.audio.Sink", "Connect", + DBUS_TYPE_INVALID); + + env->ReleaseStringUTFChars(path, c_path); + if (!ret) { + free(c_path_copy); + return JNI_FALSE; + } + return JNI_TRUE; + } +#endif + return JNI_FALSE; +} + +static jboolean disconnectSinkNative(JNIEnv *env, jobject object, + jstring path) { +#ifdef HAVE_BLUETOOTH + LOGV(__FUNCTION__); + if (nat) { + const char *c_path = env->GetStringUTFChars(path, NULL); + size_t path_sz = env->GetStringUTFLength(path) + 1; + char *c_path_copy = (char *)malloc(path_sz); // callback data + strncpy(c_path_copy, c_path, path_sz); + + bool ret = + dbus_func_args_async(env, nat->conn, -1, + onDisconnectSinkResult, (void *)c_path_copy, c_path, + "org.bluez.audio.Sink", "Disconnect", + DBUS_TYPE_INVALID); + env->ReleaseStringUTFChars(path, c_path); + if (!ret) { + free(c_path_copy); + return JNI_FALSE; + } + return JNI_TRUE; + } +#endif + return JNI_FALSE; +} + +static jboolean isSinkConnectedNative(JNIEnv *env, jobject object, jstring path) { +#ifdef HAVE_BLUETOOTH + LOGV(__FUNCTION__); + if (nat) { + const char *c_path = env->GetStringUTFChars(path, NULL); + DBusMessage *reply = + dbus_func_args(env, nat->conn, c_path, + "org.bluez.audio.Sink", "IsConnected", + DBUS_TYPE_INVALID); + env->ReleaseStringUTFChars(path, c_path); + return reply ? dbus_returns_boolean(env, reply) : JNI_FALSE; + } +#endif + return JNI_FALSE; +} + +#ifdef HAVE_BLUETOOTH +static void onConnectSinkResult(DBusMessage *msg, void *user) { + LOGV(__FUNCTION__); + + char *c_path = (char *)user; + DBusError err; + dbus_error_init(&err); + JNIEnv *env = event_loop_nat->env; + + LOGV("... path = %s", c_path); + if (dbus_set_error_from_message(&err, msg)) { + /* if (!strcmp(err.name, BLUEZ_DBUS_BASE_IFC ".Error.AuthenticationFailed")) */ + LOGE("%s: D-Bus error: %s (%s)\n", __FUNCTION__, err.name, err.message); + dbus_error_free(&err); + env->CallVoidMethod(nat->me, + method_onSinkDisconnected, + env->NewStringUTF(c_path)); + if (env->ExceptionCheck()) { + LOGE("VM Exception occurred in native function %s (%s:%d)", + __FUNCTION__, __FILE__, __LINE__); + } + } // else Java callback is triggered by signal in a2dp_event_filter + + free(c_path); +} + +static void onDisconnectSinkResult(DBusMessage *msg, void *user) { + LOGV(__FUNCTION__); + + char *c_path = (char *)user; + DBusError err; + dbus_error_init(&err); + JNIEnv *env = event_loop_nat->env; + + LOGV("... path = %s", c_path); + if (dbus_set_error_from_message(&err, msg)) { + /* if (!strcmp(err.name, BLUEZ_DBUS_BASE_IFC ".Error.AuthenticationFailed")) */ + LOGE("%s: D-Bus error: %s (%s)\n", __FUNCTION__, err.name, err.message); + dbus_error_free(&err); + // Assume it is still connected + env->CallVoidMethod(nat->me, + method_onSinkConnected, + env->NewStringUTF(c_path)); + if (env->ExceptionCheck()) { + LOGE("VM Exception occurred in native function %s (%s:%d)", + __FUNCTION__, __FILE__, __LINE__); + } + } // else Java callback is triggered by signal in a2dp_event_filter + + free(c_path); +} + +DBusHandlerResult a2dp_event_filter(DBusMessage *msg, JNIEnv *env) { + DBusError err; + + if (!nat) { + LOGV("... skipping %s\n", __FUNCTION__); + LOGV("... ignored\n"); + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + } + + dbus_error_init(&err); + + if (dbus_message_get_type(msg) != DBUS_MESSAGE_TYPE_SIGNAL) { + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + } + + DBusHandlerResult result = DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + + if (dbus_message_is_signal(msg, + "org.bluez.audio.Manager", + "HeadsetCreated")) { + char *c_path; + if (dbus_message_get_args(msg, &err, + DBUS_TYPE_STRING, &c_path, + DBUS_TYPE_INVALID)) { + LOGV("... path = %s", c_path); + env->CallVoidMethod(nat->me, + method_onHeadsetCreated, + env->NewStringUTF(c_path)); + } else LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg); + result = DBUS_HANDLER_RESULT_HANDLED; + } else if (dbus_message_is_signal(msg, + "org.bluez.audio.Manager", + "HeadsetRemoved")) { + char *c_path; + if (dbus_message_get_args(msg, &err, + DBUS_TYPE_STRING, &c_path, + DBUS_TYPE_INVALID)) { + LOGV("... path = %s", c_path); + env->CallVoidMethod(nat->me, + method_onHeadsetRemoved, + env->NewStringUTF(c_path)); + } else LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg); + result = DBUS_HANDLER_RESULT_HANDLED; + } else if (dbus_message_is_signal(msg, + "org.bluez.audio.Sink", + "Connected")) { + const char *c_path = dbus_message_get_path(msg); + LOGV("... path = %s", c_path); + env->CallVoidMethod(nat->me, + method_onSinkConnected, + env->NewStringUTF(c_path)); + result = DBUS_HANDLER_RESULT_HANDLED; + } else if (dbus_message_is_signal(msg, + "org.bluez.audio.Sink", + "Disconnected")) { + const char *c_path = dbus_message_get_path(msg); + LOGV("... path = %s", c_path); + env->CallVoidMethod(nat->me, + method_onSinkDisconnected, + env->NewStringUTF(c_path)); + result = DBUS_HANDLER_RESULT_HANDLED; + } else if (dbus_message_is_signal(msg, + "org.bluez.audio.Sink", + "Playing")) { + const char *c_path = dbus_message_get_path(msg); + LOGV("... path = %s", c_path); + env->CallVoidMethod(nat->me, + method_onSinkPlaying, + env->NewStringUTF(c_path)); + result = DBUS_HANDLER_RESULT_HANDLED; + } else if (dbus_message_is_signal(msg, + "org.bluez.audio.Sink", + "Stopped")) { + const char *c_path = dbus_message_get_path(msg); + LOGV("... path = %s", c_path); + env->CallVoidMethod(nat->me, + method_onSinkStopped, + env->NewStringUTF(c_path)); + result = DBUS_HANDLER_RESULT_HANDLED; + } + + if (result == DBUS_HANDLER_RESULT_NOT_YET_HANDLED) { + LOGV("... ignored"); + } + if (env->ExceptionCheck()) { + LOGE("VM Exception occurred while handling %s.%s (%s) in %s," + " leaving for VM", + dbus_message_get_interface(msg), dbus_message_get_member(msg), + dbus_message_get_path(msg), __FUNCTION__); + } + + return result; +} +#endif + + +static JNINativeMethod sMethods[] = { + {"initNative", "()Z", (void *)initNative}, + {"cleanupNative", "()V", (void *)cleanupNative}, + + /* Bluez audio 3.36 API */ + {"listHeadsetsNative", "()[Ljava/lang/String;", (void*)listHeadsetsNative}, + {"createHeadsetNative", "(Ljava/lang/String;)Ljava/lang/String;", (void*)createHeadsetNative}, + {"removeHeadsetNative", "(Ljava/lang/String;)Z", (void*)removeHeadsetNative}, + {"getAddressNative", "(Ljava/lang/String;)Ljava/lang/String;", (void*)getAddressNative}, + {"connectSinkNative", "(Ljava/lang/String;)Z", (void*)connectSinkNative}, + {"disconnectSinkNative", "(Ljava/lang/String;)Z", (void*)disconnectSinkNative}, + {"isSinkConnectedNative", "(Ljava/lang/String;)Z", (void*)isSinkConnectedNative}, +}; + +int register_android_server_BluetoothA2dpService(JNIEnv *env) { + jclass clazz = env->FindClass("android/server/BluetoothA2dpService"); + if (clazz == NULL) { + LOGE("Can't find android/server/BluetoothA2dpService"); + return -1; + } + +#ifdef HAVE_BLUETOOTH + method_onHeadsetCreated = env->GetMethodID(clazz, "onHeadsetCreated", "(Ljava/lang/String;)V"); + method_onHeadsetRemoved = env->GetMethodID(clazz, "onHeadsetRemoved", "(Ljava/lang/String;)V"); + method_onSinkConnected = env->GetMethodID(clazz, "onSinkConnected", "(Ljava/lang/String;)V"); + method_onSinkDisconnected = env->GetMethodID(clazz, "onSinkDisconnected", "(Ljava/lang/String;)V"); + method_onSinkPlaying = env->GetMethodID(clazz, "onSinkPlaying", "(Ljava/lang/String;)V"); + method_onSinkStopped = env->GetMethodID(clazz, "onSinkStopped", "(Ljava/lang/String;)V"); +#endif + + return AndroidRuntime::registerNativeMethods(env, + "android/server/BluetoothA2dpService", sMethods, NELEM(sMethods)); +} + +} /* namespace android */ diff --git a/core/jni/android_server_BluetoothEventLoop.cpp b/core/jni/android_server_BluetoothEventLoop.cpp index 395a45cc20bc96a8cdf8045eadfe62cb0676acf0..1aef138ce463acdd7e9ceac2a7b62e25c0b8213d 100644 --- a/core/jni/android_server_BluetoothEventLoop.cpp +++ b/core/jni/android_server_BluetoothEventLoop.cpp @@ -39,6 +39,7 @@ namespace android { static jfieldID field_mNativeData; static jmethodID method_onModeChanged; +static jmethodID method_onNameChanged; static jmethodID method_onDiscoveryStarted; static jmethodID method_onDiscoveryCompleted; static jmethodID method_onRemoteDeviceFound; @@ -60,17 +61,10 @@ static jmethodID method_onGetRemoteServiceChannelResult; static jmethodID method_onPasskeyAgentRequest; static jmethodID method_onPasskeyAgentCancel; -struct native_data_t { - DBusConnection *conn; - /* These variables are set in waitForAndDispatchEventNative() and are - valid only within the scope of this function. At any other time, they - are NULL. */ - jobject me; - JNIEnv *env; -}; +typedef event_loop_native_data_t native_data_t; // Only valid during waitForAndDispatchEventNative() -static native_data_t *event_loop_nat; +native_data_t *event_loop_nat; static inline native_data_t * get_native_data(JNIEnv *env, jobject object) { return (native_data_t *)(env->GetIntField(object, @@ -83,6 +77,7 @@ static void classInitNative(JNIEnv* env, jclass clazz) { #ifdef HAVE_BLUETOOTH method_onModeChanged = env->GetMethodID(clazz, "onModeChanged", "(Ljava/lang/String;)V"); + method_onNameChanged = env->GetMethodID(clazz, "onNameChanged", "(Ljava/lang/String;)V"); method_onDiscoveryStarted = env->GetMethodID(clazz, "onDiscoveryStarted", "()V"); method_onDiscoveryCompleted = env->GetMethodID(clazz, "onDiscoveryCompleted", "()V"); method_onRemoteDeviceFound = env->GetMethodID(clazz, "onRemoteDeviceFound", "(Ljava/lang/String;IS)V"); @@ -142,8 +137,6 @@ static void cleanupNativeDataNative(JNIEnv* env, jobject object) { } #ifdef HAVE_BLUETOOTH -static jboolean add_adapter_event_match(JNIEnv *env, native_data_t *nat); -static void remove_adapter_event_match(JNIEnv *env, native_data_t *nat); static DBusHandlerResult event_filter(DBusConnection *conn, DBusMessage *msg, void *data); static DBusHandlerResult passkey_agent_event_filter(DBusConnection *conn, @@ -160,15 +153,46 @@ static jboolean setUpEventLoopNative(JNIEnv *env, jobject object) { LOGV(__FUNCTION__); dbus_threads_init_default(); native_data_t *nat = get_native_data(env, object); + DBusError err; + dbus_error_init(&err); + if (nat != NULL && nat->conn != NULL) { + // Add a filter for all incoming messages if (!dbus_connection_add_filter(nat->conn, event_filter, nat, NULL)){ return JNI_FALSE; } - if (add_adapter_event_match(env, nat) != JNI_TRUE) { + // Set which messages will be processed by this dbus connection + dbus_bus_add_match(nat->conn, + "type='signal',interface='"BLUEZ_DBUS_BASE_IFC".Adapter'", + &err); + if (dbus_error_is_set(&err)) { + LOG_AND_FREE_DBUS_ERROR(&err); + return JNI_FALSE; + } + dbus_bus_add_match(nat->conn, + "type='signal',interface='org.bluez.audio.Manager'", + &err); + if (dbus_error_is_set(&err)) { + LOG_AND_FREE_DBUS_ERROR(&err); + return JNI_FALSE; + } + dbus_bus_add_match(nat->conn, + "type='signal',interface='org.bluez.audio.Device'", + &err); + if (dbus_error_is_set(&err)) { + LOG_AND_FREE_DBUS_ERROR(&err); + return JNI_FALSE; + } + dbus_bus_add_match(nat->conn, + "type='signal',interface='org.bluez.audio.Sink'", + &err); + if (dbus_error_is_set(&err)) { + LOG_AND_FREE_DBUS_ERROR(&err); return JNI_FALSE; } + // Add an object handler for passkey agent method calls const char *path = "/android/bluetooth/PasskeyAgent"; if (!dbus_connection_register_object_path(nat->conn, path, &passkey_agent_vtable, NULL)) { @@ -177,9 +201,6 @@ static jboolean setUpEventLoopNative(JNIEnv *env, jobject object) { return JNI_FALSE; } - DBusError err; - dbus_error_init(&err); - // RegisterDefaultPasskeyAgent() will fail until hcid is up, so keep // trying for 10 seconds. int attempt; @@ -219,6 +240,9 @@ static void tearDownEventLoopNative(JNIEnv *env, jobject object) { native_data_t *nat = get_native_data(env, object); if (nat != NULL && nat->conn != NULL) { + DBusError err; + dbus_error_init(&err); + const char *path = "/android/bluetooth/PasskeyAgent"; DBusMessage *reply = dbus_func_args(env, nat->conn, BLUEZ_DBUS_BASE_PATH, @@ -227,50 +251,40 @@ static void tearDownEventLoopNative(JNIEnv *env, jobject object) { DBUS_TYPE_INVALID); if (reply) dbus_message_unref(reply); - DBusError err; - dbus_error_init(&err); - (void)dbus_connection_remove_filter(nat->conn, - event_filter, - nat); - dbus_connection_unregister_object_path(nat->conn, path); - remove_adapter_event_match(env, nat); + dbus_bus_remove_match(nat->conn, + "type='signal',interface='org.bluez.audio.Sink'", + &err); + if (dbus_error_is_set(&err)) { + LOG_AND_FREE_DBUS_ERROR(&err); + } + dbus_bus_remove_match(nat->conn, + "type='signal',interface='org.bluez.audio.Device'", + &err); + if (dbus_error_is_set(&err)) { + LOG_AND_FREE_DBUS_ERROR(&err); + } + dbus_bus_remove_match(nat->conn, + "type='signal',interface='org.bluez.audio.Manager'", + &err); + if (dbus_error_is_set(&err)) { + LOG_AND_FREE_DBUS_ERROR(&err); + } + dbus_bus_remove_match(nat->conn, + "type='signal',interface='"BLUEZ_DBUS_BASE_IFC".Adapter'", + &err); + if (dbus_error_is_set(&err)) { + LOG_AND_FREE_DBUS_ERROR(&err); + } + + dbus_connection_remove_filter(nat->conn, event_filter, nat); } #endif } #ifdef HAVE_BLUETOOTH -static const char *const adapter_event_match = - "type='signal',interface='"BLUEZ_DBUS_BASE_IFC".Adapter'"; - -static jboolean add_adapter_event_match(JNIEnv *env, native_data_t *nat) { - if (nat == NULL || nat->conn == NULL) { - LOGE("%s: Not connected to d-bus!", __FUNCTION__); - return JNI_FALSE; - } - DBusError err; - dbus_error_init(&err); - dbus_bus_add_match(nat->conn, adapter_event_match, &err); - if (dbus_error_is_set(&err)) { - LOG_AND_FREE_DBUS_ERROR(&err); - return JNI_FALSE; - } - return JNI_TRUE; -} - -static void remove_adapter_event_match(JNIEnv *env, native_data_t *nat) { - if (nat->conn == NULL) { - LOGE("%s: Not connected to d-bus!", __FUNCTION__); - return; - } - DBusError err; - dbus_error_init(&err); - dbus_bus_remove_match(nat->conn, adapter_event_match, &err); - if (dbus_error_is_set(&err)) { - LOG_AND_FREE_DBUS_ERROR(&err); - } -} +extern DBusHandlerResult a2dp_event_filter(DBusMessage *msg, JNIEnv *env); // Called by dbus during WaitForAndDispatchEventNative() static DBusHandlerResult event_filter(DBusConnection *conn, DBusMessage *msg, @@ -288,8 +302,9 @@ static DBusHandlerResult event_filter(DBusConnection *conn, DBusMessage *msg, return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; } - LOGV("%s: Received signal %s:%s", __FUNCTION__, - dbus_message_get_interface(msg), dbus_message_get_member(msg)); + LOGV("%s: Received signal %s:%s from %s", __FUNCTION__, + dbus_message_get_interface(msg), dbus_message_get_member(msg), + dbus_message_get_path(msg)); if (dbus_message_is_signal(msg, "org.bluez.Adapter", @@ -471,11 +486,35 @@ static DBusHandlerResult event_filter(DBusConnection *conn, DBusMessage *msg, env->NewStringUTF(c_address)); } else LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg); return DBUS_HANDLER_RESULT_HANDLED; - } else { - LOGV("... ignored"); + } else if (dbus_message_is_signal(msg, + "org.bluez.Adapter", + "ModeChanged")) { + char *c_mode; + if (dbus_message_get_args(msg, &err, + DBUS_TYPE_STRING, &c_mode, + DBUS_TYPE_INVALID)) { + LOGV("... mode = %s", c_mode); + env->CallVoidMethod(nat->me, + method_onModeChanged, + env->NewStringUTF(c_mode)); + } else LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg); + return DBUS_HANDLER_RESULT_HANDLED; + } else if (dbus_message_is_signal(msg, + "org.bluez.Adapter", + "NameChanged")) { + char *c_name; + if (dbus_message_get_args(msg, &err, + DBUS_TYPE_STRING, &c_name, + DBUS_TYPE_INVALID)) { + LOGV("... name = %s", c_name); + env->CallVoidMethod(nat->me, + method_onNameChanged, + env->NewStringUTF(c_name)); + } else LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg); + return DBUS_HANDLER_RESULT_HANDLED; } - return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + return a2dp_event_filter(msg, env); } // Called by dbus during WaitForAndDispatchEventNative() @@ -557,9 +596,9 @@ static jboolean waitForAndDispatchEventNative(JNIEnv *env, jobject object, nat->me = object; nat->env = env; event_loop_nat = nat; - ret = dbus_connection_read_write_dispatch(nat->conn, - timeout_ms) == TRUE ? - JNI_TRUE : JNI_FALSE; + ret = dbus_connection_read_write_dispatch_greedy(nat->conn, + timeout_ms) == TRUE ? + JNI_TRUE : JNI_FALSE; event_loop_nat = NULL; nat->me = NULL; nat->env = NULL; @@ -604,7 +643,7 @@ void onGetRemoteServiceChannelResult(DBusMessage *msg, void *user) { JNIEnv *env = event_loop_nat->env; jint channel = -2; - LOGV("... address = %s", context->address); + LOGV("... address = %s", address); if (dbus_set_error_from_message(&err, msg) || !dbus_message_get_args(msg, &err, diff --git a/core/jni/android_text_AndroidCharacter.cpp b/core/jni/android_text_AndroidCharacter.cpp index 97daed3404a4bbc099c3773fadb518c6101534be..450cee2df16cc115966b7b6d4ecde445527364b8 100644 --- a/core/jni/android_text_AndroidCharacter.cpp +++ b/core/jni/android_text_AndroidCharacter.cpp @@ -43,7 +43,7 @@ static void getDirectionalities(JNIEnv* env, jobject obj, jcharArray srcArray, j } if (env->GetArrayLength(srcArray) < count || env->GetArrayLength(destArray) < count) { - jniThrowException(env, "java/lang/ArrayIndexException", NULL); + jniThrowException(env, "java/lang/ArrayIndexOutOfBoundsException", NULL); goto DIRECTION_END; } @@ -81,7 +81,7 @@ static jboolean mirror(JNIEnv* env, jobject obj, jcharArray charArray, int start } if (start > start + count || env->GetArrayLength(charArray) < count) { - jniThrowException(env, "java/lang/ArrayIndexException", NULL); + jniThrowException(env, "java/lang/ArrayIndexOutOfBoundsException", NULL); goto MIRROR_END; } diff --git a/core/jni/android_pim_Time.cpp b/core/jni/android_text_format_Time.cpp similarity index 68% rename from core/jni/android_pim_Time.cpp rename to core/jni/android_text_format_Time.cpp index c1dd4998c33935a492a5d247e0644d249f32d16f..8e41ec76a80144b8b8ba88f654cea0e47b4290ff 100644 --- a/core/jni/android_pim_Time.cpp +++ b/core/jni/android_text_format_Time.cpp @@ -25,6 +25,7 @@ #include "android_runtime/AndroidRuntime.h" #include #include +#include namespace android { @@ -41,6 +42,17 @@ static jfieldID g_isdstField = 0; static jfieldID g_gmtoffField = 0; static jfieldID g_timezoneField = 0; +static jfieldID g_shortMonthsField = 0; +static jfieldID g_longMonthsField = 0; +static jfieldID g_shortWeekdaysField = 0; +static jfieldID g_longWeekdaysField = 0; +static jfieldID g_timeOnlyFormatField = 0; +static jfieldID g_dateOnlyFormatField = 0; +static jfieldID g_dateTimeFormatField = 0; +static jfieldID g_amField = 0; +static jfieldID g_pmField = 0; +static jfieldID g_dateCommandField = 0; + static inline bool java2time(JNIEnv* env, Time* t, jobject o) { t->t.tm_sec = env->GetIntField(o, g_secField); @@ -89,7 +101,7 @@ static inline void time2java(JNIEnv* env, jobject o, const Time &t) // ============================================================================ -static jlong android_pim_Time_normalize(JNIEnv* env, jobject This, +static jlong android_text_format_Time_normalize(JNIEnv* env, jobject This, jboolean ignoreDst) { Time t; @@ -104,7 +116,7 @@ static jlong android_pim_Time_normalize(JNIEnv* env, jobject This, return result; } -static void android_pim_Time_switchTimezone(JNIEnv* env, jobject This, +static void android_text_format_Time_switchTimezone(JNIEnv* env, jobject This, jstring timezoneObject) { Time t; @@ -123,7 +135,7 @@ static void android_pim_Time_switchTimezone(JNIEnv* env, jobject This, env->SetObjectField(This, g_timezoneField, timezoneObject); } -static jint android_pim_Time_compare(JNIEnv* env, jobject clazz, +static jint android_text_format_Time_compare(JNIEnv* env, jobject clazz, jobject aObject, jobject bObject) { Time a, b; @@ -142,7 +154,7 @@ static jint android_pim_Time_compare(JNIEnv* env, jobject clazz, return result; } -static jstring android_pim_Time_format2445(JNIEnv* env, jobject This) +static jstring android_text_format_Time_format2445(JNIEnv* env, jobject This) { Time t; if (!java2time(env, &t, This)) return env->NewStringUTF(""); @@ -168,25 +180,91 @@ static jstring android_pim_Time_format2445(JNIEnv* env, jobject This) } } -static jstring android_pim_Time_format(JNIEnv* env, jobject This, +static jstring android_text_format_Time_format(JNIEnv* env, jobject This, jstring formatObject) { Time t; + struct strftime_locale locale; + jclass timeClass = env->FindClass("android/text/format/Time"); + jstring js_mon[12], js_month[12], js_wday[7], js_weekday[7]; + jstring js_X_fmt, js_x_fmt, js_c_fmt, js_am, js_pm, js_date_fmt; + jobjectArray ja; + if (!java2time(env, &t, This)) return env->NewStringUTF(""); + + ja = (jobjectArray) env->GetStaticObjectField(timeClass, g_shortMonthsField); + for (int i = 0; i < 12; i++) { + js_mon[i] = (jstring) env->GetObjectArrayElement(ja, i); + locale.mon[i] = env->GetStringUTFChars(js_mon[i], NULL); + } + + ja = (jobjectArray) env->GetStaticObjectField(timeClass, g_longMonthsField); + for (int i = 0; i < 12; i++) { + js_month[i] = (jstring) env->GetObjectArrayElement(ja, i); + locale.month[i] = env->GetStringUTFChars(js_month[i], NULL); + } + + ja = (jobjectArray) env->GetStaticObjectField(timeClass, g_shortWeekdaysField); + for (int i = 0; i < 7; i++) { + js_wday[i] = (jstring) env->GetObjectArrayElement(ja, i); + locale.wday[i] = env->GetStringUTFChars(js_wday[i], NULL); + } + + ja = (jobjectArray) env->GetStaticObjectField(timeClass, g_longWeekdaysField); + for (int i = 0; i < 7; i++) { + js_weekday[i] = (jstring) env->GetObjectArrayElement(ja, i); + locale.weekday[i] = env->GetStringUTFChars(js_weekday[i], NULL); + } + + js_X_fmt = (jstring) env->GetStaticObjectField(timeClass, g_timeOnlyFormatField); + locale.X_fmt = env->GetStringUTFChars(js_X_fmt, NULL); + + js_x_fmt = (jstring) env->GetStaticObjectField(timeClass, g_dateOnlyFormatField); + locale.x_fmt = env->GetStringUTFChars(js_x_fmt, NULL); + + js_c_fmt = (jstring) env->GetStaticObjectField(timeClass, g_dateTimeFormatField); + locale.c_fmt = env->GetStringUTFChars(js_c_fmt, NULL); + + js_am = (jstring) env->GetStaticObjectField(timeClass, g_amField); + locale.am = env->GetStringUTFChars(js_am, NULL); + + js_pm = (jstring) env->GetStaticObjectField(timeClass, g_pmField); + locale.pm = env->GetStringUTFChars(js_pm, NULL); + + js_date_fmt = (jstring) env->GetStaticObjectField(timeClass, g_dateCommandField); + locale.date_fmt = env->GetStringUTFChars(js_date_fmt, NULL); + ACQUIRE_TIMEZONE(This, t) const char* format = env->GetStringUTFChars(formatObject, NULL); - String8 r = t.format(format); + String8 r = t.format(format, &locale); env->ReleaseStringUTFChars(formatObject, format); RELEASE_TIMEZONE(This, t) + for (int i = 0; i < 12; i++) { + env->ReleaseStringUTFChars(js_mon[i], locale.mon[i]); + env->ReleaseStringUTFChars(js_month[i], locale.month[i]); + } + + for (int i = 0; i < 7; i++) { + env->ReleaseStringUTFChars(js_wday[i], locale.wday[i]); + env->ReleaseStringUTFChars(js_weekday[i], locale.weekday[i]); + } + + env->ReleaseStringUTFChars(js_X_fmt, locale.X_fmt); + env->ReleaseStringUTFChars(js_x_fmt, locale.x_fmt); + env->ReleaseStringUTFChars(js_c_fmt, locale.c_fmt); + env->ReleaseStringUTFChars(js_am, locale.am); + env->ReleaseStringUTFChars(js_pm, locale.pm); + env->ReleaseStringUTFChars(js_date_fmt, locale.date_fmt); + return env->NewStringUTF(r.string()); } -static jstring android_pim_Time_toString(JNIEnv* env, jobject This) +static jstring android_text_format_Time_toString(JNIEnv* env, jobject This) { Time t; if (!java2time(env, &t, This)) return env->NewStringUTF("");; @@ -199,7 +277,7 @@ static jstring android_pim_Time_toString(JNIEnv* env, jobject This) return env->NewStringUTF(r.string()); } -static void android_pim_Time_setToNow(JNIEnv* env, jobject This) +static void android_text_format_Time_setToNow(JNIEnv* env, jobject This) { env->SetBooleanField(This, g_allDayField, JNI_FALSE); Time t; @@ -211,7 +289,7 @@ static void android_pim_Time_setToNow(JNIEnv* env, jobject This) RELEASE_TIMEZONE(This, t) } -static jlong android_pim_Time_toMillis(JNIEnv* env, jobject This, +static jlong android_text_format_Time_toMillis(JNIEnv* env, jobject This, jboolean ignoreDst) { Time t; @@ -225,7 +303,7 @@ static jlong android_pim_Time_toMillis(JNIEnv* env, jobject This, return result; } -static void android_pim_Time_set(JNIEnv* env, jobject This, jlong millis) +static void android_text_format_Time_set(JNIEnv* env, jobject This, jlong millis) { env->SetBooleanField(This, g_allDayField, JNI_FALSE); Time t; @@ -271,48 +349,71 @@ static bool check_char(JNIEnv* env, const jchar *s, int spos, jchar expected) } -static void android_pim_Time_parse(JNIEnv* env, jobject This, jstring strObj) +static jboolean android_text_format_Time_parse(JNIEnv* env, jobject This, jstring strObj) { jsize len = env->GetStringLength(strObj); const jchar *s = env->GetStringChars(strObj, NULL); bool thrown = false; int n; + jboolean inUtc = false; + if (len < 8) { + char msg[100]; + sprintf(msg, "String too short -- expected at least 8 characters."); + jniThrowException(env, "android/util/TimeFormatException", msg); + return false; + } + + // year n = get_char(env, s, 0, 1000, &thrown); n += get_char(env, s, 1, 100, &thrown); n += get_char(env, s, 2, 10, &thrown); n += get_char(env, s, 3, 1, &thrown); - if (thrown) return; + if (thrown) return false; env->SetIntField(This, g_yearField, n); + // month n = get_char(env, s, 4, 10, &thrown); n += get_char(env, s, 5, 1, &thrown); n--; - if (thrown) return; + if (thrown) return false; env->SetIntField(This, g_monField, n); + // day of month n = get_char(env, s, 6, 10, &thrown); n += get_char(env, s, 7, 1, &thrown); - if (thrown) return; + if (thrown) return false; env->SetIntField(This, g_mdayField, n); - if (len >= 15) { + if (len > 8) { + // T + if (!check_char(env, s, 8, 'T')) return false; env->SetBooleanField(This, g_allDayField, JNI_FALSE); + + // hour n = get_char(env, s, 9, 10, &thrown); n += get_char(env, s, 10, 1, &thrown); - if (thrown) return; + if (thrown) return false; env->SetIntField(This, g_hourField, n); + // min n = get_char(env, s, 11, 10, &thrown); n += get_char(env, s, 12, 1, &thrown); - if (thrown) return; + if (thrown) return false; env->SetIntField(This, g_minField, n); + // sec n = get_char(env, s, 13, 10, &thrown); n += get_char(env, s, 14, 1, &thrown); - if (thrown) return; + if (thrown) return false; env->SetIntField(This, g_secField, n); + + if (len > 15) { + // Z + if (!check_char(env, s, 15, 'Z')) return false; + inUtc = true; + } } else { env->SetBooleanField(This, g_allDayField, JNI_TRUE); env->SetIntField(This, g_hourField, 0); @@ -325,93 +426,11 @@ static void android_pim_Time_parse(JNIEnv* env, jobject This, jstring strObj) env->SetIntField(This, g_isdstField, -1); env->SetLongField(This, g_gmtoffField, 0); - env->ReleaseStringChars(strObj, s); -} - -static jboolean android_pim_Time_parse2445(JNIEnv* env, jobject This, - jstring strObj) -{ - jsize len = env->GetStringLength(strObj); - const jchar *s = env->GetStringChars(strObj, NULL); - - bool thrown = false; - int n; - jboolean inUtc = false; - - if (len < 8) { - char msg[100]; - sprintf(msg, "String too short -- expected at least 8 characters."); - jniThrowException(env, "android/util/TimeFormatException", msg); - return false; - } - - // year - n = get_char(env, s, 0, 1000, &thrown); - n += get_char(env, s, 1, 100, &thrown); - n += get_char(env, s, 2, 10, &thrown); - n += get_char(env, s, 3, 1, &thrown); - if (thrown) return false; - env->SetIntField(This, g_yearField, n); - - // month - n = get_char(env, s, 4, 10, &thrown); - n += get_char(env, s, 5, 1, &thrown); - n--; - if (thrown) return false; - env->SetIntField(This, g_monField, n); - - // day of month - n = get_char(env, s, 6, 10, &thrown); - n += get_char(env, s, 7, 1, &thrown); - if (thrown) return false; - env->SetIntField(This, g_mdayField, n); - - if (len > 8) { - // T - if (!check_char(env, s, 8, 'T')) return false; - env->SetBooleanField(This, g_allDayField, JNI_FALSE); - - // hour - n = get_char(env, s, 9, 10, &thrown); - n += get_char(env, s, 10, 1, &thrown); - if (thrown) return false; - env->SetIntField(This, g_hourField, n); - - // min - n = get_char(env, s, 11, 10, &thrown); - n += get_char(env, s, 12, 1, &thrown); - if (thrown) return false; - env->SetIntField(This, g_minField, n); - - // sec - n = get_char(env, s, 13, 10, &thrown); - n += get_char(env, s, 14, 1, &thrown); - if (thrown) return false; - env->SetIntField(This, g_secField, n); - - if (len > 15) { - // Z - if (!check_char(env, s, 15, 'Z')) return false; - inUtc = true; - } - } else { - // all day - env->SetBooleanField(This, g_allDayField, JNI_TRUE); - env->SetIntField(This, g_hourField, 0); - env->SetIntField(This, g_minField, 0); - env->SetIntField(This, g_secField, 0); - } - - env->SetIntField(This, g_wdayField, 0); - env->SetIntField(This, g_ydayField, 0); - env->SetIntField(This, g_isdstField, -1); - env->SetLongField(This, g_gmtoffField, 0); - env->ReleaseStringChars(strObj, s); return inUtc; } -static jboolean android_pim_Time_parse3339(JNIEnv* env, +static jboolean android_text_format_Time_parse3339(JNIEnv* env, jobject This, jstring strObj) { @@ -531,7 +550,7 @@ static jboolean android_pim_Time_parse3339(JNIEnv* env, if (offset != 0) { // we need to normalize after applying the hour and minute offsets - android_pim_Time_normalize(env, This, false /* use isdst */); + android_text_format_Time_normalize(env, This, false /* use isdst */); // The timezone is set to UTC in the calling Java code. } } else { @@ -556,23 +575,22 @@ static jboolean android_pim_Time_parse3339(JNIEnv* env, */ static JNINativeMethod gMethods[] = { /* name, signature, funcPtr */ - { "normalize", "(Z)J", (void*)android_pim_Time_normalize }, - { "switchTimezone", "(Ljava/lang/String;)V", (void*)android_pim_Time_switchTimezone }, - { "compare", "(Landroid/pim/Time;Landroid/pim/Time;)I", (void*)android_pim_Time_compare }, - { "format", "(Ljava/lang/String;)Ljava/lang/String;", (void*)android_pim_Time_format }, - { "format2445", "()Ljava/lang/String;", (void*)android_pim_Time_format2445 }, - { "toString", "()Ljava/lang/String;", (void*)android_pim_Time_toString }, - { "parse", "(Ljava/lang/String;)V", (void*)android_pim_Time_parse }, - { "nativeParse2445", "(Ljava/lang/String;)Z", (void*)android_pim_Time_parse2445 }, - { "nativeParse3339", "(Ljava/lang/String;)Z", (void*)android_pim_Time_parse3339 }, - { "setToNow", "()V", (void*)android_pim_Time_setToNow }, - { "toMillis", "(Z)J", (void*)android_pim_Time_toMillis }, - { "set", "(J)V", (void*)android_pim_Time_set } + { "normalize", "(Z)J", (void*)android_text_format_Time_normalize }, + { "switchTimezone", "(Ljava/lang/String;)V", (void*)android_text_format_Time_switchTimezone }, + { "compare", "(Landroid/text/format/Time;Landroid/text/format/Time;)I", (void*)android_text_format_Time_compare }, + { "format1", "(Ljava/lang/String;)Ljava/lang/String;", (void*)android_text_format_Time_format }, + { "format2445", "()Ljava/lang/String;", (void*)android_text_format_Time_format2445 }, + { "toString", "()Ljava/lang/String;", (void*)android_text_format_Time_toString }, + { "nativeParse", "(Ljava/lang/String;)Z", (void*)android_text_format_Time_parse }, + { "nativeParse3339", "(Ljava/lang/String;)Z", (void*)android_text_format_Time_parse3339 }, + { "setToNow", "()V", (void*)android_text_format_Time_setToNow }, + { "toMillis", "(Z)J", (void*)android_text_format_Time_toMillis }, + { "set", "(J)V", (void*)android_text_format_Time_set } }; -int register_android_pim_Time(JNIEnv* env) +int register_android_text_format_Time(JNIEnv* env) { - jclass timeClass = env->FindClass("android/pim/Time"); + jclass timeClass = env->FindClass("android/text/format/Time"); g_allDayField = env->GetFieldID(timeClass, "allDay", "Z"); g_secField = env->GetFieldID(timeClass, "second", "I"); @@ -587,7 +605,18 @@ int register_android_pim_Time(JNIEnv* env) g_gmtoffField = env->GetFieldID(timeClass, "gmtoff", "J"); g_timezoneField = env->GetFieldID(timeClass, "timezone", "Ljava/lang/String;"); - return AndroidRuntime::registerNativeMethods(env, "android/pim/Time", gMethods, NELEM(gMethods)); + g_shortMonthsField = env->GetStaticFieldID(timeClass, "sShortMonths", "[Ljava/lang/String;"); + g_longMonthsField = env->GetStaticFieldID(timeClass, "sLongMonths", "[Ljava/lang/String;"); + g_shortWeekdaysField = env->GetStaticFieldID(timeClass, "sShortWeekdays", "[Ljava/lang/String;"); + g_longWeekdaysField = env->GetStaticFieldID(timeClass, "sLongWeekdays", "[Ljava/lang/String;"); + g_timeOnlyFormatField = env->GetStaticFieldID(timeClass, "sTimeOnlyFormat", "Ljava/lang/String;"); + g_dateOnlyFormatField = env->GetStaticFieldID(timeClass, "sDateOnlyFormat", "Ljava/lang/String;"); + g_dateTimeFormatField = env->GetStaticFieldID(timeClass, "sDateTimeFormat", "Ljava/lang/String;"); + g_amField = env->GetStaticFieldID(timeClass, "sAm", "Ljava/lang/String;"); + g_pmField = env->GetStaticFieldID(timeClass, "sPm", "Ljava/lang/String;"); + g_dateCommandField = env->GetStaticFieldID(timeClass, "sDateCommand", "Ljava/lang/String;"); + + return AndroidRuntime::registerNativeMethods(env, "android/text/format/Time", gMethods, NELEM(gMethods)); } }; // namespace android diff --git a/core/jni/android_util_AssetManager.cpp b/core/jni/android_util_AssetManager.cpp index 8a62159f42838d46c4589006ecdda2f57df393cf..add108053f87b24eb309318e21b01fec9f442a0d 100644 --- a/core/jni/android_util_AssetManager.cpp +++ b/core/jni/android_util_AssetManager.cpp @@ -901,7 +901,8 @@ static jboolean android_content_AssetManager_applyStyle(JNIEnv* env, jobject cla return JNI_FALSE; } - jint* dest = (jint*)env->GetPrimitiveArrayCritical(outValues, 0); + jint* baseDest = (jint*)env->GetPrimitiveArrayCritical(outValues, 0); + jint* dest = baseDest; if (dest == NULL) { env->ReleasePrimitiveArrayCritical(attrs, src, 0); doThrow(env, "java/lang/OutOfMemoryError"); @@ -1074,7 +1075,7 @@ static jboolean android_content_AssetManager_applyStyle(JNIEnv* env, jobject cla indices[0] = indicesIdx; env->ReleasePrimitiveArrayCritical(outIndices, indices, 0); } - env->ReleasePrimitiveArrayCritical(outValues, dest, 0); + env->ReleasePrimitiveArrayCritical(outValues, baseDest, 0); env->ReleasePrimitiveArrayCritical(attrs, src, 0); return JNI_TRUE; @@ -1112,7 +1113,8 @@ static jboolean android_content_AssetManager_retrieveAttributes(JNIEnv* env, job return JNI_FALSE; } - jint* dest = (jint*)env->GetPrimitiveArrayCritical(outValues, 0); + jint* baseDest = (jint*)env->GetPrimitiveArrayCritical(outValues, 0); + jint* dest = baseDest; if (dest == NULL) { env->ReleasePrimitiveArrayCritical(attrs, src, 0); doThrow(env, "java/lang/OutOfMemoryError"); @@ -1201,7 +1203,7 @@ static jboolean android_content_AssetManager_retrieveAttributes(JNIEnv* env, job env->ReleasePrimitiveArrayCritical(outIndices, indices, 0); } - env->ReleasePrimitiveArrayCritical(outValues, dest, 0); + env->ReleasePrimitiveArrayCritical(outValues, baseDest, 0); env->ReleasePrimitiveArrayCritical(attrs, src, 0); return JNI_TRUE; @@ -1243,7 +1245,8 @@ static jint android_content_AssetManager_retrieveArray(JNIEnv* env, jobject claz const jsize NV = env->GetArrayLength(outValues); - jint* dest = (jint*)env->GetPrimitiveArrayCritical(outValues, 0); + jint* baseDest = (jint*)env->GetPrimitiveArrayCritical(outValues, 0); + jint* dest = baseDest; if (dest == NULL) { doThrow(env, "java/lang/OutOfMemoryError"); return JNI_FALSE; @@ -1295,7 +1298,7 @@ static jint android_content_AssetManager_retrieveArray(JNIEnv* env, jobject claz res.unlock(); - env->ReleasePrimitiveArrayCritical(outValues, dest, 0); + env->ReleasePrimitiveArrayCritical(outValues, baseDest, 0); return i; } diff --git a/core/jni/android_util_Process.cpp b/core/jni/android_util_Process.cpp index 08c4f1ca61991773ddd27a197f6379745407ac32..3feccde03c311e88e8e6ba37f34cda0646b4f57b 100644 --- a/core/jni/android_util_Process.cpp +++ b/core/jni/android_util_Process.cpp @@ -88,6 +88,11 @@ jint android_os_Process_myPid(JNIEnv* env, jobject clazz) return getpid(); } +jint android_os_Process_myUid(JNIEnv* env, jobject clazz) +{ + return getuid(); +} + jint android_os_Process_myTid(JNIEnv* env, jobject clazz) { #ifdef HAVE_GETTID @@ -707,6 +712,7 @@ static jlong android_os_Process_getPss(JNIEnv* env, jobject clazz, jint pid) static const JNINativeMethod methods[] = { {"myPid", "()I", (void*)android_os_Process_myPid}, {"myTid", "()I", (void*)android_os_Process_myTid}, + {"myUid", "()I", (void*)android_os_Process_myUid}, {"getUidForName", "(Ljava/lang/String;)I", (void*)android_os_Process_getUidForName}, {"getGidForName", "(Ljava/lang/String;)I", (void*)android_os_Process_getGidForName}, {"setThreadPriority", "(II)V", (void*)android_os_Process_setThreadPriority}, diff --git a/core/jni/com_google_android_gles_jni_EGLImpl.cpp b/core/jni/com_google_android_gles_jni_EGLImpl.cpp index af0301659664bb094fe86ccef307a96de57e00ab..a985c246cfa6c246f21e80ddebe775d1cba40abb 100644 --- a/core/jni/com_google_android_gles_jni_EGLImpl.cpp +++ b/core/jni/com_google_android_gles_jni_EGLImpl.cpp @@ -332,12 +332,8 @@ jboolean jni_eglGetConfigs(JNIEnv *_env, jobject _this, jobject display, if (success && configs) { for (int i=0 ; iGetObjectArrayElement(configs, i); - if (obj == NULL) { - doThrow(_env, "java/lang/NullPointerException"); - break; - } - _env->SetIntField(obj, gConfig_EGLConfigFieldID, (jint)nativeConfigs[i]); + jobject obj = _env->NewObject(gConfig_class, gConfig_ctorID, (jint)nativeConfigs[i]); + _env->SetObjectArrayElement(configs, i, obj); } } return success; @@ -396,8 +392,7 @@ jboolean jni_eglMakeCurrent(JNIEnv *_env, jobject _this, jobject display, jobjec jstring jni_eglQueryString(JNIEnv *_env, jobject _this, jobject display, jint name) { EGLDisplay dpy = getDisplay(_env, display); const char* chars = eglQueryString(dpy, name); - return _env->NewString((const jchar *)chars, - (jsize)strlen((const char *)chars)); + return _env->NewStringUTF(chars); } jboolean jni_eglSwapBuffers(JNIEnv *_env, jobject _this, jobject display, jobject surface) { diff --git a/core/jni/com_google_android_gles_jni_GLImpl.cpp b/core/jni/com_google_android_gles_jni_GLImpl.cpp index 1cd23b0ba70f914cc5c3578d91210f5cafc473b9..9b09c9b82c0b4f9c16f5b95e25b1f872bd979e1c 100644 --- a/core/jni/com_google_android_gles_jni_GLImpl.cpp +++ b/core/jni/com_google_android_gles_jni_GLImpl.cpp @@ -35,6 +35,7 @@ static jclass bufferClass; static jclass OOMEClass; static jclass UOEClass; static jclass IAEClass; +static jclass AIOOBEClass; static jmethodID getBasePointerID; static jmethodID getBaseArrayID; static jmethodID getBaseArrayOffsetID; @@ -78,10 +79,13 @@ nativeClassInit(JNIEnv *_env, jclass glImplClass) _env->FindClass("java/lang/OutOfMemoryError"); jclass UOEClassLocal = _env->FindClass("java/lang/UnsupportedOperationException"); + jclass AIOOBEClassLocal = + _env->FindClass("java/lang/ArrayIndexOutOfBoundsException"); IAEClass = (jclass) _env->NewGlobalRef(IAEClassLocal); OOMEClass = (jclass) _env->NewGlobalRef(OOMEClassLocal); UOEClass = (jclass) _env->NewGlobalRef(UOEClassLocal); + AIOOBEClass = (jclass) _env->NewGlobalRef(AIOOBEClassLocal); } static void * @@ -526,12 +530,18 @@ android_glDrawElements__IIILjava_nio_Buffer_2 GLvoid *indices = (GLvoid *) 0; indices = (GLvoid *)getPointer(_env, indices_buf, &_array, &_remaining); + if (_remaining < count) { + _env->ThrowNew(AIOOBEClass, "remaining() < count"); + goto exit; + } glDrawElements( (GLenum)mode, (GLsizei)count, (GLenum)type, (GLvoid *)indices ); + +exit: if (_array) { releasePointer(_env, _array, indices, JNI_FALSE); } @@ -1647,20 +1657,8 @@ exit: jstring android_glGetString (JNIEnv *_env, jobject _this, jint name) { - const GLubyte * chars = glGetString((GLenum)name); - - int len = strlen((const char *)chars); - jchar * wchars = (jchar *)malloc(len * sizeof(jchar)); - if (wchars == (jchar*) 0) { - _env->ThrowNew(OOMEClass, "No space for glGetString output"); - return (jstring) 0; - } - // Copy bytes -> chars, including trailing '\0' - for (int i = 0; i <= len; i++) { - wchars[i] = (jchar) chars[i]; - } - jstring output = _env->NewString(wchars, (jsize) len); - free(wchars); + const char * chars = (const char *)glGetString((GLenum)name); + jstring output = _env->NewStringUTF(chars); return output; } /* void glHint ( GLenum target, GLenum mode ) */ diff --git a/core/jni/server/Android.mk b/core/jni/server/Android.mk index d108330fcf6b9f988ec00f5d8ee339e3e87602b0..bd08da3640fe65453e5cb2134fcd53b0aef0adcf 100644 --- a/core/jni/server/Android.mk +++ b/core/jni/server/Android.mk @@ -21,11 +21,13 @@ LOCAL_SHARED_LIBRARIES := \ libutils \ libui +ifeq ($(TARGET_SIMULATOR),true) ifeq ($(TARGET_OS),linux) ifeq ($(TARGET_ARCH),x86) LOCAL_LDLIBS += -lpthread -ldl -lrt endif endif +endif ifeq ($(WITH_MALLOC_LEAK_CHECK),true) LOCAL_CFLAGS += -DMALLOC_LEAK_CHECK diff --git a/core/jni/server/com_android_server_AlarmManagerService.cpp b/core/jni/server/com_android_server_AlarmManagerService.cpp index a81a0ff45b1e6f71083421300fd0492b858e4397..0f37921b8d714ebaf630ea20916f9c634a4119b0 100644 --- a/core/jni/server/com_android_server_AlarmManagerService.cpp +++ b/core/jni/server/com_android_server_AlarmManagerService.cpp @@ -44,6 +44,23 @@ namespace android { +static jint android_server_AlarmManagerService_setKernelTimezone(JNIEnv* env, jobject obj, jint fd, jint minswest) +{ +#if HAVE_ANDROID_OS + struct timezone tz; + + tz.tz_minuteswest = minswest; + tz.tz_dsttime = 0; + + int result = ioctl(fd, ANDROID_ALARM_SET_TIMEZONE, &tz); + if (result < 0) { + LOGE("Unable to set kernel timezone to %d: %s\n", minswest, strerror(errno)); + return -1; + } + return 0; +#endif +} + static jint android_server_AlarmManagerService_init(JNIEnv* env, jobject obj) { #if HAVE_ANDROID_OS @@ -101,6 +118,7 @@ static JNINativeMethod sMethods[] = { {"close", "(I)V", (void*)android_server_AlarmManagerService_close}, {"set", "(IIJ)V", (void*)android_server_AlarmManagerService_set}, {"waitForAlarm", "(I)I", (void*)android_server_AlarmManagerService_waitForAlarm}, + {"setKernelTimezone", "(II)I", (void*)android_server_AlarmManagerService_setKernelTimezone}, }; int register_android_server_AlarmManagerService(JNIEnv* env) diff --git a/core/jni/server/com_android_server_SensorService.cpp b/core/jni/server/com_android_server_SensorService.cpp index 37f6231535dedadb9bc58db6958368bc1cb4abd7..695a8a3898fb0ad49cf909c4a26e49ea6e2c0a70 100644 --- a/core/jni/server/com_android_server_SensorService.cpp +++ b/core/jni/server/com_android_server_SensorService.cpp @@ -23,7 +23,6 @@ namespace android { - static struct file_descriptor_offsets_t { jclass mClass; @@ -41,16 +40,26 @@ static struct parcel_file_descriptor_offsets_t * The method below are not thread-safe and not intended to be */ +static sensors_control_device_t* sSensorDevice = 0; + static jint android_init(JNIEnv *env, jclass clazz) { - return sensors_control_init(); + sensors_module_t* module; + if (hw_get_module(SENSORS_HARDWARE_MODULE_ID, (const hw_module_t**)&module) == 0) { + if (sensors_control_open(&module->common, &sSensorDevice) == 0) { + const struct sensor_t* list; + int count = module->get_sensors_list(module, &list); + return count; + } + } + return 0; } static jobject android_open(JNIEnv *env, jclass clazz) { - int fd = sensors_control_open(); + int fd = sSensorDevice->open_data_source(sSensorDevice); // new FileDescriptor() jobject filedescriptor = env->NewObject( gFileDescriptorOffsets.mClass, @@ -70,20 +79,29 @@ android_open(JNIEnv *env, jclass clazz) static jboolean android_activate(JNIEnv *env, jclass clazz, jint sensor, jboolean activate) { - uint32_t active = sensors_control_activate(activate ? sensor : 0, sensor); - return (activate && !active) ? false : true; + int active = sSensorDevice->activate(sSensorDevice, sensor, activate); + return (active<0) ? false : true; } static jint android_set_delay(JNIEnv *env, jclass clazz, jint ms) { - return sensors_control_delay(ms); + return sSensorDevice->set_delay(sSensorDevice, ms); +} + +static jint +android_data_wake(JNIEnv *env, jclass clazz) +{ + int res = sSensorDevice->wake(sSensorDevice); + return res; } + static JNINativeMethod gMethods[] = { {"_sensors_control_init", "()I", (void*) android_init }, {"_sensors_control_open", "()Landroid/os/ParcelFileDescriptor;", (void*) android_open }, {"_sensors_control_activate", "(IZ)Z", (void*) android_activate }, + {"_sensors_control_wake", "()I", (void*) android_data_wake }, {"_sensors_control_set_delay","(I)I", (void*) android_set_delay }, }; diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index 104ba8846e8e209feea13b51cd2a2a0e55c534f2..2e04885397b43704f17436e751fc22e1166e39f6 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -367,6 +367,12 @@ android:label="@string/permlab_writeSettings" android:description="@string/permdesc_writeSettings" /> + + + + + + + + + + + + @@ -873,6 +901,7 @@ @@ -880,7 +909,8 @@ + android:theme="@style/Theme.Dialog.Alert" + android:excludeFromRecents="true"> - + body { background-color: black; } a:hover { text-decoration: none; } - a:link { color: white; } - a:visited { color: white; } + a:link { color: black; } + a:visited { color: black; } + #bg { + position: fixed; + margin: 0px; + border: 0px; + padding: 0px; + left: 0px; + top: 0px; + width: 100%; + height: 100%; + overflow: hidden; + z-index: 0; + } + #main { + position: absolute; + left: 0%; + top: 0%; + width: 100%; + height: 100%; + padding: 0%; + z-index: 10; + } - - - - - - -
              - -
              - Open YouTube player -
              - -
              +

              + + + + +
              + +
              +
              +
              + + + + + + + +
              + + + +
              + +
              +
              diff --git a/core/res/res/anim/dialog_enter.xml b/core/res/res/anim/dialog_enter.xml new file mode 100644 index 0000000000000000000000000000000000000000..fd08cd03eae383e012429add18d71c51ba68e042 --- /dev/null +++ b/core/res/res/anim/dialog_enter.xml @@ -0,0 +1,29 @@ + + + + + + + diff --git a/core/res/res/anim/dialog_exit.xml b/core/res/res/anim/dialog_exit.xml new file mode 100644 index 0000000000000000000000000000000000000000..e1b7a775978fa08481c7f5e9ebd17456bcda1018 --- /dev/null +++ b/core/res/res/anim/dialog_exit.xml @@ -0,0 +1,28 @@ + + + + + + diff --git a/core/res/res/anim/input_method_enter.xml b/core/res/res/anim/input_method_enter.xml new file mode 100644 index 0000000000000000000000000000000000000000..5e8a084245b483a8a7f928f78b3165877d9ae1db --- /dev/null +++ b/core/res/res/anim/input_method_enter.xml @@ -0,0 +1,32 @@ + + + + + + + + diff --git a/core/res/res/anim/input_method_exit.xml b/core/res/res/anim/input_method_exit.xml new file mode 100644 index 0000000000000000000000000000000000000000..843cb185ebc39ebdd171117fdacae68e559fee4f --- /dev/null +++ b/core/res/res/anim/input_method_exit.xml @@ -0,0 +1,31 @@ + + + + + + + diff --git a/core/res/res/anim/search_bar_enter.xml b/core/res/res/anim/search_bar_enter.xml new file mode 100644 index 0000000000000000000000000000000000000000..ecb86c152f4529bc957e817146549cd43a245aaa --- /dev/null +++ b/core/res/res/anim/search_bar_enter.xml @@ -0,0 +1,24 @@ + + + + + + + diff --git a/core/res/res/anim/search_bar_exit.xml b/core/res/res/anim/search_bar_exit.xml new file mode 100644 index 0000000000000000000000000000000000000000..db7142eb33ba1512279edce0b330dbd6ebf1340b --- /dev/null +++ b/core/res/res/anim/search_bar_exit.xml @@ -0,0 +1,25 @@ + + + + + + + + diff --git a/core/res/res/anim/task_close_exit.xml b/core/res/res/anim/task_close_exit.xml index 7309656879ddcf7f150df5f07413c463faaa63a0..48dc31aa81213d0fec7c7e8a8081b515ccb97f99 100644 --- a/core/res/res/anim/task_close_exit.xml +++ b/core/res/res/anim/task_close_exit.xml @@ -20,5 +20,5 @@ - + diff --git a/core/res/res/anim/task_open_enter.xml b/core/res/res/anim/task_open_enter.xml index ca8a7e60991af5f0046a180e6410e757ceed19bb..e498c9da0c210b5250e410c571ff8a7c220c5799 100644 --- a/core/res/res/anim/task_open_enter.xml +++ b/core/res/res/anim/task_open_enter.xml @@ -20,5 +20,5 @@ - + diff --git a/core/res/res/drawable/btn_check_buttonless_off.png b/core/res/res/drawable/btn_check_buttonless_off.png new file mode 100755 index 0000000000000000000000000000000000000000..f8972fc458f22599dc97503835503ea4b378bd81 Binary files /dev/null and b/core/res/res/drawable/btn_check_buttonless_off.png differ diff --git a/core/res/res/drawable/btn_check_buttonless_on.png b/core/res/res/drawable/btn_check_buttonless_on.png new file mode 100755 index 0000000000000000000000000000000000000000..a10a37ae54480e0c364f6fc6290b1996aa967f7d Binary files /dev/null and b/core/res/res/drawable/btn_check_buttonless_on.png differ diff --git a/core/res/res/drawable/btn_check_off.png b/core/res/res/drawable/btn_check_off.png index 47924a3324c077cbdbcdb28da09f4a07d24f0671..56d3861542ea408e871b7003c38e36dd3b7fae61 100644 Binary files a/core/res/res/drawable/btn_check_off.png and b/core/res/res/drawable/btn_check_off.png differ diff --git a/core/res/res/drawable/btn_check_off_disable.png b/core/res/res/drawable/btn_check_off_disable.png index f131eeaba319d77224d44179c8475e3aeaeb5ad3..6c065bde1cf882359303ebfcae12a4f446d6494b 100644 Binary files a/core/res/res/drawable/btn_check_off_disable.png and b/core/res/res/drawable/btn_check_off_disable.png differ diff --git a/core/res/res/drawable/btn_check_off_disable_focused.png b/core/res/res/drawable/btn_check_off_disable_focused.png index 00ec08e533d054e97f2766cb08fbada5a4c206a4..cf23690371b733eec0f813b6d60d32cbfc926a15 100644 Binary files a/core/res/res/drawable/btn_check_off_disable_focused.png and b/core/res/res/drawable/btn_check_off_disable_focused.png differ diff --git a/core/res/res/drawable/btn_check_off_longpress.png b/core/res/res/drawable/btn_check_off_longpress.png index 2117113d8b805add07dd5761db1116ce07a328c5..c81e119960ca7fa5fe5a69b9f81f9312eaa5df7c 100644 Binary files a/core/res/res/drawable/btn_check_off_longpress.png and b/core/res/res/drawable/btn_check_off_longpress.png differ diff --git a/core/res/res/drawable/btn_check_off_pressed.png b/core/res/res/drawable/btn_check_off_pressed.png index 24793cd6109c8b9d07f0833f31d884167019f7cb..47c1a460f110f500a9de3d832594dc794e3ae90c 100644 Binary files a/core/res/res/drawable/btn_check_off_pressed.png and b/core/res/res/drawable/btn_check_off_pressed.png differ diff --git a/core/res/res/drawable/btn_check_off_selected.png b/core/res/res/drawable/btn_check_off_selected.png index c2aa44da3f81536375f47cbb41c3257412ade8f1..cf53075c0aad86c68d34ef221d1877db850d54b8 100644 Binary files a/core/res/res/drawable/btn_check_off_selected.png and b/core/res/res/drawable/btn_check_off_selected.png differ diff --git a/core/res/res/drawable/btn_check_on.png b/core/res/res/drawable/btn_check_on.png index 29764ec62da243700cacbdc36deffd0450d61fba..791ac1d92c32ec46bd745eef0c9aded20f9da024 100644 Binary files a/core/res/res/drawable/btn_check_on.png and b/core/res/res/drawable/btn_check_on.png differ diff --git a/core/res/res/drawable/btn_check_on_disable.png b/core/res/res/drawable/btn_check_on_disable.png index 9ff0072712ab2167814cfb10305ee3f156ba876c..8e9f633e13ac023c5a2433f06877bc7f7da6ae30 100644 Binary files a/core/res/res/drawable/btn_check_on_disable.png and b/core/res/res/drawable/btn_check_on_disable.png differ diff --git a/core/res/res/drawable/btn_check_on_disable_focused.png b/core/res/res/drawable/btn_check_on_disable_focused.png index 2b31a0e04febda20eb7aa5a020e79e569c77fe6c..0abb0519f7a1d96b5c892af2c6a56f63a09dfc2b 100644 Binary files a/core/res/res/drawable/btn_check_on_disable_focused.png and b/core/res/res/drawable/btn_check_on_disable_focused.png differ diff --git a/core/res/res/drawable/btn_check_on_longpress.png b/core/res/res/drawable/btn_check_on_longpress.png index 6337033a7c50e65c160d4e3c012664bcf19aa7fb..367760b9f1acf178aeafc31798bee40b10214ec5 100644 Binary files a/core/res/res/drawable/btn_check_on_longpress.png and b/core/res/res/drawable/btn_check_on_longpress.png differ diff --git a/core/res/res/drawable/btn_check_on_pressed.png b/core/res/res/drawable/btn_check_on_pressed.png index 9c1f0eb11b427e56ae18667d431019c00c8dcfc8..ee2175d04711605373602c5b92fa4507e3958be8 100644 Binary files a/core/res/res/drawable/btn_check_on_pressed.png and b/core/res/res/drawable/btn_check_on_pressed.png differ diff --git a/core/res/res/drawable/btn_check_on_selected.png b/core/res/res/drawable/btn_check_on_selected.png index 21745aae0e738dc354ed82545e402b345d696050..9356456577b43d874e8c2c05b4a556628dfc177e 100644 Binary files a/core/res/res/drawable/btn_check_on_selected.png and b/core/res/res/drawable/btn_check_on_selected.png differ diff --git a/core/res/res/drawable/btn_close.xml b/core/res/res/drawable/btn_close.xml new file mode 100644 index 0000000000000000000000000000000000000000..9d90e4b6eb52704fd9ccdb10cc20e11a4c9d8480 --- /dev/null +++ b/core/res/res/drawable/btn_close.xml @@ -0,0 +1,25 @@ + + + + + + + + + + diff --git a/core/res/res/drawable/btn_close_normal.png b/core/res/res/drawable/btn_close_normal.png new file mode 100644 index 0000000000000000000000000000000000000000..ecc4ddee6bc7a45d6d956e7ef0214214e0a10c6b Binary files /dev/null and b/core/res/res/drawable/btn_close_normal.png differ diff --git a/core/res/res/drawable/btn_close_pressed.png b/core/res/res/drawable/btn_close_pressed.png new file mode 100644 index 0000000000000000000000000000000000000000..49223c54df82173b814d6575d5ad07f2e1e6f80a Binary files /dev/null and b/core/res/res/drawable/btn_close_pressed.png differ diff --git a/core/res/res/drawable/btn_default_longpress.9.png b/core/res/res/drawable/btn_default_longpress.9.png index ba1a880e06f892a4eb8d9f9fe5e058a8176ff351..d42ae0b3456fd9f45778f964a9d99cc3a5f5599e 100644 Binary files a/core/res/res/drawable/btn_default_longpress.9.png and b/core/res/res/drawable/btn_default_longpress.9.png differ diff --git a/core/res/res/drawable/btn_default_normal.9.png b/core/res/res/drawable/btn_default_normal.9.png index 6644ad0206ae759bc7398ff6669d437822afe904..ad1634ad273e0fec4e10cf97aca1b757ac49a97a 100644 Binary files a/core/res/res/drawable/btn_default_normal.9.png and b/core/res/res/drawable/btn_default_normal.9.png differ diff --git a/core/res/res/drawable/btn_default_normal_disable.9.png b/core/res/res/drawable/btn_default_normal_disable.9.png index 27d98a9d6e724f53272313e1063e4a2db4c6cb40..a89f37d82d9a2fd1592844ef4e644c02db5a4422 100644 Binary files a/core/res/res/drawable/btn_default_normal_disable.9.png and b/core/res/res/drawable/btn_default_normal_disable.9.png differ diff --git a/core/res/res/drawable/btn_default_normal_disable_focused.9.png b/core/res/res/drawable/btn_default_normal_disable_focused.9.png index b36b2d3fab6b2c4fac873c3c5a1a70320e9dbaa5..b71dae9250fbea7e24bd00577859815d4add64a7 100644 Binary files a/core/res/res/drawable/btn_default_normal_disable_focused.9.png and b/core/res/res/drawable/btn_default_normal_disable_focused.9.png differ diff --git a/core/res/res/drawable/btn_default_pressed.9.png b/core/res/res/drawable/btn_default_pressed.9.png index 0fca4d9d9601ef561fa38857b11b2db38eee0067..f496a86b8655899d50722f642c8be51016e4cfb8 100644 Binary files a/core/res/res/drawable/btn_default_pressed.9.png and b/core/res/res/drawable/btn_default_pressed.9.png differ diff --git a/core/res/res/drawable/btn_default_selected.9.png b/core/res/res/drawable/btn_default_selected.9.png index a3f756e69412bf665591ad8093408b9e7588b6fd..c9e7e647a3e4f8ac3f8a2e788901fb64b17e505a 100644 Binary files a/core/res/res/drawable/btn_default_selected.9.png and b/core/res/res/drawable/btn_default_selected.9.png differ diff --git a/core/res/res/drawable/btn_default_small_longpress.9.png b/core/res/res/drawable/btn_default_small_longpress.9.png index 15df06f8bcdbc8f1eab0559b1770de0c492fb672..63c28c01822827e7147db92d9fab377c170a92cc 100644 Binary files a/core/res/res/drawable/btn_default_small_longpress.9.png and b/core/res/res/drawable/btn_default_small_longpress.9.png differ diff --git a/core/res/res/drawable/btn_default_small_normal.9.png b/core/res/res/drawable/btn_default_small_normal.9.png index 6726b0421a04496a9dd57abb8a8ece961fde189a..faac205a9966fd4144a0f022a0e4ffc5d5356826 100644 Binary files a/core/res/res/drawable/btn_default_small_normal.9.png and b/core/res/res/drawable/btn_default_small_normal.9.png differ diff --git a/core/res/res/drawable/btn_default_small_normal_disable.9.png b/core/res/res/drawable/btn_default_small_normal_disable.9.png index 2ead262b34a2b0b56906a2da34ea48fa4960fb77..ce4fd287e680acb005557d081e73c12a7f561e72 100644 Binary files a/core/res/res/drawable/btn_default_small_normal_disable.9.png and b/core/res/res/drawable/btn_default_small_normal_disable.9.png differ diff --git a/core/res/res/drawable/btn_default_small_normal_disable_focused.9.png b/core/res/res/drawable/btn_default_small_normal_disable_focused.9.png index d60370b0494add3c2b7f42af72442acd7be51ec6..1f04c18bd5431783301ed2d0e5c14a00c1854528 100644 Binary files a/core/res/res/drawable/btn_default_small_normal_disable_focused.9.png and b/core/res/res/drawable/btn_default_small_normal_disable_focused.9.png differ diff --git a/core/res/res/drawable/btn_default_small_pressed.9.png b/core/res/res/drawable/btn_default_small_pressed.9.png index 04cdc64fa0c018fb49898888c1ec1347eda98347..dab005bb452ff60a344cfb0cf99d9003986ea925 100644 Binary files a/core/res/res/drawable/btn_default_small_pressed.9.png and b/core/res/res/drawable/btn_default_small_pressed.9.png differ diff --git a/core/res/res/drawable/btn_default_small_selected.9.png b/core/res/res/drawable/btn_default_small_selected.9.png index 0a2b9e927de9b712b4573c534a6beabf687fa0af..5dec50465bc53c461023b42e86db2674f62efdbe 100644 Binary files a/core/res/res/drawable/btn_default_small_selected.9.png and b/core/res/res/drawable/btn_default_small_selected.9.png differ diff --git a/core/res/res/drawable/btn_dropdown_disabled.9.png b/core/res/res/drawable/btn_dropdown_disabled.9.png index dc6e6794e7171b4ff8c431cc35ab26570e95d447..529511aa1ba4ccb467006acfb6ba6b8989774a04 100644 Binary files a/core/res/res/drawable/btn_dropdown_disabled.9.png and b/core/res/res/drawable/btn_dropdown_disabled.9.png differ diff --git a/core/res/res/drawable/btn_dropdown_normal.9.png b/core/res/res/drawable/btn_dropdown_normal.9.png index 16edcec719871caf2412e892b7eacf61280c30d5..f6e9a19b3239e5526e2fd093d96a559f9d661751 100644 Binary files a/core/res/res/drawable/btn_dropdown_normal.9.png and b/core/res/res/drawable/btn_dropdown_normal.9.png differ diff --git a/core/res/res/drawable/btn_dropdown_pressed.9.png b/core/res/res/drawable/btn_dropdown_pressed.9.png index 405a5e271918d5d26c949344e88132bc7130ef9d..3bdf52d4627fde5d87fbf4f4a92d2bbdcb521b43 100644 Binary files a/core/res/res/drawable/btn_dropdown_pressed.9.png and b/core/res/res/drawable/btn_dropdown_pressed.9.png differ diff --git a/core/res/res/drawable/btn_dropdown_selected.9.png b/core/res/res/drawable/btn_dropdown_selected.9.png index 467ce8b989369debf3aded33410b2aa718dfb272..087956e4b402ed92c06f61371805d753b75f3a37 100644 Binary files a/core/res/res/drawable/btn_dropdown_selected.9.png and b/core/res/res/drawable/btn_dropdown_selected.9.png differ diff --git a/core/res/res/drawable/btn_keyboard_key.xml b/core/res/res/drawable/btn_keyboard_key.xml new file mode 100644 index 0000000000000000000000000000000000000000..45578e582f6ddef083bcd78167b26e52c6b8b43d --- /dev/null +++ b/core/res/res/drawable/btn_keyboard_key.xml @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + + + diff --git a/core/res/res/drawable/btn_keyboard_key_longpress.9.png b/core/res/res/drawable/btn_keyboard_key_longpress.9.png new file mode 100644 index 0000000000000000000000000000000000000000..a62a60de6a8cfa21c825f31bb5d2d7f4dfbc621e Binary files /dev/null and b/core/res/res/drawable/btn_keyboard_key_longpress.9.png differ diff --git a/core/res/res/drawable/btn_keyboard_key_longpress_off.9.png b/core/res/res/drawable/btn_keyboard_key_longpress_off.9.png new file mode 100644 index 0000000000000000000000000000000000000000..f03f29c03da98b412b4c7f3525424548de043559 Binary files /dev/null and b/core/res/res/drawable/btn_keyboard_key_longpress_off.9.png differ diff --git a/core/res/res/drawable/btn_keyboard_key_longpress_on.9.png b/core/res/res/drawable/btn_keyboard_key_longpress_on.9.png new file mode 100644 index 0000000000000000000000000000000000000000..90e572adce94d4995295961e9a9c8229e49bfcab Binary files /dev/null and b/core/res/res/drawable/btn_keyboard_key_longpress_on.9.png differ diff --git a/core/res/res/drawable/btn_keyboard_key_normal.9.png b/core/res/res/drawable/btn_keyboard_key_normal.9.png new file mode 100644 index 0000000000000000000000000000000000000000..5c8a94514d9bc80093b7d79c1d02dd434d4cc4a1 Binary files /dev/null and b/core/res/res/drawable/btn_keyboard_key_normal.9.png differ diff --git a/core/res/res/drawable/btn_keyboard_key_normal_off.9.png b/core/res/res/drawable/btn_keyboard_key_normal_off.9.png new file mode 100644 index 0000000000000000000000000000000000000000..e6e640a54e9ecc9ec91bac1de1c2a1ca8c0424b6 Binary files /dev/null and b/core/res/res/drawable/btn_keyboard_key_normal_off.9.png differ diff --git a/core/res/res/drawable/btn_keyboard_key_normal_on.9.png b/core/res/res/drawable/btn_keyboard_key_normal_on.9.png new file mode 100644 index 0000000000000000000000000000000000000000..ce97a44140d512a127234e8c0f92c83f86a680b0 Binary files /dev/null and b/core/res/res/drawable/btn_keyboard_key_normal_on.9.png differ diff --git a/core/res/res/drawable/btn_keyboard_key_pressed.9.png b/core/res/res/drawable/btn_keyboard_key_pressed.9.png new file mode 100755 index 0000000000000000000000000000000000000000..f2e9f04511cb6eea6c2be1e689203f543e7ac139 Binary files /dev/null and b/core/res/res/drawable/btn_keyboard_key_pressed.9.png differ diff --git a/core/res/res/drawable/btn_keyboard_key_pressed_off.9.png b/core/res/res/drawable/btn_keyboard_key_pressed_off.9.png new file mode 100644 index 0000000000000000000000000000000000000000..d541f95c9ecc885ce3a2a3827f1ad9b566bfed6d Binary files /dev/null and b/core/res/res/drawable/btn_keyboard_key_pressed_off.9.png differ diff --git a/core/res/res/drawable/btn_keyboard_key_pressed_on.9.png b/core/res/res/drawable/btn_keyboard_key_pressed_on.9.png new file mode 100644 index 0000000000000000000000000000000000000000..1cd6d459600e20f949e7a2cfa71a3b4673ebcc3f Binary files /dev/null and b/core/res/res/drawable/btn_keyboard_key_pressed_on.9.png differ diff --git a/core/res/res/drawable/btn_radio_off.png b/core/res/res/drawable/btn_radio_off.png index de865b6605017dd85dad661e6a407574d2640d5d..407632b1c0d51f94411215028a5cd8de6eac5e76 100644 Binary files a/core/res/res/drawable/btn_radio_off.png and b/core/res/res/drawable/btn_radio_off.png differ diff --git a/core/res/res/drawable/btn_radio_off_disable.png b/core/res/res/drawable/btn_radio_off_disable.png index 7fa1609a15a470b34645578b16b1131d9ac28b4d..166a9f3dfc2288a4cf3e0a6044944f59bf1c125c 100755 Binary files a/core/res/res/drawable/btn_radio_off_disable.png and b/core/res/res/drawable/btn_radio_off_disable.png differ diff --git a/core/res/res/drawable/btn_radio_off_disable_focused.png b/core/res/res/drawable/btn_radio_off_disable_focused.png index 10eb731ef8e095b5abd3c836f40ed72326ef027e..cdec0c3f6c0d4ca14b330c36f39004c7826af793 100755 Binary files a/core/res/res/drawable/btn_radio_off_disable_focused.png and b/core/res/res/drawable/btn_radio_off_disable_focused.png differ diff --git a/core/res/res/drawable/btn_radio_off_longpress.png b/core/res/res/drawable/btn_radio_off_longpress.png index 2ca7ddaa495651f786fb871ae4dd5a643e0c313d..8938ae402e1145d46a4bb89230ac655c7c31d65d 100644 Binary files a/core/res/res/drawable/btn_radio_off_longpress.png and b/core/res/res/drawable/btn_radio_off_longpress.png differ diff --git a/core/res/res/drawable/btn_radio_off_pressed.png b/core/res/res/drawable/btn_radio_off_pressed.png index 3c92a2473feea84c9f8c2111cc3d6373a3eacae6..41120ae82e21ecb650781d21282c4c2c3682a3e9 100644 Binary files a/core/res/res/drawable/btn_radio_off_pressed.png and b/core/res/res/drawable/btn_radio_off_pressed.png differ diff --git a/core/res/res/drawable/btn_radio_off_selected.png b/core/res/res/drawable/btn_radio_off_selected.png index 4c7f4f2922254033d73e4e7915eeb9f6f231e83c..8b5535d0520e34b8099c3e1af0c915c51360c173 100644 Binary files a/core/res/res/drawable/btn_radio_off_selected.png and b/core/res/res/drawable/btn_radio_off_selected.png differ diff --git a/core/res/res/drawable/btn_radio_on.png b/core/res/res/drawable/btn_radio_on.png index 01be1e30f9fc4292f0ec582355c630bc7d73a3a9..7286b312aeea0290e81f97ed3e69c4b82e5376ba 100644 Binary files a/core/res/res/drawable/btn_radio_on.png and b/core/res/res/drawable/btn_radio_on.png differ diff --git a/core/res/res/drawable/btn_radio_on_disable.png b/core/res/res/drawable/btn_radio_on_disable.png index f44267417e83116c3dd4489edc906770109e1403..26c75f8f7f0efb247b18bac0d6f2463efec3a666 100755 Binary files a/core/res/res/drawable/btn_radio_on_disable.png and b/core/res/res/drawable/btn_radio_on_disable.png differ diff --git a/core/res/res/drawable/btn_radio_on_disable_focused.png b/core/res/res/drawable/btn_radio_on_disable_focused.png index b372b31a4e0e5bd36c1e9a3f55d30356c8f328ac..12b9b91d80207932579c18fe3fbb001fa707e989 100755 Binary files a/core/res/res/drawable/btn_radio_on_disable_focused.png and b/core/res/res/drawable/btn_radio_on_disable_focused.png differ diff --git a/core/res/res/drawable/btn_radio_on_longpress.png b/core/res/res/drawable/btn_radio_on_longpress.png index e6d9f738e8b85f179053a92ba76eceb9ed8d6207..8588977a404fd047a58e927fcef3f7c866c2d40e 100644 Binary files a/core/res/res/drawable/btn_radio_on_longpress.png and b/core/res/res/drawable/btn_radio_on_longpress.png differ diff --git a/core/res/res/drawable/btn_radio_on_pressed.png b/core/res/res/drawable/btn_radio_on_pressed.png index 03779e49629ff77fbd8ebc285d5d4382b59e654b..20ce0ec0055c4b7c468eadb2622e03b0fb397a66 100644 Binary files a/core/res/res/drawable/btn_radio_on_pressed.png and b/core/res/res/drawable/btn_radio_on_pressed.png differ diff --git a/core/res/res/drawable/btn_radio_on_selected.png b/core/res/res/drawable/btn_radio_on_selected.png index ed866bd5834fc06859beeb34f9b81b1f86d230bf..ed53dc7f81ded974452e754d5e89bc3c8d9be503 100644 Binary files a/core/res/res/drawable/btn_radio_on_selected.png and b/core/res/res/drawable/btn_radio_on_selected.png differ diff --git a/core/res/res/drawable/btn_star_big_buttonless_off.png b/core/res/res/drawable/btn_star_big_buttonless_off.png new file mode 100755 index 0000000000000000000000000000000000000000..5b9cd81efd04ce4135fcf9665df2cb8e9ace52d7 Binary files /dev/null and b/core/res/res/drawable/btn_star_big_buttonless_off.png differ diff --git a/core/res/res/drawable/btn_star_big_buttonless_on.png b/core/res/res/drawable/btn_star_big_buttonless_on.png new file mode 100755 index 0000000000000000000000000000000000000000..5957c65d5e412875cdceca001d9e0b378201fa85 Binary files /dev/null and b/core/res/res/drawable/btn_star_big_buttonless_on.png differ diff --git a/core/res/res/drawable/btn_star_buttonless.xml b/core/res/res/drawable/btn_star_buttonless.xml new file mode 100644 index 0000000000000000000000000000000000000000..8d60ed238acb676d3f7b40175a0163b33ed84fb8 --- /dev/null +++ b/core/res/res/drawable/btn_star_buttonless.xml @@ -0,0 +1,51 @@ + + + + + + + + + + + diff --git a/core/res/res/drawable/ic_btn_search.png b/core/res/res/drawable/ic_btn_search.png new file mode 100644 index 0000000000000000000000000000000000000000..3f8913e2aa08439d0367487fb05a56cf0bfbb534 Binary files /dev/null and b/core/res/res/drawable/ic_btn_search.png differ diff --git a/core/res/res/drawable/ic_volume_bluetooth_ad2p.png b/core/res/res/drawable/ic_volume_bluetooth_ad2p.png new file mode 100644 index 0000000000000000000000000000000000000000..cf86ab3602474bc13cf3954da3174414fac36c96 Binary files /dev/null and b/core/res/res/drawable/ic_volume_bluetooth_ad2p.png differ diff --git a/core/res/res/drawable/ic_volume_bluetooth_in_call.png b/core/res/res/drawable/ic_volume_bluetooth_in_call.png new file mode 100644 index 0000000000000000000000000000000000000000..94801fc7cdae5dcee9ce9f40e4a1824c9c8e232a Binary files /dev/null and b/core/res/res/drawable/ic_volume_bluetooth_in_call.png differ diff --git a/core/res/res/drawable/ime_qwerty.png b/core/res/res/drawable/ime_qwerty.png new file mode 100644 index 0000000000000000000000000000000000000000..e6e5cda48df4de3ec62369b648f4ebd83a709e30 Binary files /dev/null and b/core/res/res/drawable/ime_qwerty.png differ diff --git a/core/res/res/drawable/indicator_check_mark_dark.xml b/core/res/res/drawable/indicator_check_mark_dark.xml index 9713cc4b65ced54f142bce6a92eadc6a3fc93c98..f363a2d2abb4efc5280b460a93e498e6ac2bfbb4 100644 --- a/core/res/res/drawable/indicator_check_mark_dark.xml +++ b/core/res/res/drawable/indicator_check_mark_dark.xml @@ -17,12 +17,12 @@ + android:drawable="@drawable/btn_check_buttonless_on" /> - - + android:drawable="@drawable/btn_check_buttonless_off" /> + + diff --git a/core/res/res/drawable/indicator_check_mark_light.xml b/core/res/res/drawable/indicator_check_mark_light.xml index e0129e9df7b94d7ee6eefe732553af6525d6bc30..3c8bb6cd0c19f34dac39d78aba4a887fde5b13f9 100644 --- a/core/res/res/drawable/indicator_check_mark_light.xml +++ b/core/res/res/drawable/indicator_check_mark_light.xml @@ -17,12 +17,12 @@ + android:drawable="@drawable/btn_check_buttonless_on" /> - - - + android:drawable="@drawable/btn_check_buttonless_off" /> + + + diff --git a/core/res/res/drawable/keyboard_background.9.png b/core/res/res/drawable/keyboard_background.9.png new file mode 100644 index 0000000000000000000000000000000000000000..595acc587efe6e086c9a4a61612683f27c1dc7e7 Binary files /dev/null and b/core/res/res/drawable/keyboard_background.9.png differ diff --git a/core/res/res/drawable/keyboard_key_feedback.xml b/core/res/res/drawable/keyboard_key_feedback.xml new file mode 100644 index 0000000000000000000000000000000000000000..e55854df6af653c35c2b0d3165f56e42957f6e27 --- /dev/null +++ b/core/res/res/drawable/keyboard_key_feedback.xml @@ -0,0 +1,22 @@ + + + + + + + + diff --git a/core/res/res/drawable/keyboard_key_feedback_background.9.png b/core/res/res/drawable/keyboard_key_feedback_background.9.png new file mode 100644 index 0000000000000000000000000000000000000000..2a80f096d200d5ae8a7700d7b7399be4f7743d8a Binary files /dev/null and b/core/res/res/drawable/keyboard_key_feedback_background.9.png differ diff --git a/core/res/res/drawable/keyboard_key_feedback_more_background.9.png b/core/res/res/drawable/keyboard_key_feedback_more_background.9.png new file mode 100755 index 0000000000000000000000000000000000000000..29aa285bd5446fa30710c24efe602ec948b44ea4 Binary files /dev/null and b/core/res/res/drawable/keyboard_key_feedback_more_background.9.png differ diff --git a/core/res/res/drawable/keyboard_popup_panel_background.9.png b/core/res/res/drawable/keyboard_popup_panel_background.9.png new file mode 100644 index 0000000000000000000000000000000000000000..36d75df6f9d09d5fda2692891d8e8ac04119e6c6 Binary files /dev/null and b/core/res/res/drawable/keyboard_popup_panel_background.9.png differ diff --git a/core/res/res/drawable/spinner_dropdown_background_down.9.png b/core/res/res/drawable/spinner_dropdown_background_down.9.png index 0a5e4c8eace612c0ed867b53671aa966bc644dd4..8fd22f466701691cf5f94ade8a350c8549dd9e59 100644 Binary files a/core/res/res/drawable/spinner_dropdown_background_down.9.png and b/core/res/res/drawable/spinner_dropdown_background_down.9.png differ diff --git a/core/res/res/drawable/spinner_dropdown_background_up.9.png b/core/res/res/drawable/spinner_dropdown_background_up.9.png index 240a98223cf32d9a452c06781b530c04526ef883..1354feb77621a075b3dd45a0346c56a969206e76 100644 Binary files a/core/res/res/drawable/spinner_dropdown_background_up.9.png and b/core/res/res/drawable/spinner_dropdown_background_up.9.png differ diff --git a/core/res/res/drawable/stat_notify_calibrate_compass.png b/core/res/res/drawable/stat_notify_calibrate_compass.png deleted file mode 100755 index 28bd386b9e10645831aac3e59cdb80bef28a213d..0000000000000000000000000000000000000000 Binary files a/core/res/res/drawable/stat_notify_calibrate_compass.png and /dev/null differ diff --git a/core/res/res/layout-land/icon_menu_layout.xml b/core/res/res/layout-land/icon_menu_layout.xml index 761f767045528152dec43bf3fb0720fef13ab1d8..d1b25d91382d047686575030535a280b1bba4ee8 100644 --- a/core/res/res/layout-land/icon_menu_layout.xml +++ b/core/res/res/layout-land/icon_menu_layout.xml @@ -19,5 +19,6 @@ android:layout_width="fill_parent" android:layout_height="wrap_content" android:rowHeight="65dip" - android:maxRows="1" + android:maxItems="6" + android:maxRows="2" android:maxItemsPerRow="6" /> diff --git a/core/res/res/layout-port/icon_menu_layout.xml b/core/res/res/layout-port/icon_menu_layout.xml index 05ffe106e7e34ef11d3d4e38dda501fe1f087de7..08edfcc20dceba33b1446c5484ca48f8d5c0a53a 100644 --- a/core/res/res/layout-port/icon_menu_layout.xml +++ b/core/res/res/layout-port/icon_menu_layout.xml @@ -19,5 +19,6 @@ android:layout_width="fill_parent" android:layout_height="wrap_content" android:rowHeight="65dip" - android:maxRows="2" + android:maxItems="6" + android:maxRows="3" android:maxItemsPerRow="3" /> diff --git a/core/res/res/layout/alert_dialog.xml b/core/res/res/layout/alert_dialog.xml index e3de682e24ec92403c2cff284e89869b9f39567d..cf2de055ead49354fed5b945777bce574f91821f 100644 --- a/core/res/res/layout/alert_dialog.xml +++ b/core/res/res/layout/alert_dialog.xml @@ -50,8 +50,10 @@ android:paddingTop="6dip" android:paddingRight="10dip" android:src="@drawable/ic_dialog_info" /> - diff --git a/core/res/res/layout/always_use_checkbox.xml b/core/res/res/layout/always_use_checkbox.xml index 90c9a447a8051d72b790d8b45f2e2223a4529fd1..20fc4030b594478cebad21af85f53bf114b59015 100644 --- a/core/res/res/layout/always_use_checkbox.xml +++ b/core/res/res/layout/always_use_checkbox.xml @@ -19,7 +19,9 @@ + android:layout_height="wrap_content" + android:paddingLeft="14dip" + android:paddingRight="15dip"> - - diff --git a/core/res/res/layout/icon_menu_item_layout.xml b/core/res/res/layout/icon_menu_item_layout.xml index 06f609881b1608ca85691a75b4d134a8324cc8d1..c6d94960f2b0480fcbc05c21f49815e5a70f4900 100644 --- a/core/res/res/layout/icon_menu_item_layout.xml +++ b/core/res/res/layout/icon_menu_item_layout.xml @@ -19,6 +19,8 @@ android:layout_width="fill_parent" android:layout_height="fill_parent" android:paddingBottom="1dip" - android:gravity="bottom|center_horizontal" + android:paddingLeft="3dip" + android:paddingRight="3dip" android:singleLine="true" - android:ellipsize="end" /> + android:ellipsize="marquee" + android:fadingEdge="horizontal" /> diff --git a/core/res/res/layout/input_method.xml b/core/res/res/layout/input_method.xml new file mode 100644 index 0000000000000000000000000000000000000000..ec75cf1f9184ba5f6038f40fb8065cc1e672d30f --- /dev/null +++ b/core/res/res/layout/input_method.xml @@ -0,0 +1,46 @@ + + + + + + + + + + + + + + diff --git a/core/res/res/layout/input_method_extract_view.xml b/core/res/res/layout/input_method_extract_view.xml new file mode 100644 index 0000000000000000000000000000000000000000..f8a4bdee04799bd46721b398b80b4087eff07741 --- /dev/null +++ b/core/res/res/layout/input_method_extract_view.xml @@ -0,0 +1,28 @@ + + + + + diff --git a/core/res/res/layout/keyboard_key_preview.xml b/core/res/res/layout/keyboard_key_preview.xml new file mode 100644 index 0000000000000000000000000000000000000000..a6e096b4ef2ff614f3b24e709f9116c8c89a48ae --- /dev/null +++ b/core/res/res/layout/keyboard_key_preview.xml @@ -0,0 +1,29 @@ + + + + diff --git a/core/res/res/layout/keyboard_popup_keyboard.xml b/core/res/res/layout/keyboard_popup_keyboard.xml new file mode 100644 index 0000000000000000000000000000000000000000..0cdd9da043c479d4bb9ae082ebfa96413c73920f --- /dev/null +++ b/core/res/res/layout/keyboard_popup_keyboard.xml @@ -0,0 +1,47 @@ + + + + + + + \ No newline at end of file diff --git a/core/res/res/layout/keyguard_screen_unlock_landscape.xml b/core/res/res/layout/keyguard_screen_unlock_landscape.xml index f8906435103c4ebb6f443c41a9a72748e0bc8ea6..175a3a54962158c4298b92d9b23c573e0bd097a5 100644 --- a/core/res/res/layout/keyguard_screen_unlock_landscape.xml +++ b/core/res/res/layout/keyguard_screen_unlock_landscape.xml @@ -100,6 +100,7 @@ android:layout_width="fill_parent" android:layout_height="wrap_content" android:textSize="14sp" + android:visibility="invisible" /> + + + + diff --git a/media/tests/MediaFrameworkTest/res/layout/surface_view.xml b/media/tests/MediaFrameworkTest/res/layout/surface_view.xml new file mode 100644 index 0000000000000000000000000000000000000000..c25e4760744d956787edbeb43c5c44a934b6f789 --- /dev/null +++ b/media/tests/MediaFrameworkTest/res/layout/surface_view.xml @@ -0,0 +1,43 @@ + + + + + + + + + + + + + + + diff --git a/media/tests/MediaFrameworkTest/res/raw/shortmp3.mp3 b/media/tests/MediaFrameworkTest/res/raw/shortmp3.mp3 new file mode 100644 index 0000000000000000000000000000000000000000..3af32a1561d254112fcad09b0b7454e73a464c2d Binary files /dev/null and b/media/tests/MediaFrameworkTest/res/raw/shortmp3.mp3 differ diff --git a/media/tests/MediaFrameworkTest/res/raw/testmidi.mid b/media/tests/MediaFrameworkTest/res/raw/testmidi.mid new file mode 100644 index 0000000000000000000000000000000000000000..df84e2092c7616b9afd9e4b7fac9acc1cf4527e0 Binary files /dev/null and b/media/tests/MediaFrameworkTest/res/raw/testmidi.mid differ diff --git a/media/tests/MediaFrameworkTest/res/raw/testmp3.mp3 b/media/tests/MediaFrameworkTest/res/raw/testmp3.mp3 new file mode 100644 index 0000000000000000000000000000000000000000..89c44b049087d91ab44d968ca7786dbdfa69445f Binary files /dev/null and b/media/tests/MediaFrameworkTest/res/raw/testmp3.mp3 differ diff --git a/media/tests/MediaFrameworkTest/res/values/strings.xml b/media/tests/MediaFrameworkTest/res/values/strings.xml new file mode 100644 index 0000000000000000000000000000000000000000..a24309fdc01229f1a1d7ce03be1a30fd689e0c4f --- /dev/null +++ b/media/tests/MediaFrameworkTest/res/values/strings.xml @@ -0,0 +1,5 @@ + + + mediaPlayerApiTest + Open + diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaFrameworkPerfTestRunner.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaFrameworkPerfTestRunner.java new file mode 100755 index 0000000000000000000000000000000000000000..eaaa798166ec397a897bcf7e68581415301d2a5f --- /dev/null +++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaFrameworkPerfTestRunner.java @@ -0,0 +1,51 @@ +/* + * 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.android.mediaframeworktest; + +import com.android.mediaframeworktest.performance.MediaPlayerPerformance; + +import junit.framework.TestSuite; + +import android.test.InstrumentationTestRunner; +import android.test.InstrumentationTestSuite; + + +/** + * Instrumentation Test Runner for all MediaPlayer tests. + * + * Running all tests: + * + * adb shell am instrument \ + * -w com.android.smstests.MediaPlayerInstrumentationTestRunner + */ + +public class MediaFrameworkPerfTestRunner extends InstrumentationTestRunner { + + + @Override + public TestSuite getAllTests() { + TestSuite suite = new InstrumentationTestSuite(this); + suite.addTestSuite(MediaPlayerPerformance.class); + return suite; + } + + @Override + public ClassLoader getLoader() { + return MediaFrameworkTestRunner.class.getClassLoader(); + } +} + diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaFrameworkTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaFrameworkTest.java new file mode 100644 index 0000000000000000000000000000000000000000..e65cf41975feca12637f301408e5c259ba702a8f --- /dev/null +++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaFrameworkTest.java @@ -0,0 +1,149 @@ +/* + * 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.android.mediaframeworktest; + +import android.app.Activity; +import android.content.Context; +import android.content.Intent; +import android.content.res.AssetFileDescriptor; +import android.graphics.Color; +import android.media.MediaPlayer; +import android.net.Uri; +import android.os.Bundle; +import android.provider.Downloads; +import android.util.Log; +import android.util.Log; +import android.view.KeyEvent; +import android.view.Menu; +import android.view.SurfaceHolder; +import android.view.SurfaceView; +import android.view.View.OnClickListener; +import android.view.View; +import android.view.ViewGroup; +import android.widget.Button; +import android.widget.EditText; +import android.widget.MediaController; +import android.widget.VideoView; +import com.android.mediaframeworktest.MediaNames; + +import java.io.File; +import java.io.FileDescriptor; + + +public class MediaFrameworkTest extends Activity { + + //public static Surface video_sf; + public static SurfaceView mSurfaceView; + private MediaController mMediaController; + private String urlpath; + private MediaPlayer mpmidi; + private MediaPlayer mpmp3; + private String testfilepath = "/sdcard/awb.awb"; + + public static AssetFileDescriptor midiafd; + public static AssetFileDescriptor mp3afd; + + + public MediaFrameworkTest() { + } + + + /** Called when the activity is first created. */ + @Override + public void onCreate(Bundle icicle) { + super.onCreate(icicle); + setContentView(R.layout.surface_view); + mSurfaceView = (SurfaceView)findViewById(R.id.surface_view); + ViewGroup.LayoutParams lp = mSurfaceView.getLayoutParams(); + lp.width = 320; + lp.height = 240; + mSurfaceView.setLayoutParams(lp); + mSurfaceView.getHolder().setFixedSize(320, 240); + mSurfaceView.getHolder().setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); + + //Get the midi fd + midiafd = this.getResources().openRawResourceFd(R.raw.testmidi); + + //Get the mp3 fd + mp3afd = this.getResources().openRawResourceFd(R.raw.testmp3); + } + + public void startPlayback(String filename){ + String mimetype = "audio/mpeg"; + Uri path = Uri.parse(filename); + Intent intent = new Intent(Intent.ACTION_VIEW); + intent.setDataAndType(path, mimetype); + startActivity(intent); + } + + @Override public boolean onKeyDown(int keyCode, KeyEvent event) { + switch (keyCode) { + case KeyEvent.KEYCODE_0: + MediaPlayer mp = new MediaPlayer(); + try{ + mp.setDataSource(MediaNames.VIDEO_RTSP3GP); + Log.v("emily","awb " + testfilepath); + mp.setDisplay(mSurfaceView.getHolder()); + mp.prepare(); + mp.start(); + }catch (Exception e){} + break; + + //start the music player intent with the test URL from PV + case KeyEvent.KEYCODE_1: + startPlayback(MediaNames.STREAM_MP3_1); + break; + + case KeyEvent.KEYCODE_2: + startPlayback(MediaNames.STREAM_MP3_2); + break; + + case KeyEvent.KEYCODE_3: + startPlayback(MediaNames.STREAM_MP3_3); + break; + + case KeyEvent.KEYCODE_4: + startPlayback(MediaNames.STREAM_MP3_4); + break; + + case KeyEvent.KEYCODE_5: + startPlayback(MediaNames.STREAM_MP3_5); + break; + + case KeyEvent.KEYCODE_6: + startPlayback(MediaNames.STREAM_MP3_6); + break; + + case KeyEvent.KEYCODE_7: + startPlayback(MediaNames.STREAM_MP3_7); + break; + + case KeyEvent.KEYCODE_8: + startPlayback(MediaNames.STREAM_MP3_8); + break; + + case KeyEvent.KEYCODE_9: + startPlayback(MediaNames.STREAM_MP3_9); + break; + + + + } + return super.onKeyDown(keyCode, event); + + } +} diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaFrameworkTestRunner.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaFrameworkTestRunner.java new file mode 100755 index 0000000000000000000000000000000000000000..3d3878efd21f7b5df02c2fa3cae1afdc1486e11b --- /dev/null +++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaFrameworkTestRunner.java @@ -0,0 +1,59 @@ +/* + * 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.android.mediaframeworktest; + +import com.android.mediaframeworktest.functional.MediaPlayerApiTest; +import com.android.mediaframeworktest.functional.SimTonesTest; +import com.android.mediaframeworktest.functional.MediaMetadataTest; +import com.android.mediaframeworktest.functional.CameraTest; +import com.android.mediaframeworktest.functional.MediaRecorderTest; + +import junit.framework.TestSuite; + +import android.test.InstrumentationTestRunner; +import android.test.InstrumentationTestSuite; + + +/** + * Instrumentation Test Runner for all MediaPlayer tests. + * + * Running all tests: + * + * adb shell am instrument \ + * -w com.android.smstests.MediaPlayerInstrumentationTestRunner + */ + +public class MediaFrameworkTestRunner extends InstrumentationTestRunner { + + + @Override + public TestSuite getAllTests() { + TestSuite suite = new InstrumentationTestSuite(this); + suite.addTestSuite(MediaPlayerApiTest.class); + suite.addTestSuite(SimTonesTest.class); + suite.addTestSuite(MediaMetadataTest.class); + suite.addTestSuite(CameraTest.class); + suite.addTestSuite(MediaRecorderTest.class); + return suite; + } + + @Override + public ClassLoader getLoader() { + return MediaFrameworkTestRunner.class.getClassLoader(); + } +} + diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaFrameworkUnitTestRunner.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaFrameworkUnitTestRunner.java new file mode 100755 index 0000000000000000000000000000000000000000..81d59da5c4928daa2159d6535fb7336c18993dde --- /dev/null +++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaFrameworkUnitTestRunner.java @@ -0,0 +1,91 @@ +/* + * 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.android.mediaframeworktest; + +import android.test.InstrumentationTestRunner; +import android.test.InstrumentationTestSuite; +import com.android.mediaframeworktest.unit.*; + +import junit.framework.TestSuite; + +/** + * Instrumentation Test Runner for all media framework unit tests. + * + * Make sure that MediaFrameworkUnitTestRunner has been added to + * AndroidManifest.xml file, and then "make -j4 mediaframeworktest; adb sync" + * to build and upload mediaframeworktest to the phone or emulator. + * + * Example on running all unit tests for a single class: + * adb shell am instrument -e class \ + * com.android.mediaframeworktest.unit.MediaMetadataRetrieverUnitTest \ + * -w com.android.mediaframeworktest/.MediaFrameworkUnitTestRunner + * + * Example on running all unit tests for the media framework: + * adb shell am instrument \ + * -w com.android.mediaframeworktest/.MediaFrameworkUnitTestRunner + */ + +public class MediaFrameworkUnitTestRunner extends InstrumentationTestRunner { + + @Override + public TestSuite getAllTests() { + TestSuite suite = new InstrumentationTestSuite(this); + addMediaMetadataRetrieverStateUnitTests(suite); + addMediaRecorderStateUnitTests(suite); + addMediaPlayerStateUnitTests(suite); + return suite; + } + + @Override + public ClassLoader getLoader() { + return MediaFrameworkUnitTestRunner.class.getClassLoader(); + } + + // Running all unit tests checking the state machine may be time-consuming. + private void addMediaMetadataRetrieverStateUnitTests(TestSuite suite) { + suite.addTestSuite(MediaMetadataRetrieverTest.class); + } + + // Running all unit tests checking the state machine may be time-consuming. + private void addMediaRecorderStateUnitTests(TestSuite suite) { + suite.addTestSuite(MediaRecorderPrepareStateUnitTest.class); + suite.addTestSuite(MediaRecorderResetStateUnitTest.class); + suite.addTestSuite(MediaRecorderSetAudioEncoderStateUnitTest.class); + suite.addTestSuite(MediaRecorderSetAudioSourceStateUnitTest.class); + suite.addTestSuite(MediaRecorderSetOutputFileStateUnitTest.class); + suite.addTestSuite(MediaRecorderSetOutputFormatStateUnitTest.class); + suite.addTestSuite(MediaRecorderStartStateUnitTest.class); + suite.addTestSuite(MediaRecorderStopStateUnitTest.class); + } + + // Running all unit tests checking the state machine may be time-consuming. + private void addMediaPlayerStateUnitTests(TestSuite suite) { + suite.addTestSuite(MediaPlayerGetDurationStateUnitTest.class); + suite.addTestSuite(MediaPlayerSeekToStateUnitTest.class); + suite.addTestSuite(MediaPlayerGetCurrentPositionStateUnitTest.class); + suite.addTestSuite(MediaPlayerGetVideoWidthStateUnitTest.class); + suite.addTestSuite(MediaPlayerGetVideoHeightStateUnitTest.class); + suite.addTestSuite(MediaPlayerIsPlayingStateUnitTest.class); + suite.addTestSuite(MediaPlayerResetStateUnitTest.class); + suite.addTestSuite(MediaPlayerPauseStateUnitTest.class); + suite.addTestSuite(MediaPlayerStartStateUnitTest.class); + suite.addTestSuite(MediaPlayerStopStateUnitTest.class); + suite.addTestSuite(MediaPlayerSetLoopingStateUnitTest.class); + suite.addTestSuite(MediaPlayerSetAudioStreamTypeStateUnitTest.class); + suite.addTestSuite(MediaPlayerSetVolumeStateUnitTest.class); + } +} diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaNames.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaNames.java new file mode 100755 index 0000000000000000000000000000000000000000..584300775a87ea7cef61953b28e3bd5a355abbf5 --- /dev/null +++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaNames.java @@ -0,0 +1,479 @@ +/* + * 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.android.mediaframeworktest; + +/** + * + * This class has the names of the all the activity name and variables + * in the instrumentation test. + * + */ +public class MediaNames { + + //Audio files + public static final String MP3CBR = "/sdcard/music/MP3CBR.mp3"; + public static final String MP3VBR = "/sdcard/music/MP3VBR.mp3"; + public static final String SHORTMP3 = "/sdcard/music/SHORTMP3.mp3"; + public static final String MIDI = "/sdcard/music/MIDI.mid"; + public static final String WMA9 = "/sdcard/music/WMA9.wma"; + public static final String WMA10 = "/sdcard/music/WMA10.wma"; + public static final String WAV = "/sdcard/music/complicated_wav.wav"; + public static final String AMR = "/sdcard/music/AMRNB.amr"; + public static final String OGG = "/sdcard/music/Mists_of_Time-4T.ogg"; + public static final String OGGSHORT = "/sdcard/music/Skippy.ogg"; + + public static final int MP3CBR_LENGTH = 231116; + public static final int MP3VBR_LENGTH = 126407; + public static final int SHORTMP3_LENGTH = 286; + public static final int MIDI_LENGTH = 210528; + public static final int WMA9_LENGTH = 126559; + public static final int WMA10_LENGTH = 126559; + public static final int AMR_LENGTH = 126540; + public static final int OGG_LENGTH = 40000; + public static final int SEEK_TIME = 10000; + + public static final long PAUSE_WAIT_TIME = 3000; + public static final long WAIT_TIME = 2000; + public static final long WAIT_LONG = 4000; + + //Streaming Video + public static final String VIDEO_HTTP3GP = "http://pvs.pv.com/jj/lipsync0.3gp"; + public static final String VIDEO_RTSP3GP = "rtsp://63.241.31.203/public/jj/md.3gp"; + public static final String VIDEO_RTSP3GP2 = "rtsp://pvs.pv.com/public/live_dvd1.3gp"; + public static final String VIDEO_RTSP3GP3 = + "rtsp://ehug.rtsp-youtube.l.google.com/" + + "Ci4LENy73wIaJQmeRVCJq4HuQBMYDSANFEIJbXYtZ29vZ2xlSARSB2RldGFpbHMM/0/0/0/video.3gp"; + //public static final String VIDEO_RTSP3GP = "rtsp://193.159.241.21/sp/alizee05.3gp"; + + //local video + public static final String VIDEO_MP4 = "/sdcard/video/gingerkids.MP4"; + public static final String VIDEO_LONG_3GP = "/sdcard/video/radiohead.3gp"; + public static final String VIDEO_SHORT_3GP = "/sdcard/video/short.3gp"; + public static final String VIDEO_LARGE_SIZE_3GP = "/sdcard/video/border_large.3gp"; + public static final String VIDEO_H263_AAC = "/sdcard/video/H263_AAC.3gp"; + public static final String VIDEO_H263_AMR = "/sdcard/video/H263_AMR.3gp"; + public static final String VIDEO_H264_AAC = "/sdcard/video/H264_AAC.3gp"; + public static final String VIDEO_H264_AMR = "/sdcard/video/H264_AMR.3gp"; + public static final String VIDEO_WMV = "/sdcard/video/bugs.wmv"; + public static final String VIDEO_HIGHRES_H263 = "/sdcard/video/h263_qcif_30fps.3gp"; + public static final String VIDEO_HIGHRES_MP4 = "/sdcard/video/mpeg4_qvga_24fps.3gp"; + + //ringtone + public static final String ringtone = "/sdcard/ringtones/F1_NewVoicemail.mp3"; + + //streaming mp3 + public static final String STREAM_LARGE_MP3 = + "http://wms.pv.com:7070/MediaDownloadContent/mp3/BuenaVista_04_Pueblo_Nuevo.mp3"; + public static final String STREAM_SMALL_MP3 = + "http://wms.pv.com:7070/MediaDownloadContent/mp3/ID3V2_TestFile.mp3"; + public static final String STREAM_REGULAR_MP3 = + "http://wms.pv.com:7070/MediaDownloadContent/mp3/ElectricCosmo.mp3"; + + //streaming mp3 + public static final String STREAM_MP3_1 = + "http://wms.pv.com:7070/MediaDownloadContent/mp3/chadthi_jawani_128kbps.mp3"; + public static final String STREAM_MP3_2 = + "http://wms.pv.com:7070/MediaDownloadContent/mp3/dualStereo.mp3"; + public static final String STREAM_MP3_3 = + "http://wms.pv.com:7070/mediadownloadcontent/UserUploads/15%20Keep%20Holding%20On.mp3"; + public static final String STREAM_MP3_4 = + "http://wms.pv.com:7070/mediadownloadcontent/UserUploads/1%20-%20Apologize.mp3"; + public static final String STREAM_MP3_5 = + "http://wms.pv.com:7070/mediadownloadcontent/UserUploads/" + + "03%20You're%20Gonna%20Miss%20This.mp3"; + public static final String STREAM_MP3_6 = + "http://wms.pv.com:7070/mediadownloadcontent/UserUploads" + + "/02%20Looney%20Tunes%20%C3%82%C2%B7%20Light%20Cavalry%20Overture%20(LP%20Version).mp3"; + public static final String STREAM_MP3_7 = + "http://wms.pv.com:7070/mediadownloadcontent/UserUploads" + + "/01%20Love%20Song%20(Album%20Version).mp3"; + public static final String STREAM_MP3_8 = + "http://wms.pv.com:7070/MediaDownloadContent/UserUploads/1%20-%20Apologize.mp3"; + public static final String STREAM_MP3_9 = + "http://wms.pv.com:7070/MediaDownloadContent/UserUploads" + + "/1%20-%20Smile%20(Explicit%20Version).mp3"; + public static final String STREAM_MP3_10 = + "http://wms.pv.com:7070/MediaDownloadContent/UserUploads/beefcake.mp3"; + + //Sonivox + public static String MIDIFILES[] = { "/sdcard/music/Leadsol.mxmf", + "/sdcard/music/abba.imy", "/sdcard/music/ants.mid", + "/sdcard/music/greensleeves.rtttl", "/sdcard/music/test.ota"}; + + //Performance measurement + public static String[] WAVFILES = { "/sdcard/music_perf/WAV/M1F1-AlawWE-AFsp.wav", + "/sdcard/music_perf/WAV/M1F1-float64-AFsp.wav", + "/sdcard/music_perf/WAV/song.wav", + "/sdcard/music_perf/WAV/WAVEtest.wav", + "/sdcard/music_perf/WAV/WAVEtest_out.wav", + "/sdcard/music_perf/WAV/test_out.wav"}; + + public static String[] AMRNBFILES = { + "/sdcard/music_perf/AMR/AI_AMR-NB_5.9kbps_6.24kbps_8khz_mono_NMC.amr", + "/sdcard/music_perf/AMR/AI_AMR-NB_5.15kbps_5.46kbps_8khz_mono_NMC.amr", + "/sdcard/music_perf/AMR/AI_AMR-NB_7.4kbps_7.80kbps_8khz_mono_NMC.amr", + "/sdcard/music_perf/AMR/AI_AMR-NB_7.95kbps_9.6kbps_8khz_mono_NMC.amr", + "/sdcard/music_perf/AMR/AI_AMR-NB_10.2kbps_10.48kbps_8khz_mono_NMC.amr"}; + + public static String[] AMRWBFILES = { + "/sdcard/music_perf/AMRWB/NIN_AMR-WB_15.85kbps_16kbps.amr", + "/sdcard/music_perf/AMRWB/NIN_AMR-WB_18.25kbps_18kbps.amr", + "/sdcard/music_perf/AMRWB/NIN_AMR-WB_19.85kbps_20kbps.amr", + "/sdcard/music_perf/AMRWB/NIN_AMR-WB_23.05kbps_23kbps.amr", + "/sdcard/music_perf/AMRWB/NIN_AMR-WB_23.85kbps_24kbps.amr", + "/sdcard/music_perf/AMRWB/PD_AMR-WB_19.85kbps_20kbps.amr", + "/sdcard/music_perf/AMRWB/PD_AMR-WB_23.05kbps_23kbps.amr", + "/sdcard/music_perf/AMRWB/PD_AMR-WB_23.85kbps_24kbps.amr", + "/sdcard/music_perf/AMRWB/WC_AMR-WB_23.05kbps_23kbps.amr", + "/sdcard/music_perf/AMRWB/WC_AMR-WB_23.85kbps_24kbps.amr", }; + + public static String[] MP3FILES = { + "/sdcard/music_perf/MP3/NIN_56kbps_32khz_stereo_VBR_MCA.MP3", + "/sdcard/music_perf/MP3/NIN_80kbps_32khz_stereo_VBR_MCA.mp3", + "/sdcard/music_perf/MP3/NIN_80kbps_44.1khz_stereo_VBR_MCA.mp3", + "/sdcard/music_perf/MP3/NIN_80kbps_48khz_stereo_VBR_MCA.mp3", + "/sdcard/music_perf/MP3/NIN_112kbps_32khz_stereo_VBR_MCA.mp3", + "/sdcard/music_perf/MP3/NIN_112kbps_44.1khz_stereo_VBR_MCA.mp3", + "/sdcard/music_perf/MP3/NIN_112kbps_48khz_stereo_VBR_MCA.mp3", + "/sdcard/music_perf/MP3/NIN_192kbps_32khz_mono_CBR_MCA.mp3", + "/sdcard/music_perf/MP3/NIN_192kbps_44.1khz_mono_CBR_MCA.mp3", + "/sdcard/music_perf/MP3/NIN_192kbps_48khz_mono_CBR_MCA.mp3", + "/sdcard/music_perf/MP3/NIN_256kbps_44.1khz_mono_CBR_MCA.mp3", + "/sdcard/music_perf/MP3/NIN_256kbps_48khz_mono_CBR_MCA.mp3", + "/sdcard/music_perf/MP3/PD_112kbps_32khz_stereo_VBR_MCA.mp3", + "/sdcard/music_perf/MP3/PD_112kbps_44.1khz_stereo_VBR_MCA.mp3", + "/sdcard/music_perf/MP3/PD_112kbps_48khz_stereo_VBR_MCA.mp3", + "/sdcard/music_perf/MP3/PD_192kbps_32khz_mono_CBR_DPA.mp3", + "/sdcard/music_perf/MP3/PD_256kbps_44.1khz_mono_CBR_DPA.mp3", + "/sdcard/music_perf/MP3/PD_256kbps_48khz_mono_CBR_MCA.mp3", + "/sdcard/music_perf/MP3/WC_256kbps_44.1khz_mono_CBR_DPA.mp3", + "/sdcard/music_perf/MP3/WC_256kbps_48khz_mono_CBR_DPA.mp3", + "/sdcard/music_perf/regular_album_photo/Apologize.mp3", + "/sdcard/music_perf/regular_album_photo/Because_Of_You.mp3", + "/sdcard/music_perf/regular_album_photo/Complicated.mp3", + "/sdcard/music_perf/regular_album_photo/Glamorous.mp3", + "/sdcard/music_perf/regular_album_photo/Im_With_You.mp3", + "/sdcard/music_perf/regular_album_photo/Smile.mp3", + "/sdcard/music_perf/regular_album_photo/Suddenly_I_See.mp3", + "/sdcard/music_perf/regular_album_photo/When You Say Nothing At All.mp3", + "/sdcard/music_perf/regular_album_photo/my_happy_ending.mp3"}; + + public static String[] AACFILES = { + "/sdcard/music_perf/AAC/AI_AAC_24kbps_12khz_Mono_1pCBR_SSE.mp4", + "/sdcard/music_perf/AAC/AI_AAC_56kbps_22.05khz_Stereo_1pCBR_SSE.mp4", + "/sdcard/music_perf/AAC/AI_AAC_56kbps_32khz_Stereo_CBR_SSE.mp4", + "/sdcard/music_perf/AAC/AI_AAC_56kbps_44.1khz_Stereo_1pCBR_SSE.mp4", + "/sdcard/music_perf/AAC/AI_AAC_80kbps_32khz_Stereo_1pCBR_SSE.mp4", + "/sdcard/music_perf/AAC/AI_AAC_80kbps_32khz_Stereo_CBR_SSE.mp4", + "/sdcard/music_perf/AAC/NIN_AAC_56kbps_22.05khz_Stereo_1pCBR_SSE.mp4", + "/sdcard/music_perf/AAC/NIN_AAC_56kbps_32khz_Stereo_CBR_SSE.mp4", + "/sdcard/music_perf/AAC/NIN_AAC_56kbps_44.1khz_Stereo_1pCBR_SSE.mp4", + "/sdcard/music_perf/AAC/NIN_AAC_80kbps_32khz_Stereo_1pCBR_SSE.mp4", + "/sdcard/music_perf/AAC/NIN_AAC_80kbps_32khz_Stereo_CBR_SSE.mp4", + "/sdcard/music_perf/AAC/PD_AAC_56kbps_22.05khz_Stereo_1pCBR_SSE.mp4", + "/sdcard/music_perf/AAC/PD_AAC_56kbps_32khz_Stereo_CBR_SSE.mp4", + "/sdcard/music_perf/AAC/PD_AAC_56kbps_44.1khz_Stereo_1pCBR_SSE.mp4", + "/sdcard/music_perf/AAC/PD_AAC_80kbps_32khz_Stereo_1pCBR_SSE.mp4", + "/sdcard/music_perf/AAC/PD_AAC_80kbps_32khz_Stereo_CBR_SSE.mp4", + "/sdcard/music_perf/AAC/PV_AAC_56kbps_22.05khz_Stereo_1pCBR_SSE.mp4", + "/sdcard/music_perf/AAC/PV_AAC_56kbps_32khz_Stereo_CBR_SSE.mp4", + "/sdcard/music_perf/AAC/PV_AAC_56kbps_44.1khz_Stereo_1pCBR_SSE.mp4", + "/sdcard/music_perf/AAC/PV_AAC_80kbps_32khz_Stereo_1pCBR_SSE.mp4", + "/sdcard/music_perf/AAC/PV_AAC_80kbps_32khz_Stereo_CBR_SSE.mp4", + "/sdcard/music_perf/AAC/WC_AAC_56kbps_22.05khz_Stereo_1pCBR_SSE.mp4", + "/sdcard/music_perf/AAC/WC_AAC_56kbps_32khz_Stereo_CBR_SSE.mp4", + "/sdcard/music_perf/AAC/WC_AAC_56kbps_44.1khz_Stereo_1pCBR_SSE.mp4", + "/sdcard/music_perf/AAC/WC_AAC_80kbps_32khz_Stereo_1pCBR_SSE.mp4", + "/sdcard/music_perf/AAC/WC_AAC_80kbps_32khz_Stereo_CBR_SSE.mp4", + }; + + public static String[] VIDEOFILES = { "/sdcard/video_perf/AI_CTO_Mpeg4_32kbps_10fps_SQCIF_128x96+AAC_8kbps_8khz_mono_QTE.mp4", + "/sdcard/video_perf/AI_CTO_Mpeg4_32kbps_12fps_SQCIF_128x96+AAC_8kbps_8khz_mono_QTE.mp4", + "/sdcard/video_perf/AI_CTO_Mpeg4_32kbps_15fps_SQCIF_128x96+AAC_8kbps_8khz_mono_QTE.mp4", + "/sdcard/video_perf/AI_CTO_Mpeg4_32kbps_5fps_SQCIF_128x96+AAC_8kbps_8khz_mono_QTE.mp4", + "/sdcard/video_perf/AI_CTO_Mpeg4_32kbps_5fps_SQCIF_128x96+AAC_8kbps_8khz_mono_SSE.mp4", + "/sdcard/video_perf/AI_CTO_Mpeg4_32kbps_7.5fps_SQCIF_128x96+AAC_8kbps_8khz_mono_QTE.mp4", + "/sdcard/video_perf/AI_WMV_1024kbps_20fps_QCIF_176x144_noaudio_SSE.wmv", + "/sdcard/video_perf/AI_WMV_1024kbps_25fps_QCIF_176x144_noaudio_SSE.wmv", + "/sdcard/video_perf/Chicken.wmv", + "/sdcard/video_perf/MP_qcif_15fps_100kbps_48kHz_192kbps_30secs.wmv", + "/sdcard/video_perf/NIN_CTO_H264_123kbps_5fps_QCIF_176x144+AMR_12.2kbps_8khz_mono_QTE.3gp", + "/sdcard/video_perf/NIN_CTO_H264_96kbps_10.2fps_QCIF_176x144+AMR_12.2kbps_8khz_mono_QTE.3gp", + "/sdcard/video_perf/NIN_CTO_H264_96kbps_12fps_QCIF_176x144+AMR_12.2kbps_8khz_mono_QTE.3gp", + "/sdcard/video_perf/NIN_CTO_H264_96kbps_15fps_QCIF_176x144+AMR_12.2kbps_8khz_mono_QTE.3gp", + "/sdcard/video_perf/NIN_CTO_Mpeg4_123kbps_15fps_QCIF_176x144+AAC_32kbps_22khz_mono_SSE.3gp", + "/sdcard/video_perf/NIN_CTO_Mpeg4_123kbps_7.5fps_QCIF_176x144+AAC_32kbps_22khz_stereo_SSE.3gp", + "/sdcard/video_perf/NIN_CTO_Mpeg4_128kbps_10fps_QCIF_176x144+AAC+_32kbps_48khz_stereo_SSE.3gp", + "/sdcard/video_perf/NIN_CTO_Mpeg4_128kbps_12fps_QCIF_176x144+AAC+_32kbps_48khz_stereo_SSE.3gp", + "/sdcard/video_perf/NIN_CTO_Mpeg4_128kbps_15fps_QCIF_176x144+AAC+_32kbps_48khz_stereo_SSE.3gp", + "/sdcard/video_perf/NIN_CTO_Mpeg4_128kbps_5fps_QCIF_176x144+AAC+_32kbps_48khz_stereo_SSE.3gp", + "/sdcard/video_perf/NIN_CTO_Mpeg4_128kbps_7.5fps_QCIF_176x144+AAC+_32kbps_48khz_stereo_SSE.3gp", + "/sdcard/video_perf/NIN_H263_128kbps_10fps_QCIF_174x144_noaudio_SSE.mp4", + "/sdcard/video_perf/NIN_H263_128kbps_15fps_QCIF_174x144_noaudio_SSE.mp4", + "/sdcard/video_perf/NIN_H263_48kbps_10fps_QCIF_174x144_noaudio_SSE.3gp", + "/sdcard/video_perf/NIN_H263_48kbps_12fps_QCIF_174x144_noaudio_SSE.3gp", + "/sdcard/video_perf/NIN_H264_123kbps_15fps_QCIF_176x144+AAC_32kbps_22khz_stereo_SSE.3gp", + "/sdcard/video_perf/NIN_H264_123kbps_7.5fps_QCIF_176x144+AAC_32kbps_22khz_stereo_SSE.3gp", + "/sdcard/video_perf/PV_H264_2000kbps_20fps_CIF_352x288+AAC_96kbps_48khz_stereo_SSE.mp4", + "/sdcard/video_perf/PV_H264_2000kbps_25fps_CIF_352x288+AAC_96kbps_48khz_stereo_SSE.mp4", + "/sdcard/video_perf/PV_H264_2000kbps_30fps_CIF_352x288+AAC_128kbps_48khz_stereo_SSE.mp4", + "/sdcard/video_perf/Stevie-1.wmv", + "/sdcard/video_perf/WC_H264_1600kbps_20fps_QCIF_176x144+AAC_96kbps_48khz_mono_SSE.mp4", + "/sdcard/video_perf/WC_H264_1600kbps_25fps_QCIF_176x144+AAC_96kbps_48khz_mono_SSE.mp4", + "/sdcard/video_perf/WC_H264_1600kbps_30fps_QCIF_176x144+AAC_96kbps_48khz_mono_SSE.mp4", + "/sdcard/video_perf/bugs.wmv", + "/sdcard/video_perf/niceday.wmv", + "/sdcard/video_perf/eaglesatopnflpe.wmv", + + }; + + //wma - only support up to wma 9 + public static String[] WMASUPPORTED = { + "/sdcard/music_perf/WMASUPPORTED/AI_WMA9.2_32kbps_44.1khz_mono_CBR_DPA.wma", + "/sdcard/music_perf/WMASUPPORTED/AI_WMA9.2_48kbps_44.1khz_mono_CBR_DPA.wma", + "/sdcard/music_perf/WMASUPPORTED/NIN_WMA9.2_32kbps_44.1khz_mono_CBR_DPA.wma", + "/sdcard/music_perf/WMASUPPORTED/NIN_WMA9.2_48kbps_44.1khz_mono_CBR_DPA.wma", + "/sdcard/music_perf/WMASUPPORTED/PD_WMA9.2_32kbps_44.1khz_mono_CBR_DPA.wma", + "/sdcard/music_perf/WMASUPPORTED/PD_WMA9.2_48kbps_44.1khz_mono_CBR_DPA.wma", + "/sdcard/music_perf/WMASUPPORTED/PV_WMA9.2_32kbps_44.1khz_mono_CBR_DPA.wma", + "/sdcard/music_perf/WMASUPPORTED/PV_WMA9.2_48kbps_44.1khz_mono_CBR_DPA.wma", + "/sdcard/music_perf/WMASUPPORTED/WC_WMA9.2_32kbps_44.1khz_mono_CBR_DPA.wma", + "/sdcard/music_perf/WMASUPPORTED/WC_WMA9.2_48kbps_44.1khz_mono_CBR_DPA.wma" + + }; + + public static String[] WMAUNSUPPORTED = { + "/sdcard/music_perf/WMAUNSUPPORTED/AI_WMA10_127kbps_48khz_stereo_CBR_DPA.wma", + "/sdcard/music_perf/WMAUNSUPPORTED/AI_WMA10_128kbps_44.1khz_stereo_2pVBR_DPA.wma", + "/sdcard/music_perf/WMAUNSUPPORTED/AI_WMA10_128kbps_48khz_stereo_2pVBR_DPA.wma", + "/sdcard/music_perf/WMAUNSUPPORTED/AI_WMA10_128kbps_88khz_stereo_CBR_DPA.wma", + "/sdcard/music_perf/WMAUNSUPPORTED/AI_WMA10_128kbps_96khz_stereo_CBR_DPA.wma", + "/sdcard/music_perf/WMAUNSUPPORTED/AI_WMA10_192kbps_44.1khz_stereo_2pVBR_DPA.wma", + "/sdcard/music_perf/WMAUNSUPPORTED/AI_WMA10_192kbps_88khz_stereo_CBR_DPA.wma", + "/sdcard/music_perf/WMAUNSUPPORTED/AI_WMA10_192kbps_96khz_stereo_CBR_DPA.wma", + "/sdcard/music_perf/WMAUNSUPPORTED/AI_WMA10_256kbps_44khz_stereo_CBR_DPA.wma", + "/sdcard/music_perf/WMAUNSUPPORTED/AI_WMA10_256kbps_48khz_stereo_CBR_DPA.wma", + "/sdcard/music_perf/WMAUNSUPPORTED/AI_WMA10_256kbps_88khz_stereo_CBR_DPA.wma", + "/sdcard/music_perf/WMAUNSUPPORTED/AI_WMA10_256kbps_96khz_stereo_CBR_DPA.wma", + "/sdcard/music_perf/WMAUNSUPPORTED/AI_WMA10_384kbps_44khz_stereo_CBR_DPA.wma", + "/sdcard/music_perf/WMAUNSUPPORTED/AI_WMA10_384kbps_48khz_stereo_CBR_DPA.wma", + "/sdcard/music_perf/WMAUNSUPPORTED/AI_WMA10_384kbps_88khz_stereo_CBR_DPA.wma" + }; + + //Media Recorder + public static final String RECORDER_OUTPUT = "/sdcard/recorderOutput.amr"; + + //video thumbnail + public static final String THUMBNAIL_OUTPUT = "/sdcard/videoThumbnail.png"; + public static final String GOLDEN_THUMBNAIL_OUTPUT = "/sdcard/goldenThumbnail.png"; + + //Metadata Utility + public static final String[] THUMBNAIL_CAPTURE_TEST_FILES = { + "/sdcard/metadata/test.mp4", + "/sdcard/metadata/test1.3gp", + "/sdcard/metadata/test2.3gp", + "/sdcard/metadata/test3.3gp", + "/sdcard/metadata/test4.3gp", + "/sdcard/metadata/test5.3gp", + "/sdcard/metadata/test6.3gp", + "/sdcard/metadata/test7.3gp", + "/sdcard/metadata/test8.3gp", + "/sdcard/metadata/test9.3gp", + "/sdcard/metadata/test10.3gp", + "/sdcard/metadata/test11.3gp", + "/sdcard/metadata/test12.3gp", + "/sdcard/metadata/test13.3gp", + "/sdcard/metadata/test14.3gp", + "/sdcard/metadata/test15.3gp", + "/sdcard/metadata/test16.3gp", + "/sdcard/metadata/test17.3gp", + "/sdcard/metadata/test18.3gp", + "/sdcard/metadata/test19.3gp", + "/sdcard/metadata/test20.3gp", + "/sdcard/metadata/test21.3gp", + "/sdcard/metadata/test22.3gp", + "/sdcard/metadata/test23.3gp", + "/sdcard/metadata/test24.3gp", + "/sdcard/metadata/test25.3gp", + "/sdcard/metadata/test26.3gp", + "/sdcard/metadata/test27.3gp", + "/sdcard/metadata/test28.3gp", + "/sdcard/metadata/test29.3gp", + "/sdcard/metadata/test30.3gp", + "/sdcard/metadata/test31.3gp", + "/sdcard/metadata/test32.3gp", + "/sdcard/metadata/test33.3gp", + "/sdcard/metadata/test35.mp4", + "/sdcard/metadata/test36.m4v", + "/sdcard/metadata/test34.wmv", + "/sdcard/metadata/test_metadata.mp4", + }; + + public static final String[] METADATA_RETRIEVAL_TEST_FILES = { + // Raw AAC is not supported + // "/sdcard/test_raw.aac", + // "/sdcard/test_adts.aac", + // "/sdcard/test_adif.aac", + "/sdcard/metadata/test_metadata.mp4", + "/sdcard/metadata/WMA10.wma", + "/sdcard/metadata/Leadsol_out.wav", + "/sdcard/metadata/test_aac.mp4", + "/sdcard/metadata/test_amr.mp4", + "/sdcard/metadata/test_avc_amr.mp4", + "/sdcard/metadata/test_metadata.mp4", + "/sdcard/metadata/test_vbr.mp3", + "/sdcard/metadata/test_cbr.mp3", + "/sdcard/metadata/metadata_test1.mp3", + "/sdcard/metadata/test33.3gp", + "/sdcard/metadata/test35.mp4", + "/sdcard/metadata/test36.m4v", + "/sdcard/metadata/test_m4v_amr.mp4", + "/sdcard/metadata/test_h263_amr.mp4", + "/sdcard/metadata/test34.wmv", + }; + + public static final String[] ALBUMART_TEST_FILES = { + "/sdcard/album_photo/test_22_16_mp3.mp3", + "/sdcard/album_photo/PD_256kbps_48khz_mono_CBR_MCA.mp3", + "/sdcard/album_photo/PD_256kbps_44.1khz_mono_CBR_DPA.mp3", + "/sdcard/album_photo/PD_192kbps_32khz_mono_CBR_DPA.mp3", + "/sdcard/album_photo/NIN_256kbps_48khz_mono_CBR_MCA.mp3", + "/sdcard/album_photo/NIN_256kbps_44.1khz_mono_CBR_MCA.mp3", + "/sdcard/album_photo/NIN_112kbps(96kbps)_48khz_stereo_VBR_MCA.mp3", + "/sdcard/album_photo/NIN_112kbps(96kbps)_44.1khz_stereo_VBR_MCA.mp3", + "/sdcard/album_photo/lightGreen1.mp3", + "/sdcard/album_photo/babyBlue2 1.mp3", + "/sdcard/album_photo/2-01 01 NIN_56kbps(64kbps)_32khz_stereo_VBR_MCA.mp3", + "/sdcard/album_photo/02_NIN_112kbps(80kbps)_32khz_stereo_VBR_MCA.mp3", + "/sdcard/album_photo/No_Woman_No_Cry_128K.wma", + "/sdcard/album_photo/Beethoven_2.wma", + }; + + //TEST_PATH_1: is a video and contains metadata for key "num-tracks" + // TEST_PATH_2: any valid media file. + // TEST_PATH_3: invalid media file + public static final String TEST_PATH_1 = "/sdcard/metadata/test.mp4"; + public static final String TEST_PATH_3 = "/sdcard/data.txt"; + public static final String TEST_PATH_4 = "somenonexistingpathname"; + public static final String TEST_PATH_5 = "mem://012345"; + + //Meta data expected result + //The expected tag result in the following order + //cd_track_number, album, artist, author, composer, date, genre + //title, years, duration + public static final String META_DATA_MP3 [][] = { + {"/sdcard/metaDataTestMedias/MP3/ID3V1_ID3V2.mp3", "1/10", "ID3V2.3 Album", "ID3V2.3 Artist", + "ID3V2.3 Lyricist", "ID3V2.3 Composer", null, "Blues", + "ID3V2.3 Title", "1234", "321", "1"}, + {"/sdcard/metaDataTestMedias/MP3/ID3V2.mp3", "1/10", "ID3V2.3 Album", "ID3V2.3 Artist", + "ID3V2.3 Lyricist", "ID3V2.3 Composer", null, "Blues", + "ID3V2.3 Title", "1234", "313", "1"}, + {"/sdcard/metaDataTestMedias/MP3/ID3V1.mp3", null, "test ID3V1 Album", "test ID3V1 Artist", + null, null, null, null, "test ID3V1 Title", "1234", "231332", "1"}, + {"/sdcard/metaDataTestMedias/MP3/Corrupted_ID3V1.mp3" , null, null, null, + null, null, null, null, null, null, "231330", "1"}, + //The corrupted TALB field in id3v2 would not switch to id3v1 tag automatically + {"/sdcard/metaDataTestMedias/MP3/Corrupted_ID3V2_TALB.mp3", "01", null, "ID3V2.3 Artist", + "ID3V2.3 Lyricist", "ID3V2.3 Composer", null, + "Blues", "ID3V2.3 Title", "1234", "321", "1"}, + {"/sdcard/metaDataTestMedias/MP3/Corrupted_ID3V2_TCOM.mp3", "01", "ID3V2.3 Album", + "ID3V2.3 Artist", "ID3V2.3 Lyricist", null, null, + "Blues", "ID3V2.3 Title", "1234", "321", "1"}, + {"/sdcard/metaDataTestMedias/MP3/Corrupted_ID3V2_TCOM_2.mp3", "01", "ID3V2.3 Album", + "ID3V2.3 Artist", null, null, null, "Blues", "ID3V2.3 Title", "1234", "321", "1"}, + {"/sdcard/metaDataTestMedias/MP3/Corrupted_ID3V2_TRCK.mp3", "dd", "ID3V2.3 Album", + "ID3V2.3 Artist", "ID3V2.3 Lyricist", "ID3V2.3 Composer", null, + "Blues", "ID3V2.3 Title", "1234", "321", "1"}, + {"/sdcard/metaDataTestMedias/MP3/Corrupted_ID3V2_TRCK_2.mp3", "01", "ID3V2.3 Album", + "ID3V2.3 Artist", null, null, null, null, "ID3V2.3 Title", null, "321", "1"}, + {"/sdcard/metaDataTestMedias/MP3/Corrupted_ID3V2_TYER.mp3", "01", "ID3V2.3 Album", + "ID3V2.3 Artist", null, null, null, null, "ID3V2.3 Title", "9999", "321", "1"}, + {"/sdcard/metaDataTestMedias/MP3/Corrupted_ID3V2_TYER_2.mp3", "01", "ID3V2.3 Album", + "ID3V2.3 Artist", "ID3V2.3 Lyricist", "ID3V2.3 Composer", null, + "Blues", "ID3V2.3 Title", null, "321", "1"}, + {"/sdcard/metaDataTestMedias/MP3/Corrupted_ID3V2_TIT.mp3", null, null, null, + null, null, null, null, null, null, "577", "1"} + }; + + public static final String META_DATA_OTHERS [][] = { + {"/sdcard/metaDataTestMedias/3GP/cat.3gp", null, null, null, + null, null, "20080309T002415.000Z", null, + null, null, "1404928", "2"}, + {"/sdcard/metaDataTestMedias/AMR/AMR_NB.amr", null, null, null, + null, null, null, null, + null, null, "126540", "1"}, + {"/sdcard/metaDataTestMedias/AMRWB/AMR_WB.amr", null, null, null, + null, null, null, null, + null, null, "231180", "1"}, + {"/sdcard/metaDataTestMedias/M4A/Jaws Of Life_ver1.m4a", null, "Suspended Animation", + "John Petrucci", null, null, "20070510T125223.000Z", + null, null, "2005", "231180", "1"}, + {"/sdcard/metaDataTestMedias/M4V/sample_iPod.m4v", null, null, + null, null, null, "20051220T202015.000Z", + null, null, null, "3771392", "2"}, + {"/sdcard/metaDataTestMedias/MIDI/MIDI.mid", null, "Suspended Animation", + "John Petrucci", null, null, "20070510T125223.000Z", + null, null, "2005", "231180", "1"}, + {"/sdcard/metaDataTestMedias/MP4/kung_fu_panda_h264.mp4", null, "mp4 album Kung Fu Panda", + "mp4 artist Kung Fu Panda", null, null, "20080517T091451.000Z", + "Kung Fu Panda", "Kung Fu Panda", "2008", "5667840", "2"}, + {"/sdcard/metaDataTestMedias/OGG/Ring_Classic_02.ogg", null, "Suspended Animation", + "John Petrucci", null, null, "20070510T125223.000Z", + null, null, "2005", "231180", "1"}, + {"/sdcard/metaDataTestMedias/OGG/When You Say Nothing At All.ogg", + null, "Suspended Animation", "John Petrucci", + null, null, "20070510T125223.000Z", null, null, "2005", "231180", "1"}, + {"/sdcard/metaDataTestMedias/WAV/Im With You.wav", null, null, + null, null, null, null, + null, null, null, "224000", "1"}, + {"/sdcard/metaDataTestMedias/WMA/WMA9.wma", "6", "Ten Songs in the Key of Betrayal", + "Alien Crime Syndicate", "Alien Crime Syndicate", + "wma 9 Composer", "20040521T175729.483Z", + "Rock", "Run for the Money", "2004", "134479", "1"}, + {"/sdcard/metaDataTestMedias/WMA/WMA10.wma", "09", "wma 10 Album", + "wma 10 Album Artist", "wma 10 Artist", "wma 10 Composer", "20070705T063625.097Z", + "Acid Jazz", "wma 10 Title", "2010", "126574", "1"}, + {"/sdcard/metaDataTestMedias/WMV/bugs.wmv", "8", "wmv 9 Album", + null, "wmv 9 Artist ", null, "20051122T155247.540Z", + null, "Looney Tunes - Hare-Breadth Hurry", "2005", "193482", "2"}, + {"/sdcard/metaDataTestMedias/WMV/clips_ver7.wmv", "50", "wmv 7 Album", + null, "Hallau Shoots & Company", null, "20020226T170045.891Z", + null, "CODEC Shootout", "1986", "43709", "2"} + }; + + //output recorded video + + public static final String RECORDED_HVGA_H263 = "/sdcard/HVGA_H263.3gp"; + public static final String RECORDED_QVGA_H263 = "/sdcard/QVGA_H263.3gp"; + public static final String RECORDED_SQVGA_H263 = "/sdcard/SQVGA_H263.3gp"; + public static final String RECORDED_CIF_H263 = "/sdcard/CIF_H263.3gp"; + public static final String RECORDED_QCIF_H263 = "/sdcard/QCIF_H263.3gp"; + + public static final String RECORDED_HVGA_MP4 = "/sdcard/HVGA_mp4.mp4"; + public static final String RECORDED_QVGA_MP4 = "/sdcard/QVGA_mp4.mp4"; + public static final String RECORDED_SQVGA_MP4 = "/sdcard/SQVGA_mp4.mp4"; + public static final String RECORDED_CIF_MP4 = "/sdcard/CIF_mp4.mp4"; + public static final String RECORDED_QCIF_MP4 = "/sdcard/QCIF_mp4.mp4"; + + public static final String RECORDED_VIDEO_3GP = "/sdcard/temp.3gp"; + + + public static final long RECORDED_TIME = 3000; + public static final long VALID_VIDEO_DURATION = 2000; + + +} diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/CameraTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/CameraTest.java new file mode 100644 index 0000000000000000000000000000000000000000..5981a1395b42d6fd3fd6e3d38e252f53dfe25870 --- /dev/null +++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/CameraTest.java @@ -0,0 +1,260 @@ +/* + * 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.android.mediaframeworktest.functional; + +import com.android.mediaframeworktest.MediaFrameworkTest; +import com.android.mediaframeworktest.MediaNames; + +import java.io.*; + +import android.content.Context; +import android.hardware.Camera; +import android.hardware.Camera.PictureCallback; +import android.hardware.Camera.PreviewCallback; +import android.hardware.Camera.ShutterCallback; +import android.test.ActivityInstrumentationTestCase; +import android.util.Log; +import android.view.SurfaceHolder; + +import android.os.Looper; + +import android.test.suitebuilder.annotation.LargeTest; + +/** + * Junit / Instrumentation test case for the camera api + + */ +public class CameraTest extends ActivityInstrumentationTestCase { + private String TAG = "CameraTest"; + + private boolean rawPreviewCallbackResult = false; + private boolean shutterCallbackResult = false; + private boolean rawPictureCallbackResult = false; + private boolean jpegPictureCallbackResult = false; + + private static int WAIT_FOR_COMMAND_TO_COMPLETE = 10000; // Milliseconds. + + private RawPreviewCallback mRawPreviewCallback = new RawPreviewCallback(); + private TestShutterCallback mShutterCallback = new TestShutterCallback(); + private RawPictureCallback mRawPictureCallback = new RawPictureCallback(); + private JpegPictureCallback mJpegPictureCallback = new JpegPictureCallback(); + + private boolean mInitialized = false; + private Looper mLooper = null; + private final Object lock = new Object(); + private final Object previewDone = new Object(); + + Camera mCamera; + Context mContext; + + public CameraTest() { + super("com.android.mediaframeworktest", MediaFrameworkTest.class); + } + + protected void setUp() throws Exception { + super.setUp(); + } + + /* + * Initializes the message looper so that the Camera object can + * receive the callback messages. + */ + private void initializeMessageLooper() { + Log.v(TAG, "start looper"); + new Thread() { + @Override + public void run() { + // Set up a looper to be used by camera. + Looper.prepare(); + Log.v(TAG, "start loopRun"); + // Save the looper so that we can terminate this thread + // after we are done with it. + mLooper = Looper.myLooper(); + mCamera = Camera.open(); + synchronized (lock) { + mInitialized = true; + lock.notify(); + } + Looper.loop(); // Blocks forever until Looper.quit() is called. + Log.v(TAG, "initializeMessageLooper: quit."); + } + }.start(); + } + + /* + * Terminates the message looper thread. + */ + private void terminateMessageLooper() { + mLooper.quit(); + mCamera.release(); + } + + //Implement the previewCallback + private final class RawPreviewCallback implements PreviewCallback { + public void onPreviewFrame(byte [] rawData, Camera camera) { + Log.v(TAG, "Preview callback start"); + int rawDataLength = 0; + if (rawData != null) { + rawDataLength = rawData.length; + } + if (rawDataLength > 0) { + rawPreviewCallbackResult = true; + } else { + rawPreviewCallbackResult = false; + } + synchronized (previewDone) { + Log.v(TAG, "notify the preview callback"); + previewDone.notify(); + } + + Log.v(TAG, "Preview callback stop"); + } + }; + + //Implement the shutterCallback + private final class TestShutterCallback implements ShutterCallback { + public void onShutter() { + shutterCallbackResult = true; + Log.v(TAG, "onShutter called"); + } + }; + + //Implement the RawPictureCallback + private final class RawPictureCallback implements PictureCallback { + public void onPictureTaken(byte [] rawData, Camera camera) { + if (rawData != null) { + rawPictureCallbackResult = true; + } else { + rawPictureCallbackResult = false; + } + Log.v(TAG, "RawPictureCallback callback"); + } + }; + + //Implement the JpegPictureCallback + private final class JpegPictureCallback implements PictureCallback { + public void onPictureTaken(byte [] rawData, Camera camera) { + try { + if (rawData != null) { + int rawDataLength = rawData.length; + File rawoutput = new File("/sdcard/test.bmp"); + FileOutputStream outstream = new FileOutputStream(rawoutput); + outstream.write(rawData); + Log.v(TAG, "JpegPictureCallback rawDataLength = " + rawDataLength); + jpegPictureCallbackResult = true; + } else { + jpegPictureCallbackResult = false; + } + Log.v(TAG, "Jpeg Picture callback"); + } catch (Exception e) { + Log.v(TAG, e.toString()); + } + } + }; + + + private void checkTakePicture() { + SurfaceHolder mSurfaceHolder; + try { + mSurfaceHolder = MediaFrameworkTest.mSurfaceView.getHolder(); + mCamera.setPreviewDisplay(mSurfaceHolder); + Log.v(TAG, "Start preview"); + mCamera.startPreview(); + synchronized (previewDone) { + try { + previewDone.wait(WAIT_FOR_COMMAND_TO_COMPLETE); + Log.v(TAG, "Preview Done"); + } catch (Exception e) { + Log.v(TAG, "wait was interrupted."); + } + } + mCamera.setPreviewCallback(null); + mCamera.takePicture(mShutterCallback, mRawPictureCallback, mJpegPictureCallback); + Thread.sleep(MediaNames.WAIT_LONG); + } catch (Exception e) { + Log.v(TAG, e.toString()); + } + } + + private void checkPreviewCallback() { + SurfaceHolder mSurfaceHolder; + try { + mSurfaceHolder = MediaFrameworkTest.mSurfaceView.getHolder(); + mCamera.setPreviewDisplay(mSurfaceHolder); + Log.v(TAG, "start preview"); + mCamera.startPreview(); + synchronized (previewDone) { + try { + previewDone.wait(WAIT_FOR_COMMAND_TO_COMPLETE); + Log.v(TAG, "setPreview done"); + } catch (Exception e) { + Log.v(TAG, "wait was interrupted."); + } + } + mCamera.setPreviewCallback(null); + } catch (Exception e) { + Log.v(TAG, e.toString()); + } + } + + /* + * TODO(yslau): Need to setup the golden rawData and compare the + * the new captured rawData with the golden one. + * + * Test case 1: Take a picture and verify all the callback + * functions are called properly. + */ + @LargeTest + public void testTakePicture() throws Exception { + initializeMessageLooper(); + synchronized (lock) { + try { + lock.wait(WAIT_FOR_COMMAND_TO_COMPLETE); + } catch(Exception e) { + Log.v(TAG, "runTestOnMethod: wait was interrupted."); + } + } + mCamera.setPreviewCallback(mRawPreviewCallback); + checkTakePicture(); + terminateMessageLooper(); + assertTrue("shutterCallbackResult", shutterCallbackResult); + assertTrue("rawPictureCallbackResult", rawPictureCallbackResult); + assertTrue("jpegPictureCallbackResult", jpegPictureCallbackResult); + } + + /* + * Test case 2: Set the preview and + * verify the RawPreviewCallback is called + */ + @LargeTest + public void testCheckPreview() throws Exception { + initializeMessageLooper(); + synchronized (lock) { + try { + lock.wait(WAIT_FOR_COMMAND_TO_COMPLETE); + } catch(Exception e) { + Log.v(TAG, "wait was interrupted."); + } + } + mCamera.setPreviewCallback(mRawPreviewCallback); + checkPreviewCallback(); + terminateMessageLooper(); + assertTrue("RawPreviewCallbackResult", rawPreviewCallbackResult); + } + +} + diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/CodecTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/CodecTest.java new file mode 100644 index 0000000000000000000000000000000000000000..0e88719de6bf381a7107559ef5e2e1930bf911a7 --- /dev/null +++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/CodecTest.java @@ -0,0 +1,577 @@ +/* + * 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.android.mediaframeworktest.functional; + + + +//import android.content.Resources; +import com.android.mediaframeworktest.MediaFrameworkTest; +import com.android.mediaframeworktest.MediaNames; + +import android.content.res.AssetFileDescriptor; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.media.MediaMetadataRetriever; +import android.media.MediaPlayer; +import android.media.MediaRecorder; +import android.os.SystemClock; +import android.util.Log; + +import java.io.IOException; +import java.io.InputStream; +/** + * Junit / Instrumentation test case for the media player api + + */ +public class CodecTest { + private static String TAG = "MediaPlayerApiTest"; + + public static String printCpuInfo(){ + String cm = "dumpsys cpuinfo"; + String cpuinfo =null; + int ch; + try{ + Process p = Runtime.getRuntime().exec(cm); + InputStream in = p.getInputStream(); + StringBuffer sb = new StringBuffer(512); + while ( ( ch = in.read() ) != -1 ){ + sb.append((char) ch); + } + cpuinfo = sb.toString(); + }catch (IOException e){ + Log.v(TAG, e.toString()); + } + return cpuinfo; + } + + + public static int getDuration(String filePath) { + Log.v(TAG, "getDuration - " + filePath); + MediaPlayer mp = new MediaPlayer(); + try{ + mp.setDataSource(filePath); + mp.prepare(); + }catch (Exception e){} + int duration = mp.getDuration(); + Log.v(TAG, "Duration " + duration); + mp.release(); + Log.v(TAG, "release"); + return duration; + } + + public static boolean getCurrentPosition(String filePath){ + Log.v(TAG, "GetCurrentPosition - " + filePath); + int currentPosition = 0; + long t1=0; + long t2 =0; + MediaPlayer mp = new MediaPlayer(); + try{ + mp.setDataSource(filePath); + Log.v(TAG, "start playback"); + mp.prepare(); + mp.start(); + t1=SystemClock.uptimeMillis(); + Thread.sleep(10000); + mp.pause(); + Thread.sleep(MediaNames.PAUSE_WAIT_TIME); + t2=SystemClock.uptimeMillis(); + }catch (Exception e){ + Log.v(TAG, e.toString()); + } + currentPosition = mp.getCurrentPosition(); + mp.stop(); + mp.release(); + Log.v(TAG, "mp currentPositon = " + currentPosition + " play duration = " + (t2-t1)); + //The currentposition should be within 10% of the sleep time + //For the very short mp3, it should return the length instead of 10 seconds + if (filePath.equals(MediaNames.SHORTMP3)){ + if (currentPosition < 1000 ) + return true; + } + if ((currentPosition < ((t2-t1) *1.2)) && (currentPosition > 0)) + return true; + else + return false; + } + + public static boolean seekTo(String filePath){ + Log.v(TAG, "seekTo " + filePath); + int currentPosition = 0; + MediaPlayer mp = new MediaPlayer(); + try{ + mp.setDataSource(filePath); + mp.prepare(); + mp.start(); + mp.seekTo(MediaNames.SEEK_TIME); + Thread.sleep(MediaNames.WAIT_TIME); + currentPosition = mp.getCurrentPosition(); + }catch (Exception e){ + Log.v(TAG, e.getMessage()); + } + mp.stop(); + mp.release(); + Log.v(TAG, "CurrentPosition = " + currentPosition); + //The currentposition should be at least greater than the 80% of seek time + if ((currentPosition > MediaNames.SEEK_TIME *0.8)) + return true; + else + return false; + } + + public static boolean setLooping(String filePath){ + int currentPosition = 0; + int duration = 0; + long t1 =0; + long t2 =0; + Log.v (TAG, "SetLooping - " + filePath); + MediaPlayer mp = new MediaPlayer(); + try{ + mp.setDataSource(filePath); + mp.prepare(); + duration = mp.getDuration(); + Log.v(TAG, "setLooping duration " + duration); + mp.setLooping(true); + mp.start(); + Thread.sleep(5000); + mp.seekTo(duration - 5000); + t1=SystemClock.uptimeMillis(); + Thread.sleep(20000); + t2=SystemClock.uptimeMillis(); + Log.v(TAG, "pause"); + //Bug# 1106852 - IllegalStateException will be thrown if pause is called + //in here + //mp.pause(); + currentPosition = mp.getCurrentPosition(); + Log.v(TAG, "looping position " + currentPosition + "duration = " + (t2-t1)); + }catch (Exception e){ + Log.v(TAG, "Exception : " + e.toString()); + } + mp.stop(); + mp.release(); + //The current position should be within 20% of the sleep time + //and should be greater than zero. + if ((currentPosition < ((t2-t1-5000)*1.2)) && currentPosition > 0) + return true; + else + return false; + } + + public static boolean pause(String filePath) throws Exception { + Log.v(TAG, "pause - " + filePath); + boolean misPlaying = true; + boolean pauseResult = false; + long t1=0; + long t2=0; + MediaPlayer mp = new MediaPlayer(); + mp.setDataSource(filePath); + mp.prepare(); + int duration = mp.getDuration(); + mp.start(); + t1=SystemClock.uptimeMillis(); + Thread.sleep(5000); + mp.pause(); + Thread.sleep(MediaNames.PAUSE_WAIT_TIME); + t2=SystemClock.uptimeMillis(); + misPlaying = mp.isPlaying(); + int curPosition = mp.getCurrentPosition(); + Log.v(TAG, filePath + " pause currentPositon " + curPosition); + Log.v(TAG, "isPlaying "+ misPlaying + " wait time " + (t2 - t1) ); + String cpuinfo = printCpuInfo(); + Log.v(TAG, cpuinfo); + if ((curPosition>0) && (curPosition < ((t2-t1) * 1.3)) && (misPlaying == false)) + pauseResult = true; + mp.stop(); + mp.release(); + return pauseResult; + } + + public static void prepareStopRelease(String filePath) throws Exception { + Log.v(TAG, "prepareStopRelease" + filePath); + MediaPlayer mp = new MediaPlayer(); + mp.setDataSource(filePath); + mp.prepare(); + mp.stop(); + mp.release(); + } + + public static void preparePauseRelease(String filePath) throws Exception { + Log.v(TAG, "preparePauseRelease" + filePath); + MediaPlayer mp = new MediaPlayer(); + mp.setDataSource(filePath); + mp.prepare(); + mp.pause(); + mp.release(); + } + + public static int videoHeight(String filePath) throws Exception { + Log.v(TAG, "videoHeight - " + filePath); + int videoHeight = 0; + MediaPlayer mp = new MediaPlayer(); + mp.setDataSource(filePath); + mp.setDisplay(MediaFrameworkTest.mSurfaceView.getHolder()); + mp.prepare(); + videoHeight = mp.getVideoHeight(); + mp.release(); + return videoHeight; + } + + public static int videoWidth(String filePath) throws Exception { + Log.v(TAG, "videoWidth - " + filePath); + int videoWidth = 0; + MediaPlayer mp = new MediaPlayer(); + mp.setDataSource(filePath); + mp.setDisplay(MediaFrameworkTest.mSurfaceView.getHolder()); + mp.prepare(); + videoWidth = mp.getVideoWidth(); + mp.release(); + return videoWidth; + } + + //This also test the streaming video which may take a long + //time to start the playback. + public static boolean videoSeekTo(String filePath) throws Exception { + Log.v(TAG, "videoSeekTo - " + filePath); + int currentPosition = 0; + int duration = 0; + boolean videoResult = false; + MediaPlayer mp = new MediaPlayer(); + mp.setDataSource(filePath); + mp.setDisplay(MediaFrameworkTest.mSurfaceView.getHolder()); + mp.prepare(); + mp.start(); + if (filePath.equals(MediaNames.VIDEO_SHORT_3GP)){ + mp.pause(); + Thread.sleep(MediaNames.PAUSE_WAIT_TIME); + mp.seekTo(0); + mp.start(); + Thread.sleep(1000); + currentPosition = mp.getCurrentPosition(); + Log.v(TAG,"short position " + currentPosition); + if (currentPosition > 100 ) + return true; + else + return false; + } + Thread.sleep(5000); + duration = mp.getDuration(); + Log.v(TAG, "video duration " + duration); + mp.pause(); + Thread.sleep(MediaNames.PAUSE_WAIT_TIME); + mp.seekTo(duration - 20000 ); + mp.start(); + Thread.sleep(1000); + mp.pause(); + Thread.sleep(MediaNames.PAUSE_WAIT_TIME); + mp.seekTo(duration/2); + mp.start(); + Thread.sleep(10000); + currentPosition = mp.getCurrentPosition(); + Log.v(TAG, "video currentPosition " + currentPosition); + mp.release(); + if (currentPosition > (duration /2 )*0.9) + return true; + else + return false; + + } + + public static boolean seekToEnd(String filePath){ + Log.v(TAG, "seekToEnd - " + filePath); + int duration = 0; + int currentPosition = 0; + boolean isPlaying = false; + MediaPlayer mp = new MediaPlayer(); + try{ + mp.setDataSource(filePath); + Log.v(TAG, "start playback"); + mp.prepare(); + duration = mp.getDuration(); + mp.seekTo(duration - 3000); + mp.start(); + Thread.sleep(6000); + }catch (Exception e){} + isPlaying = mp.isPlaying(); + currentPosition = mp.getCurrentPosition(); + Log.v(TAG, "seekToEnd currentPosition= " + currentPosition + " isPlaying = " + isPlaying); + mp.stop(); + mp.release(); + Log.v(TAG, "duration = " + duration); + if (currentPosition < 0.9 * duration || isPlaying) + return false; + else + return true; + } + + public static boolean shortMediaStop(String filePath){ + Log.v(TAG, "shortMediaStop - " + filePath); + //This test is only for the short media file + int duration = 0; + int currentPosition = 0; + boolean isPlaying = false; + MediaPlayer mp = new MediaPlayer(); + try{ + mp.setDataSource(filePath); + Log.v(TAG, "start playback"); + mp.prepare(); + duration = mp.getDuration(); + mp.start(); + Thread.sleep(10000); + }catch (Exception e){} + isPlaying = mp.isPlaying(); + currentPosition = mp.getCurrentPosition(); + Log.v(TAG, "seekToEnd currentPosition= " + currentPosition + " isPlaying = " + isPlaying); + mp.stop(); + mp.release(); + Log.v(TAG, "duration = " + duration); + if (currentPosition > duration || isPlaying) + return false; + else + return true; + } + + public static boolean playToEnd(String filePath){ + Log.v(TAG, "shortMediaStop - " + filePath); + //This test is only for the short media file + int duration = 200000; + int updateDuration = 0; + int currentPosition = 0; + boolean isPlaying = false; + MediaPlayer mp = new MediaPlayer(); + try{ + Thread.sleep(5000); + mp.setDataSource(filePath); + Log.v(TAG, "start playback"); + mp.prepare(); + //duration = mp.getDuration(); + mp.start(); + Thread.sleep(50000); + }catch (Exception e){} + isPlaying = mp.isPlaying(); + currentPosition = mp.getCurrentPosition(); + //updateDuration = mp.getDuration(); + Log.v(TAG, "seekToEnd currentPosition= " + currentPosition + " isPlaying = " + isPlaying); + mp.stop(); + mp.release(); + //Log.v(TAG, "duration = " + duration); + //Log.v(TAG, "Update duration = " + updateDuration); + if (currentPosition > duration || isPlaying) + return false; + else + return true; + } + + public static boolean seektoBeforeStart(String filePath){ + Log.v(TAG, "seektoBeforeStart - " + filePath); + //This test is only for the short media file + int duration = 0; + int currentPosition = 0; + + MediaPlayer mp = new MediaPlayer(); + try{ + mp.setDataSource(filePath); + mp.prepare(); + duration = mp.getDuration(); + mp.seekTo(duration - 10000); + mp.start(); + currentPosition=mp.getCurrentPosition(); + mp.stop(); + mp.release(); + }catch (Exception e){} + if (currentPosition < duration/2) + return false; + else + return true; + } + + public static boolean mediaRecorderRecord(String filePath){ + Log.v(TAG, "SoundRecording - " + filePath); + //This test is only for the short media file + int duration = 0; + try{ + MediaRecorder mRecorder = new MediaRecorder(); + mRecorder.setAudioSource(MediaRecorder.AudioSource.MIC); + mRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP); + mRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB); + mRecorder.setOutputFile(filePath); + mRecorder.prepare(); + mRecorder.start(); + Thread.sleep(500); + mRecorder.stop(); + Log.v(TAG, "sound recorded"); + mRecorder.release(); + }catch (Exception e){ + Log.v(TAG, e.toString()); + } + + //Verify the recorded file + MediaPlayer mp = new MediaPlayer(); + try{ + mp.setDataSource(filePath); + mp.prepare(); + duration = mp.getDuration(); + Log.v(TAG,"Duration " + duration); + mp.release(); + }catch (Exception e){} + //Check the record media file length is greate than zero + if (duration > 0) + return true; + else + return false; + + } + + //Test for mediaMeta Data Thumbnail + public static boolean getThumbnail(String filePath, String goldenPath){ + Log.v(TAG, "getThumbnail - " + filePath); + + int goldenHeight = 0; + int goldenWidth = 0; + int outputWidth = 0; + int outputHeight = 0; + + //This test is only for the short media file + try{ + BitmapFactory mBitmapFactory = new BitmapFactory(); + + MediaMetadataRetriever mMediaMetadataRetriever = new MediaMetadataRetriever(); + try { + mMediaMetadataRetriever.setDataSource(filePath); + } catch(Exception e) { + e.printStackTrace(); + return false; + } + Bitmap outThumbnail = mMediaMetadataRetriever.captureFrame(); + + //Verify the thumbnail + Bitmap goldenBitmap = mBitmapFactory.decodeFile(goldenPath); + + outputWidth = outThumbnail.getWidth(); + outputHeight = outThumbnail.getHeight(); + goldenHeight = goldenBitmap.getHeight(); + goldenWidth = goldenBitmap.getWidth(); + + //check the image dimension + if ((outputWidth != goldenWidth) || (outputHeight != goldenHeight)) + return false; + + //Check one line of pixel + int x = goldenHeight/2; + for (int j=0; j { + private boolean duratoinWithinTolerence = false; + private String TAG = "MediaPlayerApiTest"; + + Context mContext; + + public MediaPlayerApiTest() { + super("com.android.mediaframeworktest", MediaFrameworkTest.class); + } + + protected void setUp() throws Exception { + super.setUp(); + + } + + public boolean verifyDuration(int duration, int expectedDuration){ + if ((duration > expectedDuration * 1.1) || (duration < expectedDuration * 0.9)) + return false; + else + return true; + } + + + //Audio + //Wait for PV bugs for MP3 duration + @MediumTest + public void testMP3CBRGetDuration() throws Exception { + int duration = CodecTest.getDuration(MediaNames.MP3CBR); + duratoinWithinTolerence = verifyDuration(duration, MediaNames.MP3CBR_LENGTH); + assertTrue("MP3CBR getDuration", duratoinWithinTolerence); + } + + @MediumTest + public void testMP3VBRGetDuration() throws Exception { + int duration = CodecTest.getDuration(MediaNames.MP3VBR); + Log.v(TAG, "getDuration"); + duratoinWithinTolerence = verifyDuration(duration, MediaNames.MP3VBR_LENGTH); + assertTrue("MP3VBR getDuration", duratoinWithinTolerence); + } + + @MediumTest + public void testMIDIGetDuration() throws Exception { + int duration = CodecTest.getDuration(MediaNames.MIDI); + duratoinWithinTolerence = verifyDuration(duration, MediaNames.MIDI_LENGTH); + assertTrue("MIDI getDuration", duratoinWithinTolerence); + } + + @MediumTest + public void testWMA9GetDuration() throws Exception { + int duration = CodecTest.getDuration(MediaNames.WMA9); + duratoinWithinTolerence = verifyDuration(duration, MediaNames.WMA9_LENGTH); + assertTrue("WMA9 getDuration", duratoinWithinTolerence); + } + + @MediumTest + public void testAMRGetDuration() throws Exception { + int duration = CodecTest.getDuration(MediaNames.AMR); + duratoinWithinTolerence = verifyDuration(duration, MediaNames.AMR_LENGTH); + assertTrue("AMR getDuration", duratoinWithinTolerence); + } + + /* + public void testOGGGetDuration() throws Exception { + int duration = CodecTest.getDuration(MediaNames.OGG); + duratoinWithinTolerence = verifyDuration(duration, MediaNames.OGG_LENGTH); + assertTrue("OGG getDuration", duratoinWithinTolerence); + }*/ + + + //Test cases for GetCurrentPosition + @LargeTest + public void testMP3CBRGetCurrentPosition() throws Exception { + boolean currentPosition = CodecTest.getCurrentPosition(MediaNames.MP3CBR); + assertTrue("MP3CBR GetCurrentPosition", currentPosition); + } + + @LargeTest + public void testMP3VBRGetCurrentPosition() throws Exception { + boolean currentPosition = CodecTest.getCurrentPosition(MediaNames.MP3VBR); + assertTrue("MP3VBR GetCurrentPosition", currentPosition); + } + + @LargeTest + public void testMIDIGetCurrentPosition() throws Exception { + boolean currentPosition = CodecTest.getCurrentPosition(MediaNames.MIDI); + assertTrue("MIDI GetCurrentPosition", currentPosition); + } + + @LargeTest + public void testWMA9GetCurrentPosition() throws Exception { + boolean currentPosition = CodecTest.getCurrentPosition(MediaNames.WMA9); + assertTrue("WMA9 GetCurrentPosition", currentPosition); + } + + @LargeTest + public void testAMRGetCurrentPosition() throws Exception { + boolean currentPosition = CodecTest.getCurrentPosition(MediaNames.AMR); + assertTrue("AMR GetCurrentPosition", currentPosition); + } + + /* + public void testOGGGetCurrentPosition() throws Exception { + boolean currentPosition = CodecTest.getCurrentPosition(MediaNames.OGG); + assertTrue("OGG GetCurrentPosition", currentPosition); + */ + + //Test cases for pause + @LargeTest + public void testMP3CBRPause() throws Exception { + boolean isPaused = CodecTest.pause(MediaNames.MP3CBR); + assertTrue("MP3CBR Pause", isPaused); + } + + @LargeTest + public void testMP3VBRPause() throws Exception { + boolean isPaused = CodecTest.pause(MediaNames.MP3VBR); + assertTrue("MP3VBR Pause", isPaused); + } + + @LargeTest + public void testMIDIPause() throws Exception { + boolean isPaused = CodecTest.pause(MediaNames.MIDI); + assertTrue("MIDI Pause", isPaused); + } + + @LargeTest + public void testWMA9Pause() throws Exception { + boolean isPaused = CodecTest.pause(MediaNames.WMA9); + assertTrue("WMA9 Pause", isPaused); + } + + @LargeTest + public void testAMRPause() throws Exception { + boolean isPaused = CodecTest.pause(MediaNames.AMR); + assertTrue("AMR Pause", isPaused); + } + + /* + public void testOGGPause() throws Exception { + boolean isPaused = CodecTest.pause(MediaNames.OGG); + assertTrue("OGG Pause", isPaused); + }*/ + + @MediumTest + public void testMP3CBRPrepareStopRelease() throws Exception { + CodecTest.prepareStopRelease(MediaNames.MP3CBR); + assertTrue("MP3CBR prepareStopRelease", true); + } + + @MediumTest + public void testMIDIPrepareStopRelease() throws Exception { + CodecTest.prepareStopRelease(MediaNames.MIDI); + assertTrue("MIDI prepareStopRelease", true); + } + + //One test case for seek before start + @MediumTest + public void testMP3CBRSeekBeforeStart() throws Exception { + boolean seekBeforePlay = CodecTest.seektoBeforeStart(MediaNames.MP3CBR); + assertTrue("MP3CBR SeekBeforePlay", seekBeforePlay); + } + + //Skip test - Bug# 1120249 + /* + public void testMP3CBRpreparePauseRelease() throws Exception { + CodecTest.preparePauseRelease(MediaNames.MP3CBR); + assertTrue("MP3CBR preparePauseRelease", true); + } + + public void testMIDIpreparePauseRelease() throws Exception { + CodecTest.preparePauseRelease(MediaNames.MIDI); + assertTrue("MIDI preparePauseRelease", true); + } + */ + + + //Test cases for setLooping + @LargeTest + public void testMP3CBRSetLooping() throws Exception { + boolean isLoop = CodecTest.setLooping(MediaNames.MP3CBR); + assertTrue("MP3CBR setLooping", isLoop); + } + + @LargeTest + public void testMP3VBRSetLooping() throws Exception { + boolean isLoop = CodecTest.setLooping(MediaNames.MP3VBR); + Log.v(TAG, "setLooping"); + assertTrue("MP3VBR setLooping", isLoop); + } + + @LargeTest + public void testMIDISetLooping() throws Exception { + boolean isLoop = CodecTest.setLooping(MediaNames.MIDI); + assertTrue("MIDI setLooping", isLoop); + } + + @LargeTest + public void testWMA9SetLooping() throws Exception { + boolean isLoop = CodecTest.setLooping(MediaNames.WMA9); + assertTrue("WMA9 setLooping", isLoop); + } + + @LargeTest + public void testAMRSetLooping() throws Exception { + boolean isLoop = CodecTest.setLooping(MediaNames.AMR); + assertTrue("AMR setLooping", isLoop); + } + + /* + public void testOGGSetLooping() throws Exception { + boolean isLoop = CodecTest.setLooping(MediaNames.OGG); + assertTrue("OGG setLooping", isLoop); + } */ + + //Test cases for seekTo + @LargeTest + public void testMP3CBRSeekTo() throws Exception { + boolean isLoop = CodecTest.seekTo(MediaNames.MP3CBR); + assertTrue("MP3CBR seekTo", isLoop); + } + + @LargeTest + public void testMP3VBRSeekTo() throws Exception { + boolean isLoop = CodecTest.seekTo(MediaNames.MP3VBR); + Log.v(TAG, "seekTo"); + assertTrue("MP3VBR seekTo", isLoop); + } + + @LargeTest + public void testMIDISeekTo() throws Exception { + boolean isLoop = CodecTest.seekTo(MediaNames.MIDI); + assertTrue("MIDI seekTo", isLoop); + } + + @LargeTest + public void testWMA9SeekTo() throws Exception { + boolean isLoop = CodecTest.seekTo(MediaNames.WMA9); + assertTrue("WMA9 seekTo", isLoop); + } + + @LargeTest + public void testAMRSeekTo() throws Exception { + boolean isLoop = CodecTest.seekTo(MediaNames.AMR); + assertTrue("AMR seekTo", isLoop); + } + + /* + public void testOGGSeekTo() throws Exception { + boolean isLoop = CodecTest.seekTo(MediaNames.OGG); + assertTrue("OGG seekTo", isLoop); + }*/ + + + //Jump to the end of the files + @LargeTest + public void testMP3CBRSeekToEnd() throws Exception { + boolean isEnd = CodecTest.seekToEnd(MediaNames.MP3CBR); + assertTrue("MP3CBR seekToEnd", isEnd); + } + + @LargeTest + public void testMP3VBRSeekToEnd() throws Exception { + boolean isEnd = CodecTest.seekToEnd(MediaNames.MP3VBR); + Log.v(TAG, "seekTo"); + assertTrue("MP3VBR seekToEnd", isEnd); + } + + @LargeTest + public void testMIDISeekToEnd() throws Exception { + boolean isEnd = CodecTest.seekToEnd(MediaNames.MIDI); + assertTrue("MIDI seekToEnd", isEnd); + } + + @LargeTest + public void testWMA9SeekToEnd() throws Exception { + boolean isEnd = CodecTest.seekToEnd(MediaNames.WMA9); + assertTrue("WMA9 seekToEnd", isEnd); + } + + @LargeTest + public void testAMRSeekToEnd() throws Exception { + boolean isEnd = CodecTest.seekToEnd(MediaNames.AMR); + assertTrue("AMR seekToEnd", isEnd); + } + + /* + public void testOGGSeekToEnd() throws Exception { + boolean isEnd = CodecTest.seekToEnd(MediaNames.OGG); + assertTrue("OGG seekToEnd", isEnd); + }*/ + + @LargeTest + public void testWAVSeekToEnd() throws Exception { + boolean isEnd = CodecTest.seekToEnd(MediaNames.WAV); + assertTrue("WAV seekToEnd", isEnd); + } + + @MediumTest + public void testLargeVideoHeigth() throws Exception { + int height = 0; + height = CodecTest.videoHeight(MediaNames.VIDEO_LARGE_SIZE_3GP); + Log.v(TAG, "Video height = " + height); + assertEquals("streaming video height", 240, height); + } + + @MediumTest + public void testLargeVideoWidth() throws Exception { + int width = 0; + width = CodecTest.videoWidth(MediaNames.VIDEO_LARGE_SIZE_3GP); + Log.v(TAG, "Video width = " + width); + assertEquals("streaming video width", 320, width); + } + + @LargeTest + public void testVideoMP4SeekTo() throws Exception { + boolean isSeek = CodecTest.videoSeekTo(MediaNames.VIDEO_MP4); + assertTrue("Local MP4 SeekTo", isSeek); + } + + @LargeTest + public void testVideoLong3gpSeekTo() throws Exception { + boolean isSeek = CodecTest.videoSeekTo(MediaNames.VIDEO_LONG_3GP); + assertTrue("Local 3gp SeekTo", isSeek); + } + + @LargeTest + public void testVideoH263AACSeekTo() throws Exception { + boolean isSeek = CodecTest.videoSeekTo(MediaNames.VIDEO_H263_AAC); + assertTrue("H263AAC SeekTo", isSeek); + } + + @LargeTest + public void testVideoH263AMRSeekTo() throws Exception { + boolean isSeek = CodecTest.videoSeekTo(MediaNames.VIDEO_H263_AMR); + assertTrue("H263AMR SeekTo", isSeek); + } + + @LargeTest + public void testVideoH264AACSeekTo() throws Exception { + boolean isSeek = CodecTest.videoSeekTo(MediaNames.VIDEO_H264_AAC); + assertTrue("H264AAC SeekTo", isSeek); + } + + @LargeTest + public void testVideoH264AMRSeekTo() throws Exception { + boolean isSeek = CodecTest.videoSeekTo(MediaNames.VIDEO_H264_AMR); + assertTrue("H264AMR SeekTo", isSeek); + } + + @LargeTest + public void testVideoWMVSeekTo() throws Exception { + boolean isSeek = CodecTest.videoSeekTo(MediaNames.VIDEO_WMV); + assertTrue("WMV SeekTo", isSeek); + } + + //TODO(elaurent) + //reactivate the test until bug#1495237 fix + @Suppress + @LargeTest + public void testSoundRecord() throws Exception { + boolean isRecordered = CodecTest.mediaRecorderRecord(MediaNames.RECORDER_OUTPUT); + assertTrue("Recorder", isRecordered); + } + + @LargeTest + public void testGetThumbnail() throws Exception { + boolean getThumbnail = CodecTest.getThumbnail(MediaNames.VIDEO_H264_AAC, MediaNames.GOLDEN_THUMBNAIL_OUTPUT); + assertTrue("Get Thumbnail", getThumbnail); + } + + //Play a mid file which the duration is around 210 seconds + @LargeTest + public void testMidiResources() throws Exception { + boolean midiResources = CodecTest.resourcesPlayback(MediaFrameworkTest.midiafd,180000); + assertTrue("Play midi from resources", midiResources); + } + + @LargeTest + public void testMp3Resources() throws Exception { + boolean mp3Resources = CodecTest.resourcesPlayback(MediaFrameworkTest.mp3afd,25000); + assertTrue("Play mp3 from resources", mp3Resources); + } + + //Bug# 1422662 + @Suppress + @MediumTest + public void testPrepareAsyncReset() throws Exception { + boolean isReset = CodecTest.prepareAsyncReset(MediaNames.STREAM_LARGE_MP3); + assertTrue("PrepareAsync Reset", isReset); + } + + @MediumTest + public void testIsLooping() throws Exception { + boolean isLooping = CodecTest.isLooping(MediaNames.AMR); + assertTrue("isLooping", isLooping); + } + + @MediumTest + public void testIsLoopingAfterReset() throws Exception { + boolean isLooping = CodecTest.isLoopingAfterReset(MediaNames.AMR); + assertTrue("isLooping after reset", isLooping); + } +} + diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaRecorderTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaRecorderTest.java new file mode 100644 index 0000000000000000000000000000000000000000..d970f5e0779870223d07ee20fb4ed53cc3836442 --- /dev/null +++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaRecorderTest.java @@ -0,0 +1,276 @@ +/* + * 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.android.mediaframeworktest.functional; + +import com.android.mediaframeworktest.MediaFrameworkTest; +import com.android.mediaframeworktest.MediaNames; + +import java.io.*; + +import android.content.Context; +import android.media.MediaPlayer; +import android.media.MediaRecorder; +import android.test.ActivityInstrumentationTestCase; +import android.util.Log; +import android.view.SurfaceHolder; +import android.view.SurfaceView; + + +import android.test.suitebuilder.annotation.LargeTest; +import android.test.suitebuilder.annotation.Suppress; + + +/** + * Junit / Instrumentation test case for the media recorder api + + */ +public class MediaRecorderTest extends ActivityInstrumentationTestCase { + private String TAG = "MediaRecorderTest"; + private int mOutputDuration =0; + private int mOutputVideoWidth = 0; + private int mOutputVideoHeight= 0 ; + + private SurfaceHolder mSurfaceHolder = null; + private MediaRecorder mRecorder; + Context mContext; + + public MediaRecorderTest() { + super("com.android.mediaframeworktest", MediaFrameworkTest.class); + + } + + protected void setUp() throws Exception { + super.setUp(); + Log.v(TAG,"create the media recorder"); + mRecorder = new MediaRecorder(); + } + + private void recordVideo(int frameRate, int width, int height, + int videoFormat, int outFormat, String outFile, boolean videoOnly){ + Log.v(TAG,"startPreviewAndPrepareRecording"); + try{ + if (!videoOnly){ + Log.v(TAG, "setAudioSource"); + //mRecorder.setAudioSource(MediaRecorder.AudioSource.MIC); + } + mRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA); + mRecorder.setOutputFormat(outFormat); + Log.v(TAG, "output format " + outFormat); + mRecorder.setOutputFile(outFile); + mRecorder.setVideoFrameRate(frameRate); + mRecorder.setVideoSize(width, height); + Log.v(TAG, "setEncoder"); + mRecorder.setVideoEncoder(videoFormat); + if (!videoOnly){ + // mRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB); + } + mSurfaceHolder = MediaFrameworkTest.mSurfaceView.getHolder(); + Log.v(TAG, "setPreview"); + mRecorder.setPreviewDisplay(mSurfaceHolder.getSurface()); + Log.v(TAG, "prepare"); + mRecorder.prepare(); + Log.v(TAG, "start"); + mRecorder.start(); + Thread.sleep(MediaNames.RECORDED_TIME); + Log.v(TAG, "stop"); + mRecorder.stop(); + mRecorder.reset(); + mRecorder.release(); + } catch (Exception e){ + Log.v("record video failed ", e.toString()); + } + } + + private void getOutputVideoProperty(String outputFilePath){ + MediaPlayer mediaPlayer = new MediaPlayer(); + try{ + mediaPlayer.setDataSource(outputFilePath); + Log.v(TAG, "file Path = " + outputFilePath); + mediaPlayer.setDisplay(MediaFrameworkTest.mSurfaceView.getHolder()); + Log.v(TAG, "before player prepare"); + mediaPlayer.prepare(); + Log.v(TAG, "before getduration"); + mOutputDuration = mediaPlayer.getDuration(); + Log.v(TAG, "get video dimension"); + mOutputVideoHeight = mediaPlayer.getVideoHeight(); + mOutputVideoWidth = mediaPlayer.getVideoWidth(); + mediaPlayer.release(); + } catch (Exception e) { + Log.v(TAG, e.toString()); + } + } + + private void removeFile(String filePath){ + File fileRemove = new File(filePath); + fileRemove.delete(); + } + + private boolean validateVideo(String filePath, int width, int height){ + boolean validVideo = false; + getOutputVideoProperty(filePath); + if (mOutputVideoWidth == width && mOutputVideoHeight == height && + mOutputDuration > MediaNames.VALID_VIDEO_DURATION ){ + validVideo = true; + } + Log.v(TAG, "width = " + mOutputVideoWidth + " height = " + mOutputVideoHeight + " Duration = " + mOutputDuration); + removeFile(filePath); + return validVideo; + } + + + //Format: HVGA h263 + @Suppress + public void testHVGAH263() throws Exception { + boolean videoRecordedResult = false; + recordVideo(15, 480, 320, MediaRecorder.VideoEncoder.H263, + MediaRecorder.OutputFormat.THREE_GPP, MediaNames.RECORDED_HVGA_H263, false); + videoRecordedResult = validateVideo(MediaNames.RECORDED_HVGA_H263, 480, 320); + assertTrue("HVGAH263", videoRecordedResult); + } + + //Format: QVGA h263 + @Suppress + public void testQVGAH263() throws Exception { + boolean videoRecordedResult = false; + recordVideo(15, 320, 240, MediaRecorder.VideoEncoder.H263, + MediaRecorder.OutputFormat.THREE_GPP, MediaNames.RECORDED_QVGA_H263, false); + videoRecordedResult = validateVideo(MediaNames.RECORDED_QVGA_H263, 320, 240); + assertTrue("QVGAH263", videoRecordedResult); + } + + //Format: SQVGA h263 + @Suppress + public void testSQVGAH263() throws Exception { + boolean videoRecordedResult = false; + recordVideo(15, 240, 160, MediaRecorder.VideoEncoder.H263, + MediaRecorder.OutputFormat.THREE_GPP, MediaNames.RECORDED_SQVGA_H263, false); + videoRecordedResult = validateVideo(MediaNames.RECORDED_SQVGA_H263, 240, 160); + assertTrue("SQVGAH263", videoRecordedResult); + } + + //Format: QCIF h263 + @LargeTest + public void testQCIFH263() throws Exception { + boolean videoRecordedResult = false; + recordVideo(15, 176, 144, MediaRecorder.VideoEncoder.H263, + MediaRecorder.OutputFormat.THREE_GPP, MediaNames.RECORDED_QCIF_H263, false); + videoRecordedResult = validateVideo(MediaNames.RECORDED_QCIF_H263, 176, 144); + assertTrue("QCIFH263", videoRecordedResult); + } + + //Format: CIF h263 + @LargeTest + public void testCIFH263() throws Exception { + boolean videoRecordedResult = false; + recordVideo(15, 352, 288, MediaRecorder.VideoEncoder.H263, + MediaRecorder.OutputFormat.THREE_GPP, MediaNames.RECORDED_CIF_H263, false); + videoRecordedResult = validateVideo(MediaNames.RECORDED_CIF_H263, 352, 288); + assertTrue("CIFH263", videoRecordedResult); + } + + + + @Suppress + public void testVideoOnly() throws Exception { + boolean videoRecordedResult = false; + for (int i=0; i< 10; i++){ + recordVideo(15, 176, 144, MediaRecorder.VideoEncoder.H263, + MediaRecorder.OutputFormat.MPEG_4, MediaNames.RECORDED_VIDEO_3GP, true); + videoRecordedResult = validateVideo(MediaNames.RECORDED_VIDEO_3GP, 176, 144); + } + assertTrue("QCIFH263 Video Only", videoRecordedResult); + } + + @Suppress + public void testPortraitH263() throws Exception { + boolean videoRecordedResult = false; + recordVideo(15, 144, 176, MediaRecorder.VideoEncoder.H263, + MediaRecorder.OutputFormat.MPEG_4, MediaNames.RECORDED_VIDEO_3GP, true); + videoRecordedResult = validateVideo(MediaNames.RECORDED_VIDEO_3GP, 144, 176); + assertTrue("PortraitH263", videoRecordedResult); + } + + @LargeTest + public void testHVGAMP4() throws Exception { + boolean videoRecordedResult = false; + recordVideo(15, 480, 320, MediaRecorder.VideoEncoder.MPEG_4_SP, + MediaRecorder.OutputFormat.MPEG_4, MediaNames.RECORDED_HVGA_MP4, false); + videoRecordedResult = validateVideo(MediaNames.RECORDED_HVGA_MP4, 480, 320); + assertTrue("HVGAMP4", videoRecordedResult); + } + + @LargeTest + public void testQVGAMP4() throws Exception { + boolean videoRecordedResult = false; + recordVideo(15, 320, 240, MediaRecorder.VideoEncoder.MPEG_4_SP, + MediaRecorder.OutputFormat.MPEG_4, MediaNames.RECORDED_QVGA_MP4, false); + videoRecordedResult = validateVideo(MediaNames.RECORDED_QVGA_MP4, 320, 240); + assertTrue("QVGAMP4", videoRecordedResult); + } + + @LargeTest + public void testSQVGAMP4() throws Exception { + boolean videoRecordedResult = false; + recordVideo(15, 240, 160, MediaRecorder.VideoEncoder.MPEG_4_SP, + MediaRecorder.OutputFormat.MPEG_4, MediaNames.RECORDED_SQVGA_MP4, false); + videoRecordedResult = validateVideo(MediaNames.RECORDED_SQVGA_MP4, 240, 160); + assertTrue("SQVGAMP4", videoRecordedResult); + } + + //Format: QCIF MP4 + @LargeTest + public void testQCIFMP4() throws Exception { + boolean videoRecordedResult = false; + recordVideo(15, 176, 144, MediaRecorder.VideoEncoder.MPEG_4_SP, + MediaRecorder.OutputFormat.MPEG_4, MediaNames.RECORDED_QCIF_MP4, false); + videoRecordedResult = validateVideo(MediaNames.RECORDED_QCIF_MP4, 176, 144); + assertTrue("QCIFMP4", videoRecordedResult); + } + + + //Format: CIF h263 + @LargeTest + public void testCIFMP4() throws Exception { + boolean videoRecordedResult = false; + recordVideo(15, 352, 288, MediaRecorder.VideoEncoder.MPEG_4_SP, + MediaRecorder.OutputFormat.MPEG_4, MediaNames.RECORDED_CIF_MP4, false); + videoRecordedResult = validateVideo(MediaNames.RECORDED_CIF_MP4, 352, 288); + assertTrue("CIFMP4", videoRecordedResult); + } + + + //Format: CIF h263 outputforma 3gpp + @LargeTest + public void testCIFMP43GPP() throws Exception { + boolean videoRecordedResult = false; + recordVideo(15, 352, 288, MediaRecorder.VideoEncoder.MPEG_4_SP, + MediaRecorder.OutputFormat.THREE_GPP, MediaNames.RECORDED_VIDEO_3GP, false); + videoRecordedResult = validateVideo(MediaNames.RECORDED_VIDEO_3GP, 352, 288); + assertTrue("CIFH263", videoRecordedResult); + } + + @LargeTest + public void testQCIFH2633GPP() throws Exception { + boolean videoRecordedResult = false; + recordVideo(15, 176, 144, MediaRecorder.VideoEncoder.H263, + MediaRecorder.OutputFormat.THREE_GPP, MediaNames.RECORDED_VIDEO_3GP, false); + videoRecordedResult = validateVideo(MediaNames.RECORDED_VIDEO_3GP, 176, 144); + assertTrue("QCIFH263 3GPP", videoRecordedResult); + } + +} + diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/SimTonesTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/SimTonesTest.java new file mode 100644 index 0000000000000000000000000000000000000000..241f8d6b73276d8243ade4f5e4daf7121486d4c4 --- /dev/null +++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/SimTonesTest.java @@ -0,0 +1,73 @@ +/* + * 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.android.mediaframeworktest.functional; + +// import android.content.Resources; +import com.android.mediaframeworktest.MediaFrameworkTest; + +import android.content.Context; +import android.test.ActivityInstrumentationTestCase; +import android.test.suitebuilder.annotation.LargeTest; + +/** + * Junit / Instrumentation test case for the SIM tone generator + * + */ +public class SimTonesTest extends ActivityInstrumentationTestCase { + private String TAG = "SimTonesTest"; + + Context mContext; + + public SimTonesTest() { + super("com.android.mediaframeworktest", MediaFrameworkTest.class); + } + + protected void setUp() throws Exception { + super.setUp(); + } + + @LargeTest + public void testDtmfTones() throws Exception { + boolean result = TonesAutoTest.tonesDtmfTest(); + assertTrue("DTMF Tones", result); + } + + @LargeTest + public void testSupervisoryTones() throws Exception { + boolean result = TonesAutoTest.tonesSupervisoryTest(); + assertTrue("Supervisory Tones", result); + } + + @LargeTest + public void testProprietaryTones() throws Exception { + boolean result = TonesAutoTest.tonesProprietaryTest(); + assertTrue("Proprietary Tones", result); + } + + @LargeTest + public void testSimultaneousTones() throws Exception { + boolean result = TonesAutoTest.tonesSimultaneousTest(); + assertTrue("Simultaneous Tones", result); + } + + @LargeTest + public void testStressTones() throws Exception { + boolean result = TonesAutoTest.tonesStressTest(); + assertTrue("Stress Tones", result); + } +} + diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/TonesAutoTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/TonesAutoTest.java new file mode 100644 index 0000000000000000000000000000000000000000..020930528f7db7424c355a662d513e2c25fe7d95 --- /dev/null +++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/TonesAutoTest.java @@ -0,0 +1,180 @@ +/* + * 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.android.mediaframeworktest.functional; + + +//import android.content.Resources; +import android.util.Log; + +import android.media.ToneGenerator; +import android.media.AudioManager; + +/** + * Junit / Instrumentation test case for the Sim tones tests + + */ + public class TonesAutoTest { + private static String TAG = "TonesAutoTest"; + + // Test all DTMF tones one by one + public static boolean tonesDtmfTest() throws Exception { + Log.v(TAG, "DTMF tones test"); + ToneGenerator toneGen; + int type; + boolean result = true; + + toneGen = new ToneGenerator(AudioManager.STREAM_MUSIC, 100); + + for (type = ToneGenerator.TONE_DTMF_0; type <= ToneGenerator.TONE_DTMF_D; type++) { + if (toneGen.startTone(type)) { + Thread.sleep(200); + toneGen.stopTone(); + Thread.sleep(100); + } else { + result = false; + break; + } + } + + toneGen.release(); + return result; + } + + // Test all supervisory tones one by one + public static boolean tonesSupervisoryTest() throws Exception { + Log.v(TAG, "Supervisory tones test"); + ToneGenerator toneGen; + int type; + boolean result = true; + + toneGen = new ToneGenerator(AudioManager.STREAM_MUSIC, 100); + + for (type = ToneGenerator.TONE_SUP_DIAL; + type <= ToneGenerator.TONE_SUP_RINGTONE; type++) { + if (toneGen.startTone(type)) { + Thread.sleep(2000); + toneGen.stopTone(); + Thread.sleep(200); + } else { + result = false; + break; + } + } + + toneGen.release(); + return result; + } + + // Test all proprietary tones one by one + public static boolean tonesProprietaryTest() throws Exception { + Log.v(TAG, "Proprietary tones test"); + ToneGenerator toneGen; + int type; + boolean result = true; + + toneGen = new ToneGenerator(AudioManager.STREAM_MUSIC, 100); + + for (type = ToneGenerator.TONE_PROP_BEEP; type <= ToneGenerator.TONE_PROP_PROMPT; type++) { + if (toneGen.startTone(type)) { + Thread.sleep(1000); + toneGen.stopTone(); + Thread.sleep(100); + } else { + result = false; + break; + } + } + + toneGen.release(); + return result; + } + + // Test playback of 2 tones simultaneously + public static boolean tonesSimultaneousTest() throws Exception { + Log.v(TAG, "Simultaneous tones test"); + ToneGenerator toneGen1; + ToneGenerator toneGen2; + int type; + boolean result = true; + + toneGen1 = new ToneGenerator(AudioManager.STREAM_MUSIC, 100); + toneGen2 = new ToneGenerator(AudioManager.STREAM_MUSIC, 50); + + if (toneGen1.startTone(ToneGenerator.TONE_DTMF_1)) { + Thread.sleep(100); + if (toneGen2.startTone(ToneGenerator.TONE_DTMF_2)) { + Thread.sleep(500); + toneGen1.stopTone(); + Thread.sleep(100); + toneGen2.stopTone(); + } else { + toneGen1.stopTone(); + result = false; + } + } else { + result = false; + } + + toneGen1.release(); + toneGen2.release(); + return result; + } + + // Test start of new tone without stopping previous one + public static boolean tonesStressTest() throws Exception { + Log.v(TAG, "Stress tones test"); + ToneGenerator toneGen; + int type; + boolean result = true; + + toneGen = new ToneGenerator(AudioManager.STREAM_MUSIC, 100); + + for (type = ToneGenerator.TONE_DTMF_1; type <= ToneGenerator.TONE_DTMF_9; type++) { + if (toneGen.startTone(type)) { + Thread.sleep(200); + } else { + result = false; + break; + } + } + + toneGen.release(); + return result; + } + + // Perform all tones tests + public static boolean tonesAllTest() throws Exception { + Log.v(TAG, "All tones tests"); + + if (!tonesDtmfTest()) { + return false; + } + if (!tonesSupervisoryTest()) { + return false; + } + if (!tonesProprietaryTest()) { + return false; + } + if (!tonesSimultaneousTest()) { + return false; + } + if (!tonesStressTest()) { + return false; + } + return true; + } +} diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/performance/MediaPlayerPerformance.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/performance/MediaPlayerPerformance.java new file mode 100644 index 0000000000000000000000000000000000000000..b606f251532af6c8bc1fda133c09dfdccba55c74 --- /dev/null +++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/performance/MediaPlayerPerformance.java @@ -0,0 +1,159 @@ +/* + * 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.android.mediaframeworktest.performance; + +import com.android.mediaframeworktest.MediaFrameworkTest; +import com.android.mediaframeworktest.MediaNames; + +import android.content.Context; +import android.database.sqlite.SQLiteDatabase; +import android.media.MediaPlayer; +import android.os.SystemClock; +import android.test.ActivityInstrumentationTestCase; +import android.test.suitebuilder.annotation.LargeTest; +import android.test.suitebuilder.annotation.Suppress; +import android.util.Log; + +import java.io.FileDescriptor; +import java.io.FileInputStream; +import android.media.MediaMetadataRetriever; + +/** + * Junit / Instrumentation test case for the media player api + + */ +public class MediaPlayerPerformance extends ActivityInstrumentationTestCase { + + + private boolean mIsPlaying = true; + private String TAG = "MediaPlayerApiTest"; + Context mContext; + private SQLiteDatabase mDB; + + + public MediaPlayerPerformance() { + super("com.android.mediaframeworktest", MediaFrameworkTest.class); + } + + protected void setUp() throws Exception { + + super.setUp(); + } + + public void createDB(){ + mDB = SQLiteDatabase.openOrCreateDatabase("/sdcard/perf.db",null); + mDB.execSQL("CREATE TABLE perfdata (_id INTEGER PRIMARY KEY," + + "file TEXT," + "setdatatime LONG," +"preparetime LONG," +"playtime LONG" + ");"); + } + + public void audioPlaybackStartupTime(String[] testFile){ + long t1 = 0; + long t2 = 0; + long t3 = 0; + long t4 =0; + + long setDataSourceDuration = 0; + long prepareDuration = 0; + long startDuration=0; + + long totalSetDataTime=0; + long totalPrepareTime=0; + long totalStartDuration=0; + + int numberOfFiles = testFile.length; + Log.v(TAG, "File lenght " + numberOfFiles); + for (int k=0; kinstanceof to + * test if the interface supports GL11 or higher interfaces. + * @param config the EGLConfig of the created surface. Can be used + * to create matching pbuffers. + */ + void onSurfaceCreated(GL10 gl, EGLConfig config); + /** + * Surface changed size. + * Called after the surface is created and whenever + * the OpenGL ES surface size changes. Set your viewport here. + * @param gl the GL interface. Use instanceof to + * test if the interface supports GL11 or higher interfaces. + * @param width + * @param height + */ + void onSurfaceChanged(GL10 gl, int width, int height); + /** + * Draw the current frame. + * @param gl the GL interface. Use instanceof to + * test if the interface supports GL11 or higher interfaces. + */ + void onDrawFrame(GL10 gl); + } + + /** + * An EGL helper class. + */ + + private class EglHelper { + public EglHelper() { + + } + + /** + * Initialize EGL for a given configuration spec. + * @param configSpec + */ + public void start(int[] configSpec){ + /* + * Get an EGL instance + */ + mEgl = (EGL10) EGLContext.getEGL(); + + /* + * Get to the default display. + */ + mEglDisplay = mEgl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY); + + /* + * We can now initialize EGL for that display + */ + int[] version = new int[2]; + mEgl.eglInitialize(mEglDisplay, version); + + EGLConfig[] configs = new EGLConfig[1]; + int[] num_config = new int[1]; + mEgl.eglChooseConfig(mEglDisplay, configSpec, configs, 1, + num_config); + mEglConfig = configs[0]; + + /* + * Create an OpenGL ES context. This must be done only once, an + * OpenGL context is a somewhat heavy object. + */ + mEglContext = mEgl.eglCreateContext(mEglDisplay, mEglConfig, + EGL10.EGL_NO_CONTEXT, null); + + mEglSurface = null; + } + + /* + * React to the creation of a new surface by creating and returning an + * OpenGL interface that renders to that surface. + */ + public GL createSurface(SurfaceHolder holder) { + /* + * The window size has changed, so we need to create a new + * surface. + */ + if (mEglSurface != null) { + + /* + * Unbind and destroy the old EGL surface, if + * there is one. + */ + mEgl.eglMakeCurrent(mEglDisplay, EGL10.EGL_NO_SURFACE, + EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_CONTEXT); + mEgl.eglDestroySurface(mEglDisplay, mEglSurface); + } + + /* + * Create an EGL surface we can render into. + */ + mEglSurface = mEgl.eglCreateWindowSurface(mEglDisplay, + mEglConfig, holder, null); + + /* + * Before we can issue GL commands, we need to make sure + * the context is current and bound to a surface. + */ + mEgl.eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, + mEglContext); + + + GL gl = mEglContext.getGL(); + if (mGLWrapper != null) { + gl = mGLWrapper.wrap(gl); + } + + if ((mDebugFlags & (DEBUG_CHECK_GL_ERROR | DEBUG_LOG_GL_CALLS))!= 0) { + int configFlags = 0; + Writer log = null; + if ((mDebugFlags & DEBUG_CHECK_GL_ERROR) != 0) { + configFlags |= GLDebugHelper.CONFIG_CHECK_GL_ERROR; + } + if ((mDebugFlags & DEBUG_LOG_GL_CALLS) != 0) { + log = new LogWriter(); + } + gl = GLDebugHelper.wrap(gl, configFlags, log); + } + return gl; + } + + /** + * Display the current render surface. + * @return false if the context has been lost. + */ + public boolean swap() { + mEgl.eglSwapBuffers(mEglDisplay, mEglSurface); + + /* + * Always check for EGL_CONTEXT_LOST, which means the context + * and all associated data were lost (For instance because + * the device went to sleep). We need to sleep until we + * get a new surface. + */ + return mEgl.eglGetError() != EGL11.EGL_CONTEXT_LOST; + } + + public void finish() { + if (mEglSurface != null) { + mEgl.eglMakeCurrent(mEglDisplay, EGL10.EGL_NO_SURFACE, + EGL10.EGL_NO_SURFACE, + EGL10.EGL_NO_CONTEXT); + mEgl.eglDestroySurface(mEglDisplay, mEglSurface); + mEglSurface = null; + } + if (mEglContext != null) { + mEgl.eglDestroyContext(mEglDisplay, mEglContext); + mEglContext = null; + } + if (mEglDisplay != null) { + mEgl.eglTerminate(mEglDisplay); + mEglDisplay = null; + } + } + + EGL10 mEgl; + EGLDisplay mEglDisplay; + EGLSurface mEglSurface; + EGLConfig mEglConfig; + EGLContext mEglContext; + } + + /** + * A generic GL Thread. Takes care of initializing EGL and GL. Delegates + * to a Renderer instance to do the actual drawing. Can be configured to + * render continuously or on request. + * + */ + class GLThread extends Thread { + GLThread(Renderer renderer) { + super(); + mDone = false; + mWidth = 0; + mHeight = 0; + mRequestRender = true; + mRenderMode = RENDERMODE_CONTUOUSLY; + mRenderer = renderer; + setName("GLThread"); + } + + @Override + public void run() { + /* + * When the android framework launches a second instance of + * an activity, the new instance's onCreate() method may be + * called before the first instance returns from onDestroy(). + * + * This semaphore ensures that only one instance at a time + * accesses EGL. + */ + try { + try { + sEglSemaphore.acquire(); + } catch (InterruptedException e) { + return; + } + guardedRun(); + } catch (InterruptedException e) { + // fall thru and exit normally + } finally { + sEglSemaphore.release(); + } + } + + private void guardedRun() throws InterruptedException { + mEglHelper = new EglHelper(); + /* + * Specify a configuration for our opengl session + * and grab the first configuration that matches is + */ + int[] configSpec = mRenderer.getConfigSpec(); + mEglHelper.start(configSpec); + + GL10 gl = null; + boolean tellRendererSurfaceCreated = true; + boolean tellRendererSurfaceChanged = true; + + /* + * This is our main activity thread's loop, we go until + * asked to quit. + */ + while (!mDone) { + + /* + * Update the asynchronous state (window size) + */ + int w, h; + boolean changed; + boolean needStart = false; + synchronized (this) { + Runnable r; + while ((r = getEvent()) != null) { + r.run(); + } + if (mPaused) { + mEglHelper.finish(); + needStart = true; + } + while (needToWait()) { + wait(); + } + if (mDone) { + break; + } + changed = mSizeChanged; + w = mWidth; + h = mHeight; + mSizeChanged = false; + mRequestRender = false; + } + if (needStart) { + mEglHelper.start(configSpec); + tellRendererSurfaceCreated = true; + changed = true; + } + if (changed) { + gl = (GL10) mEglHelper.createSurface(getHolder()); + tellRendererSurfaceChanged = true; + } + if (tellRendererSurfaceCreated) { + mRenderer.onSurfaceCreated(gl, mEglHelper.mEglConfig); + tellRendererSurfaceCreated = false; + } + if (tellRendererSurfaceChanged) { + mRenderer.onSurfaceChanged(gl, w, h); + tellRendererSurfaceChanged = false; + } + if ((w > 0) && (h > 0)) { + /* draw a frame here */ + mRenderer.onDrawFrame(gl); + + /* + * Once we're done with GL, we need to call swapBuffers() + * to instruct the system to display the rendered frame + */ + mEglHelper.swap(); + } + } + + /* + * clean-up everything... + */ + mEglHelper.finish(); + } + + private boolean needToWait() { + if (mDone) { + return false; + } + + if (mPaused || (! mHasSurface)) { + return true; + } + + if ((mWidth > 0) && (mHeight > 0) && (mRequestRender || (mRenderMode == RENDERMODE_CONTUOUSLY))) { + return false; + } + + return true; + } + + public void setRenderMode(int renderMode) { + if ( !((RENDERMODE_WHEN_DIRTY <= renderMode) && (renderMode <= RENDERMODE_CONTUOUSLY)) ) { + throw new IllegalArgumentException("renderMode"); + } + synchronized(this) { + mRenderMode = renderMode; + if (renderMode == RENDERMODE_CONTUOUSLY) { + notify(); + } + } + } + + public int getRenderMode() { + synchronized(this) { + return mRenderMode; + } + } + + public void requestRender() { + synchronized(this) { + mRequestRender = true; + notify(); + } + } + + public void surfaceCreated() { + synchronized(this) { + mHasSurface = true; + notify(); + } + } + + public void surfaceDestroyed() { + synchronized(this) { + mHasSurface = false; + notify(); + } + } + + public void onPause() { + synchronized (this) { + mPaused = true; + } + } + + public void onResume() { + synchronized (this) { + mPaused = false; + notify(); + } + } + + public void onWindowResize(int w, int h) { + synchronized (this) { + mWidth = w; + mHeight = h; + mSizeChanged = true; + notify(); + } + } + + public void requestExitAndWait() { + // don't call this from GLThread thread or it is a guaranteed + // deadlock! + synchronized(this) { + mDone = true; + notify(); + } + try { + join(); + } catch (InterruptedException ex) { + Thread.currentThread().interrupt(); + } + } + + /** + * Queue an "event" to be run on the GL rendering thread. + * @param r the runnable to be run on the GL rendering thread. + */ + public void queueEvent(Runnable r) { + synchronized(this) { + mEventQueue.add(r); + } + } + + private Runnable getEvent() { + synchronized(this) { + if (mEventQueue.size() > 0) { + return mEventQueue.remove(0); + } + + } + return null; + } + + private boolean mDone; + private boolean mPaused; + private boolean mHasSurface; + private int mWidth; + private int mHeight; + private int mRenderMode; + private boolean mRequestRender; + private Renderer mRenderer; + private ArrayList mEventQueue = new ArrayList(); + private EglHelper mEglHelper; + } + + static class LogWriter extends Writer { + + @Override public void close() { + flushBuilder(); + } + + @Override public void flush() { + flushBuilder(); + } + + @Override public void write(char[] buf, int offset, int count) { + for(int i = 0; i < count; i++) { + char c = buf[offset + i]; + if ( c == '\n') { + flushBuilder(); + } + else { + mBuilder.append(c); + } + } + } + + private void flushBuilder() { + if (mBuilder.length() > 0) { + Log.v("GLSurfaceView", mBuilder.toString()); + mBuilder.delete(0, mBuilder.length()); + } + } + + private StringBuilder mBuilder = new StringBuilder(); + } + + private static final Semaphore sEglSemaphore = new Semaphore(1); + private boolean mSizeChanged = true; + + private GLThread mGLThread; + private GLWrapper mGLWrapper; + private int mDebugFlags; +} diff --git a/opengl/java/android/opengl/GLU.java b/opengl/java/android/opengl/GLU.java index ff2741a6a4bf82a0c0f3642c810ffba1e4204465..0152f42b0e418b3b30ad7af6fa82fb959539c99e 100644 --- a/opengl/java/android/opengl/GLU.java +++ b/opengl/java/android/opengl/GLU.java @@ -85,18 +85,17 @@ public class GLU { fy *= rlf; fz *= rlf; - // Normalize up - float rlup = 1.0f / Matrix.length(upX, upY, upZ); - upX *= rlup; - upY *= rlup; - upZ *= rlup; - // compute s = f x up (x means "cross product") - float sx = fy * upZ - fz * upY; float sy = fz * upX - fx * upZ; float sz = fx * upY - fy * upX; - + + // and normalize s + float rls = 1.0f / Matrix.length(sx, sy, sz); + sx *= rls; + sy *= rls; + sz *= rls; + // compute u = s x f float ux = sy * fz - sz * fy; float uy = sz * fx - sx * fz; diff --git a/opengl/libGLES_CM/gl_wrapper.cpp b/opengl/libGLES_CM/gl_wrapper.cpp index 5da4f9a222bf478bbd7dbd63bd8a842c7f2e53fc..3b7f45e7fcb87da3c31c325abe17671d2ac0d669 100644 --- a/opengl/libGLES_CM/gl_wrapper.cpp +++ b/opengl/libGLES_CM/gl_wrapper.cpp @@ -373,6 +373,7 @@ public: static sp gRevokerCallback; + static request_gpu_t* gpu_acquire(void* user) { sp server( getSurfaceFlinger() ); @@ -383,7 +384,10 @@ static request_gpu_t* gpu_acquire(void* user) } ISurfaceComposer::gpu_info_t info; - gRevokerCallback = new GPURevokeRequester(); + + if (gRevokerCallback == 0) + gRevokerCallback = new GPURevokeRequester(); + status_t err = server->requestGPU(gRevokerCallback, &info); if (err != NO_ERROR) { LOGD("requestGPU returned %d", err); @@ -549,6 +553,21 @@ int binarySearch( return -1; } +static EGLint configToUniqueId(egl_display_t const* dp, int i, int index) +{ + // NOTE: this mapping works only if we have no more than two EGLimpl + return (i>0 ? dp->numConfigs[0] : 0) + index; +} + +static void uniqueIdToConfig(egl_display_t const* dp, EGLint configId, + int& i, int& index) +{ + // NOTE: this mapping works only if we have no more than two EGLimpl + size_t numConfigs = dp->numConfigs[0]; + i = configId / numConfigs; + index = configId % numConfigs; +} + static int cmp_configs(const void* a, const void *b) { EGLConfig c0 = *(EGLConfig const *)a; @@ -557,7 +576,7 @@ static int cmp_configs(const void* a, const void *b) } static char const * const gVendorString = "Android"; -static char const * const gVersionString = "1.2 Android META-EGL"; +static char const * const gVersionString = "1.3 Android META-EGL"; static char const * const gClientApiString = "OpenGL ES"; struct extention_map_t { @@ -834,7 +853,13 @@ EGLDisplay eglGetDisplay(NativeDisplayType display) property_get("debug.egl.hw", value, "1"); if (atoi(value) != 0) { cnx->hooks = &gHooks[IMPL_HARDWARE]; - cnx->dso = load_driver("libhgl.so", cnx->hooks); + property_get("debug.egl.profiler", value, "0"); + if (atoi(value) == 0) { + cnx->dso = load_driver("libhgl.so", cnx->hooks); + } else { + LOGW("Using instrumented h/w OpenGL ES library"); + cnx->dso = load_driver("libhgld.so", cnx->hooks); + } } else { LOGD("3D hardware acceleration is disabled"); } @@ -864,6 +889,8 @@ EGLDisplay eglGetDisplay(NativeDisplayType display) d->dpys[IMPL_HARDWARE] = cnx->hooks->egl.eglGetDisplay(display); if (d->dpys[IMPL_HARDWARE] == EGL_NO_DISPLAY) { + LOGE("h/w accelerated eglGetDisplay() failed (%s)", + egl_strerror(cnx->hooks->egl.eglGetError())); dlclose((void*)cnx->dso); cnx->dso = 0; // in case of failure, we want to make sure we don't try again @@ -900,7 +927,10 @@ EGLBoolean eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor) egl_connection_t* const cnx = &gEGLImpl[i]; cnx->major = -1; cnx->minor = -1; - if (cnx->dso && cnx->hooks->egl.eglInitialize( + if (!cnx->dso) + continue; + + if (cnx->hooks->egl.eglInitialize( dp->dpys[i], &cnx->major, &cnx->minor)) { //LOGD("initialized %d dpy=%p, ver=%d.%d, cnx=%p", @@ -912,10 +942,10 @@ EGLBoolean eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor) dp->queryString[i].version = cnx->hooks->egl.eglQueryString(dp->dpys[i], EGL_VERSION); dp->queryString[i].extensions = strdup( - cnx->hooks->egl.eglQueryString(dp->dpys[i], EGL_EXTENSIONS)); + cnx->hooks->egl.eglQueryString(dp->dpys[i], EGL_EXTENSIONS)); dp->queryString[i].clientApi = cnx->hooks->egl.eglQueryString(dp->dpys[i], EGL_CLIENT_APIS); - + // Dynamically insert extensions we know about if (cnx->hooks->egl.eglSwapRectangleANDROID) add_extension(dp, dp->queryString[i].extensions, @@ -924,12 +954,15 @@ EGLBoolean eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor) if (cnx->hooks->egl.eglQueryStringConfigANDROID) add_extension(dp, dp->queryString[i].extensions, "EGL_ANDROID_query_string_config"); + } else { + LOGD("%d: eglInitialize() failed (%s)", + i, egl_strerror(cnx->hooks->egl.eglGetError())); } } - + // Build the extension list that depends on the current config. // It is the intersection of our extension list and the - // underlaying EGL's extensions list + // underlying EGL's extensions list EGLBoolean res = EGL_FALSE; for (int i=0 ; i<2 ; i++) { egl_connection_t* const cnx = &gEGLImpl[i]; @@ -951,10 +984,10 @@ EGLBoolean eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor) } while (*p); free((void*)our_extensions_org); - // remove the trailling white space + // remove the trailing white space if (extensions_config[0] != 0) { size_t l = strlen(extensions_config) - 1; // new size - extensions_config[l] = 0; // remove the trailling white space + extensions_config[l] = 0; // remove the trailing white space extensions_config = (char*)realloc(extensions_config, l+1); } else { extensions_config = (char*)realloc(extensions_config, 1); @@ -1065,15 +1098,74 @@ EGLBoolean eglChooseConfig( EGLDisplay dpy, const EGLint *attrib_list, return EGL_TRUE; } + EGLint n; EGLBoolean res = EGL_FALSE; *num_config = 0; + + + // It is unfortunate, but we need to remap the EGL_CONFIG_IDs, + // to do this, we have to go through the attrib_list array once + // to figure out both its size and if it contains an EGL_CONFIG_ID + // key. If so, the full array is copied and patched. + // NOTE: we assume that there can be only one occurrence + // of EGL_CONFIG_ID. + + EGLint patch_index = -1; + GLint attr; + size_t size = 0; + while ((attr=attrib_list[size])) { + if (attr == EGL_CONFIG_ID) + patch_index = size; + size += 2; + } + if (patch_index >= 0) { + size += 2; // we need copy the sentinel as well + EGLint* new_list = (EGLint*)malloc(size*sizeof(EGLint)); + if (new_list == 0) + return setError(EGL_BAD_ALLOC, EGL_FALSE); + memcpy(new_list, attrib_list, size*sizeof(EGLint)); + + // patch the requested EGL_CONFIG_ID + int i, index; + EGLint& configId(new_list[patch_index+1]); + uniqueIdToConfig(dp, configId, i, index); + + egl_connection_t* const cnx = &gEGLImpl[i]; + if (cnx->dso) { + cnx->hooks->egl.eglGetConfigAttrib( + dp->dpys[i], dp->configs[i][index], + EGL_CONFIG_ID, &configId); + + // and switch to the new list + attrib_list = const_cast(new_list); + + // At this point, the only configuration that can match is + // dp->configs[i][index], however, we don't know if it would be + // rejected because of the other attributes, so we do have to call + // cnx->hooks->egl.eglChooseConfig() -- but we don't have to loop + // through all the EGLimpl[]. + // We also know we can only get a single config back, and we know + // which one. + + res = cnx->hooks->egl.eglChooseConfig( + dp->dpys[i], attrib_list, configs, config_size, &n); + if (res && n>0) { + // n has to be 0 or 1, by construction, and we already know + // which config it will return (since there can be only one). + configs[0] = MAKE_CONFIG(i, index); + *num_config = 1; + } + } + + free(const_cast(attrib_list)); + return res; + } + for (int i=0 ; i<2 ; i++) { egl_connection_t* const cnx = &gEGLImpl[i]; if (cnx->dso) { - EGLint n; if (cnx->hooks->egl.eglChooseConfig( - dp->dpys[i], attrib_list, configs, config_size, &n)) - { + dp->dpys[i], attrib_list, configs, config_size, &n)) { // now we need to convert these client EGLConfig to our // internal EGLConfig format. This is done in O(n log n). for (int j=0 ; jhooks->egl.eglGetConfigAttrib( dp->dpys[i], dp->configs[i][index], attribute, value); } diff --git a/opengl/libagl/TextureObjectManager.cpp b/opengl/libagl/TextureObjectManager.cpp index 12fae63632776135338d0609d25f4a05009ce62c..ce31854172d34b123fbddf56f0b2b1c17431dba8 100644 --- a/opengl/libagl/TextureObjectManager.cpp +++ b/opengl/libagl/TextureObjectManager.cpp @@ -129,7 +129,7 @@ status_t EGLTextureObject::setSurface(GGLSurface const* s) // so for now, we just loose it. memset(crop_rect, 0, sizeof(crop_rect)); - // it would be nice id we could keep the generate_mipmap flag + // it would be nice if we could keep the generate_mipmap flag, // we would have to generate them right now though. generate_mipmap = GL_FALSE; @@ -286,7 +286,7 @@ sp EGLSurfaceManager::replaceTexture(GLuint name) void EGLSurfaceManager::deleteTextures(GLsizei n, const GLuint *tokens) { - // free all texures + // free all textures Mutex::Autolock _l(mLock); for (GLsizei i=0 ; iclipPlanes.enable) { // needs eye coords - want |= transform_state_t::MODELVIEW; + if (c->clipPlanes.enable || (enables & GGL_ENABLE_FOG)) { + want |= transform_state_t::MODELVIEW; // needs eye coords } ogles_validate_transform(c, want); diff --git a/opengl/libagl/egl.cpp b/opengl/libagl/egl.cpp index 854a49e6a7f4c5ffbd531c5efce67b9419fdc2a5..3e8dca958dc9230c1a1c1aab2d7f06fe1bc793ad 100644 --- a/opengl/libagl/egl.cpp +++ b/opengl/libagl/egl.cpp @@ -36,6 +36,7 @@ #include #include +#include #include "context.h" #include "state.h" @@ -57,7 +58,7 @@ static pthread_key_t gEGLErrorKey = -1; #ifndef HAVE_ANDROID_OS namespace gl { pthread_key_t gGLKey = -1; -}; // namspace gl +}; // namespace gl #endif template @@ -156,7 +157,7 @@ protected: egl_surface_t::egl_surface_t(EGLDisplay dpy, EGLConfig config, int32_t depthFormat) - : magic(0x31415265), dpy(dpy), config(config), ctx(0) + : magic(MAGIC), dpy(dpy), config(config), ctx(0) { depth.version = sizeof(GGLSurface); depth.data = 0; @@ -240,7 +241,7 @@ EGLBoolean egl_window_surface_t::swapBuffers() { uint32_t flags = nativeWindow->swapBuffers(nativeWindow); if (flags & EGL_NATIVES_FLAG_SIZE_CHANGED) { - // TODO: we probaly should reset the swap rect here + // TODO: we probably should reset the swap rect here // if the window size has changed // window->setSwapRectangle(Rect(info.w, info.h)); if (depth.data) { @@ -402,12 +403,13 @@ egl_pbuffer_surface_t::egl_pbuffer_surface_t(EGLDisplay dpy, { size_t size = w*h; switch (f) { - case GGL_PIXEL_FORMAT_RGB_565: size *= 2; break; - case GGL_PIXEL_FORMAT_RGBA_8888: size *= 4; break; - default: - LOGE("incompatible pixel format for pbuffer (format=%d)", f); - pbuffer.data = 0; - break; + case GGL_PIXEL_FORMAT_A_8: size *= 1; break; + case GGL_PIXEL_FORMAT_RGB_565: size *= 2; break; + case GGL_PIXEL_FORMAT_RGBA_8888: size *= 4; break; + default: + LOGE("incompatible pixel format for pbuffer (format=%d)", f); + pbuffer.data = 0; + break; } pbuffer.version = sizeof(GGLSurface); pbuffer.width = w; @@ -488,28 +490,28 @@ struct extention_map_t { }; static const extention_map_t gExtentionMap[] = { - { "eglSwapRectangleANDROID", (void(*)())&eglSwapRectangleANDROID }, - { "glDrawTexsOES", (void(*)())&glDrawTexsOES }, - { "glDrawTexiOES", (void(*)())&glDrawTexiOES }, - { "glDrawTexfOES", (void(*)())&glDrawTexfOES }, - { "glDrawTexxOES", (void(*)())&glDrawTexxOES }, - { "glDrawTexsvOES", (void(*)())&glDrawTexsvOES }, - { "glDrawTexivOES", (void(*)())&glDrawTexivOES }, - { "glDrawTexfvOES", (void(*)())&glDrawTexfvOES }, - { "glDrawTexxvOES", (void(*)())&glDrawTexxvOES }, - { "glQueryMatrixxOES", (void(*)())&glQueryMatrixxOES }, - { "glClipPlanef", (void(*)())&glClipPlanef }, - { "glClipPlanex", (void(*)())&glClipPlanex }, - { "glBindBuffer", (void(*)())&glBindBuffer }, - { "glBufferData", (void(*)())&glBufferData }, - { "glBufferSubData", (void(*)())&glBufferSubData }, - { "glDeleteBuffers", (void(*)())&glDeleteBuffers }, - { "glGenBuffers", (void(*)())&glGenBuffers }, + { "eglSwapRectangleANDROID", (void(*)())&eglSwapRectangleANDROID }, + { "glDrawTexsOES", (void(*)())&glDrawTexsOES }, + { "glDrawTexiOES", (void(*)())&glDrawTexiOES }, + { "glDrawTexfOES", (void(*)())&glDrawTexfOES }, + { "glDrawTexxOES", (void(*)())&glDrawTexxOES }, + { "glDrawTexsvOES", (void(*)())&glDrawTexsvOES }, + { "glDrawTexivOES", (void(*)())&glDrawTexivOES }, + { "glDrawTexfvOES", (void(*)())&glDrawTexfvOES }, + { "glDrawTexxvOES", (void(*)())&glDrawTexxvOES }, + { "glQueryMatrixxOES", (void(*)())&glQueryMatrixxOES }, + { "glClipPlanef", (void(*)())&glClipPlanef }, + { "glClipPlanex", (void(*)())&glClipPlanex }, + { "glBindBuffer", (void(*)())&glBindBuffer }, + { "glBufferData", (void(*)())&glBufferData }, + { "glBufferSubData", (void(*)())&glBufferSubData }, + { "glDeleteBuffers", (void(*)())&glDeleteBuffers }, + { "glGenBuffers", (void(*)())&glGenBuffers }, }; /* * In the lists below, attributes names MUST be sorted. - * Additinnaly, all configs must be sorted according to + * Additionally, all configs must be sorted according to * the EGL specification. */ @@ -517,9 +519,10 @@ static config_pair_t const config_base_attribute_list[] = { { EGL_STENCIL_SIZE, 0 }, { EGL_CONFIG_CAVEAT, EGL_SLOW_CONFIG }, { EGL_LEVEL, 0 }, - { EGL_MAX_PBUFFER_HEIGHT, 0 }, - { EGL_MAX_PBUFFER_PIXELS, 0 }, - { EGL_MAX_PBUFFER_WIDTH, 0 }, + { EGL_MAX_PBUFFER_HEIGHT, GGL_MAX_VIEWPORT_DIMS }, + { EGL_MAX_PBUFFER_PIXELS, + GGL_MAX_VIEWPORT_DIMS*GGL_MAX_VIEWPORT_DIMS }, + { EGL_MAX_PBUFFER_WIDTH, GGL_MAX_VIEWPORT_DIMS }, { EGL_NATIVE_RENDERABLE, EGL_TRUE }, { EGL_NATIVE_VISUAL_ID, 0 }, { EGL_NATIVE_VISUAL_TYPE, GGL_PIXEL_FORMAT_RGB_565 }, @@ -536,49 +539,72 @@ static config_pair_t const config_base_attribute_list[] = { }; // These configs can override the base attribute list +// NOTE: when adding a config here, don't forget to update eglCreate*Surface() static config_pair_t const config_0_attribute_list[] = { - { EGL_BUFFER_SIZE, 16 }, - { EGL_ALPHA_SIZE, 0 }, - { EGL_BLUE_SIZE, 5 }, - { EGL_GREEN_SIZE, 6 }, - { EGL_RED_SIZE, 5 }, - { EGL_DEPTH_SIZE, 0 }, - { EGL_CONFIG_ID, 0 }, - { EGL_SURFACE_TYPE, EGL_WINDOW_BIT | EGL_PIXMAP_BIT }, + { EGL_BUFFER_SIZE, 16 }, + { EGL_ALPHA_SIZE, 0 }, + { EGL_BLUE_SIZE, 5 }, + { EGL_GREEN_SIZE, 6 }, + { EGL_RED_SIZE, 5 }, + { EGL_DEPTH_SIZE, 0 }, + { EGL_CONFIG_ID, 0 }, + { EGL_SURFACE_TYPE, EGL_WINDOW_BIT|EGL_PBUFFER_BIT|EGL_PIXMAP_BIT }, }; static config_pair_t const config_1_attribute_list[] = { - { EGL_BUFFER_SIZE, 16 }, - { EGL_ALPHA_SIZE, 0 }, - { EGL_BLUE_SIZE, 5 }, - { EGL_GREEN_SIZE, 6 }, - { EGL_RED_SIZE, 5 }, - { EGL_DEPTH_SIZE, 16 }, - { EGL_CONFIG_ID, 1 }, - { EGL_SURFACE_TYPE, EGL_WINDOW_BIT | EGL_PIXMAP_BIT }, + { EGL_BUFFER_SIZE, 16 }, + { EGL_ALPHA_SIZE, 0 }, + { EGL_BLUE_SIZE, 5 }, + { EGL_GREEN_SIZE, 6 }, + { EGL_RED_SIZE, 5 }, + { EGL_DEPTH_SIZE, 16 }, + { EGL_CONFIG_ID, 1 }, + { EGL_SURFACE_TYPE, EGL_WINDOW_BIT|EGL_PBUFFER_BIT|EGL_PIXMAP_BIT }, }; static config_pair_t const config_2_attribute_list[] = { - { EGL_BUFFER_SIZE, 32 }, - { EGL_ALPHA_SIZE, 8 }, - { EGL_BLUE_SIZE, 8 }, - { EGL_GREEN_SIZE, 8 }, - { EGL_RED_SIZE, 8 }, - { EGL_DEPTH_SIZE, 0 }, - { EGL_CONFIG_ID, 2 }, - { EGL_SURFACE_TYPE, EGL_WINDOW_BIT | EGL_PIXMAP_BIT }, + { EGL_BUFFER_SIZE, 32 }, + { EGL_ALPHA_SIZE, 8 }, + { EGL_BLUE_SIZE, 8 }, + { EGL_GREEN_SIZE, 8 }, + { EGL_RED_SIZE, 8 }, + { EGL_DEPTH_SIZE, 0 }, + { EGL_CONFIG_ID, 2 }, + { EGL_SURFACE_TYPE, EGL_WINDOW_BIT|EGL_PBUFFER_BIT|EGL_PIXMAP_BIT }, }; static config_pair_t const config_3_attribute_list[] = { - { EGL_BUFFER_SIZE, 32 }, - { EGL_ALPHA_SIZE, 8 }, - { EGL_BLUE_SIZE, 8 }, - { EGL_GREEN_SIZE, 8 }, - { EGL_RED_SIZE, 8 }, - { EGL_DEPTH_SIZE, 16 }, - { EGL_CONFIG_ID, 3 }, - { EGL_SURFACE_TYPE, EGL_WINDOW_BIT | EGL_PIXMAP_BIT }, + { EGL_BUFFER_SIZE, 32 }, + { EGL_ALPHA_SIZE, 8 }, + { EGL_BLUE_SIZE, 8 }, + { EGL_GREEN_SIZE, 8 }, + { EGL_RED_SIZE, 8 }, + { EGL_DEPTH_SIZE, 16 }, + { EGL_CONFIG_ID, 3 }, + { EGL_SURFACE_TYPE, EGL_WINDOW_BIT|EGL_PBUFFER_BIT|EGL_PIXMAP_BIT }, +}; + +static config_pair_t const config_4_attribute_list[] = { + { EGL_BUFFER_SIZE, 8 }, + { EGL_ALPHA_SIZE, 8 }, + { EGL_BLUE_SIZE, 0 }, + { EGL_GREEN_SIZE, 0 }, + { EGL_RED_SIZE, 0 }, + { EGL_DEPTH_SIZE, 0 }, + { EGL_CONFIG_ID, 4 }, + { EGL_SURFACE_TYPE, EGL_WINDOW_BIT|EGL_PBUFFER_BIT|EGL_PIXMAP_BIT }, +}; + +static config_pair_t const config_5_attribute_list[] = { + { EGL_BUFFER_SIZE, 8 }, + { EGL_ALPHA_SIZE, 8 }, + { EGL_BLUE_SIZE, 0 }, + { EGL_GREEN_SIZE, 0 }, + { EGL_RED_SIZE, 0 }, + { EGL_DEPTH_SIZE, 16 }, + { EGL_CONFIG_ID, 5 }, + { EGL_SURFACE_TYPE, EGL_WINDOW_BIT|EGL_PBUFFER_BIT|EGL_PIXMAP_BIT }, }; static configs_t const gConfigs[] = { @@ -586,6 +612,8 @@ static configs_t const gConfigs[] = { { config_1_attribute_list, NELEM(config_1_attribute_list) }, { config_2_attribute_list, NELEM(config_2_attribute_list) }, { config_3_attribute_list, NELEM(config_3_attribute_list) }, + { config_4_attribute_list, NELEM(config_4_attribute_list) }, + { config_5_attribute_list, NELEM(config_5_attribute_list) }, }; static config_management_t const gConfigManagement[] = { @@ -669,7 +697,7 @@ static int isAttributeMatching(int i, EGLint attr, EGLint val) return 1; } } else { - // attribute nont found. this should NEVER happen. + // attribute not found. this should NEVER happen. } } else { // error, this attribute doesn't exist @@ -779,11 +807,19 @@ static EGLSurface createWindowSurface(EGLDisplay dpy, EGLConfig config, pixelFormat = GGL_PIXEL_FORMAT_RGBA_8888; depthFormat = GGL_PIXEL_FORMAT_Z_16; break; + case 4: + pixelFormat = GGL_PIXEL_FORMAT_A_8; + depthFormat = 0; + break; + case 5: + pixelFormat = GGL_PIXEL_FORMAT_A_8; + depthFormat = GGL_PIXEL_FORMAT_Z_16; + break; default: return setError(EGL_BAD_MATCH, EGL_NO_SURFACE); } - // XXX: we don't have access to the pixelFormat here just yet. + // FIXME: we don't have access to the pixelFormat here just yet. // (it's possible that the surface is not fully initialized) // maybe this should be done after the page-flip //if (EGLint(info.format) != pixelFormat) @@ -840,6 +876,14 @@ static EGLSurface createPixmapSurface(EGLDisplay dpy, EGLConfig config, pixelFormat = GGL_PIXEL_FORMAT_RGBA_8888; depthFormat = GGL_PIXEL_FORMAT_Z_16; break; + case 4: + pixelFormat = GGL_PIXEL_FORMAT_A_8; + depthFormat = 0; + break; + case 5: + pixelFormat = GGL_PIXEL_FORMAT_A_8; + depthFormat = GGL_PIXEL_FORMAT_Z_16; + break; default: return setError(EGL_BAD_MATCH, EGL_NO_SURFACE); } @@ -896,6 +940,14 @@ static EGLSurface createPbufferSurface(EGLDisplay dpy, EGLConfig config, pixelFormat = GGL_PIXEL_FORMAT_RGBA_8888; depthFormat = GGL_PIXEL_FORMAT_Z_16; break; + case 4: + pixelFormat = GGL_PIXEL_FORMAT_A_8; + depthFormat = 0; + break; + case 5: + pixelFormat = GGL_PIXEL_FORMAT_A_8; + depthFormat = GGL_PIXEL_FORMAT_Z_16; + break; default: return setError(EGL_BAD_MATCH, EGL_NO_SURFACE); } @@ -979,7 +1031,7 @@ EGLBoolean eglTerminate(EGLDisplay dpy) EGLBoolean res = EGL_TRUE; egl_display_t& d = egl_display_t::get_display(dpy); if (android_atomic_dec(&d.initialized) == 1) { - // TODO: destroy all resources (surfaces, contextes, etc...) + // TODO: destroy all resources (surfaces, contexts, etc...) //pthread_mutex_lock(&gInitMutex); //pthread_mutex_unlock(&gInitMutex); } @@ -1105,11 +1157,7 @@ EGLSurface eglCreatePixmapSurface( EGLDisplay dpy, EGLConfig config, EGLSurface eglCreatePbufferSurface( EGLDisplay dpy, EGLConfig config, const EGLint *attrib_list) { - // none of our configs support pbuffers - // (in fact it's working but since we can't use them as - // textures yet, it's not useful at all) - //createPbufferSurface(dpy, config, attrib_list); - return EGL_NO_SURFACE; + return createPbufferSurface(dpy, config, attrib_list); } EGLBoolean eglDestroySurface(EGLDisplay dpy, EGLSurface eglSurface) @@ -1231,6 +1279,13 @@ EGLBoolean eglMakeCurrent( EGLDisplay dpy, EGLSurface draw, } EGLContext current_ctx = EGL_NO_CONTEXT; + + if ((read == EGL_NO_SURFACE && draw == EGL_NO_SURFACE) && (ctx != EGL_NO_CONTEXT)) + return setError(EGL_BAD_MATCH, EGL_FALSE); + + if ((read != EGL_NO_SURFACE || draw != EGL_NO_SURFACE) && (ctx == EGL_NO_CONTEXT)) + return setError(EGL_BAD_MATCH, EGL_FALSE); + if (ctx == EGL_NO_CONTEXT) { // if we're detaching, we need the current context current_ctx = (EGLContext)getGlThreadSpecific(); @@ -1486,7 +1541,7 @@ EGLSurface eglCreatePbufferFromClientBuffer( } // ---------------------------------------------------------------------------- -// Android extentions +// Android extensions // ---------------------------------------------------------------------------- void (*eglGetProcAddress (const char *procname))() diff --git a/opengl/libagl/light.cpp b/opengl/libagl/light.cpp index 87725cb3a3a5bd42b632dc413d8cf488ba70cd27..25c41d0c5b9de0d541804f582fec7cec444c691d 100644 --- a/opengl/libagl/light.cpp +++ b/opengl/libagl/light.cpp @@ -117,11 +117,11 @@ int32_t clampF(GLfixed f) { } static GLfixed fog_linear(ogles_context_t* c, GLfixed z) { - return clampF(gglMulx((c->fog.end - z), c->fog.invEndMinusStart)); + return clampF(gglMulx((c->fog.end - ((z<0)?-z:z)), c->fog.invEndMinusStart)); } static GLfixed fog_exp(ogles_context_t* c, GLfixed z) { - const float e = fixedToFloat(gglMulx(c->fog.density, z)); + const float e = fixedToFloat(gglMulx(c->fog.density, ((z<0)?-z:z))); return clampF(gglFloatToFixed(fastexpf(-e))); } @@ -556,11 +556,11 @@ static void fogx(GLenum pname, GLfixed param, ogles_context_t* c) ogles_error(c, GL_INVALID_VALUE); break; case GL_FOG_START: - c->fog.start = gglClampx(param); + c->fog.start = param; c->fog.invEndMinusStart = gglRecip(c->fog.end - c->fog.start); break; case GL_FOG_END: - c->fog.end = gglClampx(param); + c->fog.end = param; c->fog.invEndMinusStart = gglRecip(c->fog.end - c->fog.start); break; case GL_FOG_MODE: diff --git a/opengl/libagl/matrix.cpp b/opengl/libagl/matrix.cpp index 441da38e3eb4102571a0486fae6eec804fa4d7be..f175cdad6e6a00c3e3d85c96717d84e7155c5107 100644 --- a/opengl/libagl/matrix.cpp +++ b/opengl/libagl/matrix.cpp @@ -98,8 +98,9 @@ static void validate_perspective(ogles_context_t* c, vertex_t* v) c->arrays.perspective = (c->clipPlanes.enable) ? ogles_vertex_clipAllPerspective3D : ogles_vertex_perspective3D; if (enables & (GGL_ENABLE_DEPTH_TEST|GGL_ENABLE_FOG)) { - c->arrays.perspective = (c->clipPlanes.enable) ? - ogles_vertex_clipAllPerspective3DZ : ogles_vertex_perspective3DZ; + c->arrays.perspective = ogles_vertex_perspective3DZ; + if (c->clipPlanes.enable || (enables&GGL_ENABLE_FOG)) + c->arrays.perspective = ogles_vertex_clipAllPerspective3DZ; } if ((c->arrays.vertex.size != 4) && (c->transforms.mvp4.flags & transform_t::FLAGS_2D_PROJECTION)) { diff --git a/opengl/libagl/primitives.cpp b/opengl/libagl/primitives.cpp index 20e8d370160fc6a214a4f060f4f4d899a7969a07..f164c02eea34924fb4c5dee81ac6eb1a18cd90cb 100644 --- a/opengl/libagl/primitives.cpp +++ b/opengl/libagl/primitives.cpp @@ -133,7 +133,7 @@ void lightVertexDarkSmoothFog(ogles_context_t* c, vertex_t* v) { if (!(v->flags & vertex_t::LIT)) { v->flags |= vertex_t::LIT; - v->fog = c->fog.fog(c, v->window.z); + v->fog = c->fog.fog(c, v->eye.z); const GLvoid* cp = c->arrays.color.element( v->index & vertex_cache_t::INDEX_MASK); c->arrays.color.fetch(c, v->color.v, cp); @@ -144,14 +144,14 @@ void lightVertexDarkFlatFog(ogles_context_t* c, vertex_t* v) { if (!(v->flags & vertex_t::LIT)) { v->flags |= vertex_t::LIT; - v->fog = c->fog.fog(c, v->window.z); + v->fog = c->fog.fog(c, v->eye.z); } } static inline void lightVertexSmoothFog(ogles_context_t* c, vertex_t* v) { if (!(v->flags & vertex_t::LIT)) { - v->fog = c->fog.fog(c, v->window.z); + v->fog = c->fog.fog(c, v->eye.z); c->lighting.lightVertex(c, v); } } @@ -243,12 +243,20 @@ void compute_iterators_t::initTriangle( m_area = m_dx01*m_dy02 + (-m_dy10)*m_dx20; } +void compute_iterators_t::initLine( + vertex_t const* v0, vertex_t const* v1) +{ + m_dx01 = m_dy02 = v1->window.x - v0->window.x; + m_dy10 = m_dx20 = v0->window.y - v1->window.y; + m_area = m_dx01*m_dy02 + (-m_dy10)*m_dx20; +} + void compute_iterators_t::initLerp(vertex_t const* v0, uint32_t enables) { m_x0 = v0->window.x; m_y0 = v0->window.y; const GGLcoord area = (m_area + TRI_HALF) >> TRI_FRACTION_BITS; - const GGLcoord minArea = 2; // cannot be inversed + const GGLcoord minArea = 2; // cannot be inverted // triangles with an area smaller than 1.0 are not smooth-shaded int q=0, s=0, d=0; @@ -336,14 +344,7 @@ void compute_iterators_t::iterators1616(GGLfixed* it, it[2] = dcdy; } -#if defined(__arm__) && !defined(__thumb__) -inline void compute_iterators_t::iterators0032(int32_t* it, - int32_t c0, int32_t c1, int32_t c2) const -{ - ::iterators0032(this, it, c0, c1, c2); -} -#else -void compute_iterators_t::iterators0032(int32_t* it, +void compute_iterators_t::iterators0032(int64_t* it, int32_t c0, int32_t c1, int32_t c2) const { const int s = m_area_scale - 16; @@ -352,11 +353,27 @@ void compute_iterators_t::iterators0032(int32_t* it, // 16.16 x 16.16 == 32.32 int64_t dcdx = gglMulii(dc01, m_dy02) + gglMulii(dc02, m_dy10); int64_t dcdy = gglMulii(dc02, m_dx01) + gglMulii(dc01, m_dx20); - int32_t c = (c0<<16) - ((dcdx*m_x0 + dcdy*m_y0)>>4); - it[ 0] = c; + it[ 0] = (c0<<16) - ((dcdx*m_x0 + dcdy*m_y0)>>4); it[ 1] = dcdx; it[ 2] = dcdy; } + +#if defined(__arm__) && !defined(__thumb__) +inline void compute_iterators_t::iterators0032(int32_t* it, + int32_t c0, int32_t c1, int32_t c2) const +{ + ::iterators0032(this, it, c0, c1, c2); +} +#else +void compute_iterators_t::iterators0032(int32_t* it, + int32_t c0, int32_t c1, int32_t c2) const +{ + int64_t it64[3]; + iterators0032(it, c0, c1, c2); + it[0] = it64[0]; + it[1] = it64[1]; + it[2] = it64[2]; +} #endif // ---------------------------------------------------------------------------- @@ -454,7 +471,7 @@ void primitive_point(ogles_context_t* c, vertex_t* v) c->arrays.color.fetch(c, v->color.v, cp); } if (enables & GGL_ENABLE_FOG) { - v->fog = c->fog.fog(c, v->window.z); + v->fog = c->fog.fog(c, v->eye.z); } } @@ -514,22 +531,12 @@ void primitive_nop_line(ogles_context_t*, vertex_t*, vertex_t*) { void primitive_line(ogles_context_t* c, vertex_t* v0, vertex_t* v1) { - // This is a cheezy implementation of line drawing that - // uses 2 triangles per line. - // That said, how often line drawing is used? - // get texture coordinates fetch_texcoord(c, v0, v1, v1); // light/shade the vertices first (they're copied below) c->lighting.lightTriangle(c, v0, v1, v1); - vertex_t v[4]; - v[0] = *v0; - v[1] = *v1; - v0 = &v[0]; - v1 = &v[1]; - // clip the line if needed if (ggl_unlikely((v0->flags | v1->flags) & vertex_t::CLIP_ALL)) { unsigned int count = clip_line(c, v0, v1); @@ -546,8 +553,8 @@ void primitive_line(ogles_context_t* c, vertex_t* v0, vertex_t* v1) GGL_ENABLE_DEPTH_TEST; if (ggl_unlikely(enables & mask)) { - c->lerp.initTriangle(v0, v1, v1); - lerp_triangle(c, v0, v1, v1); + c->lerp.initLine(v0, v1); + lerp_triangle(c, v0, v1, v0); } // render our line @@ -654,17 +661,26 @@ void lerp_triangle(ogles_context_t* c, const int32_t v0z = clampZ(v0->window.z); const int32_t v1z = clampZ(v1->window.z); const int32_t v2z = clampZ(v2->window.z); - lerp.iterators0032(itz, v0z, v1z, v2z); if (ggl_unlikely(c->polygonOffset.enable)) { + const int32_t units = (c->polygonOffset.units << 16); const GLfixed factor = c->polygonOffset.factor; - const GLfixed units = c->polygonOffset.units; - int32_t maxDepthSlope = max(abs(itz[1]), abs(itz[2])); - int32_t offset = (int64_t(maxDepthSlope)*factor + - (int64_t(units) << 16)) >> 16; - itz[0] += offset; // XXX: this can cause overflows + if (factor) { + int64_t itz64[3]; + lerp.iterators0032(itz64, v0z, v1z, v2z); + int64_t maxDepthSlope = max(itz64[1], itz64[2]); + itz[0] = uint32_t(itz64[0]) + + uint32_t((maxDepthSlope*factor)>>16) + units; + itz[1] = uint32_t(itz64[1]); + itz[2] = uint32_t(itz64[2]); + } else { + lerp.iterators0032(itz, v0z, v1z, v2z); + itz[0] += units; + } + } else { + lerp.iterators0032(itz, v0z, v1z, v2z); } c->rasterizer.procs.zGrad3xv(c, itz); - } + } if (ggl_unlikely(enables & GGL_ENABLE_FOG)) { GLfixed itf[3]; @@ -880,11 +896,11 @@ void clip_triangle(ogles_context_t* c, vertex_t** output = ovl; unsigned int oc = 0; unsigned int sentinel = 0; - // previous vertice, compute distance to the plane + // previous vertex, compute distance to the plane vertex_t* s = ivl[ic-1]; const vec4_t& equation = c->clipPlanes.plane[plane].equation; GLfixed sd = dot4(equation.v, s->eye.v); - // clip each vertice against this plane... + // clip each vertex against this plane... for (unsigned int i=0 ; ieye.v); @@ -946,10 +962,10 @@ void clip_triangle(ogles_context_t* c, vertex_t** output = ovl; unsigned int oc = 0; unsigned int sentinel = 0; - // previous vertice, compute distance to the plane + // previous vertex, compute distance to the plane vertex_t* s = ivl[ic-1]; GLfixed sd = frustumPlaneDist(plane, s->clip); - // clip each vertice against this plane... + // clip each vertex against this plane... for (unsigned int i=0 ; iclip); diff --git a/opengl/libagl/vertex.cpp b/opengl/libagl/vertex.cpp index 5bcc9dc95c9dd0c6426b53e39f54a585603f0451..dad04d6cb5b3d6da8f1c7617c4a3ec13951a7639 100644 --- a/opengl/libagl/vertex.cpp +++ b/opengl/libagl/vertex.cpp @@ -99,7 +99,7 @@ void clipFrustumPerspective(ogles_context_t* c, vertex_t* v, uint32_t enables) c->arrays.cull &= clip; if (ggl_likely(!clip)) { - // if the vertice is clipped, we don't do the perspective + // if the vertex is clipped, we don't do the perspective // divide, since we don't need its window coordinates. perspective(c, v, enables); } diff --git a/opengl/tests/Android.mk b/opengl/tests/Android.mk new file mode 100644 index 0000000000000000000000000000000000000000..5053e7d64389d3eaa35c6e807277fff9f83898f6 --- /dev/null +++ b/opengl/tests/Android.mk @@ -0,0 +1 @@ +include $(call all-subdir-makefiles) diff --git a/opengl/tests/angeles/Android.mk b/opengl/tests/angeles/Android.mk new file mode 100644 index 0000000000000000000000000000000000000000..41673cbe41b7dc532cbe3a80e319ae951d1a8eff --- /dev/null +++ b/opengl/tests/angeles/Android.mk @@ -0,0 +1,17 @@ +# Copyright 2006 The Android Open Source Project + +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) +LOCAL_SRC_FILES:= app-linux.c demo.c.arm +LOCAL_SHARED_LIBRARIES := libGLES_CM libui +LOCAL_MODULE:= angeles +LOCAL_MODULE_TAGS := tests +include $(BUILD_EXECUTABLE) + + +include $(CLEAR_VARS) +LOCAL_SRC_FILES:= gpustate.c +LOCAL_SHARED_LIBRARIES := libGLES_CM +LOCAL_MODULE:= gpustate +LOCAL_MODULE_TAGS := tests +include $(BUILD_EXECUTABLE) diff --git a/opengl/tests/angeles/MODULE_LICENSE_BSD_OR_LGPL b/opengl/tests/angeles/MODULE_LICENSE_BSD_OR_LGPL new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/opengl/tests/angeles/README.txt b/opengl/tests/angeles/README.txt new file mode 100644 index 0000000000000000000000000000000000000000..38b8a4a74d4c0336815c706b9b2312de2023aec8 --- /dev/null +++ b/opengl/tests/angeles/README.txt @@ -0,0 +1,77 @@ +------------------------------------------------------------------------ +San Angeles Observation OpenGL ES version example +Copyright 2004-2005 Jetro Lauha +Web: http://iki.fi/jetro/ +See file license.txt for licensing information. +------------------------------------------------------------------------ + +This is an OpenGL ES port of the small self-running demonstration +called "San Angeles Observation", which was first presented in the +Assembly'2004 event. It won the first place in the 4 KB intro +competition category. + +The demonstration features a sightseeing of a futuristic city +having many different kind of buildings and items. Everything is +flat shaded with three different lights. + +The original version was made for desktop with OpenGL. It was +naturally heavily size optimized in order to fit it in the size +limit. For this OpenGL ES version example much of the code is +cleaned up and the sound is removed. Also detail level is lowered, +although it still contains over 60000 faces. + +The Win32 (2000/XP) binary package of original version is +available from this address: http://jet.ro/files/angeles.zip + +First version of this OpenGL ES port was submitted to the Khronos +OpenGL ES Coding Challenge held in 2004-2005. + +As a code example, this source shows the following: + * How to create a minimal and portable ad hoc framework + for small testing/demonstration programs. This framework + compiles for both desktop and PocketPC Win32 environment, + and a separate source is included for Linux with X11. + * How to dynamically find and use the OpenGL ES DLL or + shared object, so that the library is not needed at + the compile/link stage. + * How to use the basic features of OpenGL ES 1.0/1.1 + Common Lite, such as vertex arrays, color arrays and + lighting. + * How to create a self contained small demonstration + application with objects generated using procedural + algorithms. + +As the original version was optimized for size instead of +performance, that holds true for this OpenGL ES version as +well. Thus the performance could be significantly increased, +for example by changing the code to use glDrawElements +instead of glDrawArrays. The code uses only OpenGL ES 1.0 +Common Lite -level function calls without any extensions. + +The reference OpenGL ES implementations used for this application: + * Hybrid's OpenGL ES API Implementation (Gerbera) version 2.0.4 + Prebuilt Win32 PC executable: SanOGLES-Gerbera.exe + * PowerVR MBX SDK, OpenGL ES Windows PC Emulation version 1.04.14.0170 + Prebuilt Win32 PC executable: SanOGLES-PVRSDK.exe + +Note that DISABLE_IMPORTGL preprocessor macro can be used +to specify not to use dynamic runtime binding of the library. +You also need to define preprocessor macro PVRSDK to compile +the source with PowerVR OpenGL ES SDK. + +The demo application is briefly tested with a few other OpenGL ES +implementations as well (e.g. Vincent, GLESonGL on Linux, Dell +Axim X50v). Most of these other implementations rendered the demo +erroneously in some aspect. This may indicate that the demo source +could still have some work to do with compatibility and correct +API usage, although the non-conforming implementations are most +probably unfinished as well. + +Thanks and Acknowledgements: + +* Toni Lönnberg (!Cube) created the music for original version, which + is not featured in this OpenGL ES port. +* Sara Kapli (st Rana) for additional camera work. +* Paul Bourke for information about the supershapes. + +------------------------------------------------------------------------ diff --git a/opengl/tests/angeles/app-linux.c b/opengl/tests/angeles/app-linux.c new file mode 100644 index 0000000000000000000000000000000000000000..d439eb2fbfb74a9d8a55dd21c1434f483ee7b897 --- /dev/null +++ b/opengl/tests/angeles/app-linux.c @@ -0,0 +1,222 @@ +/* San Angeles Observation OpenGL ES version example + * Copyright 2004-2005 Jetro Lauha + * All rights reserved. + * Web: http://iki.fi/jetro/ + * + * This source is free software; you can redistribute it and/or + * modify it under the terms of EITHER: + * (1) The GNU Lesser General Public License as published by the Free + * Software Foundation; either version 2.1 of the License, or (at + * your option) any later version. The text of the GNU Lesser + * General Public License is included with this source in the + * file LICENSE-LGPL.txt. + * (2) The BSD-style license that is included with this source in + * the file LICENSE-BSD.txt. + * + * This source is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files + * LICENSE-LGPL.txt and LICENSE-BSD.txt for more details. + * + * $Id: app-linux.c,v 1.4 2005/02/08 18:42:48 tonic Exp $ + * $Revision: 1.4 $ + * + * Parts of this source file is based on test/example code from + * GLESonGL implementation by David Blythe. Here is copy of the + * license notice from that source: + * + * Copyright (C) 2003 David Blythe All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * DAVID BLYTHE BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include +#include +#include + +#include + +#include "app.h" + + +int gAppAlive = 1; + +static const char sAppName[] = + "San Angeles Observation OpenGL ES version example (Linux)"; + +static int sWindowWidth = WINDOW_DEFAULT_WIDTH; +static int sWindowHeight = WINDOW_DEFAULT_HEIGHT; +static EGLDisplay sEglDisplay = EGL_NO_DISPLAY; +static EGLContext sEglContext = EGL_NO_CONTEXT; +static EGLSurface sEglSurface = EGL_NO_SURFACE; + +const char *egl_strerror(unsigned err) +{ + switch(err){ + case EGL_SUCCESS: return "SUCCESS"; + case EGL_NOT_INITIALIZED: return "NOT INITIALIZED"; + case EGL_BAD_ACCESS: return "BAD ACCESS"; + case EGL_BAD_ALLOC: return "BAD ALLOC"; + case EGL_BAD_ATTRIBUTE: return "BAD_ATTRIBUTE"; + case EGL_BAD_CONFIG: return "BAD CONFIG"; + case EGL_BAD_CONTEXT: return "BAD CONTEXT"; + case EGL_BAD_CURRENT_SURFACE: return "BAD CURRENT SURFACE"; + case EGL_BAD_DISPLAY: return "BAD DISPLAY"; + case EGL_BAD_MATCH: return "BAD MATCH"; + case EGL_BAD_NATIVE_PIXMAP: return "BAD NATIVE PIXMAP"; + case EGL_BAD_NATIVE_WINDOW: return "BAD NATIVE WINDOW"; + case EGL_BAD_PARAMETER: return "BAD PARAMETER"; + case EGL_BAD_SURFACE: return "BAD_SURFACE"; +// case EGL_CONTEXT_LOST: return "CONTEXT LOST"; + default: return "UNKNOWN"; + } +} + +void egl_error(const char *name) +{ + unsigned err = eglGetError(); + if(err != EGL_SUCCESS) { + fprintf(stderr,"%s(): egl error 0x%x (%s)\n", + name, err, egl_strerror(err)); + } +} + +static void checkGLErrors() +{ + GLenum error = glGetError(); + if (error != GL_NO_ERROR) + fprintf(stderr, "GL Error: 0x%04x\n", (int)error); +} + + +static void checkEGLErrors() +{ + EGLint error = eglGetError(); + // GLESonGL seems to be returning 0 when there is no errors? + if (error && error != EGL_SUCCESS) + fprintf(stderr, "EGL Error: 0x%04x\n", (int)error); +} + +static int initGraphics() +{ + EGLint s_configAttribs[] = { + EGL_RED_SIZE, 5, + EGL_GREEN_SIZE, 6, + EGL_BLUE_SIZE, 5, + #if 1 + EGL_DEPTH_SIZE, 16, + EGL_STENCIL_SIZE, 0, + #else + EGL_ALPHA_SIZE, EGL_DONT_CARE, + EGL_DEPTH_SIZE, EGL_DONT_CARE, + EGL_STENCIL_SIZE, EGL_DONT_CARE, + EGL_SURFACE_TYPE, EGL_DONT_CARE, + #endif + EGL_NONE + }; + + EGLint numConfigs = -1; + EGLint majorVersion; + EGLint minorVersion; + EGLConfig config; + EGLContext context; + EGLSurface surface; + + EGLDisplay dpy; + + dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY); + egl_error("eglGetDisplay"); + fprintf(stderr,"dpy = 0x%08x\n", (unsigned) dpy); + + eglInitialize(dpy, &majorVersion, &minorVersion); + egl_error("eglInitialize"); + + eglGetConfigs(dpy, NULL, 0, &numConfigs); + egl_error("eglGetConfigs"); + fprintf(stderr,"num configs %d\n", numConfigs); + + eglChooseConfig(dpy, s_configAttribs, &config, 1, &numConfigs); + egl_error("eglChooseConfig"); + + surface = eglCreateWindowSurface(dpy, config, + android_createDisplaySurface(), NULL); + egl_error("eglMapWindowSurface"); + + fprintf(stderr,"surface = %p\n", surface); + + context = eglCreateContext(dpy, config, NULL, NULL); + egl_error("eglCreateContext"); + fprintf(stderr,"context = %p\n", context); + + eglMakeCurrent(dpy, surface, surface, context); + egl_error("eglMakeCurrent"); + + eglQuerySurface(dpy, surface, EGL_WIDTH, &sWindowWidth); + eglQuerySurface(dpy, surface, EGL_HEIGHT, &sWindowHeight); + + sEglDisplay = dpy; + sEglSurface = surface; + sEglContext = context; + + return EGL_TRUE; +} + + +static void deinitGraphics() +{ + eglMakeCurrent(sEglDisplay, NULL, NULL, NULL); + eglDestroyContext(sEglDisplay, sEglContext); + eglDestroySurface(sEglDisplay, sEglSurface); + eglTerminate(sEglDisplay); +} + + +int main(int argc, char *argv[]) +{ + // not referenced: + argc = argc; + argv = argv; + + if (!initGraphics()) + { + fprintf(stderr, "Graphics initialization failed.\n"); + return EXIT_FAILURE; + } + + appInit(); + + while (gAppAlive) + { + struct timeval timeNow; + + if (gAppAlive) + { + gettimeofday(&timeNow, NULL); + appRender(timeNow.tv_sec * 1000 + timeNow.tv_usec / 1000, + sWindowWidth, sWindowHeight); + checkGLErrors(); + eglSwapBuffers(sEglDisplay, sEglSurface); + checkEGLErrors(); + } + } + + appDeinit(); + deinitGraphics(); + + return EXIT_SUCCESS; +} diff --git a/opengl/tests/angeles/app.h b/opengl/tests/angeles/app.h new file mode 100644 index 0000000000000000000000000000000000000000..70ebd35be19fc01c6591bb3b93818d3614c1af7f --- /dev/null +++ b/opengl/tests/angeles/app.h @@ -0,0 +1,56 @@ +/* San Angeles Observation OpenGL ES version example + * Copyright 2004-2005 Jetro Lauha + * All rights reserved. + * Web: http://iki.fi/jetro/ + * + * This source is free software; you can redistribute it and/or + * modify it under the terms of EITHER: + * (1) The GNU Lesser General Public License as published by the Free + * Software Foundation; either version 2.1 of the License, or (at + * your option) any later version. The text of the GNU Lesser + * General Public License is included with this source in the + * file LICENSE-LGPL.txt. + * (2) The BSD-style license that is included with this source in + * the file LICENSE-BSD.txt. + * + * This source is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files + * LICENSE-LGPL.txt and LICENSE-BSD.txt for more details. + * + * $Id: app.h,v 1.14 2005/02/06 21:13:54 tonic Exp $ + * $Revision: 1.14 $ + */ + +#ifndef APP_H_INCLUDED +#define APP_H_INCLUDED + + +#ifdef __cplusplus +extern "C" { +#endif + + +#define WINDOW_DEFAULT_WIDTH 640 +#define WINDOW_DEFAULT_HEIGHT 480 + +#define WINDOW_BPP 16 + + +// The simple framework expects the application code to define these functions. +extern void appInit(); +extern void appDeinit(); +extern void appRender(long tick, int width, int height); + +/* Value is non-zero when application is alive, and 0 when it is closing. + * Defined by the application framework. + */ +extern int gAppAlive; + + +#ifdef __cplusplus +} +#endif + + +#endif // !APP_H_INCLUDED diff --git a/opengl/tests/angeles/cams.h b/opengl/tests/angeles/cams.h new file mode 100644 index 0000000000000000000000000000000000000000..2b1acb3c350aad9fb058068c33f180393c80fc5d --- /dev/null +++ b/opengl/tests/angeles/cams.h @@ -0,0 +1,65 @@ +/* San Angeles Observation OpenGL ES version example + * Copyright 2004-2005 Jetro Lauha + * All rights reserved. + * Web: http://iki.fi/jetro/ + * + * This source is free software; you can redistribute it and/or + * modify it under the terms of EITHER: + * (1) The GNU Lesser General Public License as published by the Free + * Software Foundation; either version 2.1 of the License, or (at + * your option) any later version. The text of the GNU Lesser + * General Public License is included with this source in the + * file LICENSE-LGPL.txt. + * (2) The BSD-style license that is included with this source in + * the file LICENSE-BSD.txt. + * + * This source is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files + * LICENSE-LGPL.txt and LICENSE-BSD.txt for more details. + * + * $Id: cams.h,v 1.7 2005/01/31 22:15:15 tonic Exp $ + * $Revision: 1.7 $ + */ + +#ifndef CAMS_H_INCLUDED +#define CAMS_H_INCLUDED + + +/* Length in milliseconds of one camera track base unit. + * The value originates from the music synchronization. + */ +#define CAMTRACK_LEN 5442 + + +// Camera track definition for one camera trucking shot. +typedef struct +{ + /* Five parameters of src[5] and dest[5]: + * eyeX, eyeY, eyeZ, viewAngle, viewHeightOffs + */ + short src[5], dest[5]; + unsigned char dist; // if >0, cam rotates around eye xy on dist * 0.1 + unsigned char len; // length multiplier +} CAMTRACK; + +static CAMTRACK sCamTracks[] = +{ + { { 4500, 2700, 100, 70, -30 }, { 50, 50, -90, -100, 0 }, 20, 1 }, + { { -1448, 4294, 25, 363, 0 }, { -136, 202, 125, -98, 100 }, 0, 1 }, + { { 1437, 4930, 200, -275, -20 }, { 1684, 0, 0, 9, 0 }, 0, 1 }, + { { 1800, 3609, 200, 0, 675 }, { 0, 0, 0, 300, 0 }, 0, 1 }, + { { 923, 996, 50, 2336, -80 }, { 0, -20, -50, 0, 170 }, 0, 1 }, + { { -1663, -43, 600, 2170, 0 }, { 20, 0, -600, 0, 100 }, 0, 1 }, + { { 1049, -1420, 175, 2111, -17 }, { 0, 0, 0, -334, 0 }, 0, 2 }, + { { 0, 0, 50, 300, 25 }, { 0, 0, 0, 300, 0 }, 70, 2 }, + { { -473, -953, 3500, -353, -350 }, { 0, 0, -2800, 0, 0 }, 0, 2 }, + { { 191, 1938, 35, 1139, -17 }, { 1205, -2909, 0, 0, 0 }, 0, 2 }, + { { -1449, -2700, 150, 0, 0 }, { 0, 2000, 0, 0, 0 }, 0, 2 }, + { { 5273, 4992, 650, 373, -50 }, { -4598, -3072, 0, 0, 0 }, 0, 2 }, + { { 3223, -3282, 1075, -393, -25 }, { 1649, -1649, 0, 0, 0 }, 0, 2 } +}; +#define CAMTRACK_COUNT (sizeof(camTracks) / sizeof(camTracks[0])) + + +#endif // !CAMS_H_INCLUDED diff --git a/opengl/tests/angeles/demo.c b/opengl/tests/angeles/demo.c new file mode 100644 index 0000000000000000000000000000000000000000..802f3980faf7415887c903824a1883006d417747 --- /dev/null +++ b/opengl/tests/angeles/demo.c @@ -0,0 +1,792 @@ +/* San Angeles Observation OpenGL ES version example + * Copyright 2004-2005 Jetro Lauha + * All rights reserved. + * Web: http://iki.fi/jetro/ + * + * This source is free software; you can redistribute it and/or + * modify it under the terms of EITHER: + * (1) The GNU Lesser General Public License as published by the Free + * Software Foundation; either version 2.1 of the License, or (at + * your option) any later version. The text of the GNU Lesser + * General Public License is included with this source in the + * file LICENSE-LGPL.txt. + * (2) The BSD-style license that is included with this source in + * the file LICENSE-BSD.txt. + * + * This source is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files + * LICENSE-LGPL.txt and LICENSE-BSD.txt for more details. + * + * $Id: demo.c,v 1.10 2005/02/08 20:54:39 tonic Exp $ + * $Revision: 1.10 $ + */ + +#include +#include +#include +#include + +#include + +#include "app.h" +#include "shapes.h" +#include "cams.h" + + +// Total run length is 20 * camera track base unit length (see cams.h). +#define RUN_LENGTH (20 * CAMTRACK_LEN) +#undef PI +#define PI 3.1415926535897932f +#define RANDOM_UINT_MAX 65535 + + +static unsigned long sRandomSeed = 0; + +static void seedRandom(unsigned long seed) +{ + sRandomSeed = seed; +} + +static unsigned long randomUInt() +{ + sRandomSeed = sRandomSeed * 0x343fd + 0x269ec3; + return sRandomSeed >> 16; +} + + +// Capped conversion from float to fixed. +static long floatToFixed(float value) +{ + if (value < -32768) value = -32768; + if (value > 32767) value = 32767; + return (long)(value * 65536); +} + +#define FIXED(value) floatToFixed(value) + + +// Definition of one GL object in this demo. +typedef struct { + /* Vertex array and color array are enabled for all objects, so their + * pointers must always be valid and non-NULL. Normal array is not + * used by the ground plane, so when its pointer is NULL then normal + * array usage is disabled. + * + * Vertex array is supposed to use GL_FIXED datatype and stride 0 + * (i.e. tightly packed array). Color array is supposed to have 4 + * components per color with GL_UNSIGNED_BYTE datatype and stride 0. + * Normal array is supposed to use GL_FIXED datatype and stride 0. + */ + GLfixed *vertexArray; + GLubyte *colorArray; + GLfixed *normalArray; + GLint vertexComponents; + GLsizei count; +} GLOBJECT; + + +static long sStartTick = 0; +static long sTick = 0; + +static int sCurrentCamTrack = 0; +static long sCurrentCamTrackStartTick = 0; +static long sNextCamTrackStartTick = 0x7fffffff; + +static GLOBJECT *sSuperShapeObjects[SUPERSHAPE_COUNT] = { NULL }; +static GLOBJECT *sGroundPlane = NULL; + + +typedef struct { + float x, y, z; +} VECTOR3; + + +static void freeGLObject(GLOBJECT *object) +{ + if (object == NULL) + return; + free(object->normalArray); + free(object->colorArray); + free(object->vertexArray); + free(object); +} + + +static GLOBJECT * newGLObject(long vertices, int vertexComponents, + int useNormalArray) +{ + GLOBJECT *result; + result = (GLOBJECT *)malloc(sizeof(GLOBJECT)); + if (result == NULL) + return NULL; + result->count = vertices; + result->vertexComponents = vertexComponents; + result->vertexArray = (GLfixed *)malloc(vertices * vertexComponents * + sizeof(GLfixed)); + result->colorArray = (GLubyte *)malloc(vertices * 4 * sizeof(GLubyte)); + if (useNormalArray) + { + result->normalArray = (GLfixed *)malloc(vertices * 3 * + sizeof(GLfixed)); + } + else + result->normalArray = NULL; + if (result->vertexArray == NULL || + result->colorArray == NULL || + (useNormalArray && result->normalArray == NULL)) + { + freeGLObject(result); + return NULL; + } + return result; +} + + +static void drawGLObject(GLOBJECT *object) +{ + assert(object != NULL); + + glVertexPointer(object->vertexComponents, GL_FIXED, + 0, object->vertexArray); + glColorPointer(4, GL_UNSIGNED_BYTE, 0, object->colorArray); + + // Already done in initialization: + //glEnableClientState(GL_VERTEX_ARRAY); + //glEnableClientState(GL_COLOR_ARRAY); + + if (object->normalArray) + { + glNormalPointer(GL_FIXED, 0, object->normalArray); + glEnableClientState(GL_NORMAL_ARRAY); + } + else + glDisableClientState(GL_NORMAL_ARRAY); + glDrawArrays(GL_TRIANGLES, 0, object->count); +} + + +static void vector3Sub(VECTOR3 *dest, VECTOR3 *v1, VECTOR3 *v2) +{ + dest->x = v1->x - v2->x; + dest->y = v1->y - v2->y; + dest->z = v1->z - v2->z; +} + + +static void superShapeMap(VECTOR3 *point, float r1, float r2, float t, float p) +{ + // sphere-mapping of supershape parameters + point->x = (float)(cos(t) * cos(p) / r1 / r2); + point->y = (float)(sin(t) * cos(p) / r1 / r2); + point->z = (float)(sin(p) / r2); +} + + +static float ssFunc(const float t, const float *p) +{ + return (float)(pow(pow(fabs(cos(p[0] * t / 4)) / p[1], p[4]) + + pow(fabs(sin(p[0] * t / 4)) / p[2], p[5]), 1 / p[3])); +} + + +// Creates and returns a supershape object. +// Based on Paul Bourke's POV-Ray implementation. +// http://astronomy.swin.edu.au/~pbourke/povray/supershape/ +static GLOBJECT * createSuperShape(const float *params) +{ + const int resol1 = (int)params[SUPERSHAPE_PARAMS - 3]; + const int resol2 = (int)params[SUPERSHAPE_PARAMS - 2]; + // latitude 0 to pi/2 for no mirrored bottom + // (latitudeBegin==0 for -pi/2 to pi/2 originally) + const int latitudeBegin = resol2 / 4; + const int latitudeEnd = resol2 / 2; // non-inclusive + const int longitudeCount = resol1; + const int latitudeCount = latitudeEnd - latitudeBegin; + const long triangleCount = longitudeCount * latitudeCount * 2; + const long vertices = triangleCount * 3; + GLOBJECT *result; + float baseColor[3]; + int a, longitude, latitude; + long currentVertex, currentQuad; + + result = newGLObject(vertices, 3, 1); + if (result == NULL) + return NULL; + + for (a = 0; a < 3; ++a) + baseColor[a] = ((randomUInt() % 155) + 100) / 255.f; + + currentQuad = 0; + currentVertex = 0; + + // longitude -pi to pi + for (longitude = 0; longitude < longitudeCount; ++longitude) + { + + // latitude 0 to pi/2 + for (latitude = latitudeBegin; latitude < latitudeEnd; ++latitude) + { + float t1 = -PI + longitude * 2 * PI / resol1; + float t2 = -PI + (longitude + 1) * 2 * PI / resol1; + float p1 = -PI / 2 + latitude * 2 * PI / resol2; + float p2 = -PI / 2 + (latitude + 1) * 2 * PI / resol2; + float r0, r1, r2, r3; + + r0 = ssFunc(t1, params); + r1 = ssFunc(p1, ¶ms[6]); + r2 = ssFunc(t2, params); + r3 = ssFunc(p2, ¶ms[6]); + + if (r0 != 0 && r1 != 0 && r2 != 0 && r3 != 0) + { + VECTOR3 pa, pb, pc, pd; + VECTOR3 v1, v2, n; + float ca; + int i; + //float lenSq, invLenSq; + + superShapeMap(&pa, r0, r1, t1, p1); + superShapeMap(&pb, r2, r1, t2, p1); + superShapeMap(&pc, r2, r3, t2, p2); + superShapeMap(&pd, r0, r3, t1, p2); + + // kludge to set lower edge of the object to fixed level + if (latitude == latitudeBegin + 1) + pa.z = pb.z = 0; + + vector3Sub(&v1, &pb, &pa); + vector3Sub(&v2, &pd, &pa); + + // Calculate normal with cross product. + /* i j k i j + * v1.x v1.y v1.z | v1.x v1.y + * v2.x v2.y v2.z | v2.x v2.y + */ + + n.x = v1.y * v2.z - v1.z * v2.y; + n.y = v1.z * v2.x - v1.x * v2.z; + n.z = v1.x * v2.y - v1.y * v2.x; + + /* Pre-normalization of the normals is disabled here because + * they will be normalized anyway later due to automatic + * normalization (GL_NORMALIZE). It is enabled because the + * objects are scaled with glScale. + */ + /* + lenSq = n.x * n.x + n.y * n.y + n.z * n.z; + invLenSq = (float)(1 / sqrt(lenSq)); + n.x *= invLenSq; + n.y *= invLenSq; + n.z *= invLenSq; + */ + + ca = pa.z + 0.5f; + + for (i = currentVertex * 3; + i < (currentVertex + 6) * 3; + i += 3) + { + result->normalArray[i] = FIXED(n.x); + result->normalArray[i + 1] = FIXED(n.y); + result->normalArray[i + 2] = FIXED(n.z); + } + for (i = currentVertex * 4; + i < (currentVertex + 6) * 4; + i += 4) + { + int a, color[3]; + for (a = 0; a < 3; ++a) + { + color[a] = (int)(ca * baseColor[a] * 255); + if (color[a] > 255) color[a] = 255; + } + result->colorArray[i] = (GLubyte)color[0]; + result->colorArray[i + 1] = (GLubyte)color[1]; + result->colorArray[i + 2] = (GLubyte)color[2]; + result->colorArray[i + 3] = 0; + } + result->vertexArray[currentVertex * 3] = FIXED(pa.x); + result->vertexArray[currentVertex * 3 + 1] = FIXED(pa.y); + result->vertexArray[currentVertex * 3 + 2] = FIXED(pa.z); + ++currentVertex; + result->vertexArray[currentVertex * 3] = FIXED(pb.x); + result->vertexArray[currentVertex * 3 + 1] = FIXED(pb.y); + result->vertexArray[currentVertex * 3 + 2] = FIXED(pb.z); + ++currentVertex; + result->vertexArray[currentVertex * 3] = FIXED(pd.x); + result->vertexArray[currentVertex * 3 + 1] = FIXED(pd.y); + result->vertexArray[currentVertex * 3 + 2] = FIXED(pd.z); + ++currentVertex; + result->vertexArray[currentVertex * 3] = FIXED(pb.x); + result->vertexArray[currentVertex * 3 + 1] = FIXED(pb.y); + result->vertexArray[currentVertex * 3 + 2] = FIXED(pb.z); + ++currentVertex; + result->vertexArray[currentVertex * 3] = FIXED(pc.x); + result->vertexArray[currentVertex * 3 + 1] = FIXED(pc.y); + result->vertexArray[currentVertex * 3 + 2] = FIXED(pc.z); + ++currentVertex; + result->vertexArray[currentVertex * 3] = FIXED(pd.x); + result->vertexArray[currentVertex * 3 + 1] = FIXED(pd.y); + result->vertexArray[currentVertex * 3 + 2] = FIXED(pd.z); + ++currentVertex; + } // r0 && r1 && r2 && r3 + ++currentQuad; + } // latitude + } // longitude + + // Set number of vertices in object to the actual amount created. + result->count = currentVertex; + + return result; +} + + +static GLOBJECT * createGroundPlane() +{ + const int scale = 4; + const int yBegin = -15, yEnd = 15; // ends are non-inclusive + const int xBegin = -15, xEnd = 15; + const long triangleCount = (yEnd - yBegin) * (xEnd - xBegin) * 2; + const long vertices = triangleCount * 3; + GLOBJECT *result; + int x, y; + long currentVertex, currentQuad; + + result = newGLObject(vertices, 2, 0); + if (result == NULL) + return NULL; + + currentQuad = 0; + currentVertex = 0; + + for (y = yBegin; y < yEnd; ++y) + { + for (x = xBegin; x < xEnd; ++x) + { + GLubyte color; + int i, a; + color = (GLubyte)((randomUInt() & 0x5f) + 81); // 101 1111 + for (i = currentVertex * 4; i < (currentVertex + 6) * 4; i += 4) + { + result->colorArray[i] = color; + result->colorArray[i + 1] = color; + result->colorArray[i + 2] = color; + result->colorArray[i + 3] = 0; + } + + // Axis bits for quad triangles: + // x: 011100 (0x1c), y: 110001 (0x31) (clockwise) + // x: 001110 (0x0e), y: 100011 (0x23) (counter-clockwise) + for (a = 0; a < 6; ++a) + { + const int xm = x + ((0x1c >> a) & 1); + const int ym = y + ((0x31 >> a) & 1); + const float m = (float)(cos(xm * 2) * sin(ym * 4) * 0.75f); + result->vertexArray[currentVertex * 2] = + FIXED(xm * scale + m); + result->vertexArray[currentVertex * 2 + 1] = + FIXED(ym * scale + m); + ++currentVertex; + } + ++currentQuad; + } + } + return result; +} + + +static void drawGroundPlane() +{ + glDisable(GL_CULL_FACE); + glDisable(GL_DEPTH_TEST); + glEnable(GL_BLEND); + glBlendFunc(GL_ZERO, GL_SRC_COLOR); + glDisable(GL_LIGHTING); + + drawGLObject(sGroundPlane); + + glEnable(GL_LIGHTING); + glDisable(GL_BLEND); + glEnable(GL_DEPTH_TEST); +} + + +static void drawFadeQuad() +{ + static const GLfixed quadVertices[] = { + -0x10000, -0x10000, + 0x10000, -0x10000, + -0x10000, 0x10000, + 0x10000, -0x10000, + 0x10000, 0x10000, + -0x10000, 0x10000 + }; + + const int beginFade = sTick - sCurrentCamTrackStartTick; + const int endFade = sNextCamTrackStartTick - sTick; + const int minFade = beginFade < endFade ? beginFade : endFade; + + if (minFade < 1024) + { + const GLfixed fadeColor = minFade << 6; + glColor4x(fadeColor, fadeColor, fadeColor, 0); + + glDisable(GL_DEPTH_TEST); + glEnable(GL_BLEND); + glBlendFunc(GL_ZERO, GL_SRC_COLOR); + glDisable(GL_LIGHTING); + + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + + glDisableClientState(GL_COLOR_ARRAY); + glDisableClientState(GL_NORMAL_ARRAY); + glVertexPointer(2, GL_FIXED, 0, quadVertices); + glDrawArrays(GL_TRIANGLES, 0, 6); + + glEnableClientState(GL_COLOR_ARRAY); + + glMatrixMode(GL_MODELVIEW); + + glEnable(GL_LIGHTING); + glDisable(GL_BLEND); + glEnable(GL_DEPTH_TEST); + } +} + + +// Called from the app framework. +void appInit() +{ + int a; + + glEnable(GL_NORMALIZE); + glEnable(GL_DEPTH_TEST); + glDisable(GL_CULL_FACE); + glShadeModel(GL_FLAT); + + glEnable(GL_LIGHTING); + glEnable(GL_LIGHT0); + glEnable(GL_LIGHT1); + glEnable(GL_LIGHT2); + + glEnableClientState(GL_VERTEX_ARRAY); + glEnableClientState(GL_COLOR_ARRAY); + + seedRandom(15); + + for (a = 0; a < SUPERSHAPE_COUNT; ++a) + { + sSuperShapeObjects[a] = createSuperShape(sSuperShapeParams[a]); + assert(sSuperShapeObjects[a] != NULL); + } + sGroundPlane = createGroundPlane(); + assert(sGroundPlane != NULL); +} + + +// Called from the app framework. +void appDeinit() +{ + int a; + for (a = 0; a < SUPERSHAPE_COUNT; ++a) + freeGLObject(sSuperShapeObjects[a]); + freeGLObject(sGroundPlane); +} + + +static void gluPerspective(GLfloat fovy, GLfloat aspect, + GLfloat zNear, GLfloat zFar) +{ + GLfloat xmin, xmax, ymin, ymax; + + ymax = zNear * (GLfloat)tan(fovy * PI / 360); + ymin = -ymax; + xmin = ymin * aspect; + xmax = ymax * aspect; + + glFrustumx((GLfixed)(xmin * 65536), (GLfixed)(xmax * 65536), + (GLfixed)(ymin * 65536), (GLfixed)(ymax * 65536), + (GLfixed)(zNear * 65536), (GLfixed)(zFar * 65536)); +} + + +static void prepareFrame(int width, int height) +{ + glViewport(0, 0, width, height); + + glClearColorx((GLfixed)(0.1f * 65536), + (GLfixed)(0.2f * 65536), + (GLfixed)(0.3f * 65536), 0x10000); + glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT); + + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + gluPerspective(45, (float)width / height, 0.5f, 150); + + glMatrixMode(GL_MODELVIEW); + + glLoadIdentity(); +} + + +static void configureLightAndMaterial() +{ + static GLfixed light0Position[] = { -0x40000, 0x10000, 0x10000, 0 }; + static GLfixed light0Diffuse[] = { 0x10000, 0x6666, 0, 0x10000 }; + static GLfixed light1Position[] = { 0x10000, -0x20000, -0x10000, 0 }; + static GLfixed light1Diffuse[] = { 0x11eb, 0x23d7, 0x5999, 0x10000 }; + static GLfixed light2Position[] = { -0x10000, 0, -0x40000, 0 }; + static GLfixed light2Diffuse[] = { 0x11eb, 0x2b85, 0x23d7, 0x10000 }; + static GLfixed materialSpecular[] = { 0x10000, 0x10000, 0x10000, 0x10000 }; + + glLightxv(GL_LIGHT0, GL_POSITION, light0Position); + glLightxv(GL_LIGHT0, GL_DIFFUSE, light0Diffuse); + glLightxv(GL_LIGHT1, GL_POSITION, light1Position); + glLightxv(GL_LIGHT1, GL_DIFFUSE, light1Diffuse); + glLightxv(GL_LIGHT2, GL_POSITION, light2Position); + glLightxv(GL_LIGHT2, GL_DIFFUSE, light2Diffuse); + glMaterialxv(GL_FRONT_AND_BACK, GL_SPECULAR, materialSpecular); + + glMaterialx(GL_FRONT_AND_BACK, GL_SHININESS, 60 << 16); + glEnable(GL_COLOR_MATERIAL); +} + + +static void drawModels(float zScale) +{ + const int translationScale = 9; + int x, y; + + seedRandom(9); + + glScalex(1 << 16, 1 << 16, (GLfixed)(zScale * 65536)); + + for (y = -5; y <= 5; ++y) + { + for (x = -5; x <= 5; ++x) + { + float buildingScale; + GLfixed fixedScale; + + int curShape = randomUInt() % SUPERSHAPE_COUNT; + buildingScale = sSuperShapeParams[curShape][SUPERSHAPE_PARAMS - 1]; + fixedScale = (GLfixed)(buildingScale * 65536); + + glPushMatrix(); + glTranslatex((x * translationScale) * 65536, + (y * translationScale) * 65536, + 0); + glRotatex((GLfixed)((randomUInt() % 360) << 16), 0, 0, 1 << 16); + glScalex(fixedScale, fixedScale, fixedScale); + + drawGLObject(sSuperShapeObjects[curShape]); + glPopMatrix(); + } + } + + for (x = -2; x <= 2; ++x) + { + const int shipScale100 = translationScale * 500; + const int offs100 = x * shipScale100 + (sTick % shipScale100); + float offs = offs100 * 0.01f; + GLfixed fixedOffs = (GLfixed)(offs * 65536); + glPushMatrix(); + glTranslatex(fixedOffs, -4 * 65536, 2 << 16); + drawGLObject(sSuperShapeObjects[SUPERSHAPE_COUNT - 1]); + glPopMatrix(); + glPushMatrix(); + glTranslatex(-4 * 65536, fixedOffs, 4 << 16); + glRotatex(90 << 16, 0, 0, 1 << 16); + drawGLObject(sSuperShapeObjects[SUPERSHAPE_COUNT - 1]); + glPopMatrix(); + } +} + + +/* Following gluLookAt implementation is adapted from the + * Mesa 3D Graphics library. http://www.mesa3d.org + */ +static void gluLookAt(GLfloat eyex, GLfloat eyey, GLfloat eyez, + GLfloat centerx, GLfloat centery, GLfloat centerz, + GLfloat upx, GLfloat upy, GLfloat upz) +{ + GLfloat m[16]; + GLfloat x[3], y[3], z[3]; + GLfloat mag; + + /* Make rotation matrix */ + + /* Z vector */ + z[0] = eyex - centerx; + z[1] = eyey - centery; + z[2] = eyez - centerz; + mag = (float)sqrt(z[0] * z[0] + z[1] * z[1] + z[2] * z[2]); + if (mag) { /* mpichler, 19950515 */ + z[0] /= mag; + z[1] /= mag; + z[2] /= mag; + } + + /* Y vector */ + y[0] = upx; + y[1] = upy; + y[2] = upz; + + /* X vector = Y cross Z */ + x[0] = y[1] * z[2] - y[2] * z[1]; + x[1] = -y[0] * z[2] + y[2] * z[0]; + x[2] = y[0] * z[1] - y[1] * z[0]; + + /* Recompute Y = Z cross X */ + y[0] = z[1] * x[2] - z[2] * x[1]; + y[1] = -z[0] * x[2] + z[2] * x[0]; + y[2] = z[0] * x[1] - z[1] * x[0]; + + /* mpichler, 19950515 */ + /* cross product gives area of parallelogram, which is < 1.0 for + * non-perpendicular unit-length vectors; so normalize x, y here + */ + + mag = (float)sqrt(x[0] * x[0] + x[1] * x[1] + x[2] * x[2]); + if (mag) { + x[0] /= mag; + x[1] /= mag; + x[2] /= mag; + } + + mag = (float)sqrt(y[0] * y[0] + y[1] * y[1] + y[2] * y[2]); + if (mag) { + y[0] /= mag; + y[1] /= mag; + y[2] /= mag; + } + +#define M(row,col) m[col*4+row] + M(0, 0) = x[0]; + M(0, 1) = x[1]; + M(0, 2) = x[2]; + M(0, 3) = 0.0; + M(1, 0) = y[0]; + M(1, 1) = y[1]; + M(1, 2) = y[2]; + M(1, 3) = 0.0; + M(2, 0) = z[0]; + M(2, 1) = z[1]; + M(2, 2) = z[2]; + M(2, 3) = 0.0; + M(3, 0) = 0.0; + M(3, 1) = 0.0; + M(3, 2) = 0.0; + M(3, 3) = 1.0; +#undef M + { + int a; + GLfixed fixedM[16]; + for (a = 0; a < 16; ++a) + fixedM[a] = (GLfixed)(m[a] * 65536); + glMultMatrixx(fixedM); + } + + /* Translate Eye to Origin */ + glTranslatex((GLfixed)(-eyex * 65536), + (GLfixed)(-eyey * 65536), + (GLfixed)(-eyez * 65536)); +} + + +static void camTrack() +{ + float lerp[5]; + float eX, eY, eZ, cX, cY, cZ; + float trackPos; + CAMTRACK *cam; + long currentCamTick; + int a; + + if (sNextCamTrackStartTick <= sTick) + { + ++sCurrentCamTrack; + sCurrentCamTrackStartTick = sNextCamTrackStartTick; + } + sNextCamTrackStartTick = sCurrentCamTrackStartTick + + sCamTracks[sCurrentCamTrack].len * CAMTRACK_LEN; + + cam = &sCamTracks[sCurrentCamTrack]; + currentCamTick = sTick - sCurrentCamTrackStartTick; + trackPos = (float)currentCamTick / (CAMTRACK_LEN * cam->len); + + for (a = 0; a < 5; ++a) + lerp[a] = (cam->src[a] + cam->dest[a] * trackPos) * 0.01f; + + if (cam->dist) + { + float dist = cam->dist * 0.1f; + cX = lerp[0]; + cY = lerp[1]; + cZ = lerp[2]; + eX = cX - (float)cos(lerp[3]) * dist; + eY = cY - (float)sin(lerp[3]) * dist; + eZ = cZ - lerp[4]; + } + else + { + eX = lerp[0]; + eY = lerp[1]; + eZ = lerp[2]; + cX = eX + (float)cos(lerp[3]); + cY = eY + (float)sin(lerp[3]); + cZ = eZ + lerp[4]; + } + gluLookAt(eX, eY, eZ, cX, cY, cZ, 0, 0, 1); +} + + +// Called from the app framework. +/* The tick is current time in milliseconds, width and height + * are the image dimensions to be rendered. + */ +void appRender(long tick, int width, int height) +{ + if (sStartTick == 0) + sStartTick = tick; + if (!gAppAlive) + return; + + // Actual tick value is "blurred" a little bit. + sTick = (sTick + tick - sStartTick) >> 1; + + // Terminate application after running through the demonstration once. + if (sTick >= RUN_LENGTH) + { + gAppAlive = 0; + return; + } + + // Prepare OpenGL ES for rendering of the frame. + prepareFrame(width, height); + + // Update the camera position and set the lookat. + camTrack(); + + // Configure environment. + configureLightAndMaterial(); + + // Draw the reflection by drawing models with negated Z-axis. + glPushMatrix(); + drawModels(-1); + glPopMatrix(); + + // Blend the ground plane to the window. + drawGroundPlane(); + + // Draw all the models normally. + drawModels(1); + + // Draw fade quad over whole window (when changing cameras). + drawFadeQuad(); +} diff --git a/opengl/tests/angeles/gpustate.c b/opengl/tests/angeles/gpustate.c new file mode 100644 index 0000000000000000000000000000000000000000..3c540c9ca5fd16f20c0916a6c4d11cc0baf285a3 --- /dev/null +++ b/opengl/tests/angeles/gpustate.c @@ -0,0 +1,39 @@ +#include +#include +#include +#include +#include +#include + +static void *map_memory(const char *fn, unsigned base, unsigned size) +{ + int fd; + void *ptr; + + fd = open(fn, O_RDWR | O_SYNC); + if(fd < 0) { + perror("cannot open %s for mapping"); + return MAP_FAILED; + } + + ptr = mmap(0, size, PROT_READ | PROT_WRITE, + MAP_SHARED, fd, base); + close(fd); + + if(ptr == MAP_FAILED) { + fprintf(stderr,"cannot map %s (@%08x,%08x)\n", fn, base, size); + } + return ptr; +} + + +int main(int argc, char** argv) +{ + void *grp_regs = map_memory("/dev/hw3d", 0, 1024 * 1024); + printf("GPU base mapped at %p\n", grp_regs); + int state_offset = 0x10140; + printf("GPU state = %08lx\n", + *((long*)((char*)grp_regs + state_offset)) ); + + return 0; +} diff --git a/opengl/tests/angeles/include/GLES/egl.h b/opengl/tests/angeles/include/GLES/egl.h new file mode 100644 index 0000000000000000000000000000000000000000..cdf8410833340f0b87bd2258eb369577e5369462 --- /dev/null +++ b/opengl/tests/angeles/include/GLES/egl.h @@ -0,0 +1,229 @@ +#ifndef __egl_h_ +#define __egl_h_ + +/* +** License Applicability. Except to the extent portions of this file are +** made subject to an alternative license as permitted in the SGI Free +** Software License B, Version 1.0 (the "License"), the contents of this +** file are subject only to the provisions of the License. You may not use +** this file except in compliance with the License. You may obtain a copy +** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600 +** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at: +** +** http://oss.sgi.com/projects/FreeB +** +** Note that, as provided in the License, the Software is distributed on an +** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS +** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND +** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A +** PARTICULAR PURPOSE, AND NON-INFRINGEMENT. +** +** Original Code. The Original Code is: OpenGL Sample Implementation, +** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics, +** Inc. The Original Code is Copyright (c) 1991-2004 Silicon Graphics, Inc. +** Copyright in any portions created by third parties is as indicated +** elsewhere herein. All Rights Reserved. +** +** Additional Notice Provisions: The application programming interfaces +** established by SGI in conjunction with the Original Code are The +** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released +** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version +** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X +** Window System(R) (Version 1.3), released October 19, 1998. This software +** was created using the OpenGL(R) version 1.2.1 Sample Implementation +** published by SGI, but has not been independently verified as being +** compliant with the OpenGL(R) version 1.2.1 Specification. +*/ + +#include +#include + +/* +** egltypes.h is platform dependent. It defines: +** +** - EGL types and resources +** - Native types +** - EGL and native handle values +** +** EGL types and resources are to be typedef'ed with appropriate platform +** dependent resource handle types. EGLint must be an integer of at least +** 32-bit. +** +** NativeDisplayType, NativeWindowType and NativePixmapType are to be +** replaced with corresponding types of the native window system in egl.h. +** +** EGL and native handle values must match their types. +** +** Example egltypes.h: +*/ + +#if 0 + +#include +#include + +/* +** Types and resources +*/ +typedef int EGLBoolean; +typedef int32_t EGLint; +typedef void *EGLDisplay; +typedef void *EGLConfig; +typedef void *EGLSurface; +typedef void *EGLContext; + +/* +** EGL and native handle values +*/ +#define EGL_DEFAULT_DISPLAY ((NativeDisplayType)0) +#define EGL_NO_CONTEXT ((EGLContext)0) +#define EGL_NO_DISPLAY ((EGLDisplay)0) +#define EGL_NO_SURFACE ((EGLSurface)0) + +#endif + +/* +** Versioning and extensions +*/ +#define EGL_VERSION_1_0 1 + +/* +** Boolean +*/ +#define EGL_FALSE 0 +#define EGL_TRUE 1 + +/* +** Errors +*/ +#define EGL_SUCCESS 0x3000 +#define EGL_NOT_INITIALIZED 0x3001 +#define EGL_BAD_ACCESS 0x3002 +#define EGL_BAD_ALLOC 0x3003 +#define EGL_BAD_ATTRIBUTE 0x3004 +#define EGL_BAD_CONFIG 0x3005 +#define EGL_BAD_CONTEXT 0x3006 +#define EGL_BAD_CURRENT_SURFACE 0x3007 +#define EGL_BAD_DISPLAY 0x3008 +#define EGL_BAD_MATCH 0x3009 +#define EGL_BAD_NATIVE_PIXMAP 0x300A +#define EGL_BAD_NATIVE_WINDOW 0x300B +#define EGL_BAD_PARAMETER 0x300C +#define EGL_BAD_SURFACE 0x300D +/* 0x300E - 0x301F reserved for additional errors. */ + +/* +** Config attributes +*/ +#define EGL_BUFFER_SIZE 0x3020 +#define EGL_ALPHA_SIZE 0x3021 +#define EGL_BLUE_SIZE 0x3022 +#define EGL_GREEN_SIZE 0x3023 +#define EGL_RED_SIZE 0x3024 +#define EGL_DEPTH_SIZE 0x3025 +#define EGL_STENCIL_SIZE 0x3026 +#define EGL_CONFIG_CAVEAT 0x3027 +#define EGL_CONFIG_ID 0x3028 +#define EGL_LEVEL 0x3029 +#define EGL_MAX_PBUFFER_HEIGHT 0x302A +#define EGL_MAX_PBUFFER_PIXELS 0x302B +#define EGL_MAX_PBUFFER_WIDTH 0x302C +#define EGL_NATIVE_RENDERABLE 0x302D +#define EGL_NATIVE_VISUAL_ID 0x302E +#define EGL_NATIVE_VISUAL_TYPE 0x302F +/*#define EGL_PRESERVED_RESOURCES 0x3030*/ +#define EGL_SAMPLES 0x3031 +#define EGL_SAMPLE_BUFFERS 0x3032 +#define EGL_SURFACE_TYPE 0x3033 +#define EGL_TRANSPARENT_TYPE 0x3034 +#define EGL_TRANSPARENT_BLUE_VALUE 0x3035 +#define EGL_TRANSPARENT_GREEN_VALUE 0x3036 +#define EGL_TRANSPARENT_RED_VALUE 0x3037 + +/* +** Config attribute and value +*/ +#define EGL_NONE 0x3038 +/* 0x3039 - 0x304F reserved for additional config attributes. */ + +/* +** Config values +*/ +#define EGL_DONT_CARE ((EGLint) -1) +#define EGL_PBUFFER_BIT 0x01 +#define EGL_PIXMAP_BIT 0x02 +#define EGL_WINDOW_BIT 0x04 +#define EGL_SLOW_CONFIG 0x3050 +#define EGL_NON_CONFORMANT_CONFIG 0x3051 +#define EGL_TRANSPARENT_RGB 0x3052 + +/* +** String names +*/ +#define EGL_VENDOR 0x3053 +#define EGL_VERSION 0x3054 +#define EGL_EXTENSIONS 0x3055 + +/* +** Surface attributes +*/ +#define EGL_HEIGHT 0x3056 +#define EGL_WIDTH 0x3057 +#define EGL_LARGEST_PBUFFER 0x3058 + +/* +** Current surfaces +*/ +#define EGL_DRAW 0x3059 +#define EGL_READ 0x305A + +/* +** Engines +*/ +#define EGL_CORE_NATIVE_ENGINE 0x305B + +/* 0x305C-0x3FFFF reserved for future use */ + +/* +** Functions +*/ +#ifdef __cplusplus +extern "C" { +#endif + +GLAPI EGLint APIENTRY eglGetError (void); + +GLAPI EGLDisplay APIENTRY eglGetDisplay (NativeDisplayType display); +GLAPI EGLBoolean APIENTRY eglInitialize (EGLDisplay dpy, EGLint *major, EGLint *minor); +GLAPI EGLBoolean APIENTRY eglTerminate (EGLDisplay dpy); +GLAPI const char * APIENTRY eglQueryString (EGLDisplay dpy, EGLint name); +GLAPI void (* APIENTRY eglGetProcAddress (const char *procname))(); + +GLAPI EGLBoolean APIENTRY eglGetConfigs (EGLDisplay dpy, EGLConfig *configs, EGLint config_size, EGLint *num_config); +GLAPI EGLBoolean APIENTRY eglChooseConfig (EGLDisplay dpy, const EGLint *attrib_list, EGLConfig *configs, EGLint config_size, EGLint *num_config); +GLAPI EGLBoolean APIENTRY eglGetConfigAttrib (EGLDisplay dpy, EGLConfig config, EGLint attribute, EGLint *value); + +GLAPI EGLSurface APIENTRY eglCreateWindowSurface (EGLDisplay dpy, EGLConfig config, NativeWindowType window, const EGLint *attrib_list); +GLAPI EGLSurface APIENTRY eglCreatePixmapSurface (EGLDisplay dpy, EGLConfig config, NativePixmapType pixmap, const EGLint *attrib_list); +GLAPI EGLSurface APIENTRY eglCreatePbufferSurface (EGLDisplay dpy, EGLConfig config, const EGLint *attrib_list); +GLAPI EGLBoolean APIENTRY eglDestroySurface (EGLDisplay dpy, EGLSurface surface); +GLAPI EGLBoolean APIENTRY eglQuerySurface (EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint *value); + +GLAPI EGLContext APIENTRY eglCreateContext (EGLDisplay dpy, EGLConfig config, EGLContext share_list, const EGLint *attrib_list); +GLAPI EGLBoolean APIENTRY eglDestroyContext (EGLDisplay dpy, EGLContext ctx); +GLAPI EGLBoolean APIENTRY eglMakeCurrent (EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx); +GLAPI EGLContext APIENTRY eglGetCurrentContext (void); +GLAPI EGLSurface APIENTRY eglGetCurrentSurface (EGLint readdraw); +GLAPI EGLDisplay APIENTRY eglGetCurrentDisplay (void); +GLAPI EGLBoolean APIENTRY eglQueryContext (EGLDisplay dpy, EGLContext ctx, EGLint attribute, EGLint *value); + +GLAPI EGLBoolean APIENTRY eglWaitGL (void); +GLAPI EGLBoolean APIENTRY eglWaitNative (EGLint engine); +GLAPI EGLBoolean APIENTRY eglSwapBuffers (EGLDisplay dpy, EGLSurface draw); +GLAPI EGLBoolean APIENTRY eglCopyBuffers (EGLDisplay dpy, EGLSurface surface, NativePixmapType target); + +#ifdef __cplusplus +} +#endif + +#endif /* ___egl_h_ */ diff --git a/opengl/tests/angeles/include/GLES/egltypes.h b/opengl/tests/angeles/include/GLES/egltypes.h new file mode 100644 index 0000000000000000000000000000000000000000..9db36c98764d51e0e9a4322f3a83a6d0fcb28a20 --- /dev/null +++ b/opengl/tests/angeles/include/GLES/egltypes.h @@ -0,0 +1,20 @@ +/* +** Types and resources +*/ +typedef int EGLBoolean; +typedef long EGLint; +typedef void *EGLDisplay; +typedef void *EGLConfig; +typedef void *EGLSurface; +typedef void *EGLContext; +typedef void *NativeDisplayType; +typedef void *NativeWindowType; +typedef void *NativePixmapType; + +/* +** EGL and native handle values +*/ +#define EGL_DEFAULT_DISPLAY ((NativeDisplayType)0) +#define EGL_NO_CONTEXT ((EGLContext)0) +#define EGL_NO_DISPLAY ((EGLDisplay)0) +#define EGL_NO_SURFACE ((EGLSurface)0) diff --git a/opengl/tests/angeles/include/GLES/gl.h b/opengl/tests/angeles/include/GLES/gl.h new file mode 100644 index 0000000000000000000000000000000000000000..415482228d713d6fa7eac8808ea216f96c8a4f84 --- /dev/null +++ b/opengl/tests/angeles/include/GLES/gl.h @@ -0,0 +1,584 @@ +#ifndef __gl_h_ +#define __gl_h_ + +#ifdef __cplusplus +extern "C" { +#endif + +/* +** License Applicability. Except to the extent portions of this file are +** made subject to an alternative license as permitted in the SGI Free +** Software License B, Version 1.0 (the "License"), the contents of this +** file are subject only to the provisions of the License. You may not use +** this file except in compliance with the License. You may obtain a copy +** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600 +** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at: +** +** http://oss.sgi.com/projects/FreeB +** +** Note that, as provided in the License, the Software is distributed on an +** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS +** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND +** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A +** PARTICULAR PURPOSE, AND NON-INFRINGEMENT. +** +** Original Code. The Original Code is: OpenGL Sample Implementation, +** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics, +** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc. +** Copyright in any portions created by third parties is as indicated +** elsewhere herein. All Rights Reserved. +** +** Additional Notice Provisions: The application programming interfaces +** established by SGI in conjunction with the Original Code are The +** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released +** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version +** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X +** Window System(R) (Version 1.3), released October 19, 1998. This software +** was created using the OpenGL(R) version 1.2.1 Sample Implementation +** published by SGI, but has not been independently verified as being +** compliant with the OpenGL(R) version 1.2.1 Specification. +*/ + +#if defined(_WIN32) && !defined(APIENTRY) && !defined(__CYGWIN__) +#define WIN32_LEAN_AND_MEAN 1 +#include +#endif + +#ifndef APIENTRY +#define APIENTRY +#endif +#ifndef GLAPI +#define GLAPI extern +#endif + +typedef unsigned int GLenum; +typedef unsigned char GLboolean; +typedef unsigned int GLbitfield; +typedef signed char GLbyte; +typedef short GLshort; +typedef int GLint; +typedef int GLsizei; +typedef unsigned char GLubyte; +typedef unsigned short GLushort; +typedef unsigned int GLuint; +typedef float GLfloat; +typedef float GLclampf; +typedef void GLvoid; +typedef int GLintptrARB; +typedef int GLsizeiptrARB; +typedef int GLfixed; +typedef int GLclampx; +/* Internal convenience typedefs */ +typedef void (*_GLfuncptr)(); + +/*************************************************************/ + +/* Extensions */ +#define GL_OES_VERSION_1_0 1 +#define GL_OES_read_format 1 +#define GL_OES_compressed_paletted_texture 1 + +/* ClearBufferMask */ +#define GL_DEPTH_BUFFER_BIT 0x00000100 +#define GL_STENCIL_BUFFER_BIT 0x00000400 +#define GL_COLOR_BUFFER_BIT 0x00004000 + +/* Boolean */ +#define GL_FALSE 0 +#define GL_TRUE 1 + +/* BeginMode */ +#define GL_POINTS 0x0000 +#define GL_LINES 0x0001 +#define GL_LINE_LOOP 0x0002 +#define GL_LINE_STRIP 0x0003 +#define GL_TRIANGLES 0x0004 +#define GL_TRIANGLE_STRIP 0x0005 +#define GL_TRIANGLE_FAN 0x0006 + +/* AlphaFunction */ +#define GL_NEVER 0x0200 +#define GL_LESS 0x0201 +#define GL_EQUAL 0x0202 +#define GL_LEQUAL 0x0203 +#define GL_GREATER 0x0204 +#define GL_NOTEQUAL 0x0205 +#define GL_GEQUAL 0x0206 +#define GL_ALWAYS 0x0207 + +/* BlendingFactorDest */ +#define GL_ZERO 0 +#define GL_ONE 1 +#define GL_SRC_COLOR 0x0300 +#define GL_ONE_MINUS_SRC_COLOR 0x0301 +#define GL_SRC_ALPHA 0x0302 +#define GL_ONE_MINUS_SRC_ALPHA 0x0303 +#define GL_DST_ALPHA 0x0304 +#define GL_ONE_MINUS_DST_ALPHA 0x0305 + +/* BlendingFactorSrc */ +/* GL_ZERO */ +/* GL_ONE */ +#define GL_DST_COLOR 0x0306 +#define GL_ONE_MINUS_DST_COLOR 0x0307 +#define GL_SRC_ALPHA_SATURATE 0x0308 +/* GL_SRC_ALPHA */ +/* GL_ONE_MINUS_SRC_ALPHA */ +/* GL_DST_ALPHA */ +/* GL_ONE_MINUS_DST_ALPHA */ + +/* ColorMaterialFace */ +/* GL_FRONT_AND_BACK */ + +/* ColorMaterialParameter */ +/* GL_AMBIENT_AND_DIFFUSE */ + +/* ColorPointerType */ +/* GL_UNSIGNED_BYTE */ +/* GL_FLOAT */ +/* GL_FIXED */ + +/* CullFaceMode */ +#define GL_FRONT 0x0404 +#define GL_BACK 0x0405 +#define GL_FRONT_AND_BACK 0x0408 + +/* DepthFunction */ +/* GL_NEVER */ +/* GL_LESS */ +/* GL_EQUAL */ +/* GL_LEQUAL */ +/* GL_GREATER */ +/* GL_NOTEQUAL */ +/* GL_GEQUAL */ +/* GL_ALWAYS */ + +/* EnableCap */ +#define GL_FOG 0x0B60 +#define GL_LIGHTING 0x0B50 +#define GL_TEXTURE_2D 0x0DE1 +#define GL_CULL_FACE 0x0B44 +#define GL_ALPHA_TEST 0x0BC0 +#define GL_BLEND 0x0BE2 +#define GL_COLOR_LOGIC_OP 0x0BF2 +#define GL_DITHER 0x0BD0 +#define GL_STENCIL_TEST 0x0B90 +#define GL_DEPTH_TEST 0x0B71 +/* GL_LIGHT0 */ +/* GL_LIGHT1 */ +/* GL_LIGHT2 */ +/* GL_LIGHT3 */ +/* GL_LIGHT4 */ +/* GL_LIGHT5 */ +/* GL_LIGHT6 */ +/* GL_LIGHT7 */ +#define GL_POINT_SMOOTH 0x0B10 +#define GL_LINE_SMOOTH 0x0B20 +#define GL_SCISSOR_TEST 0x0C11 +#define GL_COLOR_MATERIAL 0x0B57 +#define GL_NORMALIZE 0x0BA1 +#define GL_RESCALE_NORMAL 0x803A +#define GL_POLYGON_OFFSET_FILL 0x8037 +#define GL_VERTEX_ARRAY 0x8074 +#define GL_NORMAL_ARRAY 0x8075 +#define GL_COLOR_ARRAY 0x8076 +#define GL_TEXTURE_COORD_ARRAY 0x8078 +#define GL_MULTISAMPLE 0x809D +#define GL_SAMPLE_ALPHA_TO_COVERAGE 0x809E +#define GL_SAMPLE_ALPHA_TO_ONE 0x809F +#define GL_SAMPLE_COVERAGE 0x80A0 + +/* ErrorCode */ +#define GL_NO_ERROR 0 +#define GL_INVALID_ENUM 0x0500 +#define GL_INVALID_VALUE 0x0501 +#define GL_INVALID_OPERATION 0x0502 +#define GL_STACK_OVERFLOW 0x0503 +#define GL_STACK_UNDERFLOW 0x0504 +#define GL_OUT_OF_MEMORY 0x0505 + +/* FogMode */ +/* GL_LINEAR */ +#define GL_EXP 0x0800 +#define GL_EXP2 0x0801 + +/* FogParameter */ +#define GL_FOG_DENSITY 0x0B62 +#define GL_FOG_START 0x0B63 +#define GL_FOG_END 0x0B64 +#define GL_FOG_MODE 0x0B65 +#define GL_FOG_COLOR 0x0B66 + +/* FrontFaceDirection */ +#define GL_CW 0x0900 +#define GL_CCW 0x0901 + +/* GetPName */ +#define GL_SMOOTH_POINT_SIZE_RANGE 0x0B12 +#define GL_SMOOTH_LINE_WIDTH_RANGE 0x0B22 +#define GL_ALIASED_POINT_SIZE_RANGE 0x846D +#define GL_ALIASED_LINE_WIDTH_RANGE 0x846E +#define GL_IMPLEMENTATION_COLOR_READ_TYPE_OES 0x8B9A +#define GL_IMPLEMENTATION_COLOR_READ_FORMAT_OES 0x8B9B +#define GL_MAX_LIGHTS 0x0D31 +#define GL_MAX_TEXTURE_SIZE 0x0D33 +#define GL_MAX_MODELVIEW_STACK_DEPTH 0x0D36 +#define GL_MAX_PROJECTION_STACK_DEPTH 0x0D38 +#define GL_MAX_TEXTURE_STACK_DEPTH 0x0D39 +#define GL_MAX_VIEWPORT_DIMS 0x0D3A +#define GL_MAX_ELEMENTS_VERTICES 0x80E8 +#define GL_MAX_ELEMENTS_INDICES 0x80E9 +#define GL_MAX_TEXTURE_UNITS 0x84E2 +#define GL_NUM_COMPRESSED_TEXTURE_FORMATS 0x86A2 +#define GL_COMPRESSED_TEXTURE_FORMATS 0x86A3 +#define GL_SUBPIXEL_BITS 0x0D50 +#define GL_RED_BITS 0x0D52 +#define GL_GREEN_BITS 0x0D53 +#define GL_BLUE_BITS 0x0D54 +#define GL_ALPHA_BITS 0x0D55 +#define GL_DEPTH_BITS 0x0D56 +#define GL_STENCIL_BITS 0x0D57 + +/* HintMode */ +#define GL_DONT_CARE 0x1100 +#define GL_FASTEST 0x1101 +#define GL_NICEST 0x1102 + +/* HintTarget */ +#define GL_PERSPECTIVE_CORRECTION_HINT 0x0C50 +#define GL_POINT_SMOOTH_HINT 0x0C51 +#define GL_LINE_SMOOTH_HINT 0x0C52 +#define GL_POLYGON_SMOOTH_HINT 0x0C53 +#define GL_FOG_HINT 0x0C54 + +/* LightModelParameter */ +#define GL_LIGHT_MODEL_AMBIENT 0x0B53 +#define GL_LIGHT_MODEL_TWO_SIDE 0x0B52 + +/* LightParameter */ +#define GL_AMBIENT 0x1200 +#define GL_DIFFUSE 0x1201 +#define GL_SPECULAR 0x1202 +#define GL_POSITION 0x1203 +#define GL_SPOT_DIRECTION 0x1204 +#define GL_SPOT_EXPONENT 0x1205 +#define GL_SPOT_CUTOFF 0x1206 +#define GL_CONSTANT_ATTENUATION 0x1207 +#define GL_LINEAR_ATTENUATION 0x1208 +#define GL_QUADRATIC_ATTENUATION 0x1209 + +/* DataType */ +#define GL_BYTE 0x1400 +#define GL_UNSIGNED_BYTE 0x1401 +#define GL_SHORT 0x1402 +#define GL_UNSIGNED_SHORT 0x1403 +#define GL_FLOAT 0x1406 +#define GL_FIXED 0x140C + +/* LogicOp */ +#define GL_CLEAR 0x1500 +#define GL_AND 0x1501 +#define GL_AND_REVERSE 0x1502 +#define GL_COPY 0x1503 +#define GL_AND_INVERTED 0x1504 +#define GL_NOOP 0x1505 +#define GL_XOR 0x1506 +#define GL_OR 0x1507 +#define GL_NOR 0x1508 +#define GL_EQUIV 0x1509 +#define GL_INVERT 0x150A +#define GL_OR_REVERSE 0x150B +#define GL_COPY_INVERTED 0x150C +#define GL_OR_INVERTED 0x150D +#define GL_NAND 0x150E +#define GL_SET 0x150F + +/* MaterialFace */ +/* GL_FRONT_AND_BACK */ + +/* MaterialParameter */ +#define GL_EMISSION 0x1600 +#define GL_SHININESS 0x1601 +#define GL_AMBIENT_AND_DIFFUSE 0x1602 +/* GL_AMBIENT */ +/* GL_DIFFUSE */ +/* GL_SPECULAR */ + +/* MatrixMode */ +#define GL_MODELVIEW 0x1700 +#define GL_PROJECTION 0x1701 +#define GL_TEXTURE 0x1702 + +/* NormalPointerType */ +/* GL_BYTE */ +/* GL_SHORT */ +/* GL_FLOAT */ +/* GL_FIXED */ + +/* PixelFormat */ +#define GL_ALPHA 0x1906 +#define GL_RGB 0x1907 +#define GL_RGBA 0x1908 +#define GL_LUMINANCE 0x1909 +#define GL_LUMINANCE_ALPHA 0x190A + +/* PixelStoreParameter */ +#define GL_UNPACK_ALIGNMENT 0x0CF5 +#define GL_PACK_ALIGNMENT 0x0D05 + +/* PixelType */ +/* GL_UNSIGNED_BYTE */ +#define GL_UNSIGNED_SHORT_4_4_4_4 0x8033 +#define GL_UNSIGNED_SHORT_5_5_5_1 0x8034 +#define GL_UNSIGNED_SHORT_5_6_5 0x8363 + +/* ShadingModel */ +#define GL_FLAT 0x1D00 +#define GL_SMOOTH 0x1D01 + +/* StencilFunction */ +/* GL_NEVER */ +/* GL_LESS */ +/* GL_EQUAL */ +/* GL_LEQUAL */ +/* GL_GREATER */ +/* GL_NOTEQUAL */ +/* GL_GEQUAL */ +/* GL_ALWAYS */ + +/* StencilOp */ +/* GL_ZERO */ +#define GL_KEEP 0x1E00 +#define GL_REPLACE 0x1E01 +#define GL_INCR 0x1E02 +#define GL_DECR 0x1E03 +/* GL_INVERT */ + +/* StringName */ +#define GL_VENDOR 0x1F00 +#define GL_RENDERER 0x1F01 +#define GL_VERSION 0x1F02 +#define GL_EXTENSIONS 0x1F03 + +/* TexCoordPointerType */ +/* GL_SHORT */ +/* GL_FLOAT */ +/* GL_FIXED */ +/* GL_BYTE */ + +/* TextureEnvMode */ +#define GL_MODULATE 0x2100 +#define GL_DECAL 0x2101 +/* GL_BLEND */ +#define GL_ADD 0x0104 +/* GL_REPLACE */ + +/* TextureEnvParameter */ +#define GL_TEXTURE_ENV_MODE 0x2200 +#define GL_TEXTURE_ENV_COLOR 0x2201 + +/* TextureEnvTarget */ +#define GL_TEXTURE_ENV 0x2300 + +/* TextureMagFilter */ +#define GL_NEAREST 0x2600 +#define GL_LINEAR 0x2601 + +/* TextureMinFilter */ +/* GL_NEAREST */ +/* GL_LINEAR */ +#define GL_NEAREST_MIPMAP_NEAREST 0x2700 +#define GL_LINEAR_MIPMAP_NEAREST 0x2701 +#define GL_NEAREST_MIPMAP_LINEAR 0x2702 +#define GL_LINEAR_MIPMAP_LINEAR 0x2703 + +/* TextureParameterName */ +#define GL_TEXTURE_MAG_FILTER 0x2800 +#define GL_TEXTURE_MIN_FILTER 0x2801 +#define GL_TEXTURE_WRAP_S 0x2802 +#define GL_TEXTURE_WRAP_T 0x2803 + +/* TextureTarget */ +/* GL_TEXTURE_2D */ + +/* TextureUnit */ +#define GL_TEXTURE0 0x84C0 +#define GL_TEXTURE1 0x84C1 +#define GL_TEXTURE2 0x84C2 +#define GL_TEXTURE3 0x84C3 +#define GL_TEXTURE4 0x84C4 +#define GL_TEXTURE5 0x84C5 +#define GL_TEXTURE6 0x84C6 +#define GL_TEXTURE7 0x84C7 +#define GL_TEXTURE8 0x84C8 +#define GL_TEXTURE9 0x84C9 +#define GL_TEXTURE10 0x84CA +#define GL_TEXTURE11 0x84CB +#define GL_TEXTURE12 0x84CC +#define GL_TEXTURE13 0x84CD +#define GL_TEXTURE14 0x84CE +#define GL_TEXTURE15 0x84CF +#define GL_TEXTURE16 0x84D0 +#define GL_TEXTURE17 0x84D1 +#define GL_TEXTURE18 0x84D2 +#define GL_TEXTURE19 0x84D3 +#define GL_TEXTURE20 0x84D4 +#define GL_TEXTURE21 0x84D5 +#define GL_TEXTURE22 0x84D6 +#define GL_TEXTURE23 0x84D7 +#define GL_TEXTURE24 0x84D8 +#define GL_TEXTURE25 0x84D9 +#define GL_TEXTURE26 0x84DA +#define GL_TEXTURE27 0x84DB +#define GL_TEXTURE28 0x84DC +#define GL_TEXTURE29 0x84DD +#define GL_TEXTURE30 0x84DE +#define GL_TEXTURE31 0x84DF + +/* TextureWrapMode */ +#define GL_REPEAT 0x2901 +#define GL_CLAMP_TO_EDGE 0x812F + +/* PixelInternalFormat */ +#define GL_PALETTE4_RGB8_OES 0x8B90 +#define GL_PALETTE4_RGBA8_OES 0x8B91 +#define GL_PALETTE4_R5_G6_B5_OES 0x8B92 +#define GL_PALETTE4_RGBA4_OES 0x8B93 +#define GL_PALETTE4_RGB5_A1_OES 0x8B94 +#define GL_PALETTE8_RGB8_OES 0x8B95 +#define GL_PALETTE8_RGBA8_OES 0x8B96 +#define GL_PALETTE8_R5_G6_B5_OES 0x8B97 +#define GL_PALETTE8_RGBA4_OES 0x8B98 +#define GL_PALETTE8_RGB5_A1_OES 0x8B99 + +/* VertexPointerType */ +/* GL_SHORT */ +/* GL_FLOAT */ +/* GL_FIXED */ +/* GL_BYTE */ + +/* LightName */ +#define GL_LIGHT0 0x4000 +#define GL_LIGHT1 0x4001 +#define GL_LIGHT2 0x4002 +#define GL_LIGHT3 0x4003 +#define GL_LIGHT4 0x4004 +#define GL_LIGHT5 0x4005 +#define GL_LIGHT6 0x4006 +#define GL_LIGHT7 0x4007 + + +/*************************************************************/ + +GLAPI void APIENTRY glActiveTexture (GLenum texture); +GLAPI void APIENTRY glAlphaFunc (GLenum func, GLclampf ref); +GLAPI void APIENTRY glAlphaFuncx (GLenum func, GLclampx ref); +GLAPI void APIENTRY glBindTexture (GLenum target, GLuint texture); +GLAPI void APIENTRY glBlendFunc (GLenum sfactor, GLenum dfactor); +GLAPI void APIENTRY glClear (GLbitfield mask); +GLAPI void APIENTRY glClearColor (GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha); +GLAPI void APIENTRY glClearColorx (GLclampx red, GLclampx green, GLclampx blue, GLclampx alpha); +GLAPI void APIENTRY glClearDepthf (GLclampf depth); +GLAPI void APIENTRY glClearDepthx (GLclampx depth); +GLAPI void APIENTRY glClearStencil (GLint s); +GLAPI void APIENTRY glClientActiveTexture (GLenum texture); +GLAPI void APIENTRY glColor4f (GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); +GLAPI void APIENTRY glColor4x (GLfixed red, GLfixed green, GLfixed blue, GLfixed alpha); +GLAPI void APIENTRY glColorMask (GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha); +GLAPI void APIENTRY glColorPointer (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); +GLAPI void APIENTRY glCompressedTexImage2D (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *data); +GLAPI void APIENTRY glCompressedTexSubImage2D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid *data); +GLAPI void APIENTRY glCopyTexImage2D (GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border); +GLAPI void APIENTRY glCopyTexSubImage2D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height); +GLAPI void APIENTRY glCullFace (GLenum mode); +GLAPI void APIENTRY glDeleteTextures (GLsizei n, const GLuint *textures); +GLAPI void APIENTRY glDepthFunc (GLenum func); +GLAPI void APIENTRY glDepthMask (GLboolean flag); +GLAPI void APIENTRY glDepthRangef (GLclampf zNear, GLclampf zFar); +GLAPI void APIENTRY glDepthRangex (GLclampx zNear, GLclampx zFar); +GLAPI void APIENTRY glDisable (GLenum cap); +GLAPI void APIENTRY glDisableClientState (GLenum array); +GLAPI void APIENTRY glDrawArrays (GLenum mode, GLint first, GLsizei count); +GLAPI void APIENTRY glDrawElements (GLenum mode, GLsizei count, GLenum type, const GLvoid *indices); +GLAPI void APIENTRY glEnable (GLenum cap); +GLAPI void APIENTRY glEnableClientState (GLenum array); +GLAPI void APIENTRY glFinish (void); +GLAPI void APIENTRY glFlush (void); +GLAPI void APIENTRY glFogf (GLenum pname, GLfloat param); +GLAPI void APIENTRY glFogfv (GLenum pname, const GLfloat *params); +GLAPI void APIENTRY glFogx (GLenum pname, GLfixed param); +GLAPI void APIENTRY glFogxv (GLenum pname, const GLfixed *params); +GLAPI void APIENTRY glFrontFace (GLenum mode); +GLAPI void APIENTRY glFrustumf (GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat zNear, GLfloat zFar); +GLAPI void APIENTRY glFrustumx (GLfixed left, GLfixed right, GLfixed bottom, GLfixed top, GLfixed zNear, GLfixed zFar); +GLAPI void APIENTRY glGenTextures (GLsizei n, GLuint *textures); +GLAPI GLenum APIENTRY glGetError (void); +GLAPI void APIENTRY glGetIntegerv (GLenum pname, GLint *params); +GLAPI const GLubyte * APIENTRY glGetString (GLenum name); +GLAPI void APIENTRY glHint (GLenum target, GLenum mode); +GLAPI void APIENTRY glLightModelf (GLenum pname, GLfloat param); +GLAPI void APIENTRY glLightModelfv (GLenum pname, const GLfloat *params); +GLAPI void APIENTRY glLightModelx (GLenum pname, GLfixed param); +GLAPI void APIENTRY glLightModelxv (GLenum pname, const GLfixed *params); +GLAPI void APIENTRY glLightf (GLenum light, GLenum pname, GLfloat param); +GLAPI void APIENTRY glLightfv (GLenum light, GLenum pname, const GLfloat *params); +GLAPI void APIENTRY glLightx (GLenum light, GLenum pname, GLfixed param); +GLAPI void APIENTRY glLightxv (GLenum light, GLenum pname, const GLfixed *params); +GLAPI void APIENTRY glLineWidth (GLfloat width); +GLAPI void APIENTRY glLineWidthx (GLfixed width); +GLAPI void APIENTRY glLoadIdentity (void); +GLAPI void APIENTRY glLoadMatrixf (const GLfloat *m); +GLAPI void APIENTRY glLoadMatrixx (const GLfixed *m); +GLAPI void APIENTRY glLogicOp (GLenum opcode); +GLAPI void APIENTRY glMaterialf (GLenum face, GLenum pname, GLfloat param); +GLAPI void APIENTRY glMaterialfv (GLenum face, GLenum pname, const GLfloat *params); +GLAPI void APIENTRY glMaterialx (GLenum face, GLenum pname, GLfixed param); +GLAPI void APIENTRY glMaterialxv (GLenum face, GLenum pname, const GLfixed *params); +GLAPI void APIENTRY glMatrixMode (GLenum mode); +GLAPI void APIENTRY glMultMatrixf (const GLfloat *m); +GLAPI void APIENTRY glMultMatrixx (const GLfixed *m); +GLAPI void APIENTRY glMultiTexCoord4f (GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q); +GLAPI void APIENTRY glMultiTexCoord4x (GLenum target, GLfixed s, GLfixed t, GLfixed r, GLfixed q); +GLAPI void APIENTRY glNormal3f (GLfloat nx, GLfloat ny, GLfloat nz); +GLAPI void APIENTRY glNormal3x (GLfixed nx, GLfixed ny, GLfixed nz); +GLAPI void APIENTRY glNormalPointer (GLenum type, GLsizei stride, const GLvoid *pointer); +GLAPI void APIENTRY glOrthof (GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat zNear, GLfloat zFar); +GLAPI void APIENTRY glOrthox (GLfixed left, GLfixed right, GLfixed bottom, GLfixed top, GLfixed zNear, GLfixed zFar); +GLAPI void APIENTRY glPixelStorei (GLenum pname, GLint param); +GLAPI void APIENTRY glPointSize (GLfloat size); +GLAPI void APIENTRY glPointSizex (GLfixed size); +GLAPI void APIENTRY glPolygonOffset (GLfloat factor, GLfloat units); +GLAPI void APIENTRY glPolygonOffsetx (GLfixed factor, GLfixed units); +GLAPI void APIENTRY glPopMatrix (void); +GLAPI void APIENTRY glPushMatrix (void); +GLAPI void APIENTRY glReadPixels (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid *pixels); +GLAPI void APIENTRY glRotatef (GLfloat angle, GLfloat x, GLfloat y, GLfloat z); +GLAPI void APIENTRY glRotatex (GLfixed angle, GLfixed x, GLfixed y, GLfixed z); +GLAPI void APIENTRY glSampleCoverage (GLclampf value, GLboolean invert); +GLAPI void APIENTRY glSampleCoveragex (GLclampx value, GLboolean invert); +GLAPI void APIENTRY glScalef (GLfloat x, GLfloat y, GLfloat z); +GLAPI void APIENTRY glScalex (GLfixed x, GLfixed y, GLfixed z); +GLAPI void APIENTRY glScissor (GLint x, GLint y, GLsizei width, GLsizei height); +GLAPI void APIENTRY glShadeModel (GLenum mode); +GLAPI void APIENTRY glStencilFunc (GLenum func, GLint ref, GLuint mask); +GLAPI void APIENTRY glStencilMask (GLuint mask); +GLAPI void APIENTRY glStencilOp (GLenum fail, GLenum zfail, GLenum zpass); +GLAPI void APIENTRY glTexCoordPointer (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); +GLAPI void APIENTRY glTexEnvf (GLenum target, GLenum pname, GLfloat param); +GLAPI void APIENTRY glTexEnvfv (GLenum target, GLenum pname, const GLfloat *params); +GLAPI void APIENTRY glTexEnvx (GLenum target, GLenum pname, GLfixed param); +GLAPI void APIENTRY glTexEnvxv (GLenum target, GLenum pname, const GLfixed *params); +GLAPI void APIENTRY glTexImage2D (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels); +GLAPI void APIENTRY glTexParameterf (GLenum target, GLenum pname, GLfloat param); +GLAPI void APIENTRY glTexParameterx (GLenum target, GLenum pname, GLfixed param); +GLAPI void APIENTRY glTexSubImage2D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels); +GLAPI void APIENTRY glTranslatef (GLfloat x, GLfloat y, GLfloat z); +GLAPI void APIENTRY glTranslatex (GLfixed x, GLfixed y, GLfixed z); +GLAPI void APIENTRY glVertexPointer (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); +GLAPI void APIENTRY glViewport (GLint x, GLint y, GLsizei width, GLsizei height); + +#ifdef __cplusplus +} +#endif + +#endif /* __gl_h_ */ diff --git a/opengl/tests/angeles/license-BSD.txt b/opengl/tests/angeles/license-BSD.txt new file mode 100644 index 0000000000000000000000000000000000000000..8924e3ca28dc9bc7ecd63900cdfde72c03103ed4 --- /dev/null +++ b/opengl/tests/angeles/license-BSD.txt @@ -0,0 +1,34 @@ +This is the BSD-style license for the "San Angeles Observation" +OpenGL ES version example source code +--------------------------------------------------------------- + +San Angeles Observation OpenGL ES version example +Copyright (c) 2004-2005, Jetro Lauha +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + * Neither the name of the software product's copyright owner nor + the names of its contributors may be used to endorse or promote + products derived from this software without specific prior written + permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/opengl/tests/angeles/license-LGPL.txt b/opengl/tests/angeles/license-LGPL.txt new file mode 100644 index 0000000000000000000000000000000000000000..b1e3f5a2638797271cbc9b91b856c05ed6942c8f --- /dev/null +++ b/opengl/tests/angeles/license-LGPL.txt @@ -0,0 +1,504 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! + + diff --git a/opengl/tests/angeles/license.txt b/opengl/tests/angeles/license.txt new file mode 100644 index 0000000000000000000000000000000000000000..620841e82e69b9b5171811202fe606e44a44a45c --- /dev/null +++ b/opengl/tests/angeles/license.txt @@ -0,0 +1,19 @@ +San Angeles Observation OpenGL ES version example +Copyright 2004-2005 Jetro Lauha +All rights reserved. +Web: http://iki.fi/jetro/ + +This source is free software; you can redistribute it and/or +modify it under the terms of EITHER: + (1) The GNU Lesser General Public License as published by the Free + Software Foundation; either version 2.1 of the License, or (at + your option) any later version. The text of the GNU Lesser + General Public License is included with this source in the + file LICENSE-LGPL.txt. + (2) The BSD-style license that is included with this source in + the file LICENSE-BSD.txt. + +This source is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files +LICENSE-LGPL.txt and LICENSE-BSD.txt for more details. diff --git a/opengl/tests/angeles/shapes.h b/opengl/tests/angeles/shapes.h new file mode 100644 index 0000000000000000000000000000000000000000..25ffae8ce4b2fe9beeaaf79db60721de8eef6467 --- /dev/null +++ b/opengl/tests/angeles/shapes.h @@ -0,0 +1,59 @@ +/* San Angeles Observation OpenGL ES version example + * Copyright 2004-2005 Jetro Lauha + * All rights reserved. + * Web: http://iki.fi/jetro/ + * + * This source is free software; you can redistribute it and/or + * modify it under the terms of EITHER: + * (1) The GNU Lesser General Public License as published by the Free + * Software Foundation; either version 2.1 of the License, or (at + * your option) any later version. The text of the GNU Lesser + * General Public License is included with this source in the + * file LICENSE-LGPL.txt. + * (2) The BSD-style license that is included with this source in + * the file LICENSE-BSD.txt. + * + * This source is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files + * LICENSE-LGPL.txt and LICENSE-BSD.txt for more details. + * + * $Id: shapes.h,v 1.6 2005/01/31 22:15:30 tonic Exp $ + * $Revision: 1.6 $ + */ + +#ifndef SHAPES_H_INCLUDED +#define SHAPES_H_INCLUDED + + +#define SUPERSHAPE_PARAMS 15 + +static const float sSuperShapeParams[][SUPERSHAPE_PARAMS] = +{ + // m a b n1 n2 n3 m a b n1 n2 n3 res1 res2 scale (org.res1,res2) + { 10, 1, 2, 90, 1, -45, 8, 1, 1, -1, 1, -0.4f, 20, 30, 2 }, // 40, 60 + { 10, 1, 2, 90, 1, -45, 4, 1, 1, 10, 1, -0.4f, 20, 20, 4 }, // 40, 40 + { 10, 1, 2, 60, 1, -10, 4, 1, 1, -1, -2, -0.4f, 41, 41, 1 }, // 82, 82 + { 6, 1, 1, 60, 1, -70, 8, 1, 1, 0.4f, 3, 0.25f, 20, 20, 1 }, // 40, 40 + { 4, 1, 1, 30, 1, 20, 12, 1, 1, 0.4f, 3, 0.25f, 10, 30, 1 }, // 20, 60 + { 8, 1, 1, 30, 1, -4, 8, 2, 1, -1, 5, 0.5f, 25, 26, 1 }, // 60, 60 + { 13, 1, 1, 30, 1, -4, 13, 1, 1, 1, 5, 1, 30, 30, 6 }, // 60, 60 + { 10, 1, 1.1f, -0.5f, 0.1f, 70, 60, 1, 1, -90, 0, -0.25f, 20, 60, 8 }, // 60, 180 + { 7, 1, 1, 20, -0.3f, -3.5f, 6, 1, 1, -1, 4.5f, 0.5f, 10, 20, 4 }, // 60, 80 + { 4, 1, 1, 10, 10, 10, 4, 1, 1, 10, 10, 10, 10, 20, 1 }, // 20, 40 + { 4, 1, 1, 1, 1, 1, 4, 1, 1, 1, 1, 1, 10, 10, 2 }, // 10, 10 + { 1, 1, 1, 38, -0.25f, 19, 4, 1, 1, 10, 10, 10, 10, 15, 2 }, // 20, 40 + { 2, 1, 1, 0.7f, 0.3f, 0.2f, 3, 1, 1, 100, 100, 100, 10, 25, 2 }, // 20, 50 + { 6, 1, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 30, 30, 2 }, // 60, 60 + { 3, 1, 1, 1, 1, 1, 6, 1, 1, 2, 1, 1, 10, 20, 2 }, // 20, 40 + { 6, 1, 1, 6, 5.5f, 100, 6, 1, 1, 25, 10, 10, 30, 20, 2 }, // 60, 40 + { 3, 1, 1, 0.5f, 1.7f, 1.7f, 2, 1, 1, 10, 10, 10, 20, 20, 2 }, // 40, 40 + { 5, 1, 1, 0.1f, 1.7f, 1.7f, 1, 1, 1, 0.3f, 0.5f, 0.5f, 20, 20, 4 }, // 40, 40 + { 2, 1, 1, 6, 5.5f, 100, 6, 1, 1, 4, 10, 10, 10, 22, 1 }, // 40, 40 + { 6, 1, 1, -1, 70, 0.1f, 9, 1, 0.5f, -98, 0.05f, -45, 20, 30, 4 }, // 60, 91 + { 6, 1, 1, -1, 90, -0.1f, 7, 1, 1, 90, 1.3f, 34, 13, 16, 1 }, // 32, 60 +}; +#define SUPERSHAPE_COUNT (sizeof(sSuperShapeParams) / sizeof(sSuperShapeParams[0])) + + +#endif // !SHAPES_H_INCLUDED diff --git a/opengl/tests/filter/Android.mk b/opengl/tests/filter/Android.mk new file mode 100644 index 0000000000000000000000000000000000000000..1c4253c2c0cc2c68543a7ea827e6a2c273a054d7 --- /dev/null +++ b/opengl/tests/filter/Android.mk @@ -0,0 +1,16 @@ +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_SRC_FILES:= \ + filter.c + +LOCAL_SHARED_LIBRARIES := \ + libcutils \ + libGLES_CM \ + libui + +LOCAL_MODULE:= test-opengl-filter + +LOCAL_MODULE_TAGS := tests + +include $(BUILD_EXECUTABLE) diff --git a/opengl/tests/filter/filter.c b/opengl/tests/filter/filter.c new file mode 100644 index 0000000000000000000000000000000000000000..c8bac06cd56218a54cf8e94e12b9c1efbfabd2e5 --- /dev/null +++ b/opengl/tests/filter/filter.c @@ -0,0 +1,125 @@ +#include +#include + +#include + +int main(int argc, char** argv) +{ + if (argc!=2 && argc!=3) { + printf("usage: %s <0-6> [pbuffer]\n", argv[0]); + return 0; + } + + const int test = atoi(argv[1]); + int usePbuffer = argc==3 && !strcmp(argv[2], "pbuffer"); + EGLint s_configAttribs[] = { + EGL_SURFACE_TYPE, EGL_PBUFFER_BIT|EGL_WINDOW_BIT, + EGL_RED_SIZE, 5, + EGL_GREEN_SIZE, 6, + EGL_BLUE_SIZE, 5, + EGL_NONE + }; + + EGLint numConfigs = -1; + EGLint majorVersion; + EGLint minorVersion; + EGLConfig config; + EGLContext context; + EGLSurface surface; + EGLint w, h; + + EGLDisplay dpy; + + dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY); + eglInitialize(dpy, &majorVersion, &minorVersion); + eglChooseConfig(dpy, s_configAttribs, &config, 1, &numConfigs); + if (!usePbuffer) { + surface = eglCreateWindowSurface(dpy, config, + android_createDisplaySurface(), NULL); + } else { + printf("using pbuffer\n"); + EGLint attribs[] = { EGL_WIDTH, 320, EGL_HEIGHT, 480, EGL_NONE }; + surface = eglCreatePbufferSurface(dpy, config, attribs); + } + context = eglCreateContext(dpy, config, NULL, NULL); + eglMakeCurrent(dpy, surface, surface, context); + eglQuerySurface(dpy, surface, EGL_WIDTH, &w); + eglQuerySurface(dpy, surface, EGL_HEIGHT, &h); + GLint dim = w +#include +#include +#include +#include + +#include + +long long systemTime() +{ + struct timespec t; + t.tv_sec = t.tv_nsec = 0; + clock_gettime(CLOCK_MONOTONIC, &t); + return (long long)(t.tv_sec)*1000000000LL + t.tv_nsec; +} + +int main(int argc, char** argv) +{ + EGLint s_configAttribs[] = { + EGL_RED_SIZE, 5, + EGL_GREEN_SIZE, 6, + EGL_BLUE_SIZE, 5, + EGL_NONE + }; + + EGLint numConfigs = -1; + EGLint majorVersion; + EGLint minorVersion; + EGLConfig config; + EGLContext context; + EGLSurface surface; + EGLint w, h; + + EGLDisplay dpy; + + dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY); + eglInitialize(dpy, &majorVersion, &minorVersion); + eglChooseConfig(dpy, s_configAttribs, &config, 1, &numConfigs); + surface = eglCreateWindowSurface(dpy, config, + android_createDisplaySurface(), NULL); + context = eglCreateContext(dpy, config, NULL, NULL); + eglMakeCurrent(dpy, surface, surface, context); + eglQuerySurface(dpy, surface, EGL_WIDTH, &w); + eglQuerySurface(dpy, surface, EGL_HEIGHT, &h); + GLint dim = w +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "egl_surface.h" + +#define LOGI(x...) do { printf("INFO: " x); } while (0) +#define LOGW(x...) do { printf("WARN: " x); } while (0) +#define LOGE(x...) do { printf("ERR: " x); } while (0) + +// ---------------------------------------------------------------------------- + +egl_native_window_t* android_createDisplaySurface() +{ + egl_native_window_t* s = new android::EGLDisplaySurface(); + s->memory_type = NATIVE_MEMORY_TYPE_GPU; + return s; +} + +#define LIKELY( exp ) (__builtin_expect( (exp) != 0, true )) +#define UNLIKELY( exp ) (__builtin_expect( (exp) != 0, false )) + +// ---------------------------------------------------------------------------- +namespace android { +// ---------------------------------------------------------------------------- + +EGLDisplaySurface::EGLDisplaySurface() + : EGLNativeSurface() +{ + egl_native_window_t::version = sizeof(egl_native_window_t); + egl_native_window_t::ident = 0; + egl_native_window_t::incRef = &EGLDisplaySurface::hook_incRef; + egl_native_window_t::decRef = &EGLDisplaySurface::hook_decRef; + egl_native_window_t::swapBuffers = &EGLDisplaySurface::hook_swapBuffers; + egl_native_window_t::setSwapRectangle = &EGLDisplaySurface::hook_setSwapRectangle; + egl_native_window_t::nextBuffer = &EGLDisplaySurface::hook_nextBuffer; + egl_native_window_t::connect = 0; + egl_native_window_t::disconnect = 0; + + mFb[0].data = 0; + mFb[1].data = 0; + egl_native_window_t::fd = mapFrameBuffer(); + if (egl_native_window_t::fd >= 0) { + const float in2mm = 25.4f; + float refreshRate = 1000000000000000LLU / ( + float( mInfo.upper_margin + mInfo.lower_margin + mInfo.yres ) + * ( mInfo.left_margin + mInfo.right_margin + mInfo.xres ) + * mInfo.pixclock); + + const GGLSurface& buffer = mFb[1 - mIndex]; + egl_native_window_t::width = buffer.width; + egl_native_window_t::height = buffer.height; + egl_native_window_t::stride = buffer.stride; + egl_native_window_t::format = buffer.format; + egl_native_window_t::base = intptr_t(mFb[0].data); + egl_native_window_t::offset = + intptr_t(buffer.data) - egl_native_window_t::base; + egl_native_window_t::flags = 0; + egl_native_window_t::xdpi = (mInfo.xres * in2mm) / mInfo.width; + egl_native_window_t::ydpi = (mInfo.yres * in2mm) / mInfo.height; + egl_native_window_t::fps = refreshRate; + egl_native_window_t::memory_type = NATIVE_MEMORY_TYPE_FB; + // no error, set the magic word + egl_native_window_t::magic = 0x600913; + } + mSwapCount = -1; + mPageFlipCount = 0; +} + +EGLDisplaySurface::~EGLDisplaySurface() +{ + magic = 0; + close(egl_native_window_t::fd); + munmap(mFb[0].data, mSize); + if (!(mFlags & PAGE_FLIP)) + free((void*)mFb[1].data); +} + +void EGLDisplaySurface::hook_incRef(NativeWindowType window) { + EGLDisplaySurface* that = static_cast(window); + that->incStrong(that); +} +void EGLDisplaySurface::hook_decRef(NativeWindowType window) { + EGLDisplaySurface* that = static_cast(window); + that->decStrong(that); +} +uint32_t EGLDisplaySurface::hook_swapBuffers(NativeWindowType window) { + EGLDisplaySurface* that = static_cast(window); + return that->swapBuffers(); +} +uint32_t EGLDisplaySurface::hook_nextBuffer(NativeWindowType window) { + EGLDisplaySurface* that = static_cast(window); + return that->nextBuffer(); +} +void EGLDisplaySurface::hook_setSwapRectangle(NativeWindowType window, + int l, int t, int w, int h) { + EGLDisplaySurface* that = static_cast(window); + that->setSwapRectangle(l, t, w, h); +} + +void EGLDisplaySurface::setSwapRectangle(int l, int t, int w, int h) +{ + mInfo.reserved[0] = 0x54445055; // "UPDT"; + mInfo.reserved[1] = (uint16_t)l | ((uint32_t)t << 16); + mInfo.reserved[2] = (uint16_t)(l+w) | ((uint32_t)(t+h) << 16); +} + +uint32_t EGLDisplaySurface::swapBuffers() +{ + if (!(mFlags & PAGE_FLIP)) + return 0; + + // do the actual flip + mIndex = 1 - mIndex; + mInfo.activate = FB_ACTIVATE_VBL; + mInfo.yoffset = mIndex ? mInfo.yres : 0; + if (ioctl(egl_native_window_t::fd, FBIOPUT_VSCREENINFO, &mInfo) == -1) { + LOGE("FBIOPUT_VSCREENINFO failed"); + return 0; + } + + /* + * this is a monstruous hack: Because the h/w accelerator is not able + * to render directly into the framebuffer, we need to copy its + * internal framebuffer out to the fb. the base address of the internal fb + * is given in oem[0]. + * All this is needed only in standalone mode, in SurfaceFlinger mode + * we control where the GPU renders. + */ + if (egl_native_window_t::memory_type == NATIVE_MEMORY_TYPE_GPU && oem[0]) { + // could use MDP here, but that's tricky because we need + // /dev/pmem_gpu* filedescriptor + const GGLSurface& buffer = mFb[mIndex]; + memcpy( buffer.data, + (void*)(oem[0] + egl_native_window_t::offset), + buffer.stride*buffer.height*2); + } + + // update the address of the buffer to draw to next + const GGLSurface& buffer = mFb[1 - mIndex]; + egl_native_window_t::offset = + intptr_t(buffer.data) - egl_native_window_t::base; + + mPageFlipCount++; + + // We don't support screen-size changes for now + return 0; +} + +int32_t EGLDisplaySurface::getPageFlipCount() const +{ + return mPageFlipCount; +} + +uint32_t EGLDisplaySurface::nextBuffer() +{ + // update the address of the buffer to draw to next + const GGLSurface& buffer = mFb[mIndex]; + egl_native_window_t::offset = + intptr_t(buffer.data) - egl_native_window_t::base; + return 0; +} + +int EGLDisplaySurface::mapFrameBuffer() +{ + char const * const device_template[] = { + "/dev/graphics/fb%u", + "/dev/fb%u", + 0 }; + int fd = -1; + int i=0; + char name[64]; + while ((fd==-1) && device_template[i]) { + snprintf(name, 64, device_template[i], 0); + fd = open(name, O_RDWR, 0); + i++; + } + if (fd < 0) + return -errno; + + struct fb_fix_screeninfo finfo; + if (ioctl(fd, FBIOGET_FSCREENINFO, &finfo) == -1) + return -errno; + + struct fb_var_screeninfo info; + if (ioctl(fd, FBIOGET_VSCREENINFO, &info) == -1) + return -errno; + + info.reserved[0] = 0; + info.reserved[1] = 0; + info.reserved[2] = 0; + info.xoffset = 0; + info.yoffset = 0; + info.yres_virtual = info.yres * 2; + info.bits_per_pixel = 16; + info.activate = FB_ACTIVATE_NOW; + + uint32_t flags = PAGE_FLIP; + if (ioctl(fd, FBIOPUT_VSCREENINFO, &info) == -1) { + info.yres_virtual = info.yres; + flags &= ~PAGE_FLIP; + LOGW("FBIOPUT_VSCREENINFO failed, page flipping not supported"); + } + + if (info.yres_virtual < info.yres * 2) { + info.yres_virtual = info.yres; + flags &= ~PAGE_FLIP; + LOGW("page flipping not supported (yres_virtual=%d, requested=%d)", + info.yres_virtual, info.yres*2); + } + + if (ioctl(fd, FBIOGET_VSCREENINFO, &info) == -1) + return -errno; + + int refreshRate = 1000000000000000LLU / + ( + uint64_t( info.upper_margin + info.lower_margin + info.yres ) + * ( info.left_margin + info.right_margin + info.xres ) + * info.pixclock + ); + + if (refreshRate == 0) { + // bleagh, bad info from the driver + refreshRate = 60*1000; // 60 Hz + } + + if (int(info.width) <= 0 || int(info.height) <= 0) { + // stupid driver, doesn't return that information + // default to Sooner's screen size (160 dpi) + info.width = 51; + info.height = 38; + } + + float xdpi = (info.xres * 25.4f) / info.width; + float ydpi = (info.yres * 25.4f) / info.height; + float fps = refreshRate / 1000.0f; + + LOGI( "using (fd=%d)\n" + "id = %s\n" + "xres = %d px\n" + "yres = %d px\n" + "xres_virtual = %d px\n" + "yres_virtual = %d px\n" + "bpp = %d\n" + "r = %2u:%u\n" + "g = %2u:%u\n" + "b = %2u:%u\n", + fd, + finfo.id, + info.xres, + info.yres, + info.xres_virtual, + info.yres_virtual, + info.bits_per_pixel, + info.red.offset, info.red.length, + info.green.offset, info.green.length, + info.blue.offset, info.blue.length + ); + + LOGI( "width = %d mm (%f dpi)\n" + "height = %d mm (%f dpi)\n" + "refresh rate = %.2f Hz\n", + info.width, xdpi, + info.height, ydpi, + fps + ); + + + if (ioctl(fd, FBIOGET_FSCREENINFO, &finfo) == -1) + return -errno; + + if (finfo.smem_len <= 0) + return -errno; + + /* + * Open and map the display. + */ + + void* buffer = (uint16_t*) mmap( + 0, finfo.smem_len, + PROT_READ | PROT_WRITE, + MAP_SHARED, + fd, 0); + + if (buffer == MAP_FAILED) + return -errno; + + // at least for now, always clear the fb + memset(buffer, 0, finfo.smem_len); + + uint8_t* offscreen[2]; + offscreen[0] = (uint8_t*)buffer; + if (flags & PAGE_FLIP) { + offscreen[1] = (uint8_t*)buffer + finfo.line_length*info.yres; + } else { + offscreen[1] = (uint8_t*)malloc(finfo.smem_len); + if (offscreen[1] == 0) { + munmap(buffer, finfo.smem_len); + return -ENOMEM; + } + } + + mFlags = flags; + mInfo = info; + mFinfo = finfo; + mSize = finfo.smem_len; + mIndex = 0; + for (int i=0 ; i<2 ; i++) { + mFb[i].version = sizeof(GGLSurface); + mFb[i].width = info.xres; + mFb[i].height = info.yres; + mFb[i].stride = finfo.line_length / (info.bits_per_pixel >> 3); + mFb[i].data = (uint8_t*)(offscreen[i]); + mFb[i].format = NATIVE_PIXEL_FORMAT_RGB_565; + } + return fd; +} + +// ---------------------------------------------------------------------------- +}; // namespace android +// ---------------------------------------------------------------------------- diff --git a/opengl/tests/sfsim/egl_surface.h b/opengl/tests/sfsim/egl_surface.h new file mode 100644 index 0000000000000000000000000000000000000000..70a94fcab994055cfd10d52bdc1beb6ac2c6d52b --- /dev/null +++ b/opengl/tests/sfsim/egl_surface.h @@ -0,0 +1,113 @@ +/* + * 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. + */ + +#ifndef ANDROID_SIM_EGL_SURFACE_H +#define ANDROID_SIM_EGL_SURFACE_H + +#include +#include +#include + +#include + +#include + +typedef struct { + ssize_t version; // always set to sizeof(GGLSurface) + uint32_t width; // width in pixels + uint32_t height; // height in pixels + int32_t stride; // stride in pixels + uint8_t* data; // pointer to the bits + uint8_t format; // pixel format + uint8_t rfu[3]; // must be zero + void* reserved; +} GGLSurface; + +// --------------------------------------------------------------------------- +namespace android { +// --------------------------------------------------------------------------- + +template +class EGLNativeSurface : public egl_native_window_t +{ +public: + EGLNativeSurface() : mCount(0) { + memset(egl_native_window_t::reserved, 0, + sizeof(egl_native_window_t::reserved)); + memset(egl_native_window_t::reserved_proc, 0, + sizeof(egl_native_window_t::reserved_proc)); + memset(egl_native_window_t::oem, 0, + sizeof(egl_native_window_t::oem)); + } + inline void incStrong(void*) const { + /* in a real implementation, the inc must be atomic */ + mCount++; + } + inline void decStrong(void*) const { + /* in a real implementation, the dec must be atomic */ + if (--mCount == 1) { + delete static_cast(this); + } + } +protected: + EGLNativeSurface& operator = (const EGLNativeSurface& rhs); + EGLNativeSurface(const EGLNativeSurface& rhs); + inline ~EGLNativeSurface() { }; + mutable volatile int32_t mCount; +}; + + +class EGLDisplaySurface : public EGLNativeSurface +{ +public: + EGLDisplaySurface(); + ~EGLDisplaySurface(); + + int32_t getPageFlipCount() const; + +private: + static void hook_incRef(NativeWindowType window); + static void hook_decRef(NativeWindowType window); + static uint32_t hook_swapBuffers(NativeWindowType window); + static void hook_setSwapRectangle(NativeWindowType window, int l, int t, int w, int h); + static uint32_t hook_nextBuffer(NativeWindowType window); + + uint32_t swapBuffers(); + uint32_t nextBuffer(); + void setSwapRectangle(int l, int t, int w, int h); + + int mapFrameBuffer(); + + enum { + PAGE_FLIP = 0x00000001 + }; + GGLSurface mFb[2]; + int mIndex; + uint32_t mFlags; + size_t mSize; + fb_var_screeninfo mInfo; + fb_fix_screeninfo mFinfo; + int32_t mPageFlipCount; + int32_t mSwapCount; + uint32_t mFeatureFlags; +}; + +// --------------------------------------------------------------------------- +}; // namespace android +// --------------------------------------------------------------------------- + +#endif // ANDROID_SIM_EGL_SURFACE_H + diff --git a/opengl/tests/sfsim/sfsim.c b/opengl/tests/sfsim/sfsim.c new file mode 100644 index 0000000000000000000000000000000000000000..14ba490d70501dfa013de1ee84513c90c2c02cdd --- /dev/null +++ b/opengl/tests/sfsim/sfsim.c @@ -0,0 +1,112 @@ +#include +#include + +#include + +int main(int argc, char** argv) +{ + if (argc != 2) { + printf("usage: %s <0-6>\n", argv[0]); + return 0; + } + + const int test = atoi(argv[1]); + + EGLint s_configAttribs[] = { + EGL_RED_SIZE, 5, + EGL_GREEN_SIZE, 6, + EGL_BLUE_SIZE, 5, + EGL_NONE + }; + + EGLint numConfigs = -1; + EGLint majorVersion; + EGLint minorVersion; + EGLConfig config; + EGLContext context; + EGLSurface surface; + EGLint w, h; + + EGLDisplay dpy; + + dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY); + eglInitialize(dpy, &majorVersion, &minorVersion); + eglChooseConfig(dpy, s_configAttribs, &config, 1, &numConfigs); + surface = eglCreateWindowSurface(dpy, config, + android_createDisplaySurface(), NULL); + context = eglCreateContext(dpy, config, NULL, NULL); + eglMakeCurrent(dpy, surface, surface, context); + eglQuerySurface(dpy, surface, EGL_WIDTH, &w); + eglQuerySurface(dpy, surface, EGL_HEIGHT, &h); + GLint dim = w +#include + +#include + +int main(int argc, char** argv) +{ + EGLint s_configAttribs[] = { + EGL_RED_SIZE, 5, + EGL_GREEN_SIZE, 6, + EGL_BLUE_SIZE, 5, + EGL_NONE + }; + + EGLint numConfigs = -1; + EGLint majorVersion; + EGLint minorVersion; + EGLConfig config; + EGLContext context; + EGLSurface surface; + EGLint w, h; + + EGLDisplay dpy; + + dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY); + eglInitialize(dpy, &majorVersion, &minorVersion); + eglChooseConfig(dpy, s_configAttribs, &config, 1, &numConfigs); + surface = eglCreateWindowSurface(dpy, config, + android_createDisplaySurface(), NULL); + context = eglCreateContext(dpy, config, NULL, NULL); + eglMakeCurrent(dpy, surface, surface, context); + eglQuerySurface(dpy, surface, EGL_WIDTH, &w); + eglQuerySurface(dpy, surface, EGL_HEIGHT, &h); + GLint dim = w +#include +#include +#include + +EGLDisplay eglDisplay; +EGLSurface eglSurface; +EGLContext eglContext; +GLuint texture; + +#define FIXED_ONE 0x10000 +#define ITERATIONS 50 + +int init_gl_surface(void); +void free_gl_surface(void); +void init_scene(void); +void render(int quads); +void create_texture(void); +int readTimer(void); + +static void gluLookAt(float eyeX, float eyeY, float eyeZ, + float centerX, float centerY, float centerZ, float upX, float upY, + float upZ) +{ + // See the OpenGL GLUT documentation for gluLookAt for a description + // of the algorithm. We implement it in a straightforward way: + + float fx = centerX - eyeX; + float fy = centerY - eyeY; + float fz = centerZ - eyeZ; + + // Normalize f + float rlf = 1.0f / sqrtf(fx*fx + fy*fy + fz*fz); + fx *= rlf; + fy *= rlf; + fz *= rlf; + + // Normalize up + float rlup = 1.0f / sqrtf(upX*upX + upY*upY + upZ*upZ); + upX *= rlup; + upY *= rlup; + upZ *= rlup; + + // compute s = f x up (x means "cross product") + + float sx = fy * upZ - fz * upY; + float sy = fz * upX - fx * upZ; + float sz = fx * upY - fy * upX; + + // compute u = s x f + float ux = sy * fz - sz * fy; + float uy = sz * fx - sx * fz; + float uz = sx * fy - sy * fx; + + float m[16] ; + m[0] = sx; + m[1] = ux; + m[2] = -fx; + m[3] = 0.0f; + + m[4] = sy; + m[5] = uy; + m[6] = -fy; + m[7] = 0.0f; + + m[8] = sz; + m[9] = uz; + m[10] = -fz; + m[11] = 0.0f; + + m[12] = 0.0f; + m[13] = 0.0f; + m[14] = 0.0f; + m[15] = 1.0f; + + glMultMatrixf(m); + glTranslatef(-eyeX, -eyeY, -eyeZ); +} + +int main(int argc, char **argv) +{ + int q; + int start, end; + + printf("Initializing EGL...\n"); + + if(!init_gl_surface()) + { + printf("GL initialisation failed - exiting\n"); + return 0; + } + + init_scene(); + + create_texture(); + + printf("Start test...\n"); + + render(argc==2 ? atoi(argv[1]) : ITERATIONS); + + free_gl_surface(); + + return 0; +} + +int init_gl_surface(void) +{ + EGLint numConfigs = 1; + EGLConfig myConfig = {0}; + EGLint attrib[] = + { + EGL_DEPTH_SIZE, 16, + EGL_NONE + }; + + if ( (eglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY)) == EGL_NO_DISPLAY ) + { + printf("eglGetDisplay failed\n"); + return 0; + } + + if ( eglInitialize(eglDisplay, NULL, NULL) != EGL_TRUE ) + { + printf("eglInitialize failed\n"); + return 0; + } + + if ( eglChooseConfig(eglDisplay, attrib, &myConfig, 1, &numConfigs) != EGL_TRUE ) + { + printf("eglChooseConfig failed\n"); + return 0; + } + + if ( (eglSurface = eglCreateWindowSurface(eglDisplay, myConfig, + android_createDisplaySurface(), 0)) == EGL_NO_SURFACE ) + { + printf("eglCreateWindowSurface failed\n"); + return 0; + } + + if ( (eglContext = eglCreateContext(eglDisplay, myConfig, 0, 0)) == EGL_NO_CONTEXT ) + { + printf("eglCreateContext failed\n"); + return 0; + } + + if ( eglMakeCurrent(eglDisplay, eglSurface, eglSurface, eglContext) != EGL_TRUE ) + { + printf("eglMakeCurrent failed\n"); + return 0; + } + + return 1; +} + +void free_gl_surface(void) +{ + if (eglDisplay != EGL_NO_DISPLAY) + { + eglMakeCurrent( EGL_NO_DISPLAY, EGL_NO_SURFACE, + EGL_NO_SURFACE, EGL_NO_CONTEXT ); + eglDestroyContext( eglDisplay, eglContext ); + eglDestroySurface( eglDisplay, eglSurface ); + eglTerminate( eglDisplay ); + eglDisplay = EGL_NO_DISPLAY; + } +} + +void init_scene(void) +{ + glDisable(GL_DITHER); + glEnable(GL_CULL_FACE); + + float ratio = 320.0f / 480.0f; + glViewport(0, 0, 320, 480); + + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glFrustumf(-ratio, ratio, -1, 1, 1, 10); + + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + gluLookAt( + 0, 0, 3, // eye + 0, 0, 0, // center + 0, 1, 0); // up + + glEnable(GL_TEXTURE_2D); + glEnableClientState(GL_VERTEX_ARRAY); + glEnableClientState(GL_TEXTURE_COORD_ARRAY); +} + +void create_texture(void) +{ + const unsigned int on = 0xff0000ff; + const unsigned int off = 0xffffffff; + const unsigned int pixels[] = + { + on, off, on, off, on, off, on, off, + off, on, off, on, off, on, off, on, + on, off, on, off, on, off, on, off, + off, on, off, on, off, on, off, on, + on, off, on, off, on, off, on, off, + off, on, off, on, off, on, off, on, + on, off, on, off, on, off, on, off, + off, on, off, on, off, on, off, on, + }; + glGenTextures(1, &texture); + glBindTexture(GL_TEXTURE_2D, texture); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 8, 8, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels); + glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); +} + +void render(int quads) +{ + int i, j; + + const GLfloat vertices[] = { + -1, -1, 0, + 1, -1, 0, + 1, 1, 0, + -1, 1, 0 + }; + + const GLfixed texCoords[] = { + 0, 0, + FIXED_ONE, 0, + FIXED_ONE, FIXED_ONE, + 0, FIXED_ONE + }; + + const GLushort template[] = { 0, 1, 2, 0, 2, 3 }; + + + GLushort* indices = (GLushort*)malloc(quads*sizeof(template)); + for (i=0 ; i out/android/graphics/Canvas.java +echo "public interface Canvas {}" >> out/android/graphics/Canvas.java + +GLFILE=out/javax/microedition/khronos/opengles/GL.java +cp stubs/GLHeader.java-if $GLFILE + +GLGEN_FILES="CFunc.java CType.java CodeEmitter.java GenerateGL.java JFunc.java JType.java JniCodeEmitter.java ParameterChecker.java" + +pushd src > /dev/null +javac ${GLGEN_FILES} +popd > /dev/null +java -classpath src GenerateGL -c glspec-1.0 glspec-1.0ext glspec-1.1 glspec-1.1ext glspec-1.1extpack glspec-checks + +pushd out > /dev/null +mkdir classes +javac -d classes com/google/android/gles_jni/GLImpl.java javax/microedition/khronos/opengles/GL10.java javax/microedition/khronos/opengles/GL10Ext.java javax/microedition/khronos/opengles/GL11.java javax/microedition/khronos/opengles/GL11Ext.java javax/microedition/khronos/opengles/GL11ExtensionPack.java +popd > /dev/null + +rm -rf generated +mkdir -p generated/C +cp out/com_google_android_gles_jni_GLImpl.cpp generated/C +cp -r out/com generated +cp -r out/javax generated + +rm -rf out + +# com_google_android_gles_jni_GLImpl.cpp +if cmp ../../../frameworks/base/core/jni/com_google_android_gles_jni_GLImpl.cpp generated/C/com_google_android_gles_jni_GLImpl.cpp ; then +echo com_google_android_gles_jni_GLImpl.cpp unchanged +else +echo Please edit ../../../frameworks/base/core/jni/com_google_android_gles_jni_GLImpl.cpp +echo Please cp generated/C/com_google_android_gles_jni_GLImpl.cpp ../../../frameworks/base/core/jni +fi + +# GLImpl.java +if cmp ../../java/com/google/android/gles_jni/GLImpl.java generated/com/google/android/gles_jni/GLImpl.java ; then +echo GLImpl.java unchanged +else +echo Please edit ../../java/com/google/android/gles_jni/GLImpl.java +echo Please cp generated/com/google/android/gles_jni/GLImpl.java ../../java/com/google/android/gles_jni +fi + +# GL.java +if cmp ../../java/javax/microedition/khronos/opengles/GL.java generated/javax/microedition/khronos/opengles/GL.java ; then +echo GL.java unchanged +else +echo Please edit ../../java/javax/microedition/khronos/opengles/GL.java +echo Please cp generated/javax/microedition/khronos/opengles/GL.java ../../java/javax/microedition/khronos/opengles/GL.java +fi + +# GL10.java +if cmp ../../java/javax/microedition/khronos/opengles/GL10.java generated/javax/microedition/khronos/opengles/GL10.java ; then +echo GL10.java unchanged +else +echo Please edit ../../java/javax/microedition/khronos/opengles/GL10.java +echo Please cp generated/javax/microedition/khronos/opengles/GL10.java ../../java/javax/microedition/khronos/opengles/GL10.java +fi + +# GL10Ext.java +if cmp ../../java/javax/microedition/khronos/opengles/GL10Ext.java generated/javax/microedition/khronos/opengles/GL10Ext.java ; then +echo GL10Ext.java unchanged +else +echo Please edit ../../java/javax/microedition/khronos/opengles/GL10Ext.java +echo Please cp generated/javax/microedition/khronos/opengles/GL10Ext.java ../../java/javax/microedition/khronos/opengles/GL10Ext.java +fi + +# GL11.java +if cmp ../../java/javax/microedition/khronos/opengles/GL11.java generated/javax/microedition/khronos/opengles/GL11.java ; then +echo GL11.java unchanged +else +echo Please edit ../../java/javax/microedition/khronos/opengles/GL11.java +echo Please cp generated/javax/microedition/khronos/opengles/GL11.java ../../java/javax/microedition/khronos/opengles/GL11.java +fi + +# GL11Ext.java +if cmp ../../java/javax/microedition/khronos/opengles/GL11Ext.java generated/javax/microedition/khronos/opengles/GL11Ext.java ; then +echo GL11Ext.java unchanged +else +echo Please edit ../../java/javax/microedition/khronos/opengles/GL11Ext.java +echo Please cp generated/javax/microedition/khronos/opengles/GL11Ext.java ../../java/javax/microedition/khronos/opengles/GL11Ext.java +fi + +# GL11ExtensionPack.java +if cmp ../../java/javax/microedition/khronos/opengles/GL11ExtensionPack.java generated/javax/microedition/khronos/opengles/GL11ExtensionPack.java ; then +echo GL11ExtensionPack.java unchanged +else +echo Please edit ../../java/javax/microedition/khronos/opengles/GL11ExtensionPack.java +echo Please cp generated/javax/microedition/khronos/opengles/GL11ExtensionPack.java ../../java/javax/microedition/khronos/opengles/GL11ExtensionPack.java +fi + +rm -rf generated diff --git a/opengl/tools/glgen/glspec-1.0 b/opengl/tools/glgen/glspec-1.0 new file mode 100644 index 0000000000000000000000000000000000000000..c442320bf5b889864e232bcd61bbb7413ddd0d07 --- /dev/null +++ b/opengl/tools/glgen/glspec-1.0 @@ -0,0 +1,106 @@ +void glActiveTexture ( GLenum texture ) +void glAlphaFunc ( GLenum func, GLclampf ref ) +void glAlphaFuncx ( GLenum func, GLclampx ref ) +void glBindTexture ( GLenum target, GLuint texture ) +void glBlendFunc ( GLenum sfactor, GLenum dfactor ) +void glClear ( GLbitfield mask ) +void glClearColor ( GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha ) +void glClearColorx ( GLclampx red, GLclampx green, GLclampx blue, GLclampx alpha ) +void glClearDepthf ( GLclampf depth ) +void glClearDepthx ( GLclampx depth ) +void glClearStencil ( GLint s ) +void glClientActiveTexture ( GLenum texture ) +void glColor4f ( GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha ) +void glColor4x ( GLfixed red, GLfixed green, GLfixed blue, GLfixed alpha ) +void glColorMask ( GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha ) +void glColorPointer ( GLint size, GLenum type, GLsizei stride, const GLvoid *pointer ) +void glCompressedTexImage2D ( GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *data ) +void glCompressedTexSubImage2D ( GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid *data ) +void glCopyTexImage2D ( GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border ) +void glCopyTexSubImage2D ( GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height ) +void glCullFace ( GLenum mode ) +void glDeleteTextures ( GLsizei n, const GLuint *textures ) +void glDepthFunc ( GLenum func ) +void glDepthMask ( GLboolean flag ) +void glDepthRangef ( GLclampf zNear, GLclampf zFar ) +void glDepthRangex ( GLclampx zNear, GLclampx zFar ) +void glDisable ( GLenum cap ) +void glDisableClientState ( GLenum array ) +void glDrawArrays ( GLenum mode, GLint first, GLsizei count ) +void glDrawElements ( GLenum mode, GLsizei count, GLenum type, const GLvoid *indices ) +void glEnable ( GLenum cap ) +void glEnableClientState ( GLenum array ) +void glFinish ( void ) +void glFlush ( void ) +void glFogf ( GLenum pname, GLfloat param ) +void glFogfv ( GLenum pname, const GLfloat *params ) +void glFogx ( GLenum pname, GLfixed param ) +void glFogxv ( GLenum pname, const GLfixed *params ) +void glFrontFace ( GLenum mode ) +void glFrustumf ( GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat zNear, GLfloat zFar ) +void glFrustumx ( GLfixed left, GLfixed right, GLfixed bottom, GLfixed top, GLfixed zNear, GLfixed zFar ) +void glGenTextures ( GLsizei n, GLuint *textures ) +GLenum glGetError ( void ) +void glGetIntegerv ( GLenum pname, GLint *params ) +const GLubyte * glGetString ( GLenum name ) +void glHint ( GLenum target, GLenum mode ) +void glLightModelf ( GLenum pname, GLfloat param ) +void glLightModelfv ( GLenum pname, const GLfloat *params ) +void glLightModelx ( GLenum pname, GLfixed param ) +void glLightModelxv ( GLenum pname, const GLfixed *params ) +void glLightf ( GLenum light, GLenum pname, GLfloat param ) +void glLightfv ( GLenum light, GLenum pname, const GLfloat *params ) +void glLightx ( GLenum light, GLenum pname, GLfixed param ) +void glLightxv ( GLenum light, GLenum pname, const GLfixed *params ) +void glLineWidth ( GLfloat width ) +void glLineWidthx ( GLfixed width ) +void glLoadIdentity ( void ) +void glLoadMatrixf ( const GLfloat *m ) +void glLoadMatrixx ( const GLfixed *m ) +void glLogicOp ( GLenum opcode ) +void glMaterialf ( GLenum face, GLenum pname, GLfloat param ) +void glMaterialfv ( GLenum face, GLenum pname, const GLfloat *params ) +void glMaterialx ( GLenum face, GLenum pname, GLfixed param ) +void glMaterialxv ( GLenum face, GLenum pname, const GLfixed *params ) +void glMatrixMode ( GLenum mode ) +void glMultMatrixf ( const GLfloat *m ) +void glMultMatrixx ( const GLfixed *m ) +void glMultiTexCoord4f ( GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q ) +void glMultiTexCoord4x ( GLenum target, GLfixed s, GLfixed t, GLfixed r, GLfixed q ) +void glNormal3f ( GLfloat nx, GLfloat ny, GLfloat nz ) +void glNormal3x ( GLfixed nx, GLfixed ny, GLfixed nz ) +void glNormalPointer ( GLenum type, GLsizei stride, const GLvoid *pointer ) +void glOrthof ( GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat zNear, GLfloat zFar ) +void glOrthox ( GLfixed left, GLfixed right, GLfixed bottom, GLfixed top, GLfixed zNear, GLfixed zFar ) +void glPixelStorei ( GLenum pname, GLint param ) +void glPointSize ( GLfloat size ) +void glPointSizex ( GLfixed size ) +void glPolygonOffset ( GLfloat factor, GLfloat units ) +void glPolygonOffsetx ( GLfixed factor, GLfixed units ) +void glPopMatrix ( void ) +void glPushMatrix ( void ) +void glReadPixels ( GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid *pixels ) +void glRotatef ( GLfloat angle, GLfloat x, GLfloat y, GLfloat z ) +void glRotatex ( GLfixed angle, GLfixed x, GLfixed y, GLfixed z ) +void glSampleCoverage ( GLclampf value, GLboolean invert ) +void glSampleCoveragex ( GLclampx value, GLboolean invert ) +void glScalef ( GLfloat x, GLfloat y, GLfloat z ) +void glScalex ( GLfixed x, GLfixed y, GLfixed z ) +void glScissor ( GLint x, GLint y, GLsizei width, GLsizei height ) +void glShadeModel ( GLenum mode ) +void glStencilFunc ( GLenum func, GLint ref, GLuint mask ) +void glStencilMask ( GLuint mask ) +void glStencilOp ( GLenum fail, GLenum zfail, GLenum zpass ) +void glTexCoordPointer ( GLint size, GLenum type, GLsizei stride, const GLvoid *pointer ) +void glTexEnvf ( GLenum target, GLenum pname, GLfloat param ) +void glTexEnvfv ( GLenum target, GLenum pname, const GLfloat *params ) +void glTexEnvx ( GLenum target, GLenum pname, GLfixed param ) +void glTexEnvxv ( GLenum target, GLenum pname, const GLfixed *params ) +void glTexImage2D ( GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels ) +void glTexParameterf ( GLenum target, GLenum pname, GLfloat param ) +void glTexParameterx ( GLenum target, GLenum pname, GLfixed param ) +void glTexSubImage2D ( GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels ) +void glTranslatef ( GLfloat x, GLfloat y, GLfloat z ) +void glTranslatex ( GLfixed x, GLfixed y, GLfixed z ) +void glVertexPointer ( GLint size, GLenum type, GLsizei stride, const GLvoid *pointer ) +void glViewport ( GLint x, GLint y, GLsizei width, GLsizei height ) diff --git a/opengl/tools/glgen/glspec-1.0ext b/opengl/tools/glgen/glspec-1.0ext new file mode 100644 index 0000000000000000000000000000000000000000..7d19758196e0382a274d5eaa5c309909b04a4f85 --- /dev/null +++ b/opengl/tools/glgen/glspec-1.0ext @@ -0,0 +1 @@ +GLbitfield glQueryMatrixxOES ( GLfixed *mantissa, GLint *exponent ) diff --git a/opengl/tools/glgen/glspec-1.1 b/opengl/tools/glgen/glspec-1.1 new file mode 100644 index 0000000000000000000000000000000000000000..9149a7f97ffa67ac838ebc76d5a4cb1c195fee25 --- /dev/null +++ b/opengl/tools/glgen/glspec-1.1 @@ -0,0 +1,42 @@ +void glBindBuffer ( GLenum target, GLuint buffer ) +void glBufferData ( GLenum target, GLsizeiptr size, const GLvoid *data, GLenum usage ) +void glBufferSubData ( GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid *data ) +void glClipPlanef ( GLenum plane, const GLfloat *equation ) +void glClipPlanex ( GLenum plane, const GLfixed *equation ) +void glColor4ub ( GLubyte red, GLubyte green, GLubyte blue, GLubyte alpha ) +void glColorPointer ( GLint size, GLenum type, GLsizei stride, GLint offset ) +void glDeleteBuffers ( GLsizei n, const GLuint *buffers ) +void glDrawElements ( GLenum mode, GLsizei count, GLenum type, GLint offset ) +void glGenBuffers ( GLsizei n, GLuint *buffers ) +void glGetBooleanv ( GLenum pname, GLboolean *params ) +void glGetBufferParameteriv ( GLenum target, GLenum pname, GLint *params ) +void glGetClipPlanef ( GLenum pname, GLfloat *eqn ) +void glGetClipPlanex ( GLenum pname, GLfixed *eqn ) +void glGetFixedv ( GLenum pname, GLfixed *params ) +void glGetFloatv ( GLenum pname, GLfloat *params ) +void glGetLightfv ( GLenum light, GLenum pname, GLfloat *params ) +void glGetLightxv ( GLenum light, GLenum pname, GLfixed *params ) +void glGetMaterialfv ( GLenum face, GLenum pname, GLfloat *params ) +void glGetMaterialxv ( GLenum face, GLenum pname, GLfixed *params ) +void glGetTexEnviv ( GLenum env, GLenum pname, GLint *params ) +void glGetTexEnvxv ( GLenum env, GLenum pname, GLfixed *params ) +void glGetTexParameterfv ( GLenum target, GLenum pname, GLfloat *params ) +void glGetTexParameteriv ( GLenum target, GLenum pname, GLint *params ) +void glGetTexParameterxv ( GLenum target, GLenum pname, GLfixed *params ) +GLboolean glIsBuffer ( GLuint buffer ) +GLboolean glIsEnabled ( GLenum cap ) +GLboolean glIsTexture ( GLuint texture ) +void glNormalPointer ( GLenum type, GLsizei stride, GLint offset ) +void glPointParameterf ( GLenum pname, GLfloat param ) +void glPointParameterfv ( GLenum pname, const GLfloat *params ) +void glPointParameterx ( GLenum pname, GLfixed param ) +void glPointParameterxv ( GLenum pname, const GLfixed *params ) +void glPointSizePointerOES ( GLenum type, GLsizei stride, const GLvoid *pointer ) +void glTexCoordPointer ( GLint size, GLenum type, GLsizei stride, GLint offset ) +void glTexEnvi ( GLenum target, GLenum pname, GLint param ) +void glTexEnviv ( GLenum target, GLenum pname, const GLint *params ) +void glTexParameterfv ( GLenum target, GLenum pname, const GLfloat *params ) +void glTexParameteri ( GLenum target, GLenum pname, GLint param ) +void glTexParameteriv ( GLenum target, GLenum pname, const GLint *params ) +void glTexParameterxv ( GLenum target, GLenum pname, const GLfixed *params ) +void glVertexPointer ( GLint size, GLenum type, GLsizei stride, GLint offset ) diff --git a/opengl/tools/glgen/glspec-1.1ext b/opengl/tools/glgen/glspec-1.1ext new file mode 100644 index 0000000000000000000000000000000000000000..cc08c7352847a5ebf27ba66d5d0f069905cedfb9 --- /dev/null +++ b/opengl/tools/glgen/glspec-1.1ext @@ -0,0 +1,16 @@ +void glCurrentPaletteMatrixOES ( GLuint matrixpaletteindex ) +void glDrawTexfOES ( GLfloat x, GLfloat y, GLfloat z, GLfloat width, GLfloat height ) +void glDrawTexfvOES ( const GLfloat *coords ) +void glDrawTexiOES ( GLint x, GLint y, GLint z, GLint width, GLint height ) +void glDrawTexivOES ( const GLint *coords ) +void glDrawTexsOES ( GLshort x, GLshort y, GLshort z, GLshort width, GLshort height ) +void glDrawTexsvOES ( const GLshort *coords ) +void glDrawTexxOES ( GLfixed x, GLfixed y, GLfixed z, GLfixed width, GLfixed height ) +void glDrawTexxvOES ( const GLfixed *coords ) +void glEnable ( GLenum cap ) +void glEnableClientState ( GLenum array ) +void glLoadPaletteFromModelViewMatrixOES ( void ) +void glMatrixIndexPointerOES ( GLint size, GLenum type, GLsizei stride, const GLvoid *pointer ) +void glMatrixIndexPointerOES ( GLint size, GLenum type, GLsizei stride, GLint offset ) +void glWeightPointerOES ( GLint size, GLenum type, GLsizei stride, const GLvoid *pointer ) +void glWeightPointerOES ( GLint size, GLenum type, GLsizei stride, GLint offset ) diff --git a/opengl/tools/glgen/glspec-1.1extpack b/opengl/tools/glgen/glspec-1.1extpack new file mode 100644 index 0000000000000000000000000000000000000000..ca9e6d2c5e3e5c1252b81349ece9af6ca75e9ae3 --- /dev/null +++ b/opengl/tools/glgen/glspec-1.1extpack @@ -0,0 +1,38 @@ +void glBindFramebufferOES ( GLint target, GLint framebuffer ) +void glBindRenderbufferOES ( GLint target, GLint renderbuffer ) +void glBindTexture ( GLint target, GLint texture ) +void glBlendEquation ( GLint mode ) +void glBlendEquationSeparate ( GLint modeRGB, GLint modeAlpha ) +void glBlendFuncSeparate ( GLint srcRGB, GLint dstRGB, GLint srcAlpha, GLint dstAlpha ) +GLint glCheckFramebufferStatusOES ( GLint target ) +void glCompressedTexImage2D ( GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *data ) +void glCopyTexImage2D ( GLint target, GLint level, GLint internalformat, GLint x, GLint y, GLint width, GLint height, GLint border ) +void glDeleteFramebuffersOES ( GLint n, GLint *framebuffers ) +void glDeleteRenderbuffersOES ( GLint n, GLint *renderbuffers ) +void glEnable ( GLint cap ) +void glFramebufferRenderbufferOES ( GLint target, GLint attachment, GLint renderbuffertarget, GLint renderbuffer ) +void glFramebufferTexture2DOES ( GLint target, GLint attachment, GLint textarget, GLint texture, GLint level ) +void glGenerateMipmapOES ( GLint target ) +void glGenFramebuffersOES ( GLint n, GLint *framebuffers ) +void glGenRenderbuffersOES ( GLint n, GLint *renderbuffers ) +void glGetFramebufferAttachmentParameterivOES ( GLint target, GLint attachment, GLint pname, GLint *params ) +void glGetIntegerv ( GLint pname, GLint *params ) +void glGetRenderbufferParameterivOES ( GLint target, GLint pname, GLint *params ) +void glGetTexGenfv ( GLint coord, GLint pname, GLfloat *params ) +void glGetTexGeniv ( GLint coord, GLint pname, GLint *params ) +void glGetTexGenxv ( GLint coord, GLint pname, GLint *params ) +GLboolean glIsFramebufferOES ( GLint framebuffer ) +GLboolean glIsRenderbufferOES ( GLint renderbuffer ) +void glRenderbufferStorageOES ( GLint target, GLint internalformat, GLint width, GLint height ) +void glStencilOp ( GLint fail, GLint zfail, GLint zpass ) +void glTexEnvf ( GLint target, GLint pname, GLfloat param ) +void glTexEnvfv ( GLint target, GLint pname, GLfloat *params ) +void glTexEnvx ( GLint target, GLint pname, GLint param ) +void glTexEnvxv ( GLint target, GLint pname, GLint *params ) +void glTexGenf ( GLint coord, GLint pname, GLfloat param ) +void glTexGenfv ( GLint coord, GLint pname, GLfloat *params ) +void glTexGeni ( GLint coord, GLint pname, GLint param ) +void glTexGeniv ( GLint coord, GLint pname, GLint *params ) +void glTexGenx ( GLint coord, GLint pname, GLint param ) +void glTexGenxv ( GLint coord, GLint pname, GLint *params ) +void glTexParameterf ( GLint target, GLint pname, GLfloat param ) diff --git a/opengl/tools/glgen/glspec-checks b/opengl/tools/glgen/glspec-checks new file mode 100644 index 0000000000000000000000000000000000000000..a84ed65332a364ce439e5c1bb4e080b719a9bc38 --- /dev/null +++ b/opengl/tools/glgen/glspec-checks @@ -0,0 +1,59 @@ +glClipPlanef check equation 4 +glClipPlanex check equation 4 +glDeleteBuffers check buffers n +glDeleteTextures check textures n +glDrawElements check_AIOOBE indices count +glFog ifcheck params 1 pname GL_FOG_MODE,GL_FOG_DENSITY,GL_FOG_START,GL_FOG_END ifcheck params 4 pname GL_FOG_COLOR +glGenBuffers check buffers n +glGenTextures check textures n +glGetClipPlane check eqn 4 +glGetIntegerv ifcheck params 1 pname GL_ALPHA_BITS,GL_ALPHA_TEST_FUNC,GL_ALPHA_TEST_REF,GL_BLEND_DST,GL_BLUE_BITS,GL_COLOR_ARRAY_BUFFER_BINDING,GL_COLOR_ARRAY_SIZE,GL_COLOR_ARRAY_STRIDE,GL_COLOR_ARRAY_TYPE,GL_CULL_FACE,GL_DEPTH_BITS,GL_DEPTH_CLEAR_VALUE,GL_DEPTH_FUNC,GL_DEPTH_WRITEMASK,GL_FOG_DENSITY,GL_FOG_END,GL_FOG_MODE,GL_FOG_START,GL_FRONT_FACE,GL_GREEN_BITS,GL_IMPLEMENTATION_COLOR_READ_FORMAT_OES,GL_IMPLEMENTATION_COLOR_READ_TYPE_OES,GL_LIGHT_MODEL_TWO_SIDE,GL_LINE_SMOOTH_HINT,GL_LINE_WIDTH,GL_LOGIC_OP_MODE,GL_MATRIX_INDEX_ARRAY_BUFFER_BINDING_OES,GL_MATRIX_INDEX_ARRAY_SIZE_OES,GL_MATRIX_INDEX_ARRAY_STRIDE_OES,GL_MATRIX_INDEX_ARRAY_TYPE_OES,GL_MATRIX_MODE,GL_MAX_CLIP_PLANES,GL_MAX_ELEMENTS_INDICES,GL_MAX_ELEMENTS_VERTICES,GL_MAX_LIGHTS,GL_MAX_MODELVIEW_STACK_DEPTH,GL_MAX_PALETTE_MATRICES_OES,GL_MAX_PROJECTION_STACK_DEPTH,GL_MAX_TEXTURE_SIZE,GL_MAX_TEXTURE_STACK_DEPTH,GL_MAX_TEXTURE_UNITS,GL_MAX_VERTEX_UNITS_OES,GL_MODELVIEW_STACK_DEPTH,GL_NORMAL_ARRAY_BUFFER_BINDING,GL_NORMAL_ARRAY_STRIDE,GL_NORMAL_ARRAY_TYPE,GL_NUM_COMPRESSED_TEXTURE_FORMATS,GL_PACK_ALIGNMENT,GL_PERSPECTIVE_CORRECTION_HINT,GL_POINT_SIZE,GL_POINT_SIZE_ARRAY_BUFFER_BINDING_OES,GL_POINT_SIZE_ARRAY_STRIDE_OES,GL_POINT_SIZE_ARRAY_TYPE_OES,GL_POINT_SMOOTH_HINT,GL_POLYGON_OFFSET_FACTOR,GL_POLYGON_OFFSET_UNITS,GL_PROJECTION_STACK_DEPTH,GL_RED_BITS,GL_SHADE_MODEL,GL_STENCIL_BITS,GL_STENCIL_CLEAR_VALUE,GL_STENCIL_FAIL,GL_STENCIL_FUNC,GL_STENCIL_PASS_DEPTH_FAIL,GL_STENCIL_PASS_DEPTH_PASS,GL_STENCIL_REF,GL_STENCIL_VALUE_MASK,GL_STENCIL_WRITEMASK,GL_SUBPIXEL_BITS,GL_TEXTURE_BINDING_2D,GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING,GL_TEXTURE_COORD_ARRAY_SIZE,GL_TEXTURE_COORD_ARRAY_STRIDE,GL_TEXTURE_COORD_ARRAY_TYPE,GL_TEXTURE_STACK_DEPTH,GL_UNPACK_ALIGNMENT,GL_VERTEX_ARRAY_BUFFER_BINDING,GL_VERTEX_ARRAY_SIZE,GL_VERTEX_ARRAY_STRIDE,GL_VERTEX_ARRAY_TYPE,GL_WEIGHT_ARRAY_BUFFER_BINDING_OES,GL_WEIGHT_ARRAY_SIZE_OES,GL_WEIGHT_ARRAY_STRIDE_OES,GL_WEIGHT_ARRAY_TYPE_OES ifcheck params 2 pname GL_ALIASED_POINT_SIZE_RANGE,GL_ALIASED_LINE_WIDTH_RANGE,GL_DEPTH_RANGE,GL_MAX_VIEWPORT_DIMS,GL_SMOOTH_LINE_WIDTH_RANGE,GL_SMOOTH_POINT_SIZE_RANGE ifcheck params 4 pname GL_COLOR_CLEAR_VALUE,GL_COLOR_WRITEMASK,GL_SCISSOR_BOX,GL_VIEWPORT ifcheck params 16 pname GL_MODELVIEW_MATRIX,GL_MODELVIEW_MATRIX_FLOAT_AS_INT_BITS_OES,GL_PROJECTION_MATRIX,GL_PROJECTION_MATRIX_FLOAT_AS_INT_BITS_OES,GL_TEXTURE_MATRIX,GL_TEXTURE_MATRIX_FLOAT_AS_INT_BITS_OES ifcheck params _NUM_COMPRESSED_TEXTURE_FORMATS pname GL_COMPRESSED_TEXTURE_FORMATS,GL_FOG_COLOR,GL_LIGHT_MODEL_AMBIENT +glGetLight ifcheck params 1 pname GL_SPOT_EXPONENT,GL_SPOT_CUTOFF,GL_CONSTANT_ATTENUATION,GL_LINEAR_ATTENUATION,GL_QUADRATIC_ATTENUATION ifcheck params 3 pname GL_SPOT_DIRECTION ifcheck params 4 pname GL_AMBIENT,GL_DIFFUSE,GL_SPECULAR,GL_EMISSION +glGetMaterial ifcheck params 1 pname GL_SHININESS ifcheck params 4 pname GL_AMBIENT,GL_DIFFUSE,GL_SPECULAR,GL_EMISSION,GL_AMBIENT_AND_DIFFUSE +glGetTexEnv ifcheck params 1 pname GL_TEXTURE_ENV_MODE,GL_COMBINE_RGB,GL_COMBINE_ALPHA ifcheck params 4 pname GL_TEXTURE_ENV_COLOR +glGetTexParameter check params 1 +glLightModel ifcheck params 1 pname GL_LIGHT_MODEL_TWO_SIDE ifcheck params 4 pname GL_LIGHT_MODEL_AMBIENT +glLight ifcheck params 1 pname GL_SPOT_EXPONENT,GL_SPOT_CUTOFF,GL_CONSTANT_ATTENUATION,GL_LINEAR_ATTENUATION,GL_QUADRATIC_ATTENUATION ifcheck params 3 pname GL_SPOT_DIRECTION ifcheck params 4 pname GL_AMBIENT,GL_DIFFUSE,GL_SPECULAR,GL_EMISSION +glLoadMatrix check m 16 +glMaterial ifcheck params 1 pname GL_SHININESS ifcheck params 4 pname GL_AMBIENT,GL_DIFFUSE,GL_SPECULAR,GL_EMISSION,GL_AMBIENT_AND_DIFFUSE +glMultMatrix check m 16 +glPointParameter check params 1 +glTexEnv ifcheck params 1 pname GL_TEXTURE_ENV_MODE,GL_COMBINE_RGB,GL_COMBINE_ALPHA ifcheck params 4 pname GL_TEXTURE_ENV_COLOR +glTexImage2D nullAllowed +glTexSubImage2D nullAllowed +glBufferData nullAllowed +glTexParameter check params 1 +glQueryMatrixxOES check mantissa 16 check exponent 16 return -1 +glDrawTexfvOES check coords 5 +glDrawTexivOES check coords 5 +glDrawTexsvOES check coords 5 +glDrawTexxvOES check coords 5 +glBindFramebufferOES unsupported +glBindRenderbufferOES unsupported +glBlendEquation unsupported +glBlendEquationSeparate unsupported +glBlendFuncSeparate unsupported +glCheckFramebufferStatusOES unsupported return 0 +glCurrentPaletteMatrixOES unsupported +glDeleteFramebuffersOES unsupported +glDeleteRenderbuffersOES unsupported +glFramebufferRenderbufferOES unsupported +glFramebufferStorageOES unsupported +glFramebufferTexture2DOES unsupported +glGenFramebuffersOES unsupported +glGenRenderbuffersOES unsupported +glGenerateMipmapOES unsupported +glGetBufferParameter unsupported +glGetFramebufferAttachmentParameterivOES unsupported +glGetRenderbufferParameterivOES unsupported +glGetTexGen unsupported +glIsFramebufferOES unsupported return JNI_FALSE +glIsRenderbufferOES unsupported return JNI_FALSE +glLoadPaletteFromModelViewMatrixOES unsupported +glMatrixIndexPointerOES unsupported +glRenderbufferStorageOES unsupported return false +glTexGen unsupported +glTexGenf unsupported +glTexGeni unsupported +glTexGenx unsupported +glWeightPointerOES unsupported diff --git a/opengl/tools/glgen/src/CFunc.java b/opengl/tools/glgen/src/CFunc.java new file mode 100644 index 0000000000000000000000000000000000000000..0794f417427bc89264646ac404fd3a0f107d8180 --- /dev/null +++ b/opengl/tools/glgen/src/CFunc.java @@ -0,0 +1,155 @@ + +import java.util.*; + +public class CFunc { + + String original; + + CType ftype; + String fname; + + List argNames = new ArrayList(); + List argTypes = new ArrayList(); + + boolean hasPointerArg = false; + boolean hasTypedPointerArg = false; + + public CFunc(String original) { + this.original = original; + } + + public String getOriginal() { + return original; + } + + public void setName(String fname) { + this.fname = fname; + } + + public String getName() { + return fname; + } + + public void setType(CType ftype) { + this.ftype = ftype; + } + + public CType getType() { + return ftype; + } + + public void addArgument(String argName, CType argType) { + argNames.add(argName); + argTypes.add(argType); + + if (argType.isPointer()) { + hasPointerArg = true; + } + if (argType.isTypedPointer()) { + hasTypedPointerArg = true; + } + } + + public int getNumArgs() { + return argNames.size(); + } + + public int getArgIndex(String name) { + int len = argNames.size(); + for (int i = 0; i < len; i++) { + if (name.equals(argNames.get(i))) { + return i; + } + } + return -1; + } + + public String getArgName(int index) { + return argNames.get(index); + } + + public CType getArgType(int index) { + return argTypes.get(index); + } + + public boolean hasPointerArg() { + return hasPointerArg; + } + + public boolean hasTypedPointerArg() { + return hasTypedPointerArg; + } + + public String toString() { + String s = "Function " + fname + " returns " + ftype + ": "; + for (int i = 0; i < argNames.size(); i++) { + if (i > 0) { + s += ", "; + } + s += argTypes.get(i) + " " + argNames.get(i); + } + return s; + } + + public static CFunc parseCFunc(String s) { + CFunc cfunc = new CFunc(s); + String[] tokens = s.split("\\s"); + + int i = 0; + CType ftype = new CType(); + String ftypeName = tokens[i++]; + if (ftypeName.equals("const")) { + ftype.setIsConst(true); + ftypeName = tokens[i++]; + } + ftype.setBaseType(ftypeName); + + String fname = tokens[i++]; + if (fname.equals("*")) { + ftype.setIsPointer(true); + fname = tokens[i++]; + } + + cfunc.setName(fname); + cfunc.setType(ftype); + + while (i < tokens.length) { + String tok = tokens[i++]; + + if (tok.equals("(")) { + continue; + } + if (tok.equals(")")) { + break; + } + + CType argType = new CType(); + + String argTypeName = tok; + String argName = ""; + + if (argTypeName.equals("const")) { + argType.setIsConst(true); + argTypeName = tokens[i++]; + } + argType.setBaseType(argTypeName); + + if (argTypeName.equals("void")) { + break; + } + + argName = tokens[i++]; + if (argName.startsWith("*")) { + argType.setIsPointer(true); + argName = argName.substring(1, argName.length()); + } + if (argName.endsWith(",")) { + argName = argName.substring(0, argName.length() - 1); + } + + cfunc.addArgument(argName, argType); + } + + return cfunc; + } +} diff --git a/opengl/tools/glgen/src/CType.java b/opengl/tools/glgen/src/CType.java new file mode 100644 index 0000000000000000000000000000000000000000..331ec625a5e0ee1e1bffa36b919273c82abc458c --- /dev/null +++ b/opengl/tools/glgen/src/CType.java @@ -0,0 +1,85 @@ + +public class CType { + + String baseType; + boolean isConst; + boolean isPointer; + + public CType() { + } + + public CType(String baseType) { + setBaseType(baseType); + } + + public CType(String baseType, boolean isConst, boolean isPointer) { + setBaseType(baseType); + setIsConst(isConst); + setIsPointer(isPointer); + } + + public String getDeclaration() { + return baseType + (isPointer ? " *" : ""); + } + + public void setIsConst(boolean isConst) { + this.isConst = isConst; + } + + public boolean isConst() { + return isConst; + } + + public void setIsPointer(boolean isPointer) { + this.isPointer = isPointer; + } + + public boolean isPointer() { + return isPointer; + } + + boolean isVoid() { + String baseType = getBaseType(); + return baseType.equals("GLvoid") || + baseType.equals("void"); + } + + public boolean isTypedPointer() { + return isPointer() && !isVoid(); + } + + public void setBaseType(String baseType) { + this.baseType = baseType; + } + + public String getBaseType() { + return baseType; + } + + public String toString() { + String s = ""; + if (isConst()) { + s += "const "; + } + s += baseType; + if (isPointer()) { + s += "*"; + } + + return s; + } + + public int hashCode() { + return baseType.hashCode() ^ (isPointer ? 2 : 0) ^ (isConst ? 1 : 0); + } + + public boolean equals(Object o) { + if (o != null && o instanceof CType) { + CType c = (CType)o; + return baseType.equals(c.baseType) && + isPointer() == c.isPointer() && + isConst() == c.isConst(); + } + return false; + } +} diff --git a/opengl/tools/glgen/src/CodeEmitter.java b/opengl/tools/glgen/src/CodeEmitter.java new file mode 100644 index 0000000000000000000000000000000000000000..3e9b90aab881abbf179c4ab9f3c39d81f2782636 --- /dev/null +++ b/opengl/tools/glgen/src/CodeEmitter.java @@ -0,0 +1,8 @@ + +public interface CodeEmitter { + + void setVersion(int version, boolean ext, boolean pack); + void emitCode(CFunc cfunc, String original); + void addNativeRegistration(String fname); + void emitNativeRegistration(); +} diff --git a/opengl/tools/glgen/src/GenerateGL.java b/opengl/tools/glgen/src/GenerateGL.java new file mode 100644 index 0000000000000000000000000000000000000000..657ee6e7c7e0c6590daf712e71c3a50ccb890b84 --- /dev/null +++ b/opengl/tools/glgen/src/GenerateGL.java @@ -0,0 +1,164 @@ + +import java.io.*; +import java.util.*; + +public class GenerateGL { + + static void copy(String filename, PrintStream out) throws IOException { + BufferedReader br = new BufferedReader(new FileReader(filename)); + String s; + while ((s = br.readLine()) != null) { + out.println(s); + } + } + + private static void emit(int version, boolean ext, boolean pack, + CodeEmitter emitter, + BufferedReader specReader, + PrintStream glStream, + PrintStream glImplStream, + PrintStream cStream) throws Exception { + String s = null; + int counter = 0; + while ((s = specReader.readLine()) != null) { + if (s.trim().startsWith("//")) { + continue; + } + + CFunc cfunc = CFunc.parseCFunc(s); + + String fname = cfunc.getName(); + File f = new File("stubs/" + fname + + ".java-1" + version + "-if"); + if (f.exists()) { + System.out.println("Special-casing function " + fname); + copy("stubs/" + fname + + ".java-1" + version + "-if", glStream); + copy("stubs/" + fname + ".java-impl", glImplStream); + copy("stubs/" + fname + ".cpp", cStream); + + // Register native function names + // This should be improved to require fewer discrete files + String filename = "stubs/" + fname + ".nativeReg"; + BufferedReader br = + new BufferedReader(new FileReader(filename)); + String nfunc; + while ((nfunc = br.readLine()) != null) { + emitter.addNativeRegistration(nfunc); + } + } else { + emitter.setVersion(version, ext, pack); + emitter.emitCode(cfunc, s); + } + } + } + + public static void main(String[] args) throws Exception { + String classPathName = "com/google/android/gles_jni/GLImpl"; + boolean useContextPointer = true; + + int aidx = 0; + while (args[aidx].charAt(0) == '-') { + switch (args[aidx].charAt(1)) { + case 'c': + useContextPointer = false; + break; + + default: + System.err.println("Unknown flag: " + args[aidx]); + System.exit(1); + } + + aidx++; + } + + System.out.println("useContextPointer = " + useContextPointer); + + BufferedReader spec10Reader = + new BufferedReader(new FileReader(args[aidx++])); + BufferedReader spec10ExtReader = + new BufferedReader(new FileReader(args[aidx++])); + BufferedReader spec11Reader = + new BufferedReader(new FileReader(args[aidx++])); + BufferedReader spec11ExtReader = + new BufferedReader(new FileReader(args[aidx++])); + BufferedReader spec11ExtPackReader = + new BufferedReader(new FileReader(args[aidx++])); + BufferedReader checksReader = + new BufferedReader(new FileReader(args[aidx++])); + + String gl10Filename = "javax/microedition/khronos/opengles/GL10.java"; + String gl10ExtFilename = + "javax/microedition/khronos/opengles/GL10Ext.java"; + String gl11Filename = "javax/microedition/khronos/opengles/GL11.java"; + String gl11ExtFilename = + "javax/microedition/khronos/opengles/GL11Ext.java"; + String gl11ExtPackFilename = + "javax/microedition/khronos/opengles/GL11ExtensionPack.java"; + String glImplFilename = "com/google/android/gles_jni/GLImpl.java"; + String cFilename = "com_google_android_gles_jni_GLImpl.cpp"; + + PrintStream gl10Stream = + new PrintStream(new FileOutputStream("out/" + gl10Filename)); + PrintStream gl10ExtStream = + new PrintStream(new FileOutputStream("out/" + gl10ExtFilename)); + PrintStream gl11Stream = + new PrintStream(new FileOutputStream("out/" + gl11Filename)); + PrintStream gl11ExtStream = + new PrintStream(new FileOutputStream("out/" + gl11ExtFilename)); + PrintStream gl11ExtPackStream = + new PrintStream(new FileOutputStream("out/" + gl11ExtPackFilename)); + PrintStream glImplStream = + new PrintStream(new FileOutputStream("out/" + glImplFilename)); + PrintStream cStream = + new PrintStream(new FileOutputStream("out/" + cFilename)); + + ParameterChecker checker = new ParameterChecker(checksReader); + + CodeEmitter emitter = + new JniCodeEmitter(classPathName, + checker, + gl10Stream, gl10ExtStream, + gl11Stream, gl11ExtStream, gl11ExtPackStream, + glImplStream, cStream, + useContextPointer); + + gl10Stream.println("/* //device/java/android/" + gl10Filename); + gl10ExtStream.println("/* //device/java/android/" + gl10ExtFilename); + gl11Stream.println("/* //device/java/android/" + gl11Filename); + gl11ExtStream.println("/* //device/java/android/" + gl11ExtFilename); + gl11ExtPackStream.println("/* //device/java/android/" + + gl11ExtPackFilename); + glImplStream.println("/* //device/java/android/" + glImplFilename); + cStream.println("/* //device/libs/android_runtime/" + cFilename); + + copy("stubs/GL10Header.java-if", gl10Stream); + copy("stubs/GL10ExtHeader.java-if", gl10ExtStream); + copy("stubs/GL11Header.java-if", gl11Stream); + copy("stubs/GL11ExtHeader.java-if", gl11ExtStream); + copy("stubs/GL11ExtensionPackHeader.java-if", gl11ExtPackStream); + copy("stubs/GLImplHeader.java-impl", glImplStream); + copy("stubs/GLCHeader.cpp", cStream); + + emit(0, false, false, + emitter, spec10Reader, gl10Stream, glImplStream, cStream); + emit(0, true, false, + emitter, spec10ExtReader, gl10ExtStream, glImplStream, cStream); + emit(1, false, false, + emitter, spec11Reader, gl11Stream, glImplStream, cStream); + emit(1, true, false, + emitter, spec11ExtReader, gl11ExtStream, glImplStream, cStream); + emit(1, true, true, + emitter, spec11ExtPackReader, gl11ExtPackStream, glImplStream, + cStream); + + emitter.emitNativeRegistration(); + + gl10Stream.println("}"); + gl10ExtStream.println("}"); + gl11Stream.println("}"); + gl11ExtStream.println("}"); + gl11ExtPackStream.println("}"); + glImplStream.println("}"); + } +} diff --git a/opengl/tools/glgen/src/JFunc.java b/opengl/tools/glgen/src/JFunc.java new file mode 100644 index 0000000000000000000000000000000000000000..42d466c33ed6d4e8e6637378f756b5761da55aed --- /dev/null +++ b/opengl/tools/glgen/src/JFunc.java @@ -0,0 +1,148 @@ + +import java.util.ArrayList; +import java.util.List; + +public class JFunc { + + String className = "com.google.android.gles_jni.GL11Impl"; + + CFunc cfunc; + JType ftype; + String fname; + + List argNames = new ArrayList(); + List argTypes = new ArrayList(); + List argCIndices = new ArrayList(); + + boolean hasBufferArg = false; + boolean hasTypedBufferArg = false; + ArrayList bufferArgNames = new ArrayList(); + + public JFunc(CFunc cfunc) { + this.cfunc = cfunc; + } + + public CFunc getCFunc() { + return cfunc; + } + + public void setName(String fname) { + this.fname = fname; + } + + public String getName() { + return fname; + } + + public void setType(JType ftype) { + this.ftype = ftype; + } + + public JType getType() { + return ftype; + } + + public void setClassName(String className) { + this.className = className; + } + + public String getClassName() { + return className; + } + + public boolean hasBufferArg() { + return hasBufferArg; + } + + public boolean hasTypedBufferArg() { + return hasTypedBufferArg; + } + + public String getBufferArgName(int index) { + return bufferArgNames.get(index); + } + + public void addArgument(String argName, JType argType, int cindex) { + argNames.add(argName); + argTypes.add(argType); + argCIndices.add(new Integer(cindex)); + + if (argType.isBuffer()) { + hasBufferArg = true; + bufferArgNames.add(argName); + } + if (argType.isTypedBuffer()) { + hasTypedBufferArg = true; + bufferArgNames.add(argName); + } + } + + public int getNumArgs() { + return argNames.size(); + } + + public int getArgIndex(String name) { + int len = argNames.size(); + for (int i = 0; i < len; i++) { + if (name.equals(argNames.get(i))) { + return i; + } + } + return -1; + } + + public String getArgName(int index) { + return argNames.get(index); + } + + public JType getArgType(int index) { + return argTypes.get(index); + } + + public int getArgCIndex(int index) { + return argCIndices.get(index).intValue(); + } + + public static JFunc convert(CFunc cfunc, boolean useArray) { + JFunc jfunc = new JFunc(cfunc); + jfunc.setName(cfunc.getName()); + jfunc.setType(JType.convert(cfunc.getType(), false)); + + int numArgs = cfunc.getNumArgs(); + int numOffsets = 0; + for (int i = 0; i < numArgs; i++) { + CType cArgType = cfunc.getArgType(i); + if (cArgType.isTypedPointer() && useArray) { + ++numOffsets; + } + } + + for (int i = 0; i < numArgs; i++) { + String cArgName = cfunc.getArgName(i); + CType cArgType = cfunc.getArgType(i); + + jfunc.addArgument(cArgName, JType.convert(cArgType, useArray), i); + if (cArgType.isTypedPointer() && useArray) { + if (numOffsets > 1) { + jfunc.addArgument(cArgName + "Offset", new JType("int"), i); + } else { + jfunc.addArgument("offset", new JType("int"), i); + } + } + } + + return jfunc; + } + + public String toString() { + String s = "Function " + fname + " returns " + ftype + ": "; + for (int i = 0; i < argNames.size(); i++) { + if (i > 0) { + s += ", "; + } + s += argTypes.get(i) + " " + argNames.get(i); + } + return s; + } + +} diff --git a/opengl/tools/glgen/src/JType.java b/opengl/tools/glgen/src/JType.java new file mode 100644 index 0000000000000000000000000000000000000000..a16d4400d83f8ebe23f51bcf7eeabbd860cfe3d3 --- /dev/null +++ b/opengl/tools/glgen/src/JType.java @@ -0,0 +1,139 @@ + +import java.util.HashMap; + +public class JType { + + String baseType; + boolean isArray; + boolean isClass; + + static HashMap typeMapping = new HashMap(); + static HashMap arrayTypeMapping = new HashMap(); + + static { + // Primitive types + typeMapping.put(new CType("GLbitfield"), new JType("int")); + typeMapping.put(new CType("GLboolean"), new JType("boolean")); + typeMapping.put(new CType("GLclampf"), new JType("float")); + typeMapping.put(new CType("GLclampx"), new JType("int")); + typeMapping.put(new CType("GLenum"), new JType("int")); + typeMapping.put(new CType("GLfloat"), new JType("float")); + typeMapping.put(new CType("GLfixed"), new JType("int")); + typeMapping.put(new CType("GLint"), new JType("int")); + typeMapping.put(new CType("GLintptr"), new JType("int")); + typeMapping.put(new CType("GLshort"), new JType("short")); + typeMapping.put(new CType("GLsizei"), new JType("int")); + typeMapping.put(new CType("GLsizeiptr"), new JType("int")); + typeMapping.put(new CType("GLubyte"), new JType("byte")); + typeMapping.put(new CType("GLuint"), new JType("int")); + typeMapping.put(new CType("void"), new JType("void")); + typeMapping.put(new CType("GLubyte", true, true), new JType("String")); + + // Untyped pointers map to untyped Buffers + typeMapping.put(new CType("GLvoid", true, true), + new JType("java.nio.Buffer", true, false)); + typeMapping.put(new CType("GLvoid", false, true), + new JType("java.nio.Buffer", true, false)); + typeMapping.put(new CType("void", false, true), + new JType("java.nio.Buffer", true, false)); + + // Typed pointers map to typed Buffers + typeMapping.put(new CType("GLboolean", false, true), + new JType("java.nio.IntBuffer", true, false)); + typeMapping.put(new CType("GLfixed", false, true), + new JType("java.nio.IntBuffer", true, false)); + typeMapping.put(new CType("GLfixed", true, true), + new JType("java.nio.IntBuffer", true, false)); + typeMapping.put(new CType("GLfloat", false, true), + new JType("java.nio.FloatBuffer", true, false)); + typeMapping.put(new CType("GLfloat", true, true), + new JType("java.nio.FloatBuffer", true, false)); + typeMapping.put(new CType("GLint", false, true), + new JType("java.nio.IntBuffer", true, false)); + typeMapping.put(new CType("GLint", true, true), + new JType("java.nio.IntBuffer", true, false)); + typeMapping.put(new CType("GLuint", false, true), + new JType("java.nio.IntBuffer", true, false)); + typeMapping.put(new CType("GLuint", true, true), + new JType("java.nio.IntBuffer", true, false)); + typeMapping.put(new CType("GLshort", true, true), + new JType("java.nio.ShortBuffer", true, false)); + + // Typed pointers map to arrays + offsets + arrayTypeMapping.put(new CType("GLboolean", false, true), + new JType("boolean", false, true)); + arrayTypeMapping.put(new CType("GLfixed", true, true), new JType("int", false, true)); + arrayTypeMapping.put(new CType("GLfixed", false, true), new JType("int", false, true)); + arrayTypeMapping.put(new CType("GLfloat", false, true), new JType("float", false, true)); + arrayTypeMapping.put(new CType("GLfloat", true, true), new JType("float", false, true)); + arrayTypeMapping.put(new CType("GLint", false, true), new JType("int", false, true)); + arrayTypeMapping.put(new CType("GLint", true, true), new JType("int", false, true)); + arrayTypeMapping.put(new CType("GLshort", true, true), new JType("short", false, true)); + arrayTypeMapping.put(new CType("GLuint", false, true), new JType("int", false, true)); + arrayTypeMapping.put(new CType("GLuint", true, true), new JType("int", false, true)); + arrayTypeMapping.put(new CType("GLintptr"), new JType("int", false, true)); + arrayTypeMapping.put(new CType("GLsizeiptr"), new JType("int", false, true)); + } + + public JType() { + } + + public JType(String primitiveTypeName) { + this.baseType = primitiveTypeName; + this.isClass = false; + this.isArray = false; + } + + public JType(String primitiveTypeName, boolean isClass, boolean isArray) { + this.baseType = primitiveTypeName; + this.isClass = isClass; + this.isArray = isArray; + } + + public String getBaseType() { + return baseType; + } + + public String toString() { + return baseType + (isArray ? "[]" : ""); + } + + public boolean isArray() { + return isArray; + } + + public boolean isClass() { + return isClass; + } + + public boolean isPrimitive() { + return !isClass() && !isArray(); + } + + public boolean isVoid() { + return baseType.equals("void"); + } + + public boolean isBuffer() { + return baseType.indexOf("Buffer") != -1; + } + + public boolean isTypedBuffer() { + return !baseType.equals("java.nio.Buffer") && + (baseType.indexOf("Buffer") != -1); + } + + public static JType convert(CType ctype, boolean useArray) { + JType javaType = null; + if (useArray) { + javaType = arrayTypeMapping.get(ctype); + } + if (javaType == null) { + javaType = typeMapping.get(ctype); + } + if (javaType == null) { + throw new RuntimeException("Unsupported C type: " + ctype); + } + return javaType; + } +} diff --git a/opengl/tools/glgen/src/JniCodeEmitter.java b/opengl/tools/glgen/src/JniCodeEmitter.java new file mode 100644 index 0000000000000000000000000000000000000000..33b9a3e538f617d6a8704146eaf197f4d8f8fa9c --- /dev/null +++ b/opengl/tools/glgen/src/JniCodeEmitter.java @@ -0,0 +1,1086 @@ +import java.io.PrintStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; + +/** + * Emits a Java interface and Java & C implementation for a C function. + * + *

              The Java interface will have Buffer and array variants for functions that + * have a typed pointer argument. The array variant will convert a single " *data" + * argument to a pair of arguments "[] data, int offset". + */ +public class JniCodeEmitter implements CodeEmitter { + + // If true, use C++ style for calling through a JNIEnv *: + // env->Func(...) + // If false, use C style: + // (*env)->Func(env, ...) + static final boolean mUseCPlusPlus = true; + + boolean mUseContextPointer = true; + + String mClassPathName; + + ParameterChecker mChecker; + PrintStream mJava10InterfaceStream; + PrintStream mJava10ExtInterfaceStream; + PrintStream mJava11InterfaceStream; + PrintStream mJava11ExtInterfaceStream; + PrintStream mJava11ExtPackInterfaceStream; + PrintStream mJavaImplStream; + PrintStream mCStream; + + PrintStream mJavaInterfaceStream; + + List nativeRegistrations = new ArrayList(); + + boolean needsExit; + + static String indent = " "; + + HashSet mFunctionsEmitted = new HashSet(); + + /** + * @param java10InterfaceStream the PrintStream to which to emit the Java interface for GL 1.0 functions + * @param java10ExtInterfaceStream the PrintStream to which to emit the Java interface for GL 1.0 extension functions + * @param java11InterfaceStream the PrintStream to which to emit the Java interface for GL 1.1 functions + * @param java11ExtInterfaceStream the PrintStream to which to emit the Java interface for GL 1.1 Extension functions + * @param java11ExtPackInterfaceStream the PrintStream to which to emit the Java interface for GL 1.1 Extension Pack functions + * @param javaImplStream the PrintStream to which to emit the Java implementation + * @param cStream the PrintStream to which to emit the C implementation + */ + public JniCodeEmitter(String classPathName, + ParameterChecker checker, + PrintStream java10InterfaceStream, + PrintStream java10ExtInterfaceStream, + PrintStream java11InterfaceStream, + PrintStream java11ExtInterfaceStream, + PrintStream java11ExtPackInterfaceStream, + PrintStream javaImplStream, + PrintStream cStream, + boolean useContextPointer) { + mClassPathName = classPathName; + mChecker = checker; + mJava10InterfaceStream = java10InterfaceStream; + mJava10ExtInterfaceStream = java10ExtInterfaceStream; + mJava11InterfaceStream = java11InterfaceStream; + mJava11ExtInterfaceStream = java11ExtInterfaceStream; + mJava11ExtPackInterfaceStream = java11ExtPackInterfaceStream; + mJavaImplStream = javaImplStream; + mCStream = cStream; + mUseContextPointer = useContextPointer; + } + + public void setVersion(int version, boolean ext, boolean pack) { + if (version == 0) { + mJavaInterfaceStream = ext ? mJava10ExtInterfaceStream : + mJava10InterfaceStream; + } else if (version == 1) { + mJavaInterfaceStream = ext ? + (pack ? mJava11ExtPackInterfaceStream : + mJava11ExtInterfaceStream) : + mJava11InterfaceStream; + } else { + throw new RuntimeException("Bad version: " + version); + } + } + + public void emitCode(CFunc cfunc, String original) { + JFunc jfunc; + String signature; + boolean duplicate; + + if (cfunc.hasTypedPointerArg()) { + jfunc = JFunc.convert(cfunc, true); + + // Don't emit duplicate functions + // These may appear because they are defined in multiple + // Java interfaces (e.g., GL11/GL11ExtensionPack) + signature = jfunc.toString(); + duplicate = false; + if (mFunctionsEmitted.contains(signature)) { + duplicate = true; + } else { + mFunctionsEmitted.add(signature); + } + + if (!duplicate) { + emitNativeDeclaration(jfunc, mJavaImplStream); + emitJavaCode(jfunc, mJavaImplStream); + } + emitJavaInterfaceCode(jfunc, mJavaInterfaceStream); + if (!duplicate) { + emitJniCode(jfunc, mCStream); + } + } + + jfunc = JFunc.convert(cfunc, false); + + signature = jfunc.toString(); + duplicate = false; + if (mFunctionsEmitted.contains(signature)) { + duplicate = true; + } else { + mFunctionsEmitted.add(signature); + } + + if (!duplicate) { + emitNativeDeclaration(jfunc, mJavaImplStream); + } + emitJavaInterfaceCode(jfunc, mJavaInterfaceStream); + if (!duplicate) { + emitJavaCode(jfunc, mJavaImplStream); + emitJniCode(jfunc, mCStream); + } + } + + public void emitNativeDeclaration(JFunc jfunc, PrintStream out) { + out.println(" // C function " + jfunc.getCFunc().getOriginal()); + out.println(); + + emitFunction(jfunc, out, true, false); + } + + public void emitJavaInterfaceCode(JFunc jfunc, PrintStream out) { + emitFunction(jfunc, out, false, true); + } + + public void emitJavaCode(JFunc jfunc, PrintStream out) { + emitFunction(jfunc, out, false, false); + } + + void emitFunctionCall(JFunc jfunc, PrintStream out, String iii, boolean grabArray ) { + boolean isVoid = jfunc.getType().isVoid(); + boolean isPointerFunc = jfunc.getName().endsWith("Pointer") && + jfunc.getCFunc().hasPointerArg(); + + if (!isVoid) { + out.println(iii + + jfunc.getType() + " _returnValue;"); + } + out.println(iii + + (isVoid ? "" : "_returnValue = ") + + jfunc.getName() + + (isPointerFunc ? "Bounds" : "" ) + + "("); + + int numArgs = jfunc.getNumArgs(); + for (int i = 0; i < numArgs; i++) { + String argName = jfunc.getArgName(i); + JType argType = jfunc.getArgType(i); + + if (grabArray && argType.isTypedBuffer()) { + String typeName = argType.getBaseType(); + typeName = typeName.substring(9, typeName.length() - 6); + out.println(iii + indent + "get" + typeName + "Array(" + argName + "),"); + out.print(iii + indent + "getOffset(" + argName + ")"); + } else { + out.print(iii + indent + argName); + } + if (i == numArgs - 1) { + if (isPointerFunc) { + out.println(","); + out.println(iii + indent + argName + ".remaining()"); + } else { + out.println(); + } + } else { + out.println(","); + } + } + + out.println(iii + ");"); + } + + void printIfcheckPostamble(PrintStream out, boolean isBuffer, + boolean emitExceptionCheck, String iii) { + printIfcheckPostamble(out, isBuffer, emitExceptionCheck, + "offset", "_remaining", iii); + } + + void printIfcheckPostamble(PrintStream out, boolean isBuffer, + boolean emitExceptionCheck, + String offset, String remaining, String iii) { + out.println(iii + " default:"); + out.println(iii + " _needed = 0;"); + out.println(iii + " break;"); + out.println(iii + "}"); + + out.println(iii + "if (" + remaining + " < _needed) {"); + if (emitExceptionCheck) { + out.println(iii + indent + "_exception = 1;"); + } + out.println(iii + indent + + (mUseCPlusPlus ? "_env" : "(*_env)") + + "->ThrowNew(" + + (mUseCPlusPlus ? "" : "_env, ") + + "IAEClass, " + + "\"" + + (isBuffer ? + "remaining()" : "length - " + offset) + + " < needed\");"); + out.println(iii + indent + "goto exit;"); + needsExit = true; + out.println(iii + "}"); + } + + boolean isNullAllowed(CFunc cfunc) { + String[] checks = mChecker.getChecks(cfunc.getName()); + int index = 1; + if (checks != null) { + while (index < checks.length) { + if (checks[index].equals("return")) { + index += 2; + } else if (checks[index].startsWith("check")) { + index += 3; + } else if (checks[index].equals("ifcheck")) { + index += 5; + } else if (checks[index].equals("unsupported")) { + index += 1; + } else if (checks[index].equals("nullAllowed")) { + return true; + } else { + System.out.println("Error: unknown keyword \"" + + checks[index] + "\""); + System.exit(0); + } + } + } + return false; + } + + String getErrorReturnValue(CFunc cfunc) { + CType returnType = cfunc.getType(); + boolean isVoid = returnType.isVoid(); + if (isVoid) { + return null; + } + + String[] checks = mChecker.getChecks(cfunc.getName()); + + int index = 1; + if (checks != null) { + while (index < checks.length) { + if (checks[index].equals("return")) { + return checks[index + 1]; + } else if (checks[index].startsWith("check")) { + index += 3; + } else if (checks[index].equals("ifcheck")) { + index += 5; + } else if (checks[index].equals("unsupported")) { + index += 1; + } else if (checks[index].equals("nullAllowed")) { + index += 1; + } else { + System.out.println("Error: unknown keyword \"" + + checks[index] + "\""); + System.exit(0); + } + } + } + + return null; + } + + boolean isUnsupportedFunc(CFunc cfunc) { + String[] checks = mChecker.getChecks(cfunc.getName()); + int index = 1; + if (checks != null) { + while (index < checks.length) { + if (checks[index].equals("unsupported")) { + return true; + } else if (checks[index].equals("return")) { + index += 2; + } else if (checks[index].startsWith("check")) { + index += 3; + } else if (checks[index].equals("ifcheck")) { + index += 5; + } else if (checks[index].equals("nullAllowed")) { + index += 1; + } else { + System.out.println("Error: unknown keyword \"" + + checks[index] + "\""); + System.exit(0); + } + } + } + return false; + } + + void emitNativeBoundsChecks(CFunc cfunc, String cname, PrintStream out, + boolean isBuffer, boolean emitExceptionCheck, + String offset, String remaining, String iii) { + CType returnType = cfunc.getType(); + boolean isVoid = returnType.isVoid(); + + String[] checks = mChecker.getChecks(cfunc.getName()); + String checkVar; + String retval = getErrorReturnValue(cfunc); + + boolean lastWasIfcheck = false; + + int index = 1; + if (checks != null) { + boolean remainingDeclared = false; + boolean nullCheckDeclared = false; + boolean offsetChecked = false; + while (index < checks.length) { + if (checks[index].startsWith("check")) { + if (lastWasIfcheck) { + printIfcheckPostamble(out, isBuffer, emitExceptionCheck, + offset, remaining, iii); + } + lastWasIfcheck = false; + if (cname != null && !cname.equals(checks[index + 1])) { + index += 3; + continue; + } + out.println(iii + "if (" + remaining + " < " + + checks[index + 2] + + ") {"); + if (emitExceptionCheck) { + out.println(iii + indent + "_exception = 1;"); + } + String exceptionClassName = "IAEClass"; + // If the "check" keyword was of the form + // "check_", use the class name in the + // exception to be thrown + int underscore = checks[index].indexOf('_'); + if (underscore >= 0) { + exceptionClassName = checks[index].substring(underscore + 1) + "Class"; + } + out.println(iii + indent + + (mUseCPlusPlus ? "_env" : "(*_env)") + + "->ThrowNew(" + + (mUseCPlusPlus ? "" : "_env, ") + + exceptionClassName + ", " + + "\"" + + (isBuffer ? + "remaining()" : "length - " + offset) + + " < " + checks[index + 2] + + "\");"); + + out.println(iii + indent + "goto exit;"); + needsExit = true; + out.println(iii + "}"); + + index += 3; + } else if (checks[index].equals("ifcheck")) { + String[] matches = checks[index + 4].split(","); + + if (!lastWasIfcheck) { + out.println(iii + "int _needed;"); + out.println(iii + + "switch (" + + checks[index + 3] + + ") {"); + } + + for (int i = 0; i < matches.length; i++) { + out.println("#if defined(" + matches[i] + ")"); + out.println(iii + + " case " + + matches[i] + + ":"); + out.println("#endif // defined(" + matches[i] + ")"); + } + out.println(iii + + " _needed = " + + checks[index + 2] + + ";"); + out.println(iii + + " break;"); + + lastWasIfcheck = true; + index += 5; + } else if (checks[index].equals("return")) { + // ignore + index += 2; + } else if (checks[index].equals("unsupported")) { + // ignore + index += 1; + } else if (checks[index].equals("nullAllowed")) { + // ignore + index += 1; + } else { + System.out.println("Error: unknown keyword \"" + + checks[index] + "\""); + System.exit(0); + } + } + } + + if (lastWasIfcheck) { + printIfcheckPostamble(out, isBuffer, emitExceptionCheck, iii); + } + } + + boolean hasNonConstArg(JFunc jfunc, CFunc cfunc, + List nonPrimitiveArgs) { + if (nonPrimitiveArgs.size() > 0) { + for (int i = nonPrimitiveArgs.size() - 1; i >= 0; i--) { + int idx = nonPrimitiveArgs.get(i).intValue(); + int cIndex = jfunc.getArgCIndex(idx); + if (jfunc.getArgType(idx).isArray()) { + if (!cfunc.getArgType(cIndex).isConst()) { + return true; + } + } else if (jfunc.getArgType(idx).isBuffer()) { + if (!cfunc.getArgType(cIndex).isConst()) { + return true; + } + } + } + } + + return false; + } + + /** + * Emit a function in several variants: + * + * if nativeDecl: public native func(args); + * + * if !nativeDecl: + * if interfaceDecl: public func(args); + * if !interfaceDecl: public func(args) { body } + */ + void emitFunction(JFunc jfunc, + PrintStream out, + boolean nativeDecl, boolean interfaceDecl) { + boolean isPointerFunc = + jfunc.getName().endsWith("Pointer") && + jfunc.getCFunc().hasPointerArg(); + + if (!nativeDecl && !interfaceDecl && !isPointerFunc) { + // If it's not a pointer function, we've already emitted it + // with nativeDecl == true + return; + } + + if (isPointerFunc) { + out.println(indent + + (nativeDecl ? "private native " : + (interfaceDecl ? "" : "public ")) + + jfunc.getType() + " " + + jfunc.getName() + + (nativeDecl ? "Bounds" : "") + + "("); + } else { + out.println(indent + + (nativeDecl ? "public native " : + (interfaceDecl ? "" : "public ")) + + jfunc.getType() + " " + + jfunc.getName() + + "("); + } + + int numArgs = jfunc.getNumArgs(); + for (int i = 0; i < numArgs; i++) { + String argName = jfunc.getArgName(i); + JType argType = jfunc.getArgType(i); + + out.print(indent + indent + argType + " " + argName); + if (i == numArgs - 1) { + if (isPointerFunc && nativeDecl) { + out.println(","); + out.println(indent + indent + "int remaining"); + } else { + out.println(); + } + } else { + out.println(","); + } + } + + if (nativeDecl || interfaceDecl) { + out.println(indent + ");"); + } else { + out.println(indent + ") {"); + + String iii = indent + indent; + + String fname = jfunc.getName(); + if (isPointerFunc) { + // TODO - deal with VBO variants + if (fname.equals("glColorPointer")) { + out.println(iii + "if ((size == 4) &&"); + out.println(iii + " ((type == GL_FLOAT) ||"); + out.println(iii + " (type == GL_UNSIGNED_BYTE) ||"); + out.println(iii + " (type == GL_FIXED)) &&"); + out.println(iii + " (stride >= 0)) {"); + out.println(iii + indent + "_colorPointer = pointer;"); + out.println(iii + "}"); + } else if (fname.equals("glNormalPointer")) { + out.println(iii + "if (((type == GL_FLOAT) ||"); + out.println(iii + " (type == GL_BYTE) ||"); + out.println(iii + " (type == GL_SHORT) ||"); + out.println(iii + " (type == GL_FIXED)) &&"); + out.println(iii + " (stride >= 0)) {"); + out.println(iii + indent + "_normalPointer = pointer;"); + out.println(iii + "}"); + } else if (fname.equals("glTexCoordPointer")) { + out.println(iii + "if (((size == 2) ||"); + out.println(iii + " (size == 3) ||"); + out.println(iii + " (size == 4)) &&"); + out.println(iii + " ((type == GL_FLOAT) ||"); + out.println(iii + " (type == GL_BYTE) ||"); + out.println(iii + " (type == GL_SHORT) ||"); + out.println(iii + " (type == GL_FIXED)) &&"); + out.println(iii + " (stride >= 0)) {"); + out.println(iii + indent + "_texCoordPointer = pointer;"); + out.println(iii + "}"); + } else if (fname.equals("glVertexPointer")) { + out.println(iii + "if (((size == 2) ||"); + out.println(iii + " (size == 3) ||"); + out.println(iii + " (size == 4)) &&"); + out.println(iii + " ((type == GL_FLOAT) ||"); + out.println(iii + " (type == GL_BYTE) ||"); + out.println(iii + " (type == GL_SHORT) ||"); + out.println(iii + " (type == GL_FIXED)) &&"); + out.println(iii + " (stride >= 0)) {"); + out.println(iii + indent + "_vertexPointer = pointer;"); + out.println(iii + "}"); + } + } + + // emitBoundsChecks(jfunc, out, iii); + emitFunctionCall(jfunc, out, iii, false); + + boolean isVoid = jfunc.getType().isVoid(); + + if (!isVoid) { + out.println(indent + indent + "return _returnValue;"); + } + out.println(indent + "}"); + } + out.println(); + } + + public static String getJniName(JType jType) { + String jniName = ""; + if (jType.isClass()) { + return "L" + jType.getBaseType() + ";"; + } else if (jType.isArray()) { + jniName = "["; + } + + String baseType = jType.getBaseType(); + if (baseType.equals("int")) { + jniName += "I"; + } else if (baseType.equals("float")) { + jniName += "F"; + } else if (baseType.equals("boolean")) { + jniName += "Z"; + } else if (baseType.equals("short")) { + jniName += "S"; + } else if (baseType.equals("long")) { + jniName += "L"; + } else if (baseType.equals("byte")) { + jniName += "B"; + } + return jniName; + } + + String getJniType(JType jType) { + if (jType.isVoid()) { + return "void"; + } + + String baseType = jType.getBaseType(); + if (jType.isPrimitive()) { + if (baseType.equals("String")) { + return "jstring"; + } else { + return "j" + baseType; + } + } else if (jType.isArray()) { + return "j" + baseType + "Array"; + } else { + return "jobject"; + } + } + + String getJniMangledName(String name) { + name = name.replaceAll("_", "_1"); + name = name.replaceAll(";", "_2"); + name = name.replaceAll("\\[", "_3"); + return name; + } + + public void emitJniCode(JFunc jfunc, PrintStream out) { + CFunc cfunc = jfunc.getCFunc(); + + // Emit comment identifying original C function + // + // Example: + // + // /* void glClipPlanef ( GLenum plane, const GLfloat *equation ) */ + // + out.println("/* " + cfunc.getOriginal() + " */"); + + // Emit JNI signature (name) + // + // Example: + // + // void + // android_glClipPlanef__I_3FI + // + + String outName = "android_" + jfunc.getName(); + boolean isPointerFunc = outName.endsWith("Pointer") && + jfunc.getCFunc().hasPointerArg(); + boolean isVBOPointerFunc = (outName.endsWith("Pointer") || + outName.endsWith("DrawElements")) && + !jfunc.getCFunc().hasPointerArg(); + if (isPointerFunc) { + outName += "Bounds"; + } + + out.print("static "); + out.println(getJniType(jfunc.getType())); + out.print(outName); + + String rsignature = getJniName(jfunc.getType()); + + String signature = ""; + int numArgs = jfunc.getNumArgs(); + for (int i = 0; i < numArgs; i++) { + JType argType = jfunc.getArgType(i); + signature += getJniName(argType); + } + if (isPointerFunc) { + signature += "I"; + } + + // Append signature to function name + String sig = getJniMangledName(signature).replace('.', '_'); + out.print("__" + sig); + outName += "__" + sig; + + signature = signature.replace('.', '/'); + rsignature = rsignature.replace('.', '/'); + + out.println(); + if (rsignature.length() == 0) { + rsignature = "V"; + } + + String s = "{\"" + + jfunc.getName() + + (isPointerFunc ? "Bounds" : "") + + "\", \"(" + signature +")" + + rsignature + + "\", (void *) " + + outName + + " },"; + nativeRegistrations.add(s); + + List nonPrimitiveArgs = new ArrayList(); + int numBufferArgs = 0; + List bufferArgNames = new ArrayList(); + + // Emit JNI signature (arguments) + // + // Example: + // + // (JNIEnv *_env, jobject this, jint plane, jfloatArray equation_ref, jint offset) { + // + out.print(" (JNIEnv *_env, jobject _this"); + for (int i = 0; i < numArgs; i++) { + out.print(", "); + JType argType = jfunc.getArgType(i); + String suffix; + if (!argType.isPrimitive()) { + if (argType.isArray()) { + suffix = "_ref"; + } else { + suffix = "_buf"; + } + nonPrimitiveArgs.add(new Integer(i)); + if (jfunc.getArgType(i).isBuffer()) { + int cIndex = jfunc.getArgCIndex(i); + String cname = cfunc.getArgName(cIndex); + bufferArgNames.add(cname); + numBufferArgs++; + } + } else { + suffix = ""; + } + + out.print(getJniType(argType) + " " + jfunc.getArgName(i) + suffix); + } + if (isPointerFunc) { + out.print(", jint remaining"); + } + out.println(") {"); + + int numArrays = 0; + int numBuffers = 0; + for (int i = 0; i < nonPrimitiveArgs.size(); i++) { + int idx = nonPrimitiveArgs.get(i).intValue(); + int cIndex = jfunc.getArgCIndex(idx); + String cname = cfunc.getArgName(cIndex); + if (jfunc.getArgType(idx).isArray()) { + ++numArrays; + } + if (jfunc.getArgType(idx).isBuffer()) { + ++numBuffers; + } + } + + // Emit method body + + // Emit local variable declarations for _exception and _returnValue + // + // Example: + // + // android::gl::ogles_context_t *ctx; + // + // jint _exception; + // GLenum _returnValue; + // + CType returnType = cfunc.getType(); + boolean isVoid = returnType.isVoid(); + + boolean isUnsupported = isUnsupportedFunc(cfunc); + if (isUnsupported) { + out.println(indent + + "_env->ThrowNew(UOEClass,"); + out.println(indent + + " \"" + cfunc.getName() + "\");"); + if (!isVoid) { + String retval = getErrorReturnValue(cfunc); + out.println(indent + "return " + retval + ";"); + } + out.println("}"); + out.println(); + return; + } + + if (mUseContextPointer) { + out.println(indent + + "android::gl::ogles_context_t *ctx = getContext(_env, _this);"); + } + + boolean emitExceptionCheck = (numArrays > 0 || numBuffers > 0) && + hasNonConstArg(jfunc, cfunc, nonPrimitiveArgs); + // mChecker.getChecks(cfunc.getName()) != null + + // Emit an _exeption variable if there will be error checks + if (emitExceptionCheck) { + out.println(indent + "jint _exception = 0;"); + } + + // Emit a single _array or multiple _XXXArray variables + if (numBufferArgs == 1) { + out.println(indent + "jarray _array = (jarray) 0;"); + } else { + for (int i = 0; i < numBufferArgs; i++) { + out.println(indent + "jarray _" + bufferArgNames.get(i) + + "Array = (jarray) 0;"); + } + } + if (!isVoid) { + String retval = getErrorReturnValue(cfunc); + if (retval != null) { + out.println(indent + returnType.getDeclaration() + + " _returnValue = " + retval + ";"); + } else { + out.println(indent + returnType.getDeclaration() + + " _returnValue;"); + } + } + + // Emit local variable declarations for pointer arguments + // + // Example: + // + // GLfixed *eqn_base; + // GLfixed *eqn; + // + String offset = "offset"; + String remaining = "_remaining"; + if (nonPrimitiveArgs.size() > 0) { + for (int i = 0; i < nonPrimitiveArgs.size(); i++) { + int idx = nonPrimitiveArgs.get(i).intValue(); + int cIndex = jfunc.getArgCIndex(idx); + String cname = cfunc.getArgName(cIndex); + + CType type = cfunc.getArgType(jfunc.getArgCIndex(idx)); + String decl = type.getDeclaration(); + if (jfunc.getArgType(idx).isArray()) { + out.println(indent + + decl + + (decl.endsWith("*") ? "" : " ") + + jfunc.getArgName(idx) + + "_base = (" + decl + ") 0;"); + } + remaining = (numArrays <= 1 && numBuffers <= 1) ? "_remaining" : + "_" + cname + "Remaining"; + out.println(indent + + "jint " + remaining + ";"); + out.println(indent + + decl + + (decl.endsWith("*") ? "" : " ") + + jfunc.getArgName(idx) + + " = (" + decl + ") 0;"); + } + + out.println(); + } + + String retval = isVoid ? "" : " _returnValue"; + + // Emit 'GetPrimitiveArrayCritical' for arrays + // Emit 'GetPointer' calls for Buffer pointers + int bufArgIdx = 0; + if (nonPrimitiveArgs.size() > 0) { + for (int i = 0; i < nonPrimitiveArgs.size(); i++) { + int idx = nonPrimitiveArgs.get(i).intValue(); + int cIndex = jfunc.getArgCIndex(idx); + + String cname = cfunc.getArgName(cIndex); + offset = numArrays <= 1 ? "offset" : + cname + "Offset"; + remaining = (numArrays <= 1 && numBuffers <= 1) ? "_remaining" : + "_" + cname + "Remaining"; + + if (jfunc.getArgType(idx).isArray()) { + out.println(indent + + "if (!" + + cname + + "_ref) {"); + if (emitExceptionCheck) { + out.println(indent + indent + "_exception = 1;"); + } + out.println(indent + " " + + (mUseCPlusPlus ? "_env" : "(*_env)") + + "->ThrowNew(" + + (mUseCPlusPlus ? "" : "_env, ") + + "IAEClass, " + + "\"" + cname + + " == null\");"); + out.println(indent + " goto exit;"); + needsExit = true; + out.println(indent + "}"); + + out.println(indent + "if (" + offset + " < 0) {"); + if (emitExceptionCheck) { + out.println(indent + indent + "_exception = 1;"); + } + out.println(indent + " " + + (mUseCPlusPlus ? "_env" : "(*_env)") + + "->ThrowNew(" + + (mUseCPlusPlus ? "" : "_env, ") + + "IAEClass, " + + "\"" + offset + " < 0\");"); + out.println(indent + " goto exit;"); + needsExit = true; + out.println(indent + "}"); + + out.println(indent + remaining + " = " + + (mUseCPlusPlus ? "_env" : "(*_env)") + + "->GetArrayLength(" + + (mUseCPlusPlus ? "" : "_env, ") + + cname + "_ref) - " + offset + ";"); + + emitNativeBoundsChecks(cfunc, cname, out, false, + emitExceptionCheck, + offset, remaining, " "); + + out.println(indent + + cname + + "_base = (" + + cfunc.getArgType(cIndex).getDeclaration() + + ")"); + out.println(indent + " " + + (mUseCPlusPlus ? "_env" : "(*_env)") + + "->GetPrimitiveArrayCritical(" + + (mUseCPlusPlus ? "" : "_env, ") + + jfunc.getArgName(idx) + + "_ref, (jboolean *)0);"); + out.println(indent + + cname + " = " + cname + "_base + " + offset + + ";"); + out.println(); + } else { + String array = numBufferArgs <= 1 ? "_array" : + "_" + bufferArgNames.get(bufArgIdx++) + "Array"; + + boolean nullAllowed = isNullAllowed(cfunc); + if (nullAllowed) { + out.println(indent + "if (" + cname + "_buf) {"); + out.print(indent); + } + + out.println(indent + + cname + + " = (" + + cfunc.getArgType(cIndex).getDeclaration() + + ")getPointer(_env, " + + cname + + "_buf, &" + array + ", &" + remaining + ");"); + + if (nullAllowed) { + out.println(indent + "}"); + } + + emitNativeBoundsChecks(cfunc, cname, out, true, + emitExceptionCheck, + offset, remaining, " "); + } + } + } + + if (!isVoid) { + out.print(indent + "_returnValue = "); + } else { + out.print(indent); + } + String name = cfunc.getName(); + + if (mUseContextPointer) { + name = name.substring(2, name.length()); // Strip off 'gl' prefix + name = name.substring(0, 1).toLowerCase() + + name.substring(1, name.length()); + out.print("ctx->procs."); + } + + out.print(name + (isPointerFunc ? "Bounds" : "") + "("); + + numArgs = cfunc.getNumArgs(); + if (numArgs == 0) { + if (mUseContextPointer) { + out.println("ctx);"); + } else { + out.println(");"); + } + } else { + if (mUseContextPointer) { + out.println("ctx,"); + } else { + out.println(); + } + for (int i = 0; i < numArgs; i++) { + String typecast; + if (i == numArgs - 1 && isVBOPointerFunc) { + typecast = "const GLvoid *"; + } else { + typecast = cfunc.getArgType(i).getDeclaration(); + } + out.print(indent + indent + + "(" + + typecast + + ")" + + cfunc.getArgName(i)); + + if (i == numArgs - 1) { + if (isPointerFunc) { + out.println(","); + out.println(indent + indent + "(GLsizei)remaining"); + } else { + out.println(); + } + } else { + out.println(","); + } + } + out.println(indent + ");"); + } + + if (needsExit) { + out.println(); + out.println("exit:"); + needsExit = false; + } + + bufArgIdx = 0; + if (nonPrimitiveArgs.size() > 0) { + for (int i = nonPrimitiveArgs.size() - 1; i >= 0; i--) { + int idx = nonPrimitiveArgs.get(i).intValue(); + + int cIndex = jfunc.getArgCIndex(idx); + if (jfunc.getArgType(idx).isArray()) { + + // If the argument is 'const', GL will not write to it. + // In this case, we can use the 'JNI_ABORT' flag to avoid + // the need to write back to the Java array + out.println(indent + + "if (" + jfunc.getArgName(idx) + "_base) {"); + out.println(indent + indent + + (mUseCPlusPlus ? "_env" : "(*_env)") + + "->ReleasePrimitiveArrayCritical(" + + (mUseCPlusPlus ? "" : "_env, ") + + jfunc.getArgName(idx) + "_ref, " + + cfunc.getArgName(cIndex) + + "_base,"); + out.println(indent + indent + indent + + (cfunc.getArgType(cIndex).isConst() ? + "JNI_ABORT" : + "_exception ? JNI_ABORT: 0") + + ");"); + out.println(indent + "}"); + } else if (jfunc.getArgType(idx).isBuffer()) { + String array = numBufferArgs <= 1 ? "_array" : + "_" + bufferArgNames.get(bufArgIdx++) + "Array"; + out.println(indent + "if (" + array + ") {"); + out.println(indent + indent + + "releasePointer(_env, " + array + ", " + + cfunc.getArgName(cIndex) + + ", " + + (cfunc.getArgType(cIndex).isConst() ? + "JNI_FALSE" : "_exception ? JNI_FALSE : JNI_TRUE") + + ");"); + out.println(indent + "}"); + } + } + } + + if (!isVoid) { + out.println(indent + "return _returnValue;"); + } + + out.println("}"); + out.println(); + } + + public void addNativeRegistration(String s) { + nativeRegistrations.add(s); + } + + public void emitNativeRegistration() { + mCStream.println("static const char *classPathName = \"" + + mClassPathName + + "\";"); + mCStream.println(); + + mCStream.println("static JNINativeMethod methods[] = {"); + + mCStream.println("{\"_nativeClassInit\", \"()V\", (void*)nativeClassInit },"); + + Iterator i = nativeRegistrations.iterator(); + while (i.hasNext()) { + mCStream.println(i.next()); + } + + mCStream.println("};"); + mCStream.println(); + + + mCStream.println("int register_com_google_android_gles_jni_GLImpl(JNIEnv *_env)"); + mCStream.println("{"); + mCStream.println(indent + + "int err;"); + + mCStream.println(indent + + "err = android::AndroidRuntime::registerNativeMethods(_env, classPathName, methods, NELEM(methods));"); + + mCStream.println(indent + "return err;"); + mCStream.println("}"); + } +} diff --git a/opengl/tools/glgen/src/ParameterChecker.java b/opengl/tools/glgen/src/ParameterChecker.java new file mode 100644 index 0000000000000000000000000000000000000000..df26acdf46aba3da47919ad190b67bbfc906bb79 --- /dev/null +++ b/opengl/tools/glgen/src/ParameterChecker.java @@ -0,0 +1,28 @@ + +import java.io.BufferedReader; +import java.util.HashMap; + +public class ParameterChecker { + + HashMap map = new HashMap(); + + public ParameterChecker(BufferedReader reader) throws Exception { + String s; + while ((s = reader.readLine()) != null) { + String[] tokens = s.split("\\s"); + map.put(tokens[0], tokens); + } + } + + public String[] getChecks(String functionName) { + String[] checks = map.get(functionName); + if (checks == null && + (functionName.endsWith("fv") || + functionName.endsWith("xv") || + functionName.endsWith("iv"))) { + functionName = functionName.substring(0, functionName.length() - 2); + checks = map.get(functionName); + } + return checks; + } +} diff --git a/opengl/tools/glgen/stubs/GL10ExtHeader.java-if b/opengl/tools/glgen/stubs/GL10ExtHeader.java-if new file mode 100644 index 0000000000000000000000000000000000000000..b0999c25f6a732a8e7fc973a7cfaa106cda1ddeb --- /dev/null +++ b/opengl/tools/glgen/stubs/GL10ExtHeader.java-if @@ -0,0 +1,22 @@ +** +** Copyright 2007, 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 source file is automatically generated + +package javax.microedition.khronos.opengles; + +public interface GL10Ext extends GL { + diff --git a/opengl/tools/glgen/stubs/GL10Header.java-if b/opengl/tools/glgen/stubs/GL10Header.java-if new file mode 100644 index 0000000000000000000000000000000000000000..8392821e7a589ff19333929dd8f8a84b01fd6b68 --- /dev/null +++ b/opengl/tools/glgen/stubs/GL10Header.java-if @@ -0,0 +1,259 @@ +** +** Copyright 2006, 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 source file is automatically generated + +package javax.microedition.khronos.opengles; + +public interface GL10 extends GL { + int GL_ADD = 0x0104; + int GL_ALIASED_LINE_WIDTH_RANGE = 0x846E; + int GL_ALIASED_POINT_SIZE_RANGE = 0x846D; + int GL_ALPHA = 0x1906; + int GL_ALPHA_BITS = 0x0D55; + int GL_ALPHA_TEST = 0x0BC0; + int GL_ALWAYS = 0x0207; + int GL_AMBIENT = 0x1200; + int GL_AMBIENT_AND_DIFFUSE = 0x1602; + int GL_AND = 0x1501; + int GL_AND_INVERTED = 0x1504; + int GL_AND_REVERSE = 0x1502; + int GL_BACK = 0x0405; + int GL_BLEND = 0x0BE2; + int GL_BLUE_BITS = 0x0D54; + int GL_BYTE = 0x1400; + int GL_CCW = 0x0901; + int GL_CLAMP_TO_EDGE = 0x812F; + int GL_CLEAR = 0x1500; + int GL_COLOR_ARRAY = 0x8076; + int GL_COLOR_BUFFER_BIT = 0x4000; + int GL_COLOR_LOGIC_OP = 0x0BF2; + int GL_COLOR_MATERIAL = 0x0B57; + int GL_COMPRESSED_TEXTURE_FORMATS = 0x86A3; + int GL_CONSTANT_ATTENUATION = 0x1207; + int GL_COPY = 0x1503; + int GL_COPY_INVERTED = 0x150C; + int GL_CULL_FACE = 0x0B44; + int GL_CW = 0x0900; + int GL_DECAL = 0x2101; + int GL_DECR = 0x1E03; + int GL_DEPTH_BITS = 0x0D56; + int GL_DEPTH_BUFFER_BIT = 0x0100; + int GL_DEPTH_TEST = 0x0B71; + int GL_DIFFUSE = 0x1201; + int GL_DITHER = 0x0BD0; + int GL_DONT_CARE = 0x1100; + int GL_DST_ALPHA = 0x0304; + int GL_DST_COLOR = 0x0306; + int GL_EMISSION = 0x1600; + int GL_EQUAL = 0x0202; + int GL_EQUIV = 0x1509; + int GL_EXP = 0x0800; + int GL_EXP2 = 0x0801; + int GL_EXTENSIONS = 0x1F03; + int GL_FALSE = 0; + int GL_FASTEST = 0x1101; + int GL_FIXED = 0x140C; + int GL_FLAT = 0x1D00; + int GL_FLOAT = 0x1406; + int GL_FOG = 0x0B60; + int GL_FOG_COLOR = 0x0B66; + int GL_FOG_DENSITY = 0x0B62; + int GL_FOG_END = 0x0B64; + int GL_FOG_HINT = 0x0C54; + int GL_FOG_MODE = 0x0B65; + int GL_FOG_START = 0x0B63; + int GL_FRONT = 0x0404; + int GL_FRONT_AND_BACK = 0x0408; + int GL_GEQUAL = 0x0206; + int GL_GREATER = 0x0204; + int GL_GREEN_BITS = 0x0D53; + int GL_IMPLEMENTATION_COLOR_READ_FORMAT_OES = 0x8B9B; + int GL_IMPLEMENTATION_COLOR_READ_TYPE_OES = 0x8B9A; + int GL_INCR = 0x1E02; + int GL_INVALID_ENUM = 0x0500; + int GL_INVALID_OPERATION = 0x0502; + int GL_INVALID_VALUE = 0x0501; + int GL_INVERT = 0x150A; + int GL_KEEP = 0x1E00; + int GL_LEQUAL = 0x0203; + int GL_LESS = 0x0201; + int GL_LIGHT_MODEL_AMBIENT = 0x0B53; + int GL_LIGHT_MODEL_TWO_SIDE = 0x0B52; + int GL_LIGHT0 = 0x4000; + int GL_LIGHT1 = 0x4001; + int GL_LIGHT2 = 0x4002; + int GL_LIGHT3 = 0x4003; + int GL_LIGHT4 = 0x4004; + int GL_LIGHT5 = 0x4005; + int GL_LIGHT6 = 0x4006; + int GL_LIGHT7 = 0x4007; + int GL_LIGHTING = 0x0B50; + int GL_LINE_LOOP = 0x0002; + int GL_LINE_SMOOTH = 0x0B20; + int GL_LINE_SMOOTH_HINT = 0x0C52; + int GL_LINE_STRIP = 0x0003; + int GL_LINEAR = 0x2601; + int GL_LINEAR_ATTENUATION = 0x1208; + int GL_LINEAR_MIPMAP_LINEAR = 0x2703; + int GL_LINEAR_MIPMAP_NEAREST = 0x2701; + int GL_LINES = 0x0001; + int GL_LUMINANCE = 0x1909; + int GL_LUMINANCE_ALPHA = 0x190A; + int GL_MAX_ELEMENTS_INDICES = 0x80E9; + int GL_MAX_ELEMENTS_VERTICES = 0x80E8; + int GL_MAX_LIGHTS = 0x0D31; + int GL_MAX_MODELVIEW_STACK_DEPTH = 0x0D36; + int GL_MAX_PROJECTION_STACK_DEPTH = 0x0D38; + int GL_MAX_TEXTURE_SIZE = 0x0D33; + int GL_MAX_TEXTURE_STACK_DEPTH = 0x0D39; + int GL_MAX_TEXTURE_UNITS = 0x84E2; + int GL_MAX_VIEWPORT_DIMS = 0x0D3A; + int GL_MODELVIEW = 0x1700; + int GL_MODULATE = 0x2100; + int GL_MULTISAMPLE = 0x809D; + int GL_NAND = 0x150E; + int GL_NEAREST = 0x2600; + int GL_NEAREST_MIPMAP_LINEAR = 0x2702; + int GL_NEAREST_MIPMAP_NEAREST = 0x2700; + int GL_NEVER = 0x0200; + int GL_NICEST = 0x1102; + int GL_NO_ERROR = 0; + int GL_NOOP = 0x1505; + int GL_NOR = 0x1508; + int GL_NORMAL_ARRAY = 0x8075; + int GL_NORMALIZE = 0x0BA1; + int GL_NOTEQUAL = 0x0205; + int GL_NUM_COMPRESSED_TEXTURE_FORMATS = 0x86A2; + int GL_ONE = 1; + int GL_ONE_MINUS_DST_ALPHA = 0x0305; + int GL_ONE_MINUS_DST_COLOR = 0x0307; + int GL_ONE_MINUS_SRC_ALPHA = 0x0303; + int GL_ONE_MINUS_SRC_COLOR = 0x0301; + int GL_OR = 0x1507; + int GL_OR_INVERTED = 0x150D; + int GL_OR_REVERSE = 0x150B; + int GL_OUT_OF_MEMORY = 0x0505; + int GL_PACK_ALIGNMENT = 0x0D05; + int GL_PALETTE4_R5_G6_B5_OES = 0x8B92; + int GL_PALETTE4_RGB5_A1_OES = 0x8B94; + int GL_PALETTE4_RGB8_OES = 0x8B90; + int GL_PALETTE4_RGBA4_OES = 0x8B93; + int GL_PALETTE4_RGBA8_OES = 0x8B91; + int GL_PALETTE8_R5_G6_B5_OES = 0x8B97; + int GL_PALETTE8_RGB5_A1_OES = 0x8B99; + int GL_PALETTE8_RGB8_OES = 0x8B95; + int GL_PALETTE8_RGBA4_OES = 0x8B98; + int GL_PALETTE8_RGBA8_OES = 0x8B96; + int GL_PERSPECTIVE_CORRECTION_HINT = 0x0C50; + int GL_POINT_SMOOTH = 0x0B10; + int GL_POINT_SMOOTH_HINT = 0x0C51; + int GL_POINTS = 0x0000; + int GL_POINT_FADE_THRESHOLD_SIZE = 0x8128; + int GL_POINT_SIZE = 0x0B11; + int GL_POLYGON_OFFSET_FILL = 0x8037; + int GL_POLYGON_SMOOTH_HINT = 0x0C53; + int GL_POSITION = 0x1203; + int GL_PROJECTION = 0x1701; + int GL_QUADRATIC_ATTENUATION = 0x1209; + int GL_RED_BITS = 0x0D52; + int GL_RENDERER = 0x1F01; + int GL_REPEAT = 0x2901; + int GL_REPLACE = 0x1E01; + int GL_RESCALE_NORMAL = 0x803A; + int GL_RGB = 0x1907; + int GL_RGBA = 0x1908; + int GL_SAMPLE_ALPHA_TO_COVERAGE = 0x809E; + int GL_SAMPLE_ALPHA_TO_ONE = 0x809F; + int GL_SAMPLE_COVERAGE = 0x80A0; + int GL_SCISSOR_TEST = 0x0C11; + int GL_SET = 0x150F; + int GL_SHININESS = 0x1601; + int GL_SHORT = 0x1402; + int GL_SMOOTH = 0x1D01; + int GL_SMOOTH_LINE_WIDTH_RANGE = 0x0B22; + int GL_SMOOTH_POINT_SIZE_RANGE = 0x0B12; + int GL_SPECULAR = 0x1202; + int GL_SPOT_CUTOFF = 0x1206; + int GL_SPOT_DIRECTION = 0x1204; + int GL_SPOT_EXPONENT = 0x1205; + int GL_SRC_ALPHA = 0x0302; + int GL_SRC_ALPHA_SATURATE = 0x0308; + int GL_SRC_COLOR = 0x0300; + int GL_STACK_OVERFLOW = 0x0503; + int GL_STACK_UNDERFLOW = 0x0504; + int GL_STENCIL_BITS = 0x0D57; + int GL_STENCIL_BUFFER_BIT = 0x0400; + int GL_STENCIL_TEST = 0x0B90; + int GL_SUBPIXEL_BITS = 0x0D50; + int GL_TEXTURE = 0x1702; + int GL_TEXTURE_2D = 0x0DE1; + int GL_TEXTURE_COORD_ARRAY = 0x8078; + int GL_TEXTURE_ENV = 0x2300; + int GL_TEXTURE_ENV_COLOR = 0x2201; + int GL_TEXTURE_ENV_MODE = 0x2200; + int GL_TEXTURE_MAG_FILTER = 0x2800; + int GL_TEXTURE_MIN_FILTER = 0x2801; + int GL_TEXTURE_WRAP_S = 0x2802; + int GL_TEXTURE_WRAP_T = 0x2803; + int GL_TEXTURE0 = 0x84C0; + int GL_TEXTURE1 = 0x84C1; + int GL_TEXTURE2 = 0x84C2; + int GL_TEXTURE3 = 0x84C3; + int GL_TEXTURE4 = 0x84C4; + int GL_TEXTURE5 = 0x84C5; + int GL_TEXTURE6 = 0x84C6; + int GL_TEXTURE7 = 0x84C7; + int GL_TEXTURE8 = 0x84C8; + int GL_TEXTURE9 = 0x84C9; + int GL_TEXTURE10 = 0x84CA; + int GL_TEXTURE11 = 0x84CB; + int GL_TEXTURE12 = 0x84CC; + int GL_TEXTURE13 = 0x84CD; + int GL_TEXTURE14 = 0x84CE; + int GL_TEXTURE15 = 0x84CF; + int GL_TEXTURE16 = 0x84D0; + int GL_TEXTURE17 = 0x84D1; + int GL_TEXTURE18 = 0x84D2; + int GL_TEXTURE19 = 0x84D3; + int GL_TEXTURE20 = 0x84D4; + int GL_TEXTURE21 = 0x84D5; + int GL_TEXTURE22 = 0x84D6; + int GL_TEXTURE23 = 0x84D7; + int GL_TEXTURE24 = 0x84D8; + int GL_TEXTURE25 = 0x84D9; + int GL_TEXTURE26 = 0x84DA; + int GL_TEXTURE27 = 0x84DB; + int GL_TEXTURE28 = 0x84DC; + int GL_TEXTURE29 = 0x84DD; + int GL_TEXTURE30 = 0x84DE; + int GL_TEXTURE31 = 0x84DF; + int GL_TRIANGLE_FAN = 0x0006; + int GL_TRIANGLE_STRIP = 0x0005; + int GL_TRIANGLES = 0x0004; + int GL_TRUE = 1; + int GL_UNPACK_ALIGNMENT = 0x0CF5; + int GL_UNSIGNED_BYTE = 0x1401; + int GL_UNSIGNED_SHORT = 0x1403; + int GL_UNSIGNED_SHORT_4_4_4_4 = 0x8033; + int GL_UNSIGNED_SHORT_5_5_5_1 = 0x8034; + int GL_UNSIGNED_SHORT_5_6_5 = 0x8363; + int GL_VENDOR = 0x1F00; + int GL_VERSION = 0x1F02; + int GL_VERTEX_ARRAY = 0x8074; + int GL_XOR = 0x1506; + int GL_ZERO = 0; + diff --git a/opengl/tools/glgen/stubs/GL11ExtHeader.java-if b/opengl/tools/glgen/stubs/GL11ExtHeader.java-if new file mode 100644 index 0000000000000000000000000000000000000000..7be2164f6307ff9a8c97d8ce543ddc194dcbe0b9 --- /dev/null +++ b/opengl/tools/glgen/stubs/GL11ExtHeader.java-if @@ -0,0 +1,40 @@ +** +** Copyright 2007, 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 source file is automatically generated + +package javax.microedition.khronos.opengles; + +public interface GL11Ext extends GL { + int GL_MATRIX_INDEX_ARRAY_BUFFER_BINDING_OES = 0x8B9E; + int GL_MATRIX_INDEX_ARRAY_OES = 0x8844; + int GL_MATRIX_INDEX_ARRAY_POINTER_OES = 0x8849; + int GL_MATRIX_INDEX_ARRAY_SIZE_OES = 0x8846; + int GL_MATRIX_INDEX_ARRAY_STRIDE_OES = 0x8848; + int GL_MATRIX_INDEX_ARRAY_TYPE_OES = 0x8847; + int GL_MATRIX_PALETTE_OES = 0x8840; + int GL_MAX_PALETTE_MATRICES_OES = 0x8842; + int GL_MAX_VERTEX_UNITS_OES = 0x86A4; + int GL_TEXTURE_CROP_RECT_OES = 0x8B9D; + int GL_WEIGHT_ARRAY_BUFFER_BINDING_OES = 0x889E; + int GL_WEIGHT_ARRAY_OES = 0x86AD; + int GL_WEIGHT_ARRAY_POINTER_OES = 0x86AC; + int GL_WEIGHT_ARRAY_SIZE_OES = 0x86AB; + int GL_WEIGHT_ARRAY_STRIDE_OES = 0x86AA; + int GL_WEIGHT_ARRAY_TYPE_OES = 0x86A9; + + void glTexParameterfv(int target, int pname, float[] param, int offset); + diff --git a/opengl/tools/glgen/stubs/GL11ExtensionPackHeader.java-if b/opengl/tools/glgen/stubs/GL11ExtensionPackHeader.java-if new file mode 100644 index 0000000000000000000000000000000000000000..a8001919c7cf73dd3da5fd0f730fc6ccce9bab71 --- /dev/null +++ b/opengl/tools/glgen/stubs/GL11ExtensionPackHeader.java-if @@ -0,0 +1,108 @@ +** +** Copyright 2007, 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 source file is automatically generated + +package javax.microedition.khronos.opengles; + +public interface GL11ExtensionPack extends GL { + int GL_BLEND_DST_ALPHA = 0x80CA; + int GL_BLEND_DST_RGB = 0x80C8; + int GL_BLEND_EQUATION = 0x8009; + int GL_BLEND_EQUATION_ALPHA = 0x883D; + int GL_BLEND_EQUATION_RGB = 0x8009; + int GL_BLEND_SRC_ALPHA = 0x80CB; + int GL_BLEND_SRC_RGB = 0x80C9; + int GL_COLOR_ATTACHMENT0_OES = 0x8CE0; + int GL_COLOR_ATTACHMENT1_OES = 0x8CE1; + int GL_COLOR_ATTACHMENT2_OES = 0x8CE2; + int GL_COLOR_ATTACHMENT3_OES = 0x8CE3; + int GL_COLOR_ATTACHMENT4_OES = 0x8CE4; + int GL_COLOR_ATTACHMENT5_OES = 0x8CE5; + int GL_COLOR_ATTACHMENT6_OES = 0x8CE6; + int GL_COLOR_ATTACHMENT7_OES = 0x8CE7; + int GL_COLOR_ATTACHMENT8_OES = 0x8CE8; + int GL_COLOR_ATTACHMENT9_OES = 0x8CE9; + int GL_COLOR_ATTACHMENT10_OES = 0x8CEA; + int GL_COLOR_ATTACHMENT11_OES = 0x8CEB; + int GL_COLOR_ATTACHMENT12_OES = 0x8CEC; + int GL_COLOR_ATTACHMENT13_OES = 0x8CED; + int GL_COLOR_ATTACHMENT14_OES = 0x8CEE; + int GL_COLOR_ATTACHMENT15_OES = 0x8CEF; + int GL_DECR_WRAP = 0x8508; + int GL_DEPTH_ATTACHMENT_OES = 0x8D00; + int GL_DEPTH_COMPONENT = 0x1902; + int GL_DEPTH_COMPONENT16 = 0x81A5; + int GL_DEPTH_COMPONENT24 = 0x81A6; + int GL_DEPTH_COMPONENT32 = 0x81A7; + int GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME_OES = 0x8CD1; + int GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE_OES = 0x8CD0; + int GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE_OES = 0x8CD3; + int GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL_OES = 0x8CD2; + int GL_FRAMEBUFFER_BINDING_OES = 0x8CA6; + int GL_FRAMEBUFFER_COMPLETE_OES = 0x8CD5; + int GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_OES = 0x8CD6; + int GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_OES = 0x8CD9; + int GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_OES = 0x8CDB; + int GL_FRAMEBUFFER_INCOMPLETE_FORMATS_OES = 0x8CDA; + int GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_OES = 0x8CD7; + int GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_OES = 0x8CDC; + int GL_FRAMEBUFFER_OES = 0x8D40; + int GL_FRAMEBUFFER_UNSUPPORTED_OES = 0x8CDD; + int GL_FUNC_ADD = 0x8006; + int GL_FUNC_REVERSE_SUBTRACT = 0x800B; + int GL_FUNC_SUBTRACT = 0x800A; + int GL_INCR_WRAP = 0x8507; + int GL_INVALID_FRAMEBUFFER_OPERATION_OES = 0x0506; + int GL_MAX_COLOR_ATTACHMENTS_OES = 0x8CDF; + int GL_MAX_CUBE_MAP_TEXTURE_SIZE = 0x851C; + int GL_MAX_RENDERBUFFER_SIZE_OES = 0x84E8; + int GL_MIRRORED_REPEAT = 0x8370; + int GL_NORMAL_MAP = 0x8511; + int GL_REFLECTION_MAP = 0x8512; + int GL_RENDERBUFFER_ALPHA_SIZE_OES = 0x8D53; + int GL_RENDERBUFFER_BINDING_OES = 0x8CA7; + int GL_RENDERBUFFER_BLUE_SIZE_OES = 0x8D52; + int GL_RENDERBUFFER_DEPTH_SIZE_OES = 0x8D54; + int GL_RENDERBUFFER_GREEN_SIZE_OES = 0x8D51; + int GL_RENDERBUFFER_HEIGHT_OES = 0x8D43; + int GL_RENDERBUFFER_INTERNAL_FORMAT_OES = 0x8D44; + int GL_RENDERBUFFER_OES = 0x8D41; + int GL_RENDERBUFFER_RED_SIZE_OES = 0x8D50; + int GL_RENDERBUFFER_STENCIL_SIZE_OES = 0x8D55; + int GL_RENDERBUFFER_WIDTH_OES = 0x8D42; + int GL_RGB5_A1 = 0x8057; + int GL_RGB565_OES = 0x8D62; + int GL_RGB8 = 0x8051; + int GL_RGBA4 = 0x8056; + int GL_RGBA8 = 0x8058; + int GL_STENCIL_ATTACHMENT_OES = 0x8D20; + int GL_STENCIL_INDEX = 0x1901; + int GL_STENCIL_INDEX1_OES = 0x8D46; + int GL_STENCIL_INDEX4_OES = 0x8D47; + int GL_STENCIL_INDEX8_OES = 0x8D48; + int GL_STR = -1; + int GL_TEXTURE_BINDING_CUBE_MAP = 0x8514; + int GL_TEXTURE_CUBE_MAP = 0x8513; + int GL_TEXTURE_CUBE_MAP_NEGATIVE_X = 0x8516; + int GL_TEXTURE_CUBE_MAP_NEGATIVE_Y = 0x8518; + int GL_TEXTURE_CUBE_MAP_NEGATIVE_Z = 0x851A; + int GL_TEXTURE_CUBE_MAP_POSITIVE_X = 0x8515; + int GL_TEXTURE_CUBE_MAP_POSITIVE_Y = 0x8517; + int GL_TEXTURE_CUBE_MAP_POSITIVE_Z = 0x8519; + int GL_TEXTURE_GEN_MODE = 0x2500; + int GL_TEXTURE_GEN_STR = 0x8D60; + diff --git a/opengl/tools/glgen/stubs/GL11Header.java-if b/opengl/tools/glgen/stubs/GL11Header.java-if new file mode 100644 index 0000000000000000000000000000000000000000..b0e5a6bea775e6b77d1908a47eff9f3950cac093 --- /dev/null +++ b/opengl/tools/glgen/stubs/GL11Header.java-if @@ -0,0 +1,145 @@ +** +** Copyright 2006, 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 source file is automatically generated + +package javax.microedition.khronos.opengles; + +public interface GL11 extends GL10 { + int GL_ACTIVE_TEXTURE = 0x84E0; + int GL_ADD_SIGNED = 0x8574; + int GL_ALPHA_SCALE = 0x0D1C; + int GL_ALPHA_TEST_FUNC = 0x0BC1; + int GL_ALPHA_TEST_REF = 0x0BC2; + int GL_ARRAY_BUFFER = 0x8892; + int GL_ARRAY_BUFFER_BINDING = 0x8894; + int GL_BLEND_DST = 0x0BE0; + int GL_BLEND_SRC = 0x0BE1; + int GL_BUFFER_ACCESS = 0x88BB; + int GL_BUFFER_SIZE = 0x8764; + int GL_BUFFER_USAGE = 0x8765; + int GL_CLIENT_ACTIVE_TEXTURE = 0x84E1; + int GL_CLIP_PLANE0 = 0x3000; + int GL_CLIP_PLANE1 = 0x3001; + int GL_CLIP_PLANE2 = 0x3002; + int GL_CLIP_PLANE3 = 0x3003; + int GL_CLIP_PLANE4 = 0x3004; + int GL_CLIP_PLANE5 = 0x3005; + int GL_COLOR_ARRAY_BUFFER_BINDING = 0x8898; + int GL_COLOR_ARRAY_POINTER = 0x8090; + int GL_COLOR_ARRAY_SIZE = 0x8081; + int GL_COLOR_ARRAY_STRIDE = 0x8083; + int GL_COLOR_ARRAY_TYPE = 0x8082; + int GL_COLOR_CLEAR_VALUE = 0x0C22; + int GL_COLOR_WRITEMASK = 0x0C23; + int GL_COMBINE = 0x8570; + int GL_COMBINE_ALPHA = 0x8572; + int GL_COMBINE_RGB = 0x8571; + int GL_CONSTANT = 0x8576; + int GL_COORD_REPLACE_OES = 0x8862; + int GL_CULL_FACE_MODE = 0x0B45; + int GL_CURRENT_COLOR = 0x0B00; + int GL_CURRENT_NORMAL = 0x0B02; + int GL_CURRENT_TEXTURE_COORDS = 0x0B03; + int GL_DEPTH_CLEAR_VALUE = 0x0B73; + int GL_DEPTH_FUNC = 0x0B74; + int GL_DEPTH_RANGE = 0x0B70; + int GL_DEPTH_WRITEMASK = 0x0B72; + int GL_DOT3_RGB = 0x86AE; + int GL_DOT3_RGBA = 0x86AF; + int GL_DYNAMIC_DRAW = 0x88E8; + int GL_ELEMENT_ARRAY_BUFFER = 0x8893; + int GL_ELEMENT_ARRAY_BUFFER_BINDING = 0x8895; + int GL_FRONT_FACE = 0x0B46; + int GL_GENERATE_MIPMAP = 0x8191; + int GL_GENERATE_MIPMAP_HINT = 0x8192; + int GL_INTERPOLATE = 0x8575; + int GL_LINE_WIDTH = 0x0B21; + int GL_LOGIC_OP_MODE = 0x0BF0; + int GL_MATRIX_MODE = 0x0BA0; + int GL_MAX_CLIP_PLANES = 0x0D32; + int GL_MODELVIEW_MATRIX = 0x0BA6; + int GL_MODELVIEW_MATRIX_FLOAT_AS_INT_BITS_OES = 0x898D; + int GL_MODELVIEW_STACK_DEPTH = 0x0BA3; + int GL_NORMAL_ARRAY_BUFFER_BINDING = 0x8897; + int GL_NORMAL_ARRAY_POINTER = 0x808F; + int GL_NORMAL_ARRAY_STRIDE = 0x807F; + int GL_NORMAL_ARRAY_TYPE = 0x807E; + int GL_OPERAND0_ALPHA = 0x8598; + int GL_OPERAND0_RGB = 0x8590; + int GL_OPERAND1_ALPHA = 0x8599; + int GL_OPERAND1_RGB = 0x8591; + int GL_OPERAND2_ALPHA = 0x859A; + int GL_OPERAND2_RGB = 0x8592; + int GL_POINT_DISTANCE_ATTENUATION = 0x8129; + int GL_POINT_FADE_THRESHOLD_SIZE = 0x8128; + int GL_POINT_SIZE = 0x0B11; + int GL_POINT_SIZE_ARRAY_BUFFER_BINDING_OES = 0x8B9F; + int GL_POINT_SIZE_ARRAY_OES = 0x8B9C; + int GL_POINT_SIZE_ARRAY_POINTER_OES = 0x898C; + int GL_POINT_SIZE_ARRAY_STRIDE_OES = 0x898B; + int GL_POINT_SIZE_ARRAY_TYPE_OES = 0x898A; + int GL_POINT_SIZE_MAX = 0x8127; + int GL_POINT_SIZE_MIN = 0x8126; + int GL_POINT_SPRITE_OES = 0x8861; + int GL_POLYGON_OFFSET_FACTOR = 0x8038; + int GL_POLYGON_OFFSET_UNITS = 0x2A00; + int GL_PREVIOUS = 0x8578; + int GL_PRIMARY_COLOR = 0x8577; + int GL_PROJECTION_MATRIX = 0x0BA7; + int GL_PROJECTION_MATRIX_FLOAT_AS_INT_BITS_OES = 0x898E; + int GL_PROJECTION_STACK_DEPTH = 0x0BA4; + int GL_RGB_SCALE = 0x8573; + int GL_SAMPLE_BUFFERS = 0x80A8; + int GL_SAMPLE_COVERAGE_INVERT = 0x80AB; + int GL_SAMPLE_COVERAGE_VALUE = 0x80AA; + int GL_SAMPLES = 0x80A9; + int GL_SCISSOR_BOX = 0x0C10; + int GL_SHADE_MODEL = 0x0B54; + int GL_SRC0_ALPHA = 0x8588; + int GL_SRC0_RGB = 0x8580; + int GL_SRC1_ALPHA = 0x8589; + int GL_SRC1_RGB = 0x8581; + int GL_SRC2_ALPHA = 0x858A; + int GL_SRC2_RGB = 0x8582; + int GL_STATIC_DRAW = 0x88E4; + int GL_STENCIL_CLEAR_VALUE = 0x0B91; + int GL_STENCIL_FAIL = 0x0B94; + int GL_STENCIL_FUNC = 0x0B92; + int GL_STENCIL_PASS_DEPTH_FAIL = 0x0B95; + int GL_STENCIL_PASS_DEPTH_PASS = 0x0B96; + int GL_STENCIL_REF = 0x0B97; + int GL_STENCIL_VALUE_MASK = 0x0B93; + int GL_STENCIL_WRITEMASK = 0x0B98; + int GL_SUBTRACT = 0x84E7; + int GL_TEXTURE_BINDING_2D = 0x8069; + int GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING = 0x889A; + int GL_TEXTURE_COORD_ARRAY_POINTER = 0x8092; + int GL_TEXTURE_COORD_ARRAY_SIZE = 0x8088; + int GL_TEXTURE_COORD_ARRAY_STRIDE = 0x808A; + int GL_TEXTURE_COORD_ARRAY_TYPE = 0x8089; + int GL_TEXTURE_MATRIX = 0x0BA8; + int GL_TEXTURE_MATRIX_FLOAT_AS_INT_BITS_OES = 0x898F; + int GL_TEXTURE_STACK_DEPTH = 0x0BA5; + int GL_VERTEX_ARRAY_BUFFER_BINDING = 0x8896; + int GL_VERTEX_ARRAY_POINTER = 0x808E; + int GL_VERTEX_ARRAY_SIZE = 0x807A; + int GL_VERTEX_ARRAY_STRIDE = 0x807C; + int GL_VERTEX_ARRAY_TYPE = 0x807B; + int GL_VIEWPORT = 0x0BA2; + int GL_WRITE_ONLY = 0x88B9; + + void glGetPointerv(int pname, java.nio.Buffer[] params); diff --git a/opengl/tools/glgen/stubs/GL11ImplHeader.java-impl b/opengl/tools/glgen/stubs/GL11ImplHeader.java-impl new file mode 100644 index 0000000000000000000000000000000000000000..501be659c0c2c116114ede0a53ec3e4d0737c07e --- /dev/null +++ b/opengl/tools/glgen/stubs/GL11ImplHeader.java-impl @@ -0,0 +1,30 @@ +// Copyright 2006 The Android Open Source Project + +// All Rights Reserved. + +// This source file is automatically generated + +package com.google.android.gles_jni; + +import java.nio.Buffer; +import javax.microedition.khronos.opengles.GL11; +import android.graphics.Canvas; + +public class GL11Impl implements GL11 { + + // Private accessors for native code + + native private static void _nativeClassInit(); + static { + _nativeClassInit(); + } + + Buffer _colorPointer = null; + Buffer _normalPointer = null; + Buffer _texCoordPointer = null; + Buffer _vertexPointer = null; + + public GL11Impl() { + } + + diff --git a/opengl/tools/glgen/stubs/GLCHeader.cpp b/opengl/tools/glgen/stubs/GLCHeader.cpp new file mode 100644 index 0000000000000000000000000000000000000000..6495686b2aad4a47ba6dcf1d7b5b352925228475 --- /dev/null +++ b/opengl/tools/glgen/stubs/GLCHeader.cpp @@ -0,0 +1,129 @@ +** +** Copyright 2006, 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 source file is automatically generated + +#include +#include + +#include +#include + +#include + +#define _NUM_COMPRESSED_TEXTURE_FORMATS \ + (::android::OGLES_NUM_COMPRESSED_TEXTURE_FORMATS) + +static int initialized = 0; + +static jclass nioAccessClass; +static jclass bufferClass; +static jclass OOMEClass; +static jclass UOEClass; +static jclass IAEClass; +static jclass AIOOBEClass; +static jmethodID getBasePointerID; +static jmethodID getBaseArrayID; +static jmethodID getBaseArrayOffsetID; +static jfieldID positionID; +static jfieldID limitID; +static jfieldID elementSizeShiftID; + +/* Cache method IDs each time the class is loaded. */ + +void +nativeClassInitBuffer(JNIEnv *_env) +{ + jclass nioAccessClassLocal = _env->FindClass("java/nio/NIOAccess"); + nioAccessClass = (jclass) _env->NewGlobalRef(nioAccessClassLocal); + + jclass bufferClassLocal = _env->FindClass("java/nio/Buffer"); + bufferClass = (jclass) _env->NewGlobalRef(bufferClassLocal); + + getBasePointerID = _env->GetStaticMethodID(nioAccessClass, + "getBasePointer", "(Ljava/nio/Buffer;)J"); + getBaseArrayID = _env->GetStaticMethodID(nioAccessClass, + "getBaseArray", "(Ljava/nio/Buffer;)Ljava/lang/Object;"); + getBaseArrayOffsetID = _env->GetStaticMethodID(nioAccessClass, + "getBaseArrayOffset", "(Ljava/nio/Buffer;)I"); + + positionID = _env->GetFieldID(bufferClass, "position", "I"); + limitID = _env->GetFieldID(bufferClass, "limit", "I"); + elementSizeShiftID = + _env->GetFieldID(bufferClass, "_elementSizeShift", "I"); +} + + +static void +nativeClassInit(JNIEnv *_env, jclass glImplClass) +{ + nativeClassInitBuffer(_env); + + jclass IAEClassLocal = + _env->FindClass("java/lang/IllegalArgumentException"); + jclass OOMEClassLocal = + _env->FindClass("java/lang/OutOfMemoryError"); + jclass UOEClassLocal = + _env->FindClass("java/lang/UnsupportedOperationException"); + jclass AIOOBEClassLocal = + _env->FindClass("java/lang/ArrayIndexOutOfBoundsException"); + + IAEClass = (jclass) _env->NewGlobalRef(IAEClassLocal); + OOMEClass = (jclass) _env->NewGlobalRef(OOMEClassLocal); + UOEClass = (jclass) _env->NewGlobalRef(UOEClassLocal); + AIOOBEClass = (jclass) _env->NewGlobalRef(AIOOBEClassLocal); +} + +static void * +getPointer(JNIEnv *_env, jobject buffer, jarray *array, jint *remaining) +{ + jint position; + jint limit; + jint elementSizeShift; + jlong pointer; + jint offset; + void *data; + + position = _env->GetIntField(buffer, positionID); + limit = _env->GetIntField(buffer, limitID); + elementSizeShift = _env->GetIntField(buffer, elementSizeShiftID); + *remaining = (limit - position) << elementSizeShift; + pointer = _env->CallStaticLongMethod(nioAccessClass, + getBasePointerID, buffer); + if (pointer != 0L) { + *array = NULL; + return (void *) (jint) pointer; + } + + *array = (jarray) _env->CallStaticObjectMethod(nioAccessClass, + getBaseArrayID, buffer); + offset = _env->CallStaticIntMethod(nioAccessClass, + getBaseArrayOffsetID, buffer); + data = _env->GetPrimitiveArrayCritical(*array, (jboolean *) 0); + + return (void *) ((char *) data + offset); +} + + +static void +releasePointer(JNIEnv *_env, jarray array, void *data, jboolean commit) +{ + _env->ReleasePrimitiveArrayCritical(array, data, + commit ? 0 : JNI_ABORT); +} + +// -------------------------------------------------------------------------- + diff --git a/opengl/tools/glgen/stubs/GLHeader.java-if b/opengl/tools/glgen/stubs/GLHeader.java-if new file mode 100644 index 0000000000000000000000000000000000000000..3b78f3d2ce7de0da6cdfc8d12154c6975f56a17a --- /dev/null +++ b/opengl/tools/glgen/stubs/GLHeader.java-if @@ -0,0 +1,22 @@ +/* //device/java/android/javax/microedition/khronos/opengles/GL.java +** +** Copyright 2006, 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 javax.microedition.khronos.opengles; + +public interface GL { +} + diff --git a/opengl/tools/glgen/stubs/GLImplHeader.java-impl b/opengl/tools/glgen/stubs/GLImplHeader.java-impl new file mode 100644 index 0000000000000000000000000000000000000000..db3a41c017977504a18399be0f197ad6361e715a --- /dev/null +++ b/opengl/tools/glgen/stubs/GLImplHeader.java-impl @@ -0,0 +1,48 @@ +** +** Copyright 2006, 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 source file is automatically generated + +package com.google.android.gles_jni; + +import java.nio.Buffer; +import javax.microedition.khronos.opengles.GL10; +import javax.microedition.khronos.opengles.GL10Ext; +import javax.microedition.khronos.opengles.GL11; +import javax.microedition.khronos.opengles.GL11Ext; +import javax.microedition.khronos.opengles.GL11ExtensionPack; + +public class GLImpl implements GL10, GL10Ext, GL11, GL11Ext, GL11ExtensionPack { + + // Private accessors for native code + + native private static void _nativeClassInit(); + static { + _nativeClassInit(); + } + + Buffer _colorPointer = null; + Buffer _normalPointer = null; + Buffer _texCoordPointer = null; + Buffer _vertexPointer = null; + + public GLImpl() { + } + + public void glGetPointerv(int pname, java.nio.Buffer[] params) { + throw new UnsupportedOperationException("glGetPointerv"); + } + diff --git a/opengl/tools/glgen/stubs/glGetString.cpp b/opengl/tools/glgen/stubs/glGetString.cpp new file mode 100644 index 0000000000000000000000000000000000000000..22e12971778df6a4fd0d4333cc370478a1b938e1 --- /dev/null +++ b/opengl/tools/glgen/stubs/glGetString.cpp @@ -0,0 +1,10 @@ +#include + +/* const GLubyte * glGetString ( GLenum name ) */ +jstring +android_glGetString + (JNIEnv *_env, jobject _this, jint name) { + const char * chars = (const char *)glGetString((GLenum)name); + jstring output = _env->NewStringUTF(chars); + return output; +} diff --git a/opengl/tools/glgen/stubs/glGetString.java-10-if b/opengl/tools/glgen/stubs/glGetString.java-10-if new file mode 100644 index 0000000000000000000000000000000000000000..898fabcf2ce0b6a6dac58749f4085edc29650253 --- /dev/null +++ b/opengl/tools/glgen/stubs/glGetString.java-10-if @@ -0,0 +1,4 @@ + public String glGetString( + int name + ); + diff --git a/opengl/tools/glgen/stubs/glGetString.java-if b/opengl/tools/glgen/stubs/glGetString.java-if new file mode 100644 index 0000000000000000000000000000000000000000..898fabcf2ce0b6a6dac58749f4085edc29650253 --- /dev/null +++ b/opengl/tools/glgen/stubs/glGetString.java-if @@ -0,0 +1,4 @@ + public String glGetString( + int name + ); + diff --git a/opengl/tools/glgen/stubs/glGetString.java-impl b/opengl/tools/glgen/stubs/glGetString.java-impl new file mode 100644 index 0000000000000000000000000000000000000000..8c7881cfd8906586519520321575eb002a6871ca --- /dev/null +++ b/opengl/tools/glgen/stubs/glGetString.java-impl @@ -0,0 +1,16 @@ + // C function const GLubyte * glGetString ( GLenum name ) + + public native String _glGetString( + int name + ); + + public String glGetString( + int name + ) { + String returnValue; + returnValue = _glGetString( + name + ); + return returnValue; + } + diff --git a/opengl/tools/glgen/stubs/glGetString.nativeReg b/opengl/tools/glgen/stubs/glGetString.nativeReg new file mode 100644 index 0000000000000000000000000000000000000000..e64187c8a3fb507082301c9a95b1f378614900d0 --- /dev/null +++ b/opengl/tools/glgen/stubs/glGetString.nativeReg @@ -0,0 +1 @@ +{"_glGetString", "(I)Ljava/lang/String;", (void *) android_glGetString }, diff --git a/packages/SettingsProvider/AndroidManifest.xml b/packages/SettingsProvider/AndroidManifest.xml index fe188ce450ed7081fef79cde1c1719f54a329e62..4abc337927bab7b9794614c964acc1bf321dc5b9 100644 --- a/packages/SettingsProvider/AndroidManifest.xml +++ b/packages/SettingsProvider/AndroidManifest.xml @@ -1,9 +1,17 @@ + + + + + + + + Write Gservices settings. + Allows the application to + change the settings in Gservices. + diff --git a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java index b69d3c7e7565324e1f48a89187402952a5c4e9e4..eb0b03f9d0f6d7b1c60e36a0cd1ade9f3b1f07f4 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java @@ -56,11 +56,6 @@ import java.util.List; * Mostly just has a bit {@link #onCreate} to initialize the database. */ class DatabaseHelper extends SQLiteOpenHelper { - /** - * Path to file containing default favorite packages, relative to ANDROID_ROOT. - */ - private static final String DEFAULT_FAVORITES_PATH = "etc/favorites.xml"; - /** * Path to file containing default bookmarks, relative to ANDROID_ROOT. */ @@ -68,8 +63,8 @@ class DatabaseHelper extends SQLiteOpenHelper { private static final String TAG = "SettingsProvider"; private static final String DATABASE_NAME = "settings.db"; - private static final int DATABASE_VERSION = 25; - + private static final int DATABASE_VERSION = 30; + private Context mContext; public DatabaseHelper(Context context) { @@ -77,6 +72,15 @@ class DatabaseHelper extends SQLiteOpenHelper { mContext = context; } + private void createSecureTable(SQLiteDatabase db) { + db.execSQL("CREATE TABLE secure (" + + "_id INTEGER PRIMARY KEY AUTOINCREMENT," + + "name TEXT UNIQUE ON CONFLICT REPLACE," + + "value TEXT" + + ");"); + db.execSQL("CREATE INDEX secureIndex1 ON secure (name);"); + } + @Override public void onCreate(SQLiteDatabase db) { db.execSQL("CREATE TABLE system (" + @@ -86,6 +90,8 @@ class DatabaseHelper extends SQLiteOpenHelper { ");"); db.execSQL("CREATE INDEX systemIndex1 ON system (name);"); + createSecureTable(db); + db.execSQL("CREATE TABLE gservices (" + "_id INTEGER PRIMARY KEY AUTOINCREMENT," + "name TEXT UNIQUE ON CONFLICT REPLACE," + @@ -113,27 +119,6 @@ class DatabaseHelper extends SQLiteOpenHelper { db.execSQL("CREATE INDEX bookmarksIndex1 ON bookmarks (folder);"); db.execSQL("CREATE INDEX bookmarksIndex2 ON bookmarks (shortcut);"); - db.execSQL("CREATE TABLE favorites (" + - "_id INTEGER PRIMARY KEY," + - "title TEXT," + - "intent TEXT," + - "container INTEGER," + - "screen INTEGER," + - "cellX INTEGER," + - "cellY INTEGER," + - "spanX INTEGER," + - "spanY INTEGER," + - "itemType INTEGER," + - "isShortcut INTEGER," + - "iconType INTEGER," + - "iconPackage TEXT," + - "iconResource TEXT," + - "icon BLOB" + - ");"); - - // Populate favorites table with initial favorites - loadFavorites(db); - // Populate bookmarks table with initial bookmarks loadBookmarks(db); @@ -146,7 +131,6 @@ class DatabaseHelper extends SQLiteOpenHelper { @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int currentVersion) { - Log.w(TAG, "Upgrading settings database from version " + oldVersion + " to " + currentVersion); @@ -215,12 +199,129 @@ class DatabaseHelper extends SQLiteOpenHelper { } upgradeVersion = 25; } + + if (upgradeVersion == 25) { + db.beginTransaction(); + try { + db.execSQL("ALTER TABLE favorites ADD uri TEXT"); + db.execSQL("ALTER TABLE favorites ADD displayMode INTEGER"); + db.setTransactionSuccessful(); + } finally { + db.endTransaction(); + } + upgradeVersion = 26; + } + + if (upgradeVersion == 26) { + // This introduces the new secure settings table. + db.beginTransaction(); + try { + createSecureTable(db); + db.setTransactionSuccessful(); + } finally { + db.endTransaction(); + } + upgradeVersion = 27; + } + if (upgradeVersion == 27) { + // Copy settings values from 'system' to 'secure' and delete them from 'system' + SQLiteStatement insertStmt = null; + SQLiteStatement deleteStmt = null; + + db.beginTransaction(); + try { + insertStmt = + db.compileStatement("INSERT INTO secure (name,value) SELECT name,value FROM " + + "system WHERE name=?"); + deleteStmt = db.compileStatement("DELETE FROM system WHERE name=?"); + + String[] settingsToMove = { + Settings.Secure.ADB_ENABLED, + Settings.Secure.ANDROID_ID, + Settings.Secure.BLUETOOTH_ON, + Settings.Secure.DATA_ROAMING, + Settings.Secure.DEVICE_PROVISIONED, + Settings.Secure.HTTP_PROXY, + Settings.Secure.INSTALL_NON_MARKET_APPS, + Settings.Secure.LOCATION_PROVIDERS_ALLOWED, + Settings.Secure.LOGGING_ID, + Settings.Secure.NETWORK_PREFERENCE, + Settings.Secure.PARENTAL_CONTROL_ENABLED, + Settings.Secure.PARENTAL_CONTROL_LAST_UPDATE, + Settings.Secure.PARENTAL_CONTROL_REDIRECT_URL, + Settings.Secure.SETTINGS_CLASSNAME, + Settings.Secure.USB_MASS_STORAGE_ENABLED, + Settings.Secure.USE_GOOGLE_MAIL, + Settings.Secure.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON, + Settings.Secure.WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY, + Settings.Secure.WIFI_NUM_OPEN_NETWORKS_KEPT, + Settings.Secure.WIFI_ON, + Settings.Secure.WIFI_WATCHDOG_ACCEPTABLE_PACKET_LOSS_PERCENTAGE, + Settings.Secure.WIFI_WATCHDOG_AP_COUNT, + Settings.Secure.WIFI_WATCHDOG_BACKGROUND_CHECK_DELAY_MS, + Settings.Secure.WIFI_WATCHDOG_BACKGROUND_CHECK_ENABLED, + Settings.Secure.WIFI_WATCHDOG_BACKGROUND_CHECK_TIMEOUT_MS, + Settings.Secure.WIFI_WATCHDOG_INITIAL_IGNORED_PING_COUNT, + Settings.Secure.WIFI_WATCHDOG_MAX_AP_CHECKS, + Settings.Secure.WIFI_WATCHDOG_ON, + Settings.Secure.WIFI_WATCHDOG_PING_COUNT, + Settings.Secure.WIFI_WATCHDOG_PING_DELAY_MS, + Settings.Secure.WIFI_WATCHDOG_PING_TIMEOUT_MS, + }; + + for (String setting : settingsToMove) { + insertStmt.bindString(1, setting); + insertStmt.execute(); + + deleteStmt.bindString(1, setting); + deleteStmt.execute(); + } + db.setTransactionSuccessful(); + } finally { + db.endTransaction(); + if (insertStmt != null) { + insertStmt.close(); + } + if (deleteStmt != null) { + deleteStmt.close(); + } + } + upgradeVersion = 28; + } + + if (upgradeVersion == 28 || upgradeVersion == 29) { + // Note: The upgrade to 28 was flawed since it didn't delete the old + // setting first before inserting. Combining 28 and 29 with the + // fixed version. + + // This upgrade adds the STREAM_NOTIFICATION type to the list of + // types affected by ringer modes (silent, vibrate, etc.) + db.beginTransaction(); + try { + db.execSQL("DELETE FROM system WHERE name='" + + Settings.System.MODE_RINGER_STREAMS_AFFECTED + "'"); + int newValue = (1 << AudioManager.STREAM_RING) + | (1 << AudioManager.STREAM_NOTIFICATION) + | (1 << AudioManager.STREAM_SYSTEM); + db.execSQL("INSERT INTO system ('name', 'value') values ('" + + Settings.System.MODE_RINGER_STREAMS_AFFECTED + "', '" + + String.valueOf(newValue) + "')"); + db.setTransactionSuccessful(); + } finally { + db.endTransaction(); + } + + upgradeVersion = 30; + } + if (upgradeVersion != currentVersion) { Log.w(TAG, "Got stuck trying to upgrade from version " + upgradeVersion + ", must wipe the settings provider"); db.execSQL("DROP TABLE IF EXISTS system"); db.execSQL("DROP INDEX IF EXISTS systemIndex1"); + db.execSQL("DROP TABLE IF EXISTS secure"); + db.execSQL("DROP INDEX IF EXISTS secureIndex1"); db.execSQL("DROP TABLE IF EXISTS gservices"); db.execSQL("DROP INDEX IF EXISTS gservicesIndex1"); db.execSQL("DROP TABLE IF EXISTS bluetooth_devices"); @@ -255,122 +356,6 @@ class DatabaseHelper extends SQLiteOpenHelper { c.close(); } } - - /** - * Loads the default set of favorite packages from an xml file. - * - * @param db The database to write the values into - * @param startingIndex The zero-based position at which favorites in this file should begin - * @param subPath The relative path from ANDROID_ROOT to the file to read - * @param quiet If true, do no complain if the file is missing - */ - private int loadFavorites(SQLiteDatabase db, int startingIndex, String subPath, boolean quiet) { - FileReader favReader; - - // Environment.getRootDirectory() is a fancy way of saying ANDROID_ROOT or "/system". - final File favFile = new File(Environment.getRootDirectory(), subPath); - try { - favReader = new FileReader(favFile); - } catch (FileNotFoundException e) { - if (!quiet) { - Log.e(TAG, "Couldn't find or open favorites file " + favFile); - } - return 0; - } - - Intent intent = new Intent(Intent.ACTION_MAIN, null); - intent.addCategory(Intent.CATEGORY_LAUNCHER); - ContentValues values = new ContentValues(); - - PackageManager packageManager = mContext.getPackageManager(); - ActivityInfo info; - int i = startingIndex; - try { - XmlPullParser parser = Xml.newPullParser(); - parser.setInput(favReader); - - XmlUtils.beginDocument(parser, "favorites"); - - while (true) { - XmlUtils.nextElement(parser); - - String name = parser.getName(); - if (!"favorite".equals(name)) { - break; - } - - String pkg = parser.getAttributeValue(null, "package"); - String cls = parser.getAttributeValue(null, "class"); - try { - ComponentName cn = new ComponentName(pkg, cls); - info = packageManager.getActivityInfo(cn, 0); - intent.setComponent(cn); - intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - values.put(com.android.internal.provider.Settings.Favorites.INTENT, - intent.toURI()); - values.put(com.android.internal.provider.Settings.Favorites.TITLE, - info.loadLabel(packageManager).toString()); - values.put(com.android.internal.provider.Settings.Favorites.CONTAINER, - com.android.internal.provider.Settings.Favorites.CONTAINER_DESKTOP); - values.put(com.android.internal.provider.Settings.Favorites.ITEM_TYPE, - com.android.internal.provider.Settings.Favorites.ITEM_TYPE_APPLICATION); - values.put(com.android.internal.provider.Settings.Favorites.SCREEN, - parser.getAttributeValue(null, "screen")); - values.put(com.android.internal.provider.Settings.Favorites.CELLX, - parser.getAttributeValue(null, "x")); - values.put(com.android.internal.provider.Settings.Favorites.CELLY, - parser.getAttributeValue(null, "y")); - values.put(com.android.internal.provider.Settings.Favorites.SPANX, 1); - values.put(com.android.internal.provider.Settings.Favorites.SPANY, 1); - db.insert("favorites", null, values); - i++; - } catch (PackageManager.NameNotFoundException e) { - Log.w(TAG, "Unable to add favorite: " + pkg + "/" + cls, e); - } - } - } catch (XmlPullParserException e) { - Log.w(TAG, "Got execption parsing favorites.", e); - } catch (IOException e) { - Log.w(TAG, "Got execption parsing favorites.", e); - } - - // Add a clock - values.clear(); - values.put(com.android.internal.provider.Settings.Favorites.CONTAINER, - com.android.internal.provider.Settings.Favorites.CONTAINER_DESKTOP); - values.put(com.android.internal.provider.Settings.Favorites.ITEM_TYPE, - com.android.internal.provider.Settings.Favorites.ITEM_TYPE_WIDGET_CLOCK); - values.put(com.android.internal.provider.Settings.Favorites.SCREEN, 1); - values.put(com.android.internal.provider.Settings.Favorites.CELLX, 1); - values.put(com.android.internal.provider.Settings.Favorites.CELLY, 0); - values.put(com.android.internal.provider.Settings.Favorites.SPANX, 2); - values.put(com.android.internal.provider.Settings.Favorites.SPANY, 2); - db.insert("favorites", null, values); - - // Add a search box - values.clear(); - values.put(com.android.internal.provider.Settings.Favorites.CONTAINER, - com.android.internal.provider.Settings.Favorites.CONTAINER_DESKTOP); - values.put(com.android.internal.provider.Settings.Favorites.ITEM_TYPE, - com.android.internal.provider.Settings.Favorites.ITEM_TYPE_WIDGET_SEARCH); - values.put(com.android.internal.provider.Settings.Favorites.SCREEN, 2); - values.put(com.android.internal.provider.Settings.Favorites.CELLX, 0); - values.put(com.android.internal.provider.Settings.Favorites.CELLY, 0); - values.put(com.android.internal.provider.Settings.Favorites.SPANX, 4); - values.put(com.android.internal.provider.Settings.Favorites.SPANY, 1); - db.insert("favorites", null, values); - - return i; - } - - /** - * Loads the default set of favorite packages. - * - * @param db The database to write the values into - */ - private void loadFavorites(SQLiteDatabase db) { - loadFavorites(db, 0, DEFAULT_FAVORITES_PATH, false); - } /** * Loads the default set of bookmarked shortcuts from an xml file. @@ -466,23 +451,36 @@ class DatabaseHelper extends SQLiteOpenHelper { SQLiteStatement stmt = db.compileStatement("INSERT OR IGNORE INTO system(name,value)" + " VALUES(?,?);"); - // Music has double the number of levels - loadSetting(stmt, Settings.System.VOLUME_MUSIC, AudioManager.DEFAULT_STREAM_VOLUME[AudioManager.STREAM_MUSIC]); - loadSetting(stmt, Settings.System.VOLUME_RING, AudioManager.DEFAULT_STREAM_VOLUME[AudioManager.STREAM_RING]); - loadSetting(stmt, Settings.System.VOLUME_SYSTEM, AudioManager.DEFAULT_STREAM_VOLUME[AudioManager.STREAM_SYSTEM]); - loadSetting(stmt, Settings.System.VOLUME_VOICE, AudioManager.DEFAULT_STREAM_VOLUME[AudioManager.STREAM_VOICE_CALL]); - loadSetting(stmt, Settings.System.VOLUME_ALARM, AudioManager.DEFAULT_STREAM_VOLUME[AudioManager.STREAM_ALARM]); - loadSetting(stmt, Settings.System.MODE_RINGER, AudioManager.RINGER_MODE_NORMAL); + loadSetting(stmt, Settings.System.VOLUME_MUSIC, + AudioManager.DEFAULT_STREAM_VOLUME[AudioManager.STREAM_MUSIC]); + loadSetting(stmt, Settings.System.VOLUME_RING, + AudioManager.DEFAULT_STREAM_VOLUME[AudioManager.STREAM_RING]); + loadSetting(stmt, Settings.System.VOLUME_SYSTEM, + AudioManager.DEFAULT_STREAM_VOLUME[AudioManager.STREAM_SYSTEM]); + loadSetting( + stmt, + Settings.System.VOLUME_VOICE, + AudioManager.DEFAULT_STREAM_VOLUME[AudioManager.STREAM_VOICE_CALL]); + loadSetting(stmt, Settings.System.VOLUME_ALARM, + AudioManager.DEFAULT_STREAM_VOLUME[AudioManager.STREAM_ALARM]); + loadSetting( + stmt, + Settings.System.VOLUME_NOTIFICATION, + AudioManager.DEFAULT_STREAM_VOLUME[AudioManager.STREAM_NOTIFICATION]); + loadSetting(stmt, Settings.System.MODE_RINGER, + AudioManager.RINGER_MODE_NORMAL); loadVibrateSetting(db, false); // By default, only the ring/notification and system streams are affected loadSetting(stmt, Settings.System.MODE_RINGER_STREAMS_AFFECTED, - (1 << AudioManager.STREAM_RING) | (1 << AudioManager.STREAM_SYSTEM)); + (1 << AudioManager.STREAM_RING) | (1 << AudioManager.STREAM_NOTIFICATION) | + (1 << AudioManager.STREAM_SYSTEM)); loadSetting(stmt, Settings.System.MUTE_STREAMS_AFFECTED, ((1 << AudioManager.STREAM_MUSIC) | (1 << AudioManager.STREAM_RING) | + (1 << AudioManager.STREAM_NOTIFICATION) | (1 << AudioManager.STREAM_SYSTEM))); stmt.close(); @@ -506,7 +504,11 @@ class DatabaseHelper extends SQLiteOpenHelper { } private void loadSettings(SQLiteDatabase db) { - + loadSystemSettings(db); + loadSecureSettings(db); + } + + private void loadSystemSettings(SQLiteDatabase db) { SQLiteStatement stmt = db.compileStatement("INSERT OR IGNORE INTO system(name,value)" + " VALUES(?,?);"); @@ -520,15 +522,6 @@ class DatabaseHelper extends SQLiteOpenHelper { + Settings.System.RADIO_BLUETOOTH + "," + Settings.System.RADIO_WIFI); loadSetting(stmt, Settings.System.AIRPLANE_MODE_ON, 0); - loadSetting(stmt, Settings.System.BLUETOOTH_ON, 0); - - // USB mass storage on by default - loadSetting(stmt, Settings.System.USB_MASS_STORAGE_ENABLED, 1); - - loadSetting(stmt, Settings.System.WIFI_ON, 0); - loadSetting(stmt, Settings.System.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON, 1); - loadSetting(stmt, Settings.System.NETWORK_PREFERENCE, - ConnectivityManager.DEFAULT_NETWORK_PREFERENCE); loadSetting(stmt, Settings.System.AUTO_TIME, 1); // Sync time to NITZ @@ -536,31 +529,52 @@ class DatabaseHelper extends SQLiteOpenHelper { loadSetting(stmt, Settings.System.SCREEN_BRIGHTNESS, (int) (android.os.Power.BRIGHTNESS_ON * 0.4f)); - // Don't allow non-market apps to be installed - loadSetting(stmt, Settings.System.INSTALL_NON_MARKET_APPS, 0); - // Enable normal window animations (menus, toasts); disable // activity transition animations. loadSetting(stmt, Settings.System.WINDOW_ANIMATION_SCALE, "1"); - loadSetting(stmt, Settings.System.TRANSITION_ANIMATION_SCALE, "0"); - - // Set the default location providers to network based (cell-id) - loadSetting(stmt, Settings.System.LOCATION_PROVIDERS_ALLOWED, - LocationManager.NETWORK_PROVIDER); + loadSetting(stmt, Settings.System.TRANSITION_ANIMATION_SCALE, "1"); - // Data roaming default, based on build - loadSetting(stmt, Settings.System.DATA_ROAMING, - "true".equalsIgnoreCase( - SystemProperties.get("ro.com.android.dataroaming", - "false")) ? 1 : 0); // Default date format based on build loadSetting(stmt, Settings.System.DATE_FORMAT, SystemProperties.get("ro.com.android.dateformat", "MM-dd-yyyy")); + stmt.close(); + } + + private void loadSecureSettings(SQLiteDatabase db) { + SQLiteStatement stmt = db.compileStatement("INSERT OR IGNORE INTO secure(name,value)" + + " VALUES(?,?);"); + + // Bluetooth off + loadSetting(stmt, Settings.Secure.BLUETOOTH_ON, 0); + + // Data roaming default, based on build + loadSetting(stmt, Settings.Secure.DATA_ROAMING, + "true".equalsIgnoreCase( + SystemProperties.get("ro.com.android.dataroaming", + "false")) ? 1 : 0); + + // Don't allow non-market apps to be installed + loadSetting(stmt, Settings.Secure.INSTALL_NON_MARKET_APPS, 0); + + // Set the default location providers to network based (cell-id) + loadSetting(stmt, Settings.Secure.LOCATION_PROVIDERS_ALLOWED, + LocationManager.NETWORK_PROVIDER); + + loadSetting(stmt, Settings.Secure.NETWORK_PREFERENCE, + ConnectivityManager.DEFAULT_NETWORK_PREFERENCE); + // USB mass storage on by default + loadSetting(stmt, Settings.Secure.USB_MASS_STORAGE_ENABLED, 1); + + // WIFI on, notify about available networks + loadSetting(stmt, Settings.Secure.WIFI_ON, 0); + loadSetting(stmt, Settings.Secure.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON, 1); + // Don't do this. The SystemServer will initialize ADB_ENABLED from a // persistent system property instead. - //loadSetting(stmt, Settings.System.ADB_ENABLED, 0); + //loadSetting(stmt, Settings.Secure.ADB_ENABLED, 0); + stmt.close(); } diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java index c8a3cce12003d54a026b57a70c8e3f3f7c8a0574..35bf6b011bfb9aad969ea61e9d3242ccfcf7ac60 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java @@ -40,8 +40,6 @@ public class SettingsProvider extends ContentProvider { private static final String TAG = "SettingsProvider"; private static final boolean LOCAL_LOGV = false; - private static final String WRITE_GSERVICES_PERMISSION = "android.permission.WRITE_GSERVICES"; - private DatabaseHelper mOpenHelper; /** @@ -65,7 +63,8 @@ public class SettingsProvider extends ContentProvider { throw new UnsupportedOperationException("WHERE clause not supported: " + url); } else { this.table = url.getPathSegments().get(0); - if ("gservices".equals(this.table) || "system".equals(this.table)) { + if ("gservices".equals(this.table) || "system".equals(this.table) + || "secure".equals(this.table)) { this.where = Settings.NameValueTable.NAME + "=?"; this.args = new String[] { url.getPathSegments().get(1) }; } else { @@ -99,7 +98,8 @@ public class SettingsProvider extends ContentProvider { throw new IllegalArgumentException("Invalid URI: " + tableUri); } String table = tableUri.getPathSegments().get(0); - if ("gservices".equals(table) || "system".equals(table)) { + if ("gservices".equals(table) || "system".equals(table) + || "secure".equals(table)) { String name = values.getAsString(Settings.NameValueTable.NAME); return Uri.withAppendedPath(tableUri, name); } else { @@ -122,6 +122,8 @@ public class SettingsProvider extends ContentProvider { String property = null, table = uri.getPathSegments().get(0); if (table.equals("system")) { property = Settings.System.SYS_PROP_SETTING_VERSION; + } else if (table.equals("secure")) { + property = Settings.Secure.SYS_PROP_SETTING_VERSION; } else if (table.equals("gservices")) { property = Settings.Gservices.SYS_PROP_SETTING_VERSION; } @@ -149,9 +151,16 @@ public class SettingsProvider extends ContentProvider { * @throws SecurityException if the caller is forbidden to write. */ private void checkWritePermissions(SqlArguments args) { + if ("secure".equals(args.table) && + getContext().checkCallingOrSelfPermission( + android.Manifest.permission.WRITE_SECURE_SETTINGS) != + PackageManager.PERMISSION_GRANTED) { + throw new SecurityException("Cannot write secure settings table"); + // TODO: Move gservices into its own provider so we don't need this nonsense. - if ("gservices".equals(args.table) && - getContext().checkCallingOrSelfPermission(WRITE_GSERVICES_PERMISSION) != + } else if ("gservices".equals(args.table) && + getContext().checkCallingOrSelfPermission( + android.Manifest.permission.WRITE_GSERVICES) != PackageManager.PERMISSION_GRANTED) { throw new SecurityException("Cannot write gservices table"); } @@ -166,6 +175,13 @@ public class SettingsProvider extends ContentProvider { @Override public Cursor query(Uri url, String[] select, String where, String[] whereArgs, String sort) { SqlArguments args = new SqlArguments(url, where, whereArgs); + // The favorites table was moved from this provider to a provider inside Home + // Home still need to query this table to upgrade from pre-cupcake builds + // However, a cupcake+ build with no data does not contain this table which will + // cause an exception in the SQL stack. The following line is a special case to + // let the caller of the query have a chance to recover and avoid the exception + if ("favorites".equals(args.table)) return null; + SQLiteQueryBuilder qb = new SQLiteQueryBuilder(); qb.setTables(args.table); diff --git a/preloaded-classes b/preloaded-classes index 7ef2869b9ab4f917fee314bc91251ab59da912f2..773cf0b28cda92e0fcb4f2c75a9b2e1980ae6a86 100644 --- a/preloaded-classes +++ b/preloaded-classes @@ -232,8 +232,8 @@ android.os.ServiceManager android.os.ServiceManagerNative android.os.ServiceManagerProxy android.os.Vibrator -android.pim.DateUtils -android.pim.Time +android.text.format.DateUtils +android.text.format.Time android.preference.DialogPreference android.preference.ListPreference android.preference.Preference @@ -263,11 +263,6 @@ android.provider.Telephony$MmsSms$PendingMessages android.provider.Telephony$Threads android.server.search.SearchableInfo android.server.search.SearchableInfo$1 -android.speech.recognition.Codec -android.speech.recognition.EmbeddedGrammarListener -android.speech.recognition.impl.EmbeddedRecognizerImpl -android.speech.recognition.impl.MicrophoneImpl -android.speech.recognition.impl.System android.telephony.PhoneNumberUtils android.telephony.ServiceState android.telephony.gsm.SmsManager @@ -481,13 +476,6 @@ com.android.internal.os.RuntimeInit com.android.internal.os.RuntimeInit$UncaughtHandler com.android.internal.os.ZygoteInit$MethodAndArgsCaller com.android.internal.policy.PolicyManager -com.android.internal.policy.impl.PhoneLayoutInflater -com.android.internal.policy.impl.PhoneWindow -com.android.internal.policy.impl.PhoneWindow$1 -com.android.internal.policy.impl.PhoneWindow$ContextMenuCallback -com.android.internal.policy.impl.PhoneWindow$DecorView -com.android.internal.policy.impl.PhoneWindow$PanelFeatureState -com.android.internal.policy.impl.PhoneWindow$PanelFeatureState$SavedState com.android.internal.telephony.Phone com.android.internal.telephony.Phone$DataActivityState com.android.internal.telephony.Phone$DataState @@ -635,8 +623,6 @@ java.util.TreeSet java.util.Vector java.util.WeakHashMap java.util.WeakHashMap$Entry -java.util.ZoneInfo -java.util.ZoneInfoDB java.util.concurrent.TimeUnit java.util.concurrent.atomic.AtomicBoolean java.util.concurrent.atomic.AtomicInteger @@ -674,6 +660,8 @@ org.apache.harmony.dalvik.ddmc.ChunkHandler org.apache.harmony.dalvik.ddmc.DdmServer org.apache.harmony.luni.internal.net.www.protocol.jar.Handler org.apache.harmony.luni.internal.net.www.protocol.jar.JarURLConnection +org.apache.harmony.luni.internal.util.ZoneInfo +org.apache.harmony.luni.internal.util.ZoneInfoDB org.apache.harmony.luni.net.PlainSocketImpl2 org.apache.harmony.luni.platform.PlatformAddress org.apache.harmony.luni.util.TwoKeyHashMap diff --git a/services/java/com/android/server/AlarmManagerService.java b/services/java/com/android/server/AlarmManagerService.java index 968467bf147bd2cd91a5c3c16a808c51ed4eed0c..162585395d2e5d82a1c016f2f2332900d2925fd1 100644 --- a/services/java/com/android/server/AlarmManagerService.java +++ b/services/java/com/android/server/AlarmManagerService.java @@ -73,6 +73,17 @@ class AlarmManagerService extends IAlarmManager.Stub { private final ArrayList mElapsedRealtimeWakeupAlarms = new ArrayList(); private final ArrayList mElapsedRealtimeAlarms = new ArrayList(); + // slots corresponding with the inexact-repeat interval buckets, + // ordered from shortest to longest + private static final long sInexactSlotIntervals[] = { + AlarmManager.INTERVAL_FIFTEEN_MINUTES, + AlarmManager.INTERVAL_HALF_HOUR, + AlarmManager.INTERVAL_HOUR, + AlarmManager.INTERVAL_HALF_DAY, + AlarmManager.INTERVAL_DAY + }; + private long mInexactDeliveryTimes[] = { 0, 0, 0, 0, 0}; + private int mDescriptor; private int mBroadcastRefCount = 0; private PowerManager.WakeLock mWakeLock; @@ -162,6 +173,67 @@ class AlarmManagerService extends IAlarmManager.Stub { } } + public void setInexactRepeating(int type, long triggerAtTime, long interval, + PendingIntent operation) { + if (operation == null) { + Log.w(TAG, "setInexactRepeating ignored because there is no intent"); + return; + } + + // find the slot in the delivery-times array that we will use + int intervalSlot; + for (intervalSlot = 0; intervalSlot < sInexactSlotIntervals.length; intervalSlot++) { + if (sInexactSlotIntervals[intervalSlot] == interval) { + break; + } + } + + // Non-bucket intervals just fall back to the less-efficient + // unbucketed recurring alarm implementation + if (intervalSlot >= sInexactSlotIntervals.length) { + setRepeating(type, triggerAtTime, interval, operation); + return; + } + + // Align bucketed alarm deliveries by trying to match + // the shortest-interval bucket already scheduled + long bucketTime = 0; + for (int slot = 0; slot < mInexactDeliveryTimes.length; slot++) { + if (mInexactDeliveryTimes[slot] > 0) { + bucketTime = mInexactDeliveryTimes[slot]; + break; + } + } + + if (bucketTime == 0) { + // If nothing is scheduled yet, just start at the requested time + bucketTime = triggerAtTime; + } else { + // Align the new alarm with the existing bucketed sequence. To achieve + // alignment, we slide the start time around by min{interval, slot interval} + long adjustment = (interval <= sInexactSlotIntervals[intervalSlot]) + ? interval : sInexactSlotIntervals[intervalSlot]; + + // The bucket may have started in the past; adjust + while (bucketTime < triggerAtTime) { + bucketTime += adjustment; + } + + // Or the bucket may be set to start more than an interval beyond + // our requested trigger time; pull it back to meet our needs + while (bucketTime > triggerAtTime + adjustment) { + bucketTime -= adjustment; + } + } + + // Remember where this bucket started (reducing the amount of later + // fixup required) and set the alarm with the new, bucketed start time. + if (localLOGV) Log.v(TAG, "setInexactRepeating: interval=" + interval + + " bucketTime=" + bucketTime); + mInexactDeliveryTimes[intervalSlot] = bucketTime; + setRepeating(type, bucketTime, interval, operation); + } + public void setTimeZone(String tz) { mContext.enforceCallingOrSelfPermission( "android.permission.SET_TIME_ZONE", @@ -171,15 +243,28 @@ class AlarmManagerService extends IAlarmManager.Stub { TimeZone zone = TimeZone.getTimeZone(tz); // Prevent reentrant calls from stepping on each other when writing // the time zone property + boolean timeZoneWasChanged = false; synchronized (this) { - SystemProperties.set(TIMEZONE_PROPERTY, zone.getID()); + String current = SystemProperties.get(TIMEZONE_PROPERTY); + if (current == null || !current.equals(zone.getID())) { + if (localLOGV) Log.v(TAG, "timezone changed: " + current + ", new=" + zone.getID()); + timeZoneWasChanged = true; + SystemProperties.set(TIMEZONE_PROPERTY, zone.getID()); + + // Update the kernel timezone information + // Kernel tracks time offsets as 'minutes west of GMT' + int gmtOffset = (zone.getRawOffset() + zone.getDSTSavings()) / 60000; + setKernelTimezone(mDescriptor, -(gmtOffset)); + } } - + TimeZone.setDefault(null); - Intent intent = new Intent(Intent.ACTION_TIMEZONE_CHANGED); - intent.putExtra("time-zone", zone.getID()); - mContext.sendBroadcast(intent); + if (timeZoneWasChanged) { + Intent intent = new Intent(Intent.ACTION_TIMEZONE_CHANGED); + intent.putExtra("time-zone", zone.getID()); + mContext.sendBroadcast(intent); + } } public void remove(PendingIntent operation) { @@ -359,7 +444,8 @@ class AlarmManagerService extends IAlarmManager.Stub { private native void close(int fd); private native void set(int fd, int type, long nanoseconds); private native int waitForAlarm(int fd); - + private native int setKernelTimezone(int fd, int minuteswest); + private void triggerAlarmsLocked(ArrayList alarmList, ArrayList triggerList, long now) @@ -581,6 +667,7 @@ class AlarmManagerService extends IAlarmManager.Stub { public ClockReceiver() { IntentFilter filter = new IntentFilter(); filter.addAction(Intent.ACTION_TIME_TICK); + filter.addAction(Intent.ACTION_DATE_CHANGED); mContext.registerReceiver(this, filter); } @@ -589,6 +676,14 @@ class AlarmManagerService extends IAlarmManager.Stub { if (intent.getAction().equals(Intent.ACTION_TIME_TICK)) { scheduleTimeTickEvent(); } else if (intent.getAction().equals(Intent.ACTION_DATE_CHANGED)) { + // Since the kernel does not keep track of DST, we need to + // reset the TZ information at the beginning of each day + // based off of the current Zone gmt offset + userspace tracked + // daylight savings information. + TimeZone zone = TimeZone.getTimeZone(SystemProperties.get(TIMEZONE_PROPERTY)); + int gmtOffset = (zone.getRawOffset() + zone.getDSTSavings()) / 60000; + + setKernelTimezone(mDescriptor, -(gmtOffset)); scheduleDateChangedEvent(); } } diff --git a/services/java/com/android/server/BatteryService.java b/services/java/com/android/server/BatteryService.java index 608299c8ce6fcde6a06769e01e832803beb708c0..dba8fcac78b248fb4c82864907cf4d5fafaf5e08 100644 --- a/services/java/com/android/server/BatteryService.java +++ b/services/java/com/android/server/BatteryService.java @@ -17,7 +17,7 @@ package com.android.server; import com.android.internal.app.IBatteryStats; -import com.android.server.am.BatteryStats; +import com.android.server.am.BatteryStatsService; import android.app.ActivityManagerNative; import android.content.Context; @@ -27,7 +27,6 @@ import android.os.BatteryManager; import android.os.Binder; import android.os.RemoteException; import android.os.UEventObserver; -import android.util.Config; import android.util.EventLog; import android.util.Log; @@ -90,9 +89,9 @@ class BatteryService extends Binder { public BatteryService(Context context) { mContext = context; - mBatteryStats = BatteryStats.getService(); + mBatteryStats = BatteryStatsService.getService(); - mUEventObserver.startObserving("DEVPATH=/class/power_supply"); + mUEventObserver.startObserving("SUBSYSTEM=power_supply"); // set initial status update(); @@ -103,6 +102,28 @@ class BatteryService extends Binder { return (mAcOnline || mUsbOnline || mBatteryStatus == BatteryManager.BATTERY_STATUS_UNKNOWN); } + final boolean isPowered(int plugTypeSet) { + // assume we are powered if battery state is unknown so + // the "stay on while plugged in" option will work. + if (mBatteryStatus == BatteryManager.BATTERY_STATUS_UNKNOWN) { + return true; + } + if (plugTypeSet == 0) { + return false; + } + int plugTypeBit = 0; + if (mAcOnline) { + plugTypeBit = BatteryManager.BATTERY_PLUGGED_AC; + } else if (mUsbOnline) { + plugTypeBit = BatteryManager.BATTERY_PLUGGED_USB; + } + return (plugTypeSet & plugTypeBit) != 0; + } + + final int getPlugType() { + return mPlugType; + } + private UEventObserver mUEventObserver = new UEventObserver() { @Override public void onUEvent(UEventObserver.UEvent event) { diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index 11f34cc8619f9b3ce1be438ce62885a295cbafc5..65e36509a9c51759982dabb70df29e4588ae8d18 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -35,7 +35,6 @@ import android.os.Message; import android.os.ServiceManager; import android.os.SystemProperties; import android.provider.Settings; -import android.telephony.TelephonyManager; import android.util.EventLog; import android.util.Log; @@ -43,7 +42,7 @@ import java.io.FileDescriptor; import java.io.PrintWriter; /** - * {@hide} + * @hide */ public class ConnectivityService extends IConnectivityManager.Stub { @@ -59,7 +58,6 @@ public class ConnectivityService extends IConnectivityManager.Stub { * abstractly. */ private NetworkStateTracker mNetTrackers[]; - private boolean mTeardownRequested[]; private WifiStateTracker mWifiStateTracker; private MobileDataStateTracker mMobileDataStateTracker; private WifiWatchdogService mWifiWatchdogService; @@ -69,11 +67,11 @@ public class ConnectivityService extends IConnectivityManager.Stub { private NetworkStateTracker mActiveNetwork; private int mNumDnsEntries; - private static int mDnsChangeCounter; + private static int sDnsChangeCounter; private boolean mTestMode; private static ConnectivityService sServiceInstance; - + private static class ConnectivityThread extends Thread { private Context mContext; @@ -101,7 +99,9 @@ public class ConnectivityService extends IConnectivityManager.Stub { try { // Wait until sServiceInstance has been initialized. thread.wait(); - } catch (InterruptedException e) { + } catch (InterruptedException ignore) { + Log.e(TAG, + "Unexpected InterruptedException while waiting for ConnectivityService thread"); } } } @@ -118,7 +118,6 @@ public class ConnectivityService extends IConnectivityManager.Stub { if (DBG) Log.v(TAG, "ConnectivityService starting up"); mContext = context; mNetTrackers = new NetworkStateTracker[2]; - mTeardownRequested = new boolean[2]; Handler handler = new MyHandler(); mNetworkPreference = getPersistedNetworkPreference(); @@ -134,7 +133,6 @@ public class ConnectivityService extends IConnectivityManager.Stub { mWifiStateTracker = new WifiStateTracker(context, handler); WifiService wifiService = new WifiService(context, mWifiStateTracker); ServiceManager.addService(Context.WIFI_SERVICE, wifiService); - // The WifiStateTracker should appear first in the list mNetTrackers[ConnectivityManager.TYPE_WIFI] = mWifiStateTracker; mMobileDataStateTracker = new MobileDataStateTracker(context, handler); @@ -160,10 +158,11 @@ public class ConnectivityService extends IConnectivityManager.Stub { public synchronized void setNetworkPreference(int preference) { enforceChangePermission(); if (ConnectivityManager.isNetworkTypeValid(preference)) { - int oldPreference = mNetworkPreference; - persistNetworkPreference(preference); - if (mNetworkPreference != oldPreference) + if (mNetworkPreference != preference) { + persistNetworkPreference(preference); + mNetworkPreference = preference; enforcePreference(); + } } } @@ -174,14 +173,14 @@ public class ConnectivityService extends IConnectivityManager.Stub { private void persistNetworkPreference(int networkPreference) { final ContentResolver cr = mContext.getContentResolver(); - Settings.System.putInt(cr, Settings.System.NETWORK_PREFERENCE, networkPreference); + Settings.Secure.putInt(cr, Settings.Secure.NETWORK_PREFERENCE, networkPreference); } private int getPersistedNetworkPreference() { final ContentResolver cr = mContext.getContentResolver(); - final int networkPrefSetting = Settings.System - .getInt(cr, Settings.System.NETWORK_PREFERENCE, -1); + final int networkPrefSetting = Settings.Secure + .getInt(cr, Settings.Secure.NETWORK_PREFERENCE, -1); if (networkPrefSetting != -1) { return networkPrefSetting; } @@ -219,7 +218,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { private boolean teardown(NetworkStateTracker netTracker) { if (netTracker.teardown()) { - mTeardownRequested[netTracker.getNetworkInfo().getType()] = true; + netTracker.setTeardownRequested(true); return true; } else { return false; @@ -227,9 +226,9 @@ public class ConnectivityService extends IConnectivityManager.Stub { } /** - * Return NetworkInfo for the active network interface. It is assumed that at most - * one network is active at a time. If more than one is active, it is indeterminate - * which will be returned. + * Return NetworkInfo for the active (i.e., connected) network interface. + * It is assumed that at most one network is active at a time. If more + * than one is active, it is indeterminate which will be returned. * @return the info for the active network, or {@code null} if none is active */ public NetworkInfo getActiveNetworkInfo() { @@ -291,7 +290,6 @@ public class ConnectivityService extends IConnectivityManager.Stub { return tracker.startUsingNetworkFeature(feature, getCallingPid(), getCallingUid()); } return -1; - } public int stopUsingNetworkFeature(int networkType, String feature) { @@ -339,8 +337,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { int numConnectedNets = 0; for (NetworkStateTracker nt : mNetTrackers) { - if (nt.getNetworkInfo().isConnected() - && !mTeardownRequested[nt.getNetworkInfo().getType()]) { + if (nt.getNetworkInfo().isConnected() && !nt.isTeardownRequested()) { ++numConnectedNets; } } @@ -369,13 +366,13 @@ public class ConnectivityService extends IConnectivityManager.Stub { if (DBG) Log.v(TAG, "Handle DISCONNECT for " + info.getTypeName()); + mNetTrackers[info.getType()].setTeardownRequested(false); /* * If the disconnected network is not the active one, then don't report * this as a loss of connectivity. What probably happened is that we're * getting the disconnect for a network that we explicitly disabled * in accordance with network preference policies. */ - mTeardownRequested[info.getType()] = false; if (mActiveNetwork == null || info.getType() != mActiveNetwork.getNetworkInfo().getType()) return; @@ -386,13 +383,23 @@ public class ConnectivityService extends IConnectivityManager.Stub { newNet = mMobileDataStateTracker; } + /** + * See if the other network is available to fail over to. + * If is not available, we enable it anyway, so that it + * will be able to connect when it does become available, + * but we report a total loss of connectivity rather than + * report that we are attempting to fail over. + */ NetworkInfo switchTo = null; if (newNet.isAvailable()) { mActiveNetwork = newNet; switchTo = newNet.getNetworkInfo(); switchTo.setFailover(true); - if (!switchTo.isConnectedOrConnecting()) + if (!switchTo.isConnectedOrConnecting()) { newNet.reconnect(); + } + } else { + newNet.reconnect(); } boolean otherNetworkConnected = false; @@ -449,8 +456,12 @@ public class ConnectivityService extends IConnectivityManager.Stub { mContext.sendStickyBroadcast(intent); } + /** + * Called when an attempt to fail over to another network has failed. + * @param info the {@link NetworkInfo} for the failed network + */ private void handleConnectionFailure(NetworkInfo info) { - mTeardownRequested[info.getType()] = false; + mNetTrackers[info.getType()].setTeardownRequested(false); if (getActiveNetworkInfo() == null) { String reason = info.getReason(); String extraInfo = info.getExtraInfo(); @@ -496,10 +507,9 @@ public class ConnectivityService extends IConnectivityManager.Stub { otherNet = mMobileDataStateTracker; } /* - * Check policy to see whether we are now connected to a network that - * takes precedence over the other one. If so, we need to tear down - * the other one. - */ + * Check policy to see whether we are connected to a non-preferred + * network that now needs to be torn down. + */ NetworkInfo wifiInfo = mWifiStateTracker.getNetworkInfo(); NetworkInfo mobileInfo = mMobileDataStateTracker.getNetworkInfo(); if (wifiInfo.isConnected() && mobileInfo.isConnected()) { @@ -510,7 +520,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { } boolean toredown = false; - mTeardownRequested[info.getType()] = false; + thisNet.setTeardownRequested(false); if (!mTestMode && deadnet != null) { if (DBG) Log.v(TAG, "Policy requires " + deadnet.getNetworkInfo().getTypeName() + " teardown"); @@ -520,6 +530,10 @@ public class ConnectivityService extends IConnectivityManager.Stub { } } + /* + * Note that if toredown is true, deadnet cannot be null, so there is + * no danger of a null pointer exception here.. + */ if (!toredown || deadnet.getNetworkInfo().getType() != info.getType()) { mActiveNetwork = thisNet; if (DBG) Log.v(TAG, "Sending CONNECT bcast for " + info.getTypeName()); @@ -592,10 +606,9 @@ public class ConnectivityService extends IConnectivityManager.Stub { int incrValue = ConnectivityManager.TYPE_MOBILE - ConnectivityManager.TYPE_WIFI; int stopValue = ConnectivityManager.TYPE_MOBILE + incrValue; - for (int net = ConnectivityManager.TYPE_WIFI; net != stopValue; net += incrValue) { - NetworkStateTracker nt = mNetTrackers[net]; - if (nt.getNetworkInfo().isConnected() - && !mTeardownRequested[nt.getNetworkInfo().getType()]) { + for (int netType = ConnectivityManager.TYPE_WIFI; netType != stopValue; netType += incrValue) { + NetworkStateTracker nt = mNetTrackers[netType]; + if (nt.getNetworkInfo().isConnected() && !nt.isTeardownRequested()) { ++numConnectedNets; String[] dnsList = nt.getNameServers(); for (int i = 0; i < dnsList.length && dnsList[i] != null; i++) { @@ -613,7 +626,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { } mNumDnsEntries = index - 1; // Notify the name resolver library of the change - SystemProperties.set("net.dnschange", String.valueOf(mDnsChangeCounter++)); + SystemProperties.set("net.dnschange", String.valueOf(sDnsChangeCounter++)); return numConnectedNets; } @@ -650,13 +663,13 @@ public class ConnectivityService extends IConnectivityManager.Stub { info.getState() + "/" + info.getDetailedState()); // Connectivity state changed: - // [31-11] Reserved for future use - // [10-9] Mobile network connection type (as defined by the TelephonyManager) - // [8-3] Detailed state ordinal (as defined by NetworkInfo.DetailedState) + // [31-13] Reserved for future use + // [12-9] Network subtype (for mobile network, as defined by TelephonyManager) + // [8-3] Detailed state ordinal (as defined by NetworkInfo.DetailedState) // [2-0] Network type (as defined by ConnectivityManager) int eventLogParam = (info.getType() & 0x7) | - ((info.getDetailedState().ordinal() & 0x3f) << 3) | - (TelephonyManager.getDefault().getNetworkType() << 9); + ((info.getDetailedState().ordinal() & 0x3f) << 3) | + (info.getSubtype() << 9); EventLog.writeEvent(EVENTLOG_CONNECTIVITY_STATE_CHANGED, eventLogParam); if (info.getDetailedState() == NetworkInfo.DetailedState.FAILED) { @@ -687,6 +700,14 @@ public class ConnectivityService extends IConnectivityManager.Stub { case NetworkStateTracker.EVENT_CONFIGURATION_CHANGED: handleConfigurationChange(); break; + + case NetworkStateTracker.EVENT_ROAMING_CHANGED: + // fill me in + break; + + case NetworkStateTracker.EVENT_NETWORK_SUBTYPE_CHANGED: + // fill me in + break; } } } diff --git a/services/java/com/android/server/DeviceStorageMonitorService.java b/services/java/com/android/server/DeviceStorageMonitorService.java new file mode 100644 index 0000000000000000000000000000000000000000..04b19003744508c37b1f2d64c1d8e0ce072627e5 --- /dev/null +++ b/services/java/com/android/server/DeviceStorageMonitorService.java @@ -0,0 +1,294 @@ +/* + * Copyright (C) 2007-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.android.server; + +import com.android.server.am.ActivityManagerService; +import android.app.Notification; +import android.app.NotificationManager; +import android.app.PendingIntent; +import android.content.ContentResolver; +import android.content.Context; +import android.content.Intent; +import android.content.pm.IPackageDataObserver; +import android.content.pm.IPackageManager; +import android.os.Binder; +import android.os.Handler; +import android.os.Message; +import android.os.Process; +import android.os.RemoteException; +import android.os.ServiceManager; +import android.os.StatFs; +import android.os.SystemClock; +import android.os.SystemProperties; +import android.provider.Settings.Gservices; +import android.util.Config; +import android.util.EventLog; +import android.util.Log; +import android.provider.Settings; + +/** + * This class implements a service to monitor the amount of disk storage space + * on the device. If the free storage on device is less than a tunable threshold value + * (default is 10%. this value is a gservices parameter) a low memory notification is + * displayed to alert the user. If the user clicks on the low memory notification the + * Application Manager application gets launched to let the user free storage space. + * Event log events: + * A low memory event with the free storage on device in bytes is logged to the event log + * when the device goes low on storage space. + * The amount of free storage on the device is periodically logged to the event log. The log + * interval is a gservices parameter with a default value of 12 hours + * When the free storage differential goes below a threshold(again a gservices parameter with + * a default value of 2MB), the free memory is logged to the event log + */ +class DeviceStorageMonitorService extends Binder { + private static final String TAG = "DeviceStorageMonitorService"; + private static final boolean DEBUG = false; + private static final boolean localLOGV = DEBUG ? Config.LOGD : Config.LOGV; + private static final int DEVICE_MEMORY_WHAT = 1; + private static final int MONITOR_INTERVAL = 1; //in minutes + private static final int LOW_MEMORY_NOTIFICATION_ID = 1; + private static final int DEFAULT_THRESHOLD_PERCENTAGE = 10; + private static final int DEFAULT_FREE_STORAGE_LOG_INTERVAL_IN_MINUTES = 12*60; //in minutes + private static final int EVENT_LOG_STORAGE_BELOW_THRESHOLD = 2744; + private static final int EVENT_LOG_LOW_STORAGE_NOTIFICATION = 2745; + private static final int EVENT_LOG_FREE_STORAGE_LEFT = 2746; + private static final long DEFAULT_DISK_FREE_CHANGE_REPORTING_THRESHOLD = 2 * 1024 * 1024; // 2MB + private long mFreeMem; + private long mLastReportedFreeMem; + private long mLastReportedFreeMemTime; + private boolean mLowMemFlag=false; + private Context mContext; + private ContentResolver mContentResolver; + int mBlkSize; + long mTotalMemory; + StatFs mFileStats; + private static final String DATA_PATH="/data"; + long mThreadStartTime = -1; + boolean mClearSucceeded = false; + boolean mClearingCache; + private Intent mStorageLowIntent; + private Intent mStorageOkIntent; + + /** + * This string is used for ServiceManager access to this class. + */ + static final String SERVICE = "devicestoragemonitor"; + + /** + * Handler that checks the amount of disk space on the device and sends a + * notification if the device runs low on disk space + */ + Handler mHandler = new Handler() { + @Override + public void handleMessage(Message msg) { + //dont handle an invalid message + if (msg.what != DEVICE_MEMORY_WHAT) { + Log.e(TAG, "Will not process invalid message"); + return; + } + checkMemory(); + } + }; + + class CachePackageDataObserver extends IPackageDataObserver.Stub { + public void onRemoveCompleted(String packageName, boolean succeeded) { + mClearSucceeded = succeeded; + mClearingCache = false; + if(localLOGV) Log.i(TAG, " Clear succeeded:"+mClearSucceeded + +", mClearingCache:"+mClearingCache); + } + } + + private final void restatDataDir() { + mFileStats.restat(DATA_PATH); + mFreeMem = mFileStats.getAvailableBlocks()*mBlkSize; + // Allow freemem to be overridden by debug.freemem for testing + String debugFreeMem = SystemProperties.get("debug.freemem"); + if (!"".equals(debugFreeMem)) { + mFreeMem = Long.parseLong(debugFreeMem); + } + // Read the log interval from Gservices + long freeMemLogInterval = Gservices.getLong(mContentResolver, + Gservices.SYS_FREE_STORAGE_LOG_INTERVAL, + DEFAULT_FREE_STORAGE_LOG_INTERVAL_IN_MINUTES)*60*1000; + //log the amount of free memory in event log + long currTime = SystemClock.elapsedRealtime(); + if((mLastReportedFreeMemTime == 0) || + (currTime-mLastReportedFreeMemTime) >= freeMemLogInterval) { + mLastReportedFreeMemTime = currTime; + EventLog.writeEvent(EVENT_LOG_FREE_STORAGE_LEFT, mFreeMem); + } + // Read the reporting threshold from Gservices + long threshold = Gservices.getLong(mContentResolver, + Gservices.DISK_FREE_CHANGE_REPORTING_THRESHOLD, + DEFAULT_DISK_FREE_CHANGE_REPORTING_THRESHOLD); + // If mFree changed significantly log the new value + long delta = mFreeMem - mLastReportedFreeMem; + if (delta > threshold || delta < -threshold) { + mLastReportedFreeMem = mFreeMem; + EventLog.writeEvent(EVENT_LOG_STORAGE_BELOW_THRESHOLD, mFreeMem); + } + } + + private final void clearCache() { + CachePackageDataObserver observer = new CachePackageDataObserver(); + mClearingCache = true; + try { + IPackageManager.Stub.asInterface(ServiceManager.getService("package")). + freeApplicationCache(getMemThreshold(), observer); + } catch (RemoteException e) { + Log.w(TAG, "Failed to get handle for PackageManger Exception: "+e); + mClearingCache = false; + mClearSucceeded = false; + } + } + + private final void checkMemory() { + //if the thread that was started to clear cache is still running do nothing till its + //finished clearing cache. Ideally this flag could be modified by clearCache + // and should be accessed via a lock but even if it does this test will fail now and + //hopefully the next time this flag will be set to the correct value. + if(mClearingCache) { + if(localLOGV) Log.i(TAG, "Thread already running just skip"); + //make sure the thread is not hung for too long + long diffTime = System.currentTimeMillis() - mThreadStartTime; + if(diffTime > (10*60*1000)) { + Log.w(TAG, "Thread that clears cache file seems to run for ever"); + } + } else { + restatDataDir(); + if (localLOGV) Log.v(TAG, "freeMemory="+mFreeMem); + //post intent to NotificationManager to display icon if necessary + long memThreshold = getMemThreshold(); + if (mFreeMem < memThreshold) { + if (!mLowMemFlag) { + //see if clearing cache helps + mThreadStartTime = System.currentTimeMillis(); + clearCache(); + Log.i(TAG, "Running low on memory. Sending notification"); + sendNotification(); + mLowMemFlag = true; + } else { + if (localLOGV) Log.v(TAG, "Running low on memory " + + "notification already sent. do nothing"); + } + } else { + if (mLowMemFlag) { + Log.i(TAG, "Memory available. Cancelling notification"); + cancelNotification(); + mLowMemFlag = false; + } + } + } + if(localLOGV) Log.i(TAG, "Posting Message again"); + //keep posting messages to itself periodically + mHandler.sendMessageDelayed(mHandler.obtainMessage(DEVICE_MEMORY_WHAT), + MONITOR_INTERVAL*60*1000); + } + + /* + * just query settings to retrieve the memory threshold. + * Preferred this over using a ContentObserver since Settings.Gservices caches the value + * any way + */ + private long getMemThreshold() { + int value = Settings.Gservices.getInt( + mContentResolver, + Settings.Gservices.SYS_STORAGE_THRESHOLD_PERCENTAGE, + DEFAULT_THRESHOLD_PERCENTAGE); + if(localLOGV) Log.v(TAG, "Threshold Percentage="+value); + //evaluate threshold value + return mTotalMemory*value; + } + + /** + * Constructor to run service. initializes the disk space threshold value + * and posts an empty message to kickstart the process. + */ + public DeviceStorageMonitorService(Context context) { + mLastReportedFreeMemTime = 0; + mContext = context; + mContentResolver = mContext.getContentResolver(); + //create StatFs object + mFileStats = new StatFs(DATA_PATH); + //initialize block size + mBlkSize = mFileStats.getBlockSize(); + //initialize total storage on device + mTotalMemory = (mFileStats.getBlockCount()*mBlkSize)/100; + mStorageLowIntent = new Intent(Intent.ACTION_DEVICE_STORAGE_LOW); + mStorageOkIntent = new Intent(Intent.ACTION_DEVICE_STORAGE_OK); + checkMemory(); + } + + + /** + * This method sends a notification to NotificationManager to display + * an error dialog indicating low disk space and launch the Installer + * application + */ + private final void sendNotification() { + if(localLOGV) Log.i(TAG, "Sending low memory notification"); + //log the event to event log with the amount of free storage(in bytes) left on the device + EventLog.writeEvent(EVENT_LOG_LOW_STORAGE_NOTIFICATION, mFreeMem); + // Pack up the values and broadcast them to everyone + Intent lowMemIntent = new Intent(Intent.ACTION_MANAGE_PACKAGE_STORAGE); + lowMemIntent.putExtra("memory", mFreeMem); + lowMemIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + NotificationManager mNotificationMgr = + (NotificationManager)mContext.getSystemService( + Context.NOTIFICATION_SERVICE); + CharSequence title = mContext.getText( + com.android.internal.R.string.low_internal_storage_view_title); + CharSequence details = mContext.getText( + com.android.internal.R.string.low_internal_storage_view_text); + PendingIntent intent = PendingIntent.getActivity(mContext, 0, lowMemIntent, 0); + Notification notification = new Notification(); + notification.icon = com.android.internal.R.drawable.stat_notify_disk_full; + notification.tickerText = title; + notification.flags |= Notification.FLAG_NO_CLEAR; + notification.setLatestEventInfo(mContext, title, details, intent); + mNotificationMgr.notify(LOW_MEMORY_NOTIFICATION_ID, notification); + mContext.sendStickyBroadcast(mStorageLowIntent); + } + + /** + * Cancels low storage notification and sends OK intent. + */ + private final void cancelNotification() { + if(localLOGV) Log.i(TAG, "Canceling low memory notification"); + NotificationManager mNotificationMgr = + (NotificationManager)mContext.getSystemService( + Context.NOTIFICATION_SERVICE); + //cancel notification since memory has been freed + mNotificationMgr.cancel(LOW_MEMORY_NOTIFICATION_ID); + + mContext.removeStickyBroadcast(mStorageLowIntent); + mContext.sendBroadcast(mStorageOkIntent); + } + + public void updateMemory() { + ActivityManagerService ams = (ActivityManagerService)ServiceManager.getService("activity"); + int callingUid = getCallingUid(); + if(callingUid != Process.SYSTEM_UID) { + return; + } + //remove queued messages + mHandler.removeMessages(DEVICE_MEMORY_WHAT); + //force an early check + checkMemory(); + } +} diff --git a/services/java/com/android/server/HeadsetObserver.java b/services/java/com/android/server/HeadsetObserver.java index 9f7701d609d86684476cc494518f63539b7e113a..cb681e065ea5e89f70ecbf564b30e9445adb51d7 100644 --- a/services/java/com/android/server/HeadsetObserver.java +++ b/services/java/com/android/server/HeadsetObserver.java @@ -32,7 +32,7 @@ import java.io.FileNotFoundException; class HeadsetObserver extends UEventObserver { private static final String TAG = HeadsetObserver.class.getSimpleName(); - private static final String HEADSET_UEVENT_MATCH = "DEVPATH=/class/switch/h2w"; + private static final String HEADSET_UEVENT_MATCH = "DEVPATH=/devices/virtual/switch/h2w"; private static final String HEADSET_STATE_PATH = "/sys/class/switch/h2w/state"; private static final String HEADSET_NAME_PATH = "/sys/class/switch/h2w/name"; diff --git a/services/java/com/android/server/InputDevice.java b/services/java/com/android/server/InputDevice.java index 70bf38e03e4232646b905a6836d8eeb153457a04..7b8a2a47e5bf0283c422b785e2ca56bac6688e55 100644 --- a/services/java/com/android/server/InputDevice.java +++ b/services/java/com/android/server/InputDevice.java @@ -75,6 +75,7 @@ public class InputDevice { float temp; float scaledPressure = 1.0f; float scaledSize = 0; + int edgeFlags = 0; if (isAbs) { int w = display.getWidth()-1; int h = display.getHeight()-1; @@ -118,6 +119,19 @@ public class InputDevice { scaledY = temp; break; } + + if (scaledX == 0) { + edgeFlags += MotionEvent.EDGE_LEFT; + } else if (scaledX == display.getWidth() - 1.0f) { + edgeFlags += MotionEvent.EDGE_RIGHT; + } + + if (scaledY == 0) { + edgeFlags += MotionEvent.EDGE_TOP; + } else if (scaledY == display.getHeight() - 1.0f) { + edgeFlags += MotionEvent.EDGE_BOTTOM; + } + } else { scaledX *= xMoveScale; scaledY *= yMoveScale; @@ -138,19 +152,6 @@ public class InputDevice { break; } } - - int edgeFlags = 0; - if (scaledX == 0) { - edgeFlags += MotionEvent.EDGE_LEFT; - } else if (scaledX == display.getWidth() - 1.0f) { - edgeFlags += MotionEvent.EDGE_RIGHT; - } - - if (scaledY == 0) { - edgeFlags += MotionEvent.EDGE_TOP; - } else if (scaledY == display.getHeight() - 1.0f) { - edgeFlags += MotionEvent.EDGE_BOTTOM; - } changed = false; if (down != lastDown) { @@ -171,6 +172,8 @@ public class InputDevice { xPrecision, yPrecision, device.id, edgeFlags); } else { if (currentMove != null) { + if (false) Log.i("InputDevice", "Adding batch x=" + scaledX + + " y=" + scaledY + " to " + currentMove); currentMove.addBatch(curTime, scaledX, scaledY, scaledPressure, scaledSize, metaState); if (WindowManagerPolicy.WATCH_POINTER) { diff --git a/services/java/com/android/server/InputMethodManagerService.java b/services/java/com/android/server/InputMethodManagerService.java new file mode 100644 index 0000000000000000000000000000000000000000..c701ca118c776f12f161ac006d3591d5dcd459ec --- /dev/null +++ b/services/java/com/android/server/InputMethodManagerService.java @@ -0,0 +1,1305 @@ +/* + * Copyright (C) 2006-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.android.server; + +import com.android.internal.os.HandlerCaller; +import com.android.internal.view.IInputContext; +import com.android.internal.view.IInputMethod; +import com.android.internal.view.IInputMethodCallback; +import com.android.internal.view.IInputMethodClient; +import com.android.internal.view.IInputMethodManager; +import com.android.internal.view.IInputMethodSession; +import com.android.internal.view.InputBindResult; + +import com.android.server.status.IconData; +import com.android.server.status.StatusBarService; + +import org.xmlpull.v1.XmlPullParserException; + +import android.app.AlertDialog; +import android.content.ComponentName; +import android.content.ContentResolver; +import android.content.Context; +import android.content.DialogInterface; +import android.content.IntentFilter; +import android.content.DialogInterface.OnCancelListener; +import android.content.Intent; +import android.content.ServiceConnection; +import android.content.pm.PackageManager; +import android.content.pm.ResolveInfo; +import android.content.pm.ServiceInfo; +import android.content.res.Resources; +import android.content.res.TypedArray; +import android.database.ContentObserver; +import android.net.Uri; +import android.os.Binder; +import android.os.Handler; +import android.os.IBinder; +import android.os.IInterface; +import android.os.Message; +import android.os.Parcel; +import android.os.RemoteException; +import android.os.ServiceManager; +import android.provider.Settings; +import android.text.TextUtils; +import android.util.Log; +import android.util.PrintWriterPrinter; +import android.util.Printer; +import android.view.IWindowManager; +import android.view.WindowManager; +import android.view.inputmethod.DefaultInputMethod; +import android.view.inputmethod.InputBinding; +import android.view.inputmethod.InputMethod; +import android.view.inputmethod.InputMethodInfo; +import android.view.inputmethod.InputMethodManager; +import android.view.inputmethod.EditorInfo; + +import java.io.FileDescriptor; +import java.io.IOException; +import java.io.PrintWriter; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +/** + * This class provides a system service that manages input methods. + */ +public class InputMethodManagerService extends IInputMethodManager.Stub + implements ServiceConnection, Handler.Callback { + static final boolean DEBUG = false; + static final String TAG = "InputManagerService"; + + static final int MSG_SHOW_IM_PICKER = 1; + + static final int MSG_UNBIND_INPUT = 1000; + static final int MSG_BIND_INPUT = 1010; + static final int MSG_SHOW_SOFT_INPUT = 1020; + static final int MSG_HIDE_SOFT_INPUT = 1030; + static final int MSG_ATTACH_TOKEN = 1040; + static final int MSG_CREATE_SESSION = 1050; + + static final int MSG_START_INPUT = 2000; + static final int MSG_RESTART_INPUT = 2010; + + static final int MSG_UNBIND_METHOD = 3000; + static final int MSG_BIND_METHOD = 3010; + + final Context mContext; + final Handler mHandler; + final SettingsObserver mSettingsObserver; + final StatusBarService mStatusBar; + final IBinder mInputMethodIcon; + final IconData mInputMethodData; + final IWindowManager mIWindowManager; + final HandlerCaller mCaller; + + final InputBindResult mNoBinding = new InputBindResult(null, null, -1); + + // All known input methods. mMethodMap also serves as the global + // lock for this class. + final ArrayList mMethodList + = new ArrayList(); + final HashMap mMethodMap + = new HashMap(); + + final TextUtils.SimpleStringSplitter mStringColonSplitter + = new TextUtils.SimpleStringSplitter(':'); + + class SessionState { + final ClientState client; + final IInputMethod method; + final IInputMethodSession session; + + @Override + public String toString() { + return "SessionState{uid " + client.uid + " pid " + client.pid + + " method " + Integer.toHexString( + System.identityHashCode(method)) + + " session " + Integer.toHexString( + System.identityHashCode(session)) + + "}"; + } + + SessionState(ClientState _client, IInputMethod _method, + IInputMethodSession _session) { + client = _client; + method = _method; + session = _session; + } + } + + class ClientState { + final IInputMethodClient client; + final IInputContext inputContext; + final int uid; + final int pid; + final InputBinding binding; + + boolean sessionRequested; + SessionState curSession; + + @Override + public String toString() { + return "ClientState{" + Integer.toHexString( + System.identityHashCode(this)) + " uid " + uid + + " pid " + pid + "}"; + } + + ClientState(IInputMethodClient _client, IInputContext _inputContext, + int _uid, int _pid) { + client = _client; + inputContext = _inputContext; + uid = _uid; + pid = _pid; + binding = new InputBinding(null, inputContext.asBinder(), uid, pid); + } + } + + final HashMap mClients + = new HashMap(); + + /** + * Id of the currently selected input method. + */ + String mCurMethodId; + + /** + * The current binding sequence number, incremented every time there is + * a new bind performed. + */ + int mCurSeq; + + /** + * The client that is currently bound to an input method. + */ + ClientState mCurClient; + + /** + * The attributes last provided by the current client. + */ + EditorInfo mCurAttribute; + + /** + * The input method ID of the input method service that we are currently + * connected to or in the process of connecting to. + */ + String mCurId; + + /** + * Set to true if our ServiceConnection is currently actively bound to + * a service (whether or not we have gotten its IBinder back yet). + */ + boolean mHaveConnection; + + /** + * Set if the client has asked for the input method to be shown. + */ + boolean mShowRequested; + + /** + * Set if we last told the input method to show itself. + */ + boolean mInputShown; + + /** + * The Intent used to connect to the current input method. + */ + Intent mCurIntent; + + /** + * The token we have made for the currently active input method, to + * identify it in the future. + */ + IBinder mCurToken; + + /** + * If non-null, this is the input method service we are currently connected + * to. + */ + IInputMethod mCurMethod; + + /** + * Have we called mCurMethod.bindInput()? + */ + boolean mBoundToMethod; + + /** + * Currently enabled session. Only touched by service thread, not + * protected by a lock. + */ + SessionState mEnabledSession; + + /** + * True if the screen is on. The value is true initially. + */ + boolean mScreenOn = true; + + AlertDialog.Builder mDialogBuilder; + AlertDialog mSwitchingDialog; + InputMethodInfo[] mIms; + CharSequence[] mItems; + + class SettingsObserver extends ContentObserver { + SettingsObserver(Handler handler) { + super(handler); + ContentResolver resolver = mContext.getContentResolver(); + resolver.registerContentObserver(Settings.Secure.getUriFor( + Settings.Secure.DEFAULT_INPUT_METHOD), false, this); + } + + @Override public void onChange(boolean selfChange) { + synchronized (mMethodMap) { + updateFromSettingsLocked(); + } + } + } + + class ScreenOnOffReceiver extends android.content.BroadcastReceiver { + @Override + public void onReceive(Context context, Intent intent) { + if (intent.getAction().equals(Intent.ACTION_SCREEN_ON)) { + mScreenOn = true; + } else if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) { + mScreenOn = false; + } else { + Log.e(TAG, "Unexpected intent " + intent); + } + + // Inform the current client of the change in active status + try { + if (mCurClient != null && mCurClient.client != null) { + mCurClient.client.setActive(mScreenOn); + } + } catch (RemoteException e) { + Log.e(TAG, "Got RemoteException sending 'screen on/off' notification", e); + } + } + } + + class PackageReceiver extends android.content.BroadcastReceiver { + @Override + public void onReceive(Context context, Intent intent) { + synchronized (mMethodMap) { + buildInputMethodListLocked(mMethodList, mMethodMap); + + InputMethodInfo curIm = null; + String curInputMethodId = Settings.Secure.getString(context + .getContentResolver(), Settings.Secure.DEFAULT_INPUT_METHOD); + final int N = mMethodList.size(); + if (curInputMethodId != null) { + for (int i=0; i enabled = getEnabledInputMethodListLocked(); + if (enabled != null && enabled.size() > 0) { + changed = true; + curIm = enabled.get(0); + curInputMethodId = curIm.getId(); + Log.i(TAG, "Switching to: " + curInputMethodId); + Settings.Secure.putString(mContext.getContentResolver(), + Settings.Secure.DEFAULT_INPUT_METHOD, + curInputMethodId); + } else if (curIm != null) { + changed = true; + curIm = null; + curInputMethodId = ""; + Log.i(TAG, "Unsetting current input method"); + Settings.Secure.putString(mContext.getContentResolver(), + Settings.Secure.DEFAULT_INPUT_METHOD, + curInputMethodId); + } + } + + } else if (curIm == null) { + // We currently don't have a default input method... is + // one now available? + List enabled = getEnabledInputMethodListLocked(); + if (enabled != null && enabled.size() > 0) { + changed = true; + curIm = enabled.get(0); + curInputMethodId = curIm.getId(); + Log.i(TAG, "New default input method: " + curInputMethodId); + Settings.Secure.putString(mContext.getContentResolver(), + Settings.Secure.DEFAULT_INPUT_METHOD, + curInputMethodId); + } + } + + if (changed) { + updateFromSettingsLocked(); + } + } + } + } + + class MethodCallback extends IInputMethodCallback.Stub { + final IInputMethod mMethod; + + MethodCallback(IInputMethod method) { + mMethod = method; + } + + public void finishedEvent(int seq, boolean handled) throws RemoteException { + } + + public void sessionCreated(IInputMethodSession session) throws RemoteException { + onSessionCreated(mMethod, session); + } + } + + public InputMethodManagerService(Context context, StatusBarService statusBar) { + mContext = context; + mHandler = new Handler(this); + mIWindowManager = IWindowManager.Stub.asInterface( + ServiceManager.getService(Context.WINDOW_SERVICE)); + mCaller = new HandlerCaller(context, new HandlerCaller.Callback() { + public void executeMessage(Message msg) { + handleMessage(msg); + } + }); + + IntentFilter packageFilt = new IntentFilter(); + packageFilt.addAction(Intent.ACTION_PACKAGE_ADDED); + packageFilt.addAction(Intent.ACTION_PACKAGE_CHANGED); + packageFilt.addAction(Intent.ACTION_PACKAGE_REMOVED); + packageFilt.addAction(Intent.ACTION_PACKAGE_RESTARTED); + packageFilt.addDataScheme("package"); + mContext.registerReceiver(new PackageReceiver(), packageFilt); + + IntentFilter screenOnOffFilt = new IntentFilter(); + screenOnOffFilt.addAction(Intent.ACTION_SCREEN_ON); + screenOnOffFilt.addAction(Intent.ACTION_SCREEN_OFF); + mContext.registerReceiver(new ScreenOnOffReceiver(), screenOnOffFilt); + + buildInputMethodListLocked(mMethodList, mMethodMap); + + final String enabledStr = Settings.Secure.getString( + mContext.getContentResolver(), + Settings.Secure.ENABLED_INPUT_METHODS); + Log.i(TAG, "Enabled input methods: " + enabledStr); + if (enabledStr == null) { + Log.i(TAG, "Enabled input methods has not been set, enabling all"); + InputMethodInfo defIm = null; + StringBuilder sb = new StringBuilder(256); + final int N = mMethodList.size(); + for (int i=0; i 0) sb.append(':'); + sb.append(imi.getId()); + if (defIm == null && imi.getIsDefaultResourceId() != 0) { + try { + Resources res = mContext.createPackageContext( + imi.getPackageName(), 0).getResources(); + if (res.getBoolean(imi.getIsDefaultResourceId())) { + defIm = imi; + Log.i(TAG, "Selected default: " + imi.getId()); + } + } catch (PackageManager.NameNotFoundException ex) { + } catch (Resources.NotFoundException ex) { + } + } + } + if (defIm == null && N > 0) { + defIm = mMethodList.get(0); + Log.i(TAG, "No default found, using " + defIm.getId()); + } + Settings.Secure.putString(mContext.getContentResolver(), + Settings.Secure.ENABLED_INPUT_METHODS, sb.toString()); + if (defIm != null) { + Settings.Secure.putString(mContext.getContentResolver(), + Settings.Secure.DEFAULT_INPUT_METHOD, defIm.getId()); + } + } + + mStatusBar = statusBar; + mInputMethodData = IconData.makeIcon("ime", null, 0, 0, 0); + mInputMethodIcon = statusBar.addIcon(mInputMethodData, null); + statusBar.setIconVisibility(mInputMethodIcon, false); + + mSettingsObserver = new SettingsObserver(mHandler); + updateFromSettingsLocked(); + } + + @Override + public boolean onTransact(int code, Parcel data, Parcel reply, int flags) + throws RemoteException { + try { + return super.onTransact(code, data, reply, flags); + } catch (RuntimeException e) { + // The input method manager only throws security exceptions, so let's + // log all others. + if (!(e instanceof SecurityException)) { + Log.e(TAG, "Input Method Manager Crash", e); + } + throw e; + } + } + + public void systemReady() { + + } + + public List getInputMethodList() { + synchronized (mMethodMap) { + return new ArrayList(mMethodList); + } + } + + public List getEnabledInputMethodList() { + synchronized (mMethodMap) { + return getEnabledInputMethodListLocked(); + } + } + + List getEnabledInputMethodListLocked() { + final ArrayList res = new ArrayList(); + + final String enabledStr = Settings.Secure.getString( + mContext.getContentResolver(), + Settings.Secure.ENABLED_INPUT_METHODS); + if (enabledStr != null) { + final TextUtils.SimpleStringSplitter splitter = mStringColonSplitter; + splitter.setString(enabledStr); + + while (splitter.hasNext()) { + InputMethodInfo info = mMethodMap.get(splitter.next()); + if (info != null) { + res.add(info); + } + } + } + + return res; + } + + public void addClient(IInputMethodClient client, + IInputContext inputContext, int uid, int pid) { + synchronized (mMethodMap) { + mClients.put(client.asBinder(), new ClientState(client, + inputContext, uid, pid)); + } + } + + public void removeClient(IInputMethodClient client) { + synchronized (mMethodMap) { + mClients.remove(client.asBinder()); + } + } + + void executeOrSendMessage(IInterface target, Message msg) { + if (target.asBinder() instanceof Binder) { + mCaller.sendMessage(msg); + } else { + handleMessage(msg); + msg.recycle(); + } + } + + void unbindCurrentInputLocked() { + if (mCurClient != null) { + if (DEBUG) Log.v(TAG, "unbindCurrentInputLocked: client = " + + mCurClient.client.asBinder()); + if (mBoundToMethod) { + mBoundToMethod = false; + if (mCurMethod != null) { + executeOrSendMessage(mCurMethod, mCaller.obtainMessageO( + MSG_UNBIND_INPUT, mCurMethod)); + } + } + executeOrSendMessage(mCurClient.client, mCaller.obtainMessageIO( + MSG_UNBIND_METHOD, mCurSeq, mCurClient.client)); + mCurClient.sessionRequested = false; + + // Call setActive(false) on the old client + try { + mCurClient.client.setActive(false); + } catch (RemoteException e) { + Log.e(TAG, "Got RemoteException sending setActive(false) notification", e); + } + mCurClient = null; + } + } + + InputBindResult attachNewInputLocked(boolean initial, boolean needResult) { + if (!mBoundToMethod) { + executeOrSendMessage(mCurMethod, mCaller.obtainMessageOO( + MSG_BIND_INPUT, mCurMethod, mCurClient.binding)); + mBoundToMethod = true; + } + final SessionState session = mCurClient.curSession; + if (initial) { + executeOrSendMessage(session.method, mCaller.obtainMessageOO( + MSG_START_INPUT, session, mCurAttribute)); + } else { + executeOrSendMessage(session.method, mCaller.obtainMessageOO( + MSG_RESTART_INPUT, session, mCurAttribute)); + } + if (mShowRequested) { + showCurrentInputLocked(); + } + return needResult + ? new InputBindResult(session.session, mCurId, mCurSeq) + : null; + } + + InputBindResult startInputLocked(IInputMethodClient client, + EditorInfo attribute, boolean initial, boolean needResult) { + // If no method is currently selected, do nothing. + if (mCurMethodId == null) { + return mNoBinding; + } + + ClientState cs = mClients.get(client.asBinder()); + if (cs == null) { + throw new IllegalArgumentException("unknown client " + + client.asBinder()); + } + + try { + if (!mIWindowManager.inputMethodClientHasFocus(cs.client)) { + // Check with the window manager to make sure this client actually + // has a window with focus. If not, reject. This is thread safe + // because if the focus changes some time before or after, the + // next client receiving focus that has any interest in input will + // be calling through here after that change happens. + Log.w(TAG, "Starting input on non-focused client " + cs.client + + " (uid=" + cs.uid + " pid=" + cs.pid + ")"); + return null; + } + } catch (RemoteException e) { + } + + if (mCurClient != cs) { + // If the client is changing, we need to switch over to the new + // one. + unbindCurrentInputLocked(); + if (DEBUG) Log.v(TAG, "switching to client: client = " + + cs.client.asBinder()); + + // If the screen is on, inform the new client it is active + if (mScreenOn) { + try { + cs.client.setActive(mScreenOn); + } catch (RemoteException e) { + Log.e(TAG, "Got RemoteException sending setActive notification", e); + } + } + } + + // Bump up the sequence for this client and attach it. + mCurSeq++; + if (mCurSeq <= 0) mCurSeq = 1; + mCurClient = cs; + mCurAttribute = attribute; + + // Check if the input method is changing. + if (mCurId != null && mCurId.equals(mCurMethodId)) { + if (cs.curSession != null) { + // Fast case: if we are already connected to the input method, + // then just return it. + return attachNewInputLocked(initial, needResult); + } + if (mHaveConnection) { + if (mCurMethod != null && !cs.sessionRequested) { + cs.sessionRequested = true; + if (DEBUG) Log.v(TAG, "Creating new session for client " + cs); + executeOrSendMessage(mCurMethod, mCaller.obtainMessageOO( + MSG_CREATE_SESSION, mCurMethod, + new MethodCallback(mCurMethod))); + } + return new InputBindResult(null, mCurId, mCurSeq); + } + } + + InputMethodInfo info = mMethodMap.get(mCurMethodId); + if (info == null) { + throw new IllegalArgumentException("Unknown id: " + mCurMethodId); + } + + if (mCurToken != null) { + try { + mIWindowManager.removeWindowToken(mCurToken); + } catch (RemoteException e) { + } + mCurToken = null; + } + + if (mHaveConnection) { + mContext.unbindService(this); + mHaveConnection = false; + } + + clearCurMethod(); + + mCurIntent = new Intent(InputMethod.SERVICE_INTERFACE); + mCurIntent.setComponent(info.getComponent()); + if (mContext.bindService(mCurIntent, this, Context.BIND_AUTO_CREATE)) { + mHaveConnection = true; + mCurId = info.getId(); + mCurToken = new Binder(); + try { + mIWindowManager.addWindowToken(mCurToken, + WindowManager.LayoutParams.TYPE_INPUT_METHOD); + } catch (RemoteException e) { + } + return new InputBindResult(null, mCurId, mCurSeq); + } else { + mCurIntent = null; + Log.e(TAG, "Failure connecting to input method service: " + + mCurIntent); + } + return null; + } + + public InputBindResult startInput(IInputMethodClient client, + EditorInfo attribute, boolean initial, boolean needResult) { + synchronized (mMethodMap) { + final long ident = Binder.clearCallingIdentity(); + try { + return startInputLocked(client, attribute, initial, needResult); + } finally { + Binder.restoreCallingIdentity(ident); + } + } + } + + public void finishInput(IInputMethodClient client) { + } + + public void onServiceConnected(ComponentName name, IBinder service) { + synchronized (mMethodMap) { + if (mCurIntent != null && name.equals(mCurIntent.getComponent())) { + mCurMethod = IInputMethod.Stub.asInterface(service); + if (mCurClient != null) { + executeOrSendMessage(mCurMethod, mCaller.obtainMessageOO( + MSG_ATTACH_TOKEN, mCurMethod, mCurToken)); + if (mCurClient != null) { + if (DEBUG) Log.v(TAG, "Creating first session while with client " + + mCurClient); + executeOrSendMessage(mCurMethod, mCaller.obtainMessageOO( + MSG_CREATE_SESSION, mCurMethod, + new MethodCallback(mCurMethod))); + } + } + } + } + } + + void onSessionCreated(IInputMethod method, IInputMethodSession session) { + synchronized (mMethodMap) { + if (mCurMethod == method) { + if (mCurClient != null) { + mCurClient.curSession = new SessionState(mCurClient, + method, session); + mCurClient.sessionRequested = false; + InputBindResult res = attachNewInputLocked(true, true); + if (res.method != null) { + executeOrSendMessage(mCurClient.client, mCaller.obtainMessageOO( + MSG_BIND_METHOD, mCurClient.client, res)); + } + } + } + } + } + + void clearCurMethod() { + if (mCurMethod != null) { + for (ClientState cs : mClients.values()) { + cs.sessionRequested = false; + cs.curSession = null; + } + mCurMethod = null; + } + } + + public void onServiceDisconnected(ComponentName name) { + synchronized (mMethodMap) { + if (DEBUG) Log.v(TAG, "Service disconnected: " + name + + " mCurIntent=" + mCurIntent); + if (mCurMethod != null && mCurIntent != null + && name.equals(mCurIntent.getComponent())) { + clearCurMethod(); + mShowRequested = mInputShown; + mInputShown = false; + if (mCurClient != null) { + executeOrSendMessage(mCurClient.client, mCaller.obtainMessageIO( + MSG_UNBIND_METHOD, mCurSeq, mCurClient.client)); + } + } + } + } + + public void updateStatusIcon(int iconId, String iconPackage) { + if (iconId == 0) { + Log.d(TAG, "hide the small icon for the input method"); + mStatusBar.setIconVisibility(mInputMethodIcon, false); + } else { + Log.d(TAG, "show a small icon for the input method"); + + if (iconPackage != null + && iconPackage + .equals(InputMethodManager.BUILDIN_INPUTMETHOD_PACKAGE)) { + iconPackage = null; + } + + mInputMethodData.iconId = iconId; + mInputMethodData.iconPackage = iconPackage; + mStatusBar.updateIcon(mInputMethodIcon, mInputMethodData, null); + mStatusBar.setIconVisibility(mInputMethodIcon, true); + } + } + + void updateFromSettingsLocked() { + String id = Settings.Secure.getString(mContext.getContentResolver(), + Settings.Secure.DEFAULT_INPUT_METHOD); + if (id != null) { + try { + setInputMethodLocked(id); + } catch (IllegalArgumentException e) { + Log.w(TAG, "Unknown input method from prefs: " + id, e); + } + } + } + + void setInputMethodLocked(String id) { + InputMethodInfo info = mMethodMap.get(id); + if (info == null) { + throw new IllegalArgumentException("Unknown id: " + mCurMethodId); + } + + if (id.equals(mCurMethodId)) { + return; + } + + final long ident = Binder.clearCallingIdentity(); + try { + mCurMethodId = id; + Settings.Secure.putString(mContext.getContentResolver(), + Settings.Secure.DEFAULT_INPUT_METHOD, id); + + Intent intent = new Intent(Intent.ACTION_INPUT_METHOD_CHANGED); + intent.putExtra("input_method_id", id); + mContext.sendBroadcast(intent); + unbindCurrentInputLocked(); + } finally { + Binder.restoreCallingIdentity(ident); + } + } + + public void showSoftInput(IInputMethodClient client) { + synchronized (mMethodMap) { + if (mCurClient == null || client == null + || mCurClient.client.asBinder() != client.asBinder()) { + try { + // We need to check if this is the current client with + // focus in the window manager, to allow this call to + // be made before input is started in it. + if (!mIWindowManager.inputMethodClientHasFocus(client)) { + Log.w(TAG, "Ignoring showSoftInput of: " + client); + return; + } + } catch (RemoteException e) { + } + } + + showCurrentInputLocked(); + } + } + + void showCurrentInputLocked() { + mShowRequested = true; + if (!mInputShown) { + if (mCurMethod != null) { + executeOrSendMessage(mCurMethod, mCaller.obtainMessageO( + MSG_SHOW_SOFT_INPUT, mCurMethod)); + mInputShown = true; + } + } + } + + public void hideSoftInput(IInputMethodClient client) { + synchronized (mMethodMap) { + if (mCurClient == null || client == null + || mCurClient.client.asBinder() != client.asBinder()) { + try { + // We need to check if this is the current client with + // focus in the window manager, to allow this call to + // be made before input is started in it. + if (!mIWindowManager.inputMethodClientHasFocus(client)) { + Log.w(TAG, "Ignoring hideSoftInput of: " + client); + return; + } + } catch (RemoteException e) { + } + } + + hideCurrentInputLocked(); + } + } + + void hideCurrentInputLocked() { + if (mInputShown && mCurMethod != null) { + executeOrSendMessage(mCurMethod, mCaller.obtainMessageO( + MSG_HIDE_SOFT_INPUT, mCurMethod)); + } + mInputShown = false; + mShowRequested = false; + } + + public void windowGainedFocus(IInputMethodClient client, + boolean viewHasFocus, int softInputMode, boolean first, + int windowFlags) { + synchronized (mMethodMap) { + if (DEBUG) Log.v(TAG, "windowGainedFocus: " + client.asBinder() + + " viewHasFocus=" + viewHasFocus + + " softInputMode=#" + Integer.toHexString(softInputMode) + + " first=" + first + " flags=#" + + Integer.toHexString(windowFlags)); + + if (mCurClient == null || client == null + || mCurClient.client.asBinder() != client.asBinder()) { + try { + // We need to check if this is the current client with + // focus in the window manager, to allow this call to + // be made before input is started in it. + if (!mIWindowManager.inputMethodClientHasFocus(client)) { + Log.w(TAG, "Ignoring focus gain of: " + client); + return; + } + } catch (RemoteException e) { + } + } + + switch (softInputMode&WindowManager.LayoutParams.SOFT_INPUT_MASK_STATE) { + case WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED: + if (!viewHasFocus || (softInputMode & + WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST) + != WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE) { + if ((windowFlags&WindowManager.LayoutParams + .FLAG_ALT_FOCUSABLE_IM) == 0) { + // There is no focus view, and this window will + // be behind any soft input window, then hide the + // soft input window if it is shown. + hideCurrentInputLocked(); + } + } + break; + case WindowManager.LayoutParams.SOFT_INPUT_STATE_UNCHANGED: + // Do nothing. + break; + case WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN: + hideCurrentInputLocked(); + break; + case WindowManager.LayoutParams.SOFT_INPUT_STATE_FIRST_VISIBLE: + if (first && !viewHasFocus && (windowFlags + & WindowManager.LayoutParams.FLAG_RESTORED_STATE) == 0) { + showCurrentInputLocked(); + } + break; + case WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE: + if (viewHasFocus) { + showCurrentInputLocked(); + } + break; + } + } + } + + public void showInputMethodPickerFromClient(IInputMethodClient client) { + synchronized (mMethodMap) { + if (mCurClient == null || client == null + || mCurClient.client.asBinder() != client.asBinder()) { + Log.w(TAG, "Ignoring showInputMethodDialogFromClient of: " + client); + } + + mHandler.sendEmptyMessage(MSG_SHOW_IM_PICKER); + } + } + + public void setInputMethod(IBinder token, String id) { + synchronized (mMethodMap) { + if (mCurToken == null || mCurToken != token) { + Log.w(TAG, "Ignoring setInputMethod of token: " + token); + } + + setInputMethodLocked(id); + } + } + + public void hideMySoftInput(IBinder token) { + synchronized (mMethodMap) { + if (mCurToken == null || mCurToken != token) { + Log.w(TAG, "Ignoring hideInputMethod of token: " + token); + } + + if (mInputShown && mCurMethod != null) { + executeOrSendMessage(mCurMethod, mCaller.obtainMessageO( + MSG_HIDE_SOFT_INPUT, mCurMethod)); + } + mInputShown = false; + mShowRequested = false; + } + } + + void setEnabledSessionInMainThread(SessionState session) { + if (mEnabledSession != session) { + if (mEnabledSession != null) { + try { + if (DEBUG) Log.v(TAG, "Disabling: " + mEnabledSession); + mEnabledSession.method.setSessionEnabled( + mEnabledSession.session, false); + } catch (RemoteException e) { + } + } + mEnabledSession = session; + try { + if (DEBUG) Log.v(TAG, "Enabling: " + mEnabledSession); + session.method.setSessionEnabled( + session.session, true); + } catch (RemoteException e) { + } + } + } + + public boolean handleMessage(Message msg) { + HandlerCaller.SomeArgs args; + switch (msg.what) { + case MSG_SHOW_IM_PICKER: + showInputMethodMenu(); + return true; + + // --------------------------------------------------------- + + case MSG_UNBIND_INPUT: + try { + ((IInputMethod)msg.obj).unbindInput(); + } catch (RemoteException e) { + // There is nothing interesting about the method dying. + } + return true; + case MSG_BIND_INPUT: + args = (HandlerCaller.SomeArgs)msg.obj; + try { + ((IInputMethod)args.arg1).bindInput((InputBinding)args.arg2); + } catch (RemoteException e) { + } + return true; + case MSG_SHOW_SOFT_INPUT: + try { + ((IInputMethod)msg.obj).showSoftInput(); + } catch (RemoteException e) { + } + return true; + case MSG_HIDE_SOFT_INPUT: + try { + ((IInputMethod)msg.obj).hideSoftInput(); + } catch (RemoteException e) { + } + return true; + case MSG_ATTACH_TOKEN: + args = (HandlerCaller.SomeArgs)msg.obj; + try { + ((IInputMethod)args.arg1).attachToken((IBinder)args.arg2); + } catch (RemoteException e) { + } + return true; + case MSG_CREATE_SESSION: + args = (HandlerCaller.SomeArgs)msg.obj; + try { + ((IInputMethod)args.arg1).createSession( + (IInputMethodCallback)args.arg2); + } catch (RemoteException e) { + } + return true; + + // --------------------------------------------------------- + + case MSG_START_INPUT: + args = (HandlerCaller.SomeArgs)msg.obj; + try { + SessionState session = (SessionState)args.arg1; + setEnabledSessionInMainThread(session); + session.method.startInput((EditorInfo)args.arg2); + } catch (RemoteException e) { + } + return true; + case MSG_RESTART_INPUT: + args = (HandlerCaller.SomeArgs)msg.obj; + try { + SessionState session = (SessionState)args.arg1; + setEnabledSessionInMainThread(session); + session.method.restartInput((EditorInfo)args.arg2); + } catch (RemoteException e) { + } + return true; + + // --------------------------------------------------------- + + case MSG_UNBIND_METHOD: + try { + ((IInputMethodClient)msg.obj).onUnbindMethod(msg.arg1); + } catch (RemoteException e) { + // There is nothing interesting about the last client dying. + } + return true; + case MSG_BIND_METHOD: + args = (HandlerCaller.SomeArgs)msg.obj; + try { + ((IInputMethodClient)args.arg1).onBindMethod( + (InputBindResult)args.arg2); + } catch (RemoteException e) { + Log.w(TAG, "Client died receiving input method " + args.arg2); + } + return true; + } + return false; + } + + void buildInputMethodListLocked(ArrayList list, + HashMap map) { + list.clear(); + map.clear(); + + PackageManager pm = mContext.getPackageManager(); + + Object[][] buildin = {{ + DefaultInputMethod.class.getName(), + DefaultInputMethod.getMetaInfo()}}; + + List services = pm.queryIntentServices( + new Intent(InputMethod.SERVICE_INTERFACE), + PackageManager.GET_META_DATA); + + for (int i = 0; i < services.size(); ++i) { + ResolveInfo ri = services.get(i); + ServiceInfo si = ri.serviceInfo; + ComponentName compName = new ComponentName(si.packageName, si.name); + if (!android.Manifest.permission.BIND_INPUT_METHOD.equals( + si.permission)) { + Log.w(TAG, "Skipping input method " + compName + + ": it does not require the permission " + + android.Manifest.permission.BIND_INPUT_METHOD); + continue; + } + + if (DEBUG) Log.d(TAG, "Checking " + compName); + + /* Built-in input methods are not currently supported... this will + * need to be reworked to bring them back (all input methods must + * now be published in a manifest). + */ + /* + if (compName.getPackageName().equals( + InputMethodManager.BUILDIN_INPUTMETHOD_PACKAGE)) { + // System build-in input methods; + String inputMethodName = null; + int kbType = 0; + String skbName = null; + + for (int j = 0; j < buildin.length; ++j) { + Object[] obj = buildin[j]; + if (compName.getClassName().equals(obj[0])) { + InputMethodMetaInfo imp = (InputMethodMetaInfo) obj[1]; + inputMethodName = imp.inputMethodName; + } + } + + InputMethodMetaInfo p = new InputMethodMetaInfo(compName, + inputMethodName, ""); + + list.add(p); + + if (DEBUG) { + Log.d(TAG, "Found a build-in input method " + p); + } + + continue; + } + */ + + try { + InputMethodInfo p = new InputMethodInfo(mContext, ri); + list.add(p); + map.put(p.getId(), p); + + if (DEBUG) { + Log.d(TAG, "Found a third-party input method " + p); + } + + } catch (XmlPullParserException e) { + Log.w(TAG, "Unable to load input method " + compName, e); + } catch (IOException e) { + Log.w(TAG, "Unable to load input method " + compName, e); + } + } + } + + // ---------------------------------------------------------------------- + + public void showInputMethodMenu() { + if (DEBUG) Log.v(TAG, "Show switching menu"); + + hideInputMethodMenu(); + + final Context context = mContext; + + final PackageManager pm = context.getPackageManager(); + + String lastInputMethodId = Settings.Secure.getString(context + .getContentResolver(), Settings.Secure.DEFAULT_INPUT_METHOD); + if (DEBUG) Log.v(TAG, "Current IME: " + lastInputMethodId); + + final List immis = getEnabledInputMethodList(); + + int N = (immis == null ? 0 : immis.size()); + + mItems = new CharSequence[N]; + mIms = new InputMethodInfo[N]; + + for (int i = 0; i < N; ++i) { + InputMethodInfo property = immis.get(i); + mItems[i] = property.loadLabel(pm); + mIms[i] = property; + } + + int checkedItem = 0; + for (int i = 0; i < N; ++i) { + if (mIms[i].getId().equals(lastInputMethodId)) { + checkedItem = i; + break; + } + } + + AlertDialog.OnClickListener adocl = new AlertDialog.OnClickListener() { + public void onClick(DialogInterface dialog, int which) { + hideInputMethodMenu(); + } + }; + + TypedArray a = context.obtainStyledAttributes(null, + com.android.internal.R.styleable.DialogPreference, + com.android.internal.R.attr.alertDialogStyle, 0); + mDialogBuilder = new AlertDialog.Builder(context) + .setTitle(com.android.internal.R.string.select_input_method) + .setOnCancelListener(new OnCancelListener() { + public void onCancel(DialogInterface dialog) { + hideInputMethodMenu(); + } + }) + .setIcon(a.getDrawable( + com.android.internal.R.styleable.DialogPreference_dialogTitle)); + a.recycle(); + + mDialogBuilder.setSingleChoiceItems(mItems, checkedItem, + new AlertDialog.OnClickListener() { + public void onClick(DialogInterface dialog, int which) { + synchronized (mMethodMap) { + InputMethodInfo im = mIms[which]; + hideInputMethodMenu(); + setInputMethodLocked(im.getId()); + } + } + }); + + synchronized (mMethodMap) { + mSwitchingDialog = mDialogBuilder.create(); + mSwitchingDialog.getWindow().setType( + WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG); + mSwitchingDialog.show(); + } + } + + void hideInputMethodMenu() { + if (DEBUG) Log.v(TAG, "Hide switching menu"); + + synchronized (mMethodMap) { + if (mSwitchingDialog != null) { + mSwitchingDialog.dismiss(); + mSwitchingDialog = null; + } + + mDialogBuilder = null; + mItems = null; + mIms = null; + } + } + + @Override + protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { + if (mContext.checkCallingPermission("android.permission.DUMP") + != PackageManager.PERMISSION_GRANTED) { + + pw.println("Permission Denial: can't dump InputMethodManager from from pid=" + + Binder.getCallingPid() + + ", uid=" + Binder.getCallingUid()); + return; + } + + synchronized (mMethodMap) { + final Printer p = new PrintWriterPrinter(pw); + p.println("Current Input Method Manager state:"); + int N = mMethodList.size(); + p.println(" Input Methods:"); + for (int i=0; i mDevices = new SparseArray(); + SparseArray mDevices = new SparseArray(); int mGlobalMetaState = 0; boolean mHaveGlobalMetaState = false; @@ -498,6 +498,7 @@ public abstract class KeyInputQueue { ev.inputDevice.mAbs.currentMove = null; } if (ev.event == ev.inputDevice.mRel.currentMove) { + if (false) Log.i(TAG, "Detach rel " + ev.event); ev.inputDevice.mRel.currentMove = null; ev.inputDevice.mRel.x = 0; ev.inputDevice.mRel.y = 0; diff --git a/services/java/com/android/server/LocationManagerService.java b/services/java/com/android/server/LocationManagerService.java index 1bf60d4bc5df3dd7f568b87656b17217c7a731d2..831d1d259d712df229ae484c0269874b78321754 100644 --- a/services/java/com/android/server/LocationManagerService.java +++ b/services/java/com/android/server/LocationManagerService.java @@ -57,9 +57,9 @@ import android.os.PowerManager; import android.os.RemoteException; import android.os.SystemClock; import android.provider.Settings; +import android.provider.Settings.SettingNotFoundException; import android.telephony.CellLocation; import android.telephony.PhoneStateListener; -import android.telephony.ServiceState; import android.telephony.TelephonyManager; import android.util.Config; import android.util.Log; @@ -145,24 +145,25 @@ public class LocationManagerService extends ILocationManager.Stub { private boolean mCellWakeLockAcquired = false; /** - * Mapping from listener IBinder to local Listener wrappers. + * Mapping from listener IBinder/PendingIntent to local Listener wrappers. */ - private final HashMap mListeners = - new HashMap(); + private final HashMap mListeners = + new HashMap(); /** - * Mapping from listener IBinder to a map from provider name to UpdateRecord. + * Mapping from listener IBinder/PendingIntent to a map from provider name to UpdateRecord. */ - private final HashMap> mLocationListeners = - new HashMap>(); + private final HashMap> mLocationListeners = + new HashMap>(); /** - * Mapping from listener IBinder to a map from provider name to last broadcast location. + * Mapping from listener IBinder/PendingIntent to a map from provider name to last broadcast + * location. */ - private final HashMap> mLastFixBroadcast = - new HashMap>(); - private final HashMap> mLastStatusBroadcast = - new HashMap>(); + private final HashMap> mLastFixBroadcast = + new HashMap>(); + private final HashMap> mLastStatusBroadcast = + new HashMap>(); /** * Mapping from provider name to all its UpdateRecords @@ -178,7 +179,7 @@ public class LocationManagerService extends ILocationManager.Stub { new HashMap(); // Proximity listeners - private ProximityListener mProximityListener = null; + private Receiver mProximityListener = null; private HashMap mProximityAlerts = new HashMap(); private HashSet mProximitiesEntered = @@ -195,7 +196,7 @@ public class LocationManagerService extends ILocationManager.Stub { // Last known cell service state private TelephonyManager mTelephonyManager; - private ServiceState mServiceState = new ServiceState(); + private int mSignalStrength = -1; // Location collector private LocationCollector mCollector; @@ -206,11 +207,82 @@ public class LocationManagerService extends ILocationManager.Stub { // Wifi Manager private WifiManager mWifiManager; - private final class Listener implements IBinder.DeathRecipient { + /** + * A wrapper class holding either an ILocationListener or a PendingIntent to receive + * location updates. + */ + private final class Receiver implements IBinder.DeathRecipient { final ILocationListener mListener; + final PendingIntent mPendingIntent; - Listener(ILocationListener listener) { + Receiver(ILocationListener listener) { mListener = listener; + mPendingIntent = null; + } + + Receiver(PendingIntent intent) { + mPendingIntent = intent; + mListener = null; + } + + public Object getKey() { + if (mListener != null) { + return mListener.asBinder(); + } else { + return mPendingIntent; + } + } + + public boolean isListener() { + return mListener != null; + } + + public boolean isPendingIntent() { + return mPendingIntent != null; + } + + public ILocationListener getListener() { + if (mListener != null) { + return mListener; + } + throw new IllegalStateException("Request for non-existent listener"); + } + + public PendingIntent getPendingIntent() { + if (mPendingIntent != null) { + return mPendingIntent; + } + throw new IllegalStateException("Request for non-existent intent"); + } + + public void onStatusChanged(String provider, int status, Bundle extras) + throws RemoteException { + if (mListener != null) { + mListener.onStatusChanged(provider, status, extras); + } else { + Intent statusChanged = new Intent(); + statusChanged.putExtras(extras); + statusChanged.putExtra(LocationManager.KEY_STATUS_CHANGED, status); + try { + mPendingIntent.send(mContext, 0, statusChanged, null, null); + } catch (PendingIntent.CanceledException e) { + _removeUpdates(this); + } + } + } + + public void onLocationChanged(Location location) throws RemoteException { + if (mListener != null) { + mListener.onLocationChanged(location); + } else { + Intent locationChanged = new Intent(); + locationChanged.putExtra(LocationManager.KEY_LOCATION_CHANGED, location); + try { + mPendingIntent.send(mContext, 0, locationChanged, null, null); + } catch (PendingIntent.CanceledException e) { + _removeUpdates(this); + } + } } public void binderDied() { @@ -218,7 +290,7 @@ public class LocationManagerService extends ILocationManager.Stub { Log.d(TAG, "Location listener died"); } synchronized (mLocationListeners) { - _removeUpdates(mListener); + _removeUpdates(this); } } } @@ -228,7 +300,7 @@ public class LocationManagerService extends ILocationManager.Stub { String s = null; try { File f = new File(LocationManager.SYSTEM_DIR + "/location." - + provider); + + provider); if (!f.exists()) { return null; } @@ -443,13 +515,22 @@ public class LocationManagerService extends ILocationManager.Stub { // Create location collector mCollector = new LocationCollector(mMasfClient); + // Alarm manager, needs to be done before calling loadProviders() below + mAlarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); + + // Create a wake lock, needs to be done before calling loadProviders() below + PowerManager powerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE); + mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_KEY); + // Load providers loadProviders(); // Listen for Radio changes mTelephonyManager = (TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE); mTelephonyManager.listen(mPhoneStateListener, - PhoneStateListener.LISTEN_SERVICE_STATE | PhoneStateListener.LISTEN_CELL_LOCATION); + PhoneStateListener.LISTEN_CELL_LOCATION | + PhoneStateListener.LISTEN_SIGNAL_STRENGTH | + PhoneStateListener.LISTEN_DATA_CONNECTION_STATE); // Register for Network (Wifi or Mobile) updates NetworkStateBroadcastReceiver networkReceiver = new NetworkStateBroadcastReceiver(); @@ -460,9 +541,6 @@ public class LocationManagerService extends ILocationManager.Stub { networkIntentFilter.addAction(GpsLocationProvider.GPS_ENABLED_CHANGE_ACTION); context.registerReceiver(networkReceiver, networkIntentFilter); - // Alarm manager - mAlarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); - // Register for power updates PowerStateBroadcastReceiver powerStateReceiver = new PowerStateBroadcastReceiver(); IntentFilter intentFilter = new IntentFilter(); @@ -472,10 +550,6 @@ public class LocationManagerService extends ILocationManager.Stub { intentFilter.addAction(Intent.ACTION_BATTERY_CHANGED); context.registerReceiver(powerStateReceiver, intentFilter); - // Create a wake lock - PowerManager powerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE); - mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_KEY); - // Get the wifi manager mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE); @@ -510,8 +584,8 @@ public class LocationManagerService extends ILocationManager.Stub { } // Use system settings ContentResolver resolver = mContext.getContentResolver(); - String allowedProviders = Settings.System.getString(resolver, - Settings.System.LOCATION_PROVIDERS_ALLOWED); + String allowedProviders = Settings.Secure.getString(resolver, + Settings.Secure.LOCATION_PROVIDERS_ALLOWED); return ((allowedProviders != null) && (allowedProviders.contains(provider))); } @@ -638,16 +712,28 @@ public class LocationManagerService extends ILocationManager.Stub { } synchronized (mRecordsByProvider) { - HashSet records = mRecordsByProvider.get(provider); if (records != null) { for (UpdateRecord record : records) { - // Sends a notification message to the listener + // Sends a notification message to the receiver try { - if (enabled) { - record.mListener.mListener.onProviderEnabled(provider); + Receiver receiver = record.mReceiver; + if (receiver.isListener()) { + if (enabled) { + receiver.getListener().onProviderEnabled(provider); + } else { + receiver.getListener().onProviderDisabled(provider); + } } else { - record.mListener.mListener.onProviderDisabled(provider); + PendingIntent intent = receiver.getPendingIntent(); + Intent providerIntent = new Intent(); + providerIntent.putExtra(LocationManager.KEY_PROVIDER_ENABLED, enabled); + try { + receiver.getPendingIntent().send(mContext, 0, + providerIntent, null, null); + } catch (PendingIntent.CanceledException e) { + _removeUpdates(receiver); + } } } catch (RemoteException e) { // The death link will clean this up. @@ -694,15 +780,15 @@ public class LocationManagerService extends ILocationManager.Stub { private class UpdateRecord { String mProvider; - Listener mListener; + Receiver mReceiver; long mMinTime; float mMinDistance; String[] mPackages; - UpdateRecord(String provider, long minTime, float minDistance, Listener listener, - String[] packages) { + UpdateRecord(String provider, long minTime, float minDistance, + Receiver receiver, String[] packages) { mProvider = provider; - mListener = listener; + mReceiver = receiver; mMinTime = minTime; mMinDistance = minDistance; mPackages = packages; @@ -740,7 +826,20 @@ public class LocationManagerService extends ILocationManager.Stub { long minTime, float minDistance, ILocationListener listener) { try { - _requestLocationUpdates(provider, minTime, minDistance, listener); + _requestLocationUpdates(provider, minTime, minDistance, + new Receiver(listener)); + } catch (SecurityException se) { + throw se; + } catch (Exception e) { + Log.e(TAG, "requestUpdates got exception:", e); + } + } + + public void requestLocationUpdatesPI(String provider, + long minTime, float minDistance, PendingIntent intent) { + try { + _requestLocationUpdates(provider, minTime, minDistance, + new Receiver(intent)); } catch (SecurityException se) { throw se; } catch (Exception e) { @@ -749,9 +848,10 @@ public class LocationManagerService extends ILocationManager.Stub { } private void _requestLocationUpdates(String provider, - long minTime, float minDistance, ILocationListener listener) { + long minTime, float minDistance, Receiver receiver) { + Object key = receiver.getKey(); if (Config.LOGD) { - Log.d(TAG, "_requestLocationUpdates: listener = " + listener.asBinder()); + Log.d(TAG, "_requestLocationUpdates: listener = " + key); } LocationProviderImpl impl = LocationProviderImpl.getProvider(provider); @@ -766,24 +866,23 @@ public class LocationManagerService extends ILocationManager.Stub { // so wakelock calls will succeed long identity = Binder.clearCallingIdentity(); try { - Listener myListener = new Listener(listener); - UpdateRecord r = new UpdateRecord(provider, minTime, minDistance, myListener, packages); - + UpdateRecord r = new UpdateRecord(provider, minTime, minDistance, receiver, packages); synchronized (mLocationListeners) { - IBinder binder = listener.asBinder(); - if (mListeners.get(binder) == null) { + if (mListeners.get(key) == null) { try { - binder.linkToDeath(myListener, 0); - mListeners.put(binder, myListener); + if (receiver.isListener()) { + receiver.getListener().asBinder().linkToDeath(receiver, 0); + } + mListeners.put(key, receiver); } catch (RemoteException e) { return; } } - HashMap records = mLocationListeners.get(binder); + HashMap records = mLocationListeners.get(key); if (records == null) { records = new HashMap(); - mLocationListeners.put(binder, records); + mLocationListeners.put(key, records); } UpdateRecord oldRecord = records.put(provider, r); if (oldRecord != null) { @@ -809,9 +908,12 @@ public class LocationManagerService extends ILocationManager.Stub { } else { try { // Notify the listener that updates are currently disabled - listener.onProviderDisabled(provider); + if (receiver.isListener()) { + receiver.getListener().onProviderDisabled(provider); + } } catch(RemoteException e) { - Log.w(TAG, "RemoteException calling onProviderDisabled on " + listener); + Log.w(TAG, "RemoteException calling onProviderDisabled on " + + receiver.getListener()); } } } @@ -822,7 +924,7 @@ public class LocationManagerService extends ILocationManager.Stub { public void removeUpdates(ILocationListener listener) { try { - _removeUpdates(listener); + _removeUpdates(new Receiver(listener)); } catch (SecurityException se) { throw se; } catch (Exception e) { @@ -830,24 +932,34 @@ public class LocationManagerService extends ILocationManager.Stub { } } - private void _removeUpdates(ILocationListener listener) { + public void removeUpdatesPI(PendingIntent intent) { + try { + _removeUpdates(new Receiver(intent)); + } catch (SecurityException se) { + throw se; + } catch (Exception e) { + Log.e(TAG, "removeUpdates got exception:", e); + } + } + + private void _removeUpdates(Receiver receiver) { + Object key = receiver.getKey(); if (Config.LOGD) { - Log.d(TAG, "_removeUpdates: listener = " + listener.asBinder()); + Log.d(TAG, "_removeUpdates: listener = " + key); } // so wakelock calls will succeed long identity = Binder.clearCallingIdentity(); try { synchronized (mLocationListeners) { - IBinder binder = listener.asBinder(); - Listener myListener = mListeners.remove(binder); - if (myListener != null) { - binder.unlinkToDeath(myListener, 0); + Receiver myReceiver = mListeners.remove(key); + if ((myReceiver != null) && (myReceiver.isListener())) { + myReceiver.getListener().asBinder().unlinkToDeath(myReceiver, 0); } // Record which providers were associated with this listener HashSet providers = new HashSet(); - HashMap oldRecords = mLocationListeners.get(binder); + HashMap oldRecords = mLocationListeners.get(key); if (oldRecords != null) { // Call dispose() on the obsolete update records. for (UpdateRecord record : oldRecords.values()) { @@ -862,9 +974,9 @@ public class LocationManagerService extends ILocationManager.Stub { providers.addAll(oldRecords.keySet()); } - mLocationListeners.remove(binder); - mLastFixBroadcast.remove(binder); - mLastStatusBroadcast.remove(binder); + mLocationListeners.remove(key); + mLastFixBroadcast.remove(key); + mLastStatusBroadcast.remove(key); // See if the providers associated with this listener have any // other listeners; if one does, inform it of the new smallest minTime @@ -894,7 +1006,7 @@ public class LocationManagerService extends ILocationManager.Stub { } } - updateWakelockStatus(mScreenOn); + updateWakelockStatus(mScreenOn); } } finally { Binder.restoreCallingIdentity(identity); @@ -905,6 +1017,11 @@ public class LocationManagerService extends ILocationManager.Stub { if (mGpsLocationProvider == null) { return false; } + if (mContext.checkCallingPermission(ACCESS_FINE_LOCATION) != + PackageManager.PERMISSION_GRANTED) { + throw new SecurityException("Requires ACCESS_FINE_LOCATION permission"); + } + try { mGpsLocationProvider.addGpsStatusListener(listener); } catch (RemoteException e) { @@ -996,7 +1113,6 @@ public class LocationManagerService extends ILocationManager.Stub { ArrayList intentsToRemove = null; for (ProximityAlert alert : mProximityAlerts.values()) { - PendingIntent intent = alert.getIntent(); long expiration = alert.getExpiration(); @@ -1115,7 +1231,7 @@ public class LocationManagerService extends ILocationManager.Stub { mProximityAlerts.put(intent, alert); if (mProximityListener == null) { - mProximityListener = new ProximityListener(); + mProximityListener = new Receiver(new ProximityListener()); LocationProvider provider = LocationProviderImpl.getProvider( LocationManager.GPS_PROVIDER); @@ -1345,15 +1461,15 @@ public class LocationManagerService extends ILocationManager.Stub { // Broadcast location or status to all listeners for (UpdateRecord r : records) { - ILocationListener listener = r.mListener.mListener; - IBinder binder = listener.asBinder(); + Receiver receiver = r.mReceiver; + Object key = receiver.getKey(); // Broadcast location only if it is valid if (locationValid) { - HashMap map = mLastFixBroadcast.get(binder); + HashMap map = mLastFixBroadcast.get(key); if (map == null) { map = new HashMap(); - mLastFixBroadcast.put(binder, map); + mLastFixBroadcast.put(key, map); } Location lastLoc = map.get(provider); if ((lastLoc == null) || shouldBroadcast(loc, lastLoc, r)) { @@ -1364,19 +1480,19 @@ public class LocationManagerService extends ILocationManager.Stub { lastLoc.set(loc); } try { - listener.onLocationChanged(loc); + receiver.onLocationChanged(loc); } catch (RemoteException doe) { - Log.w(TAG, "RemoteException calling onLocationChanged on " + listener); - _removeUpdates(listener); + Log.w(TAG, "RemoteException calling onLocationChanged on " + receiver); + _removeUpdates(receiver); } } } // Broadcast status message - HashMap statusMap = mLastStatusBroadcast.get(binder); + HashMap statusMap = mLastStatusBroadcast.get(key); if (statusMap == null) { statusMap = new HashMap(); - mLastStatusBroadcast.put(binder, statusMap); + mLastStatusBroadcast.put(key, statusMap); } long prevStatusUpdateTime = (statusMap.get(provider) != null) ? statusMap.get(provider) : 0; @@ -1386,10 +1502,10 @@ public class LocationManagerService extends ILocationManager.Stub { statusMap.put(provider, newStatusUpdateTime); try { - listener.onStatusChanged(provider, status, extras); + receiver.onStatusChanged(provider, status, extras); } catch (RemoteException doe) { - Log.w(TAG, "RemoteException calling onStatusChanged on " + listener); - _removeUpdates(listener); + Log.w(TAG, "RemoteException calling onStatusChanged on " + receiver); + _removeUpdates(receiver); } } } @@ -1423,7 +1539,8 @@ public class LocationManagerService extends ILocationManager.Stub { } if ((mWakeLockAcquireTime != 0) && - (SystemClock.elapsedRealtime() - mWakeLockAcquireTime > MAX_TIME_FOR_WAKE_LOCK)) { + (SystemClock.elapsedRealtime() - mWakeLockAcquireTime + > MAX_TIME_FOR_WAKE_LOCK)) { removeMessages(MESSAGE_ACQUIRE_WAKE_LOCK); removeMessages(MESSAGE_RELEASE_WAKE_LOCK); @@ -1449,7 +1566,7 @@ public class LocationManagerService extends ILocationManager.Stub { acquireWakeLock(); } else if (msg.what == MESSAGE_RELEASE_WAKE_LOCK) { log("LocationWorkerHandler: Release"); - + // Update wakelock status so the next alarm is set before releasing wakelock updateWakelockStatus(mScreenOn); releaseWakeLock(); @@ -1462,22 +1579,24 @@ public class LocationManagerService extends ILocationManager.Stub { } PhoneStateListener mPhoneStateListener = new PhoneStateListener() { + + private CellState mLastCellState = null; @Override public void onCellLocationChanged(CellLocation cellLocation) { try { - ServiceState serviceState = mServiceState; + int asu = mSignalStrength; // Gets cell state - CellState cellState = new CellState(serviceState, cellLocation); + mLastCellState = new CellState(mTelephonyManager, cellLocation, asu); // Notify collector - mCollector.updateCellState(cellState); + mCollector.updateCellState(mLastCellState); // Updates providers List providers = LocationProviderImpl.getProviders(); for (LocationProviderImpl provider : providers) { if (provider.requiresCell()) { - provider.updateCellState(cellState); + provider.updateCellState(mLastCellState); } } } catch (Exception e) { @@ -1486,8 +1605,19 @@ public class LocationManagerService extends ILocationManager.Stub { } @Override - public void onServiceStateChanged(ServiceState serviceState) { - mServiceState = serviceState; + public void onSignalStrengthChanged(int asu) { + mSignalStrength = asu; + + if (mLastCellState != null) { + mLastCellState.updateSignalStrength(asu); + } + } + + @Override + public void onDataConnectionStateChanged(int state) { + if (mLastCellState != null) { + mLastCellState.updateRadioType(mTelephonyManager); + } } }; @@ -1578,7 +1708,8 @@ public class LocationManagerService extends ILocationManager.Stub { } else if (action.equals(GpsLocationProvider.GPS_ENABLED_CHANGE_ACTION)) { - final boolean enabled = intent.getBooleanExtra(GpsLocationProvider.EXTRA_ENABLED, false); + final boolean enabled = intent.getBooleanExtra(GpsLocationProvider.EXTRA_ENABLED, + false); if (!enabled) { // When GPS is disabled, we are OK to release wake-lock @@ -1608,7 +1739,7 @@ public class LocationManagerService extends ILocationManager.Stub { if (screenOn) { startGps(); } else if (mScreenOn && !screenOn) { - + // We just turned the screen off so stop navigating stopGps(); } @@ -1641,13 +1772,23 @@ public class LocationManagerService extends ILocationManager.Stub { } private void acquireWakeLock() { + try { + acquireWakeLockX(); + } catch (Exception e) { + // This is to catch a runtime exception thrown when we try to release an + // already released lock. + Log.e(TAG, "exception in acquireWakeLock()", e); + } + } + + private void acquireWakeLockX() { if (mWakeLock.isHeld()) { log("Must release wakelock before acquiring"); mWakeLockAcquireTime = 0; mWakeLock.release(); } - boolean networkActive = (mNetworkLocationProvider != null) + boolean networkActive = (mNetworkLocationProvider != null) && mNetworkLocationProvider.isLocationTracking(); boolean gpsActive = (mGpsLocationProvider != null) && mGpsLocationProvider.isLocationTracking(); @@ -1668,7 +1809,7 @@ public class LocationManagerService extends ILocationManager.Stub { // Start the gps provider startGps(); - + // Acquire cell lock if (mCellWakeLockAcquired) { // Lock is already acquired @@ -1700,7 +1841,7 @@ public class LocationManagerService extends ILocationManager.Stub { } private void startGps() { - boolean gpsActive = (mGpsLocationProvider != null) + boolean gpsActive = (mGpsLocationProvider != null) && mGpsLocationProvider.isLocationTracking(); if (gpsActive) { mGpsLocationProvider.startNavigating(); @@ -1708,7 +1849,7 @@ public class LocationManagerService extends ILocationManager.Stub { } private void stopGps() { - boolean gpsActive = mGpsLocationProvider != null + boolean gpsActive = mGpsLocationProvider != null && mGpsLocationProvider.isLocationTracking(); if (gpsActive) { mGpsLocationProvider.stopNavigating(); @@ -1716,6 +1857,16 @@ public class LocationManagerService extends ILocationManager.Stub { } private void releaseWakeLock() { + try { + releaseWakeLockX(); + } catch (Exception e) { + // This is to catch a runtime exception thrown when we try to release an + // already released lock. + Log.e(TAG, "exception in releaseWakeLock()", e); + } + } + + private void releaseWakeLockX() { // Release wifi lock WifiManager.WifiLock wifiLock = getWifiWakelock(); if (wifiLock != null) { @@ -1726,22 +1877,22 @@ public class LocationManagerService extends ILocationManager.Stub { } if (!mScreenOn) { - + // Stop the gps stopGps(); } - + // Release cell lock if (mCellWakeLockAcquired) { mTelephonyManager.disableLocationUpdates(); mCellWakeLockAcquired = false; } - + // Notify NetworkLocationProvider if (mNetworkLocationProvider != null) { mNetworkLocationProvider.updateCellLockStatus(mCellWakeLockAcquired); } - + // Release wake lock mWakeLockAcquireTime = 0; if (mWakeLock.isHeld()) { @@ -1751,7 +1902,7 @@ public class LocationManagerService extends ILocationManager.Stub { log("Can't release wakelock again!"); } } - + // Geocoder public String getFromLocation(double latitude, double longitude, int maxResults, @@ -1903,14 +2054,29 @@ public class LocationManagerService extends ILocationManager.Stub { return mSupportsSpeed; } } + + private void checkMockPermissions() { + boolean allowMocks = false; + try { + allowMocks = Settings.Secure.getInt(mContext.getContentResolver(), + Settings.Secure.ALLOW_MOCK_LOCATION) == 1; + } catch (SettingNotFoundException e) { + // Do nothing + } + if (!allowMocks) { + throw new SecurityException("Requires ACCESS_MOCK_LOCATION secure setting"); + } - public void addTestProvider(String name, boolean requiresNetwork, boolean requiresSatellite, - boolean requiresCell, boolean hasMonetaryCost, boolean supportsAltitude, - boolean supportsSpeed, boolean supportsBearing, int powerRequirement, int accuracy) { if (mContext.checkCallingPermission(ACCESS_MOCK_LOCATION) != PackageManager.PERMISSION_GRANTED) { throw new SecurityException("Requires ACCESS_MOCK_LOCATION permission"); - } + } + } + + public void addTestProvider(String name, boolean requiresNetwork, boolean requiresSatellite, + boolean requiresCell, boolean hasMonetaryCost, boolean supportsAltitude, + boolean supportsSpeed, boolean supportsBearing, int powerRequirement, int accuracy) { + checkMockPermissions(); MockProvider provider = new MockProvider(name, requiresNetwork, requiresSatellite, requiresCell, hasMonetaryCost, supportsAltitude, @@ -1923,10 +2089,7 @@ public class LocationManagerService extends ILocationManager.Stub { } public void removeTestProvider(String provider) { - if (mContext.checkCallingPermission(ACCESS_MOCK_LOCATION) != - PackageManager.PERMISSION_GRANTED) { - throw new SecurityException("Requires ACCESS_MOCK_LOCATION permission"); - } + checkMockPermissions(); LocationProviderImpl p = LocationProviderImpl.getProvider(provider); if (p == null) { throw new IllegalArgumentException("Provider \"" + provider + "\" unknown"); @@ -1936,10 +2099,7 @@ public class LocationManagerService extends ILocationManager.Stub { } public void setTestProviderLocation(String provider, Location loc) { - if (mContext.checkCallingPermission(ACCESS_MOCK_LOCATION) != - PackageManager.PERMISSION_GRANTED) { - throw new SecurityException("Requires ACCESS_MOCK_LOCATION permission"); - } + checkMockPermissions(); if (LocationProviderImpl.getProvider(provider) == null) { throw new IllegalArgumentException("Provider \"" + provider + "\" unknown"); } @@ -1947,10 +2107,7 @@ public class LocationManagerService extends ILocationManager.Stub { } public void clearTestProviderLocation(String provider) { - if (mContext.checkCallingPermission(ACCESS_MOCK_LOCATION) != - PackageManager.PERMISSION_GRANTED) { - throw new SecurityException("Requires ACCESS_MOCK_LOCATION permission"); - } + checkMockPermissions(); if (LocationProviderImpl.getProvider(provider) == null) { throw new IllegalArgumentException("Provider \"" + provider + "\" unknown"); } @@ -1958,10 +2115,7 @@ public class LocationManagerService extends ILocationManager.Stub { } public void setTestProviderEnabled(String provider, boolean enabled) { - if (mContext.checkCallingPermission(ACCESS_MOCK_LOCATION) != - PackageManager.PERMISSION_GRANTED) { - throw new SecurityException("Requires ACCESS_MOCK_LOCATION permission"); - } + checkMockPermissions(); if (LocationProviderImpl.getProvider(provider) == null) { throw new IllegalArgumentException("Provider \"" + provider + "\" unknown"); } @@ -1976,10 +2130,7 @@ public class LocationManagerService extends ILocationManager.Stub { } public void clearTestProviderEnabled(String provider) { - if (mContext.checkCallingPermission(ACCESS_MOCK_LOCATION) != - PackageManager.PERMISSION_GRANTED) { - throw new SecurityException("Requires ACCESS_MOCK_LOCATION permission"); - } + checkMockPermissions(); if (LocationProviderImpl.getProvider(provider) == null) { throw new IllegalArgumentException("Provider \"" + provider + "\" unknown"); } @@ -1989,10 +2140,7 @@ public class LocationManagerService extends ILocationManager.Stub { } public void setTestProviderStatus(String provider, int status, Bundle extras, long updateTime) { - if (mContext.checkCallingPermission(ACCESS_MOCK_LOCATION) != - PackageManager.PERMISSION_GRANTED) { - throw new SecurityException("Requires ACCESS_MOCK_LOCATION permission"); - } + checkMockPermissions(); if (LocationProviderImpl.getProvider(provider) == null) { throw new IllegalArgumentException("Provider \"" + provider + "\" unknown"); } @@ -2002,10 +2150,7 @@ public class LocationManagerService extends ILocationManager.Stub { } public void clearTestProviderStatus(String provider) { - if (mContext.checkCallingPermission(ACCESS_MOCK_LOCATION) != - PackageManager.PERMISSION_GRANTED) { - throw new SecurityException("Requires ACCESS_MOCK_LOCATION permission"); - } + checkMockPermissions(); if (LocationProviderImpl.getProvider(provider) == null) { throw new IllegalArgumentException("Provider \"" + provider + "\" unknown"); } diff --git a/services/java/com/android/server/MountService.java b/services/java/com/android/server/MountService.java index 6f29332d5bc8f8f7c85e26d252095b238b94c70c..03480d19ba89a81095bea9714dbbde91510f83a2 100644 --- a/services/java/com/android/server/MountService.java +++ b/services/java/com/android/server/MountService.java @@ -22,6 +22,7 @@ import android.app.PendingIntent; import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; +import android.content.res.Resources; import android.net.Uri; import android.os.IMountService; import android.os.Environment; @@ -59,10 +60,11 @@ class MountService extends IMountService.Stub { private Notification mUsbStorageNotification; private class SdDoorListener extends UEventObserver { - static final String SD_DOOR_UEVENT_MATCH = "DEVPATH=/class/switch/sd-door"; + static final String SD_DOOR_UEVENT_MATCH = "DEVPATH=/devices/virtual/switch/sd-door"; + static final String SD_DOOR_SWITCH_NAME = "sd-door"; public void onUEvent(UEvent event) { - if ("sd-door".equals(event.get("SWITCH_NAME"))) { + if (SD_DOOR_SWITCH_NAME.equals(event.get("SWITCH_NAME"))) { sdDoorStateChanged(event.get("SWITCH_STATE")); } } @@ -127,9 +129,7 @@ class MountService extends IMountService.Stub { throw new SecurityException("Requires MOUNT_UNMOUNT_FILESYSTEMS permission"); } - // notify listeners that we are trying to eject - notifyMediaEject(mountPath); - // tell usbd to unmount the media + // tell mountd to unmount the media mListener.ejectMedia(mountPath); } @@ -269,22 +269,24 @@ class MountService extends IMountService.Stub { * @return A {@link Notification} that leads to the dialog to enable USB storage. */ private synchronized Notification getUsbStorageNotification() { + Resources r = Resources.getSystem(); + CharSequence title = + r.getText(com.android.internal.R.string.usb_storage_notification_title); + CharSequence message = + r.getText(com.android.internal.R.string.usb_storage_notification_message); + if (mUsbStorageNotification == null) { - CharSequence title = - mContext.getString(com.android.internal.R.string.usb_storage_notification_title); - CharSequence message = - mContext.getString(com.android.internal.R.string.usb_storage_notification_message); - mUsbStorageNotification = new Notification(); mUsbStorageNotification.icon = com.android.internal.R.drawable.stat_sys_data_usb; - mUsbStorageNotification.tickerText = title; mUsbStorageNotification.when = 0; mUsbStorageNotification.flags = Notification.FLAG_AUTO_CANCEL; mUsbStorageNotification.defaults |= Notification.DEFAULT_SOUND; - mUsbStorageNotification.setLatestEventInfo(mContext, title, message, - getUsbStorageDialogIntent()); } + mUsbStorageNotification.tickerText = title; + mUsbStorageNotification.setLatestEventInfo(mContext, title, message, + getUsbStorageDialogIntent()); + return mUsbStorageNotification; } diff --git a/services/java/com/android/server/NotificationManagerService.java b/services/java/com/android/server/NotificationManagerService.java index 14ac1be39097bad29797adc4d8848ee112303068..eb9ebe95aae19509e2abac14182a6c7296a07171 100644 --- a/services/java/com/android/server/NotificationManagerService.java +++ b/services/java/com/android/server/NotificationManagerService.java @@ -72,7 +72,7 @@ class NotificationManagerService extends INotificationManager.Stub private static final long[] DEFAULT_VIBRATE_PATTERN = {0, 250, 250, 250}; - private static final int DEFAULT_STREAM_TYPE = AudioManager.STREAM_RING; + private static final int DEFAULT_STREAM_TYPE = AudioManager.STREAM_NOTIFICATION; final Context mContext; final IActivityManager mAm; diff --git a/services/java/com/android/server/PackageManagerService.java b/services/java/com/android/server/PackageManagerService.java index c000d8a53e9e937fcdcf6d1a10945ee113599b77..e86ff029e99753750b1d5e0ca43f2dcd5233ddd3 100644 --- a/services/java/com/android/server/PackageManagerService.java +++ b/services/java/com/android/server/PackageManagerService.java @@ -55,6 +55,7 @@ import android.content.pm.ProviderInfo; import android.content.pm.ResolveInfo; import android.content.pm.ServiceInfo; import android.content.pm.Signature; +import android.content.pm.PackageParser.Package; import android.net.Uri; import android.os.Binder; import android.os.Bundle; @@ -177,7 +178,7 @@ class PackageManagerService extends IPackageManager.Stub { // Lock for state used when installing and doing other long running // operations. Methods that must be called with this lock held have // the prefix "LI". - Object mInstallLock = new Object(); + final Object mInstallLock = new Object(); // These are the directories in the 3rd party applications installed dir // that we have currently loaded packages from. Keys are the application's @@ -674,7 +675,7 @@ class PackageManagerService extends IPackageManager.Stub { } } - int[] appendInt(int[] cur, int val) { + static int[] appendInt(int[] cur, int val) { if (cur == null) { return new int[] { val }; } @@ -690,7 +691,7 @@ class PackageManagerService extends IPackageManager.Stub { return ret; } - int[] appendInts(int[] cur, int[] add) { + static int[] appendInts(int[] cur, int[] add) { if (add == null) return cur; if (cur == null) return add; final int N = add.length; @@ -718,6 +719,9 @@ class PackageManagerService extends IPackageManager.Stub { if (p != null) { return generatePackageInfo(p, flags); } + if((flags & PackageManager.GET_UNINSTALLED_PACKAGES) != 0) { + return generatePackageInfoFromSettingsLP(packageName, flags); + } } return null; } @@ -725,6 +729,14 @@ class PackageManagerService extends IPackageManager.Stub { public int getPackageUid(String packageName) { synchronized (mPackages) { PackageParser.Package p = mPackages.get(packageName); + if(p != null) { + return p.applicationInfo.uid; + } + PackageSetting ps = mSettings.mPackages.get(packageName); + if((ps == null) || (ps.pkg == null) || (ps.pkg.applicationInfo == null)) { + return -1; + } + p = ps.pkg; return p != null ? p.applicationInfo.uid : -1; } } @@ -796,12 +808,39 @@ class PackageManagerService extends IPackageManager.Stub { } } + private ApplicationInfo generateApplicationInfoFromSettingsLP(String packageName, int flags) { + PackageSetting ps = mSettings.mPackages.get(packageName); + if(ps != null) { + if(ps.pkg == null) { + PackageInfo pInfo = generatePackageInfoFromSettingsLP(packageName, flags); + if(pInfo != null) { + return pInfo.applicationInfo; + } + return null; + } + return PackageParser.generateApplicationInfo(ps.pkg, flags); + } + return null; + } + + private PackageInfo generatePackageInfoFromSettingsLP(String packageName, int flags) { + PackageSetting ps = mSettings.mPackages.get(packageName); + if(ps != null) { + if(ps.pkg == null) { + ps.pkg = new PackageParser.Package(packageName); + ps.pkg.applicationInfo.packageName = packageName; + } + return generatePackageInfo(ps.pkg, flags); + } + return null; + } + public ApplicationInfo getApplicationInfo(String packageName, int flags) { synchronized (mPackages) { PackageParser.Package p = mPackages.get(packageName); if (Config.LOGV) Log.v( - TAG, "getApplicationInfo " + packageName - + ": " + p); + TAG, "getApplicationInfo " + packageName + + ": " + p); if (p != null) { // Note: isEnabledLP() does not apply here - always return info return PackageParser.generateApplicationInfo(p, flags); @@ -809,10 +848,14 @@ class PackageManagerService extends IPackageManager.Stub { if ("android".equals(packageName)||"system".equals(packageName)) { return mAndroidApplication; } + if((flags & PackageManager.GET_UNINSTALLED_PACKAGES) != 0) { + return generateApplicationInfoFromSettingsLP(packageName, flags); + } } return null; } + public void freeApplicationCache(final long freeStorageSize, final IPackageDataObserver observer) { mContext.enforceCallingOrSelfPermission( android.Manifest.permission.CLEAR_APP_CACHE, null); @@ -1063,6 +1106,19 @@ class PackageManagerService extends IPackageManager.Stub { } return null; } + + public int getUidForSharedUser(String sharedUserName) { + if(sharedUserName == null) { + return -1; + } + synchronized (mPackages) { + SharedUserSetting suid = mSettings.getSharedUserLP(sharedUserName, 0, false); + if(suid == null) { + return -1; + } + return suid.userId; + } + } public ResolveInfo resolveIntent(Intent intent, String resolvedType, int flags) { @@ -1391,37 +1447,63 @@ class PackageManagerService extends IPackageManager.Stub { queryIntent(null, intent, resolvedType, flags); } } - + public List getInstalledPackages(int flags) { ArrayList finalList = new ArrayList(); synchronized (mPackages) { - Iterator i = mPackages.values().iterator(); - while (i.hasNext()) { - final PackageParser.Package p = i.next(); - PackageInfo pi = generatePackageInfo(p, flags); - if (pi != null) { - finalList.add(pi); + if((flags & PackageManager.GET_UNINSTALLED_PACKAGES) != 0) { + Iterator i = mSettings.mPackages.values().iterator(); + while (i.hasNext()) { + final PackageSetting ps = i.next(); + PackageInfo psPkg = generatePackageInfoFromSettingsLP(ps.name, flags); + if(psPkg != null) { + finalList.add(psPkg); + } + } + } + else { + Iterator i = mPackages.values().iterator(); + while (i.hasNext()) { + final PackageParser.Package p = i.next(); + if (p.applicationInfo != null) { + PackageInfo pi = generatePackageInfo(p, flags); + if(pi != null) { + finalList.add(pi); + } + } } } } - return finalList; } public List getInstalledApplications(int flags) { ArrayList finalList = new ArrayList(); - - synchronized (mPackages) { - Iterator i = mPackages.values().iterator(); - while (i.hasNext()) { - final PackageParser.Package p = i.next(); - if (p.applicationInfo != null) { - finalList.add(p.applicationInfo); + synchronized(mPackages) { + if((flags & PackageManager.GET_UNINSTALLED_PACKAGES) != 0) { + Iterator i = mSettings.mPackages.values().iterator(); + while (i.hasNext()) { + final PackageSetting ps = i.next(); + ApplicationInfo ai = generateApplicationInfoFromSettingsLP(ps.name, flags); + if(ai != null) { + finalList.add(ai); + } + } + } + else { + Iterator i = mPackages.values().iterator(); + while (i.hasNext()) { + final PackageParser.Package p = i.next(); + if (p.applicationInfo != null) { + ApplicationInfo ai = PackageParser.generateApplicationInfo(p, flags); + if(ai != null) { + finalList.add(ai); + } + } } } } - return finalList; } @@ -1569,7 +1651,7 @@ class PackageManagerService extends IPackageManager.Stub { PackageParser.Package pkg, File srcFile, int parseFlags) { if (GET_CERTIFICATES) { if (ps == null || !ps.codePath.equals(srcFile) - || ps.timeStamp != srcFile.lastModified()) { + || ps.getTimeStamp() != srcFile.lastModified()) { Log.i(TAG, srcFile.toString() + " changed; collecting certs"); if (!pp.collectCertificates(pkg, parseFlags)) { mLastScanError = pp.getParseError(); @@ -1580,6 +1662,10 @@ class PackageManagerService extends IPackageManager.Stub { return true; } + /* + * Scan a package and return the newly parsed package. + * Returns null in case of errors and the error code is stored in mLastScanError + */ private PackageParser.Package scanPackageLI(File scanFile, File destCodeFile, File destResourceFile, int parseFlags, int scanMode) { @@ -1595,11 +1681,29 @@ class PackageManagerService extends IPackageManager.Stub { return null; } PackageSetting ps; + PackageSetting updatedPkg; synchronized (mPackages) { ps = mSettings.peekPackageLP(pkg.packageName, scanFile.toString()); + updatedPkg = mSettings.mDisabledSysPackages.get(pkg.packageName); + } + if (updatedPkg != null) { + // An updated system app will not have the PARSE_IS_SYSTEM flag set initially + parseFlags |= PackageParser.PARSE_IS_SYSTEM; + } + if ((parseFlags&PackageParser.PARSE_IS_SYSTEM) != 0) { + // Check for updated system applications here + if ((updatedPkg != null) && (ps == null)) { + // The system package has been updated and the code path does not match + // Ignore entry. Just return + Log.w(TAG, "Package:" + pkg.packageName + + " has been updated. Ignoring the one from path:"+scanFile); + mLastScanError = PackageManager.INSTALL_FAILED_DUPLICATE_PACKAGE; + return null; + } } if (!collectCertificatesLI(pp, ps, pkg, scanFile, parseFlags)) { + Log.i(TAG, "Failed verifying certificates for package:" + pkg.packageName); return null; } // The apk is forward locked (not public) if its code and resources @@ -1607,6 +1711,7 @@ class PackageManagerService extends IPackageManager.Stub { if (ps != null && !ps.codePath.equals(ps.resourcePath)) { scanMode |= SCAN_FORWARD_LOCKED; } + // Note that we invoke the following method only if we are about to unpack an application return scanPackageLI(scanFile, destCodeFile, destResourceFile, pkg, parseFlags, scanMode | SCAN_UPDATE_SIGNATURE); } @@ -1652,6 +1757,7 @@ class PackageManagerService extends IPackageManager.Stub { mScanningPath = scanFile; if (pkg == null) { + mLastScanError = PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME; return null; } @@ -1681,7 +1787,7 @@ class PackageManagerService extends IPackageManager.Stub { mResolveActivity.packageName = mAndroidApplication.packageName; mResolveActivity.processName = mAndroidApplication.processName; mResolveActivity.launchMode = ActivityInfo.LAUNCH_MULTIPLE; - mResolveActivity.flags = 0; + mResolveActivity.flags = ActivityInfo.FLAG_EXCLUDE_FROM_RECENTS; mResolveActivity.theme = com.android.internal.R.style.Theme_Dialog_Alert; mResolveActivity.exported = true; mResolveActivity.enabled = true; @@ -1748,6 +1854,11 @@ class PackageManagerService extends IPackageManager.Stub { mLastScanError = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE; return null; } + synchronized(mPackages) { + if(mSettings.mDisabledSysPackages.get(pkg.packageName) != null) { + pkg.applicationInfo.flags |= ApplicationInfo.FLAG_UPDATED_SYSTEM_APP; + } + } pkg.applicationInfo.uid = pkgSetting.userId; pkg.mExtras = pkgSetting; @@ -1755,6 +1866,7 @@ class PackageManagerService extends IPackageManager.Stub { if (!verifySignaturesLP(pkgSetting, pkg, parseFlags, (scanMode&SCAN_UPDATE_SIGNATURE) != 0)) { if ((parseFlags&PackageParser.PARSE_IS_SYSTEM) == 0) { + mLastScanError = PackageManager.INSTALL_FAILED_UPDATE_INCOMPATIBLE; return null; } // The signature has changed, but this package is in the system @@ -1768,6 +1880,7 @@ class PackageManagerService extends IPackageManager.Stub { if (pkgSetting.sharedUser != null) { if (!pkgSetting.sharedUser.signatures.mergeSignatures( pkg.mSignatures, false)) { + mLastScanError = PackageManager.INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES; return null; } } @@ -1782,6 +1895,7 @@ class PackageManagerService extends IPackageManager.Stub { String msg = "System package " + pkg.packageName + " could not have data directory erased after signature change."; reportSettingsProblem(Log.WARN, msg); + mLastScanError = PackageManager.INSTALL_FAILED_REPLACE_COULDNT_DELETE; return null; } } @@ -1792,7 +1906,7 @@ class PackageManagerService extends IPackageManager.Stub { long scanFileTime = scanFile.lastModified(); final boolean forceDex = (scanMode&SCAN_FORCE_DEX) != 0; - final boolean scanFileNewer = forceDex || scanFileTime != pkgSetting.timeStamp; + final boolean scanFileNewer = forceDex || scanFileTime != pkgSetting.getTimeStamp(); // At this point we know it is okay to accept the package, though // errors can still happen as we try to install... @@ -3037,48 +3151,363 @@ class PackageManagerService extends IPackageManager.Stub { PackageRemovedInfo removedInfo; } - PackageInstalledInfo installPackageLI(Uri packageURI, int flags) { - int returnCode = PackageManager.INSTALL_SUCCEEDED; - String installedPackageName = null; - int installedPackageUid = -1; - PackageParser.Package installedPackage = null; + /* + * Install a non-existing package. + */ + private void installNewPackageLI(String pkgName, int parseFlags, + File tmpPackageFile, + String destFilePath, File destPackageFile, File destResourceFile, + PackageParser.Package pkg, boolean forwardLocked, + PackageInstalledInfo res) { + // Remember this for later, in case we need to rollback this install + boolean dataDirExists = (new File(mAppDataDir, pkgName)).exists(); + res.name = pkgName; + synchronized(mPackages) { + if (mPackages.containsKey(pkgName) || mAppDirs.containsKey(destFilePath)) { + // Don't allow installation over an existing package with the same name. + Log.w(TAG, "Attempt to re-install " + pkgName + + " without first uninstalling."); + res.returnCode = PackageManager.INSTALL_FAILED_ALREADY_EXISTS; + return; + } + } + if (destPackageFile.exists()) { + // It's safe to do this because we know (from the above check) that the file + // isn't currently used for an installed package. + destPackageFile.delete(); + } + mLastScanError = PackageManager.INSTALL_SUCCEEDED; + PackageParser.Package newPackage = scanPackageLI(tmpPackageFile, destPackageFile, + destResourceFile, pkg, parseFlags, + SCAN_MONITOR | SCAN_FORCE_DEX + | SCAN_UPDATE_SIGNATURE + | (forwardLocked ? SCAN_FORWARD_LOCKED : 0)); + if (newPackage == null) { + Log.w(TAG, "Package couldn't be installed in " + destPackageFile); + if ((res.returnCode=mLastScanError) == PackageManager.INSTALL_SUCCEEDED) { + res.returnCode = PackageManager.INSTALL_FAILED_INVALID_APK; + } + } else { + updateSettingsLI(pkgName, tmpPackageFile, + destFilePath, destPackageFile, + destResourceFile, pkg, + newPackage, + true, + forwardLocked, + res); + // delete the partially installed application. the data directory will have to be + // restored if it was already existing + if (res.returnCode != PackageManager.INSTALL_SUCCEEDED) { + // remove package from internal structures. Note that we want deletePackageX to + // delete the package data and cache directories that it created in + // scanPackageLocked, unless those directories existed before we even tried to + // install. + deletePackageLI( + pkgName, true, + dataDirExists ? PackageManager.DONT_DELETE_DATA : 0, + res.removedInfo); + } + } + } + + private void replacePackageLI(String pkgName, int parseFlags, + File tmpPackageFile, + String destFilePath, File destPackageFile, File destResourceFile, + PackageParser.Package pkg, boolean forwardLocked, + PackageInstalledInfo res) { + PackageParser.Package deletedPackage; + // First find the old package info and check signatures + synchronized(mPackages) { + deletedPackage = mPackages.get(pkgName); + if(checkSignaturesLP(pkg, deletedPackage) != PackageManager.SIGNATURE_MATCH) { + res.returnCode = PackageManager.INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES; + return; + } + } + boolean sysPkg = ((deletedPackage.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0); + if(sysPkg) { + replaceSystemPackageLI(deletedPackage, + parseFlags, + tmpPackageFile, destFilePath, + destPackageFile, destResourceFile, pkg, forwardLocked, res); + } else { + replaceNonSystemPackageLI(deletedPackage, parseFlags, tmpPackageFile, destFilePath, + destPackageFile, destResourceFile, pkg, forwardLocked, res); + } + } + + private void replaceNonSystemPackageLI(PackageParser.Package deletedPackage, int parseFlags, + File tmpPackageFile, + String destFilePath, File destPackageFile, File destResourceFile, + PackageParser.Package pkg, boolean forwardLocked, + PackageInstalledInfo res) { + PackageParser.Package newPackage = null; + String pkgName = deletedPackage.packageName; + boolean deletedPkg = true; + boolean updatedSettings = false; + // First delete the existing package while retaining the data directory + if (!deletePackageLI(pkgName, false, PackageManager.DONT_DELETE_DATA, + res.removedInfo)) { + // If the existing package was'nt successfully deleted + res.returnCode = PackageManager.INSTALL_FAILED_REPLACE_COULDNT_DELETE; + deletedPkg = false; + } else { + // Successfully deleted the old package. Now proceed with re-installation + mLastScanError = PackageManager.INSTALL_SUCCEEDED; + newPackage = scanPackageLI(tmpPackageFile, destPackageFile, + destResourceFile, pkg, parseFlags, + SCAN_MONITOR | SCAN_FORCE_DEX + | SCAN_UPDATE_SIGNATURE + | (forwardLocked ? SCAN_FORWARD_LOCKED : 0)); + if (newPackage == null) { + Log.w(TAG, "Package couldn't be installed in " + destPackageFile); + if ((res.returnCode=mLastScanError) == PackageManager.INSTALL_SUCCEEDED) { + res.returnCode = PackageManager.INSTALL_FAILED_INVALID_APK; + } + } else { + updateSettingsLI(pkgName, tmpPackageFile, + destFilePath, destPackageFile, + destResourceFile, pkg, + newPackage, + true, + forwardLocked, + res); + updatedSettings = true; + } + } + + if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) { + // If we deleted an exisiting package, the old source and resource files that we + // were keeping around in case we needed them (see below) can now be deleted + final ApplicationInfo deletedPackageAppInfo = deletedPackage.applicationInfo; + final ApplicationInfo installedPackageAppInfo = + newPackage.applicationInfo; + if (!deletedPackageAppInfo.sourceDir + .equals(installedPackageAppInfo.sourceDir)) { + new File(deletedPackageAppInfo.sourceDir).delete(); + } + if (!deletedPackageAppInfo.publicSourceDir + .equals(installedPackageAppInfo.publicSourceDir)) { + new File(deletedPackageAppInfo.publicSourceDir).delete(); + } + //update signature on the new package setting + //this should always succeed, since we checked the + //signature earlier. + synchronized(mPackages) { + verifySignaturesLP(mSettings.mPackages.get(pkgName), pkg, + parseFlags, true); + } + } else { + // remove package from internal structures. Note that we want deletePackageX to + // delete the package data and cache directories that it created in + // scanPackageLocked, unless those directories existed before we even tried to + // install. + if(updatedSettings) { + deletePackageLI( + pkgName, true, + PackageManager.DONT_DELETE_DATA, + res.removedInfo); + } + // Since we failed to install the new package we need to restore the old + // package that we deleted. + if(deletedPkg) { + installPackageLI( + Uri.fromFile(new File(deletedPackage.mPath)), + isForwardLocked(deletedPackage) + ? PackageManager.FORWARD_LOCK_PACKAGE + : 0); + } + } + } + + private void replaceSystemPackageLI(PackageParser.Package deletedPackage, int parseFlags, + File tmpPackageFile, + String destFilePath, File destPackageFile, File destResourceFile, + PackageParser.Package pkg, boolean forwardLocked, + PackageInstalledInfo res) { + PackageParser.Package newPackage = null; + boolean updatedSettings = false; + parseFlags |= PackageParser.PARSE_IS_SYSTEM; + String packageName = deletedPackage.packageName; + res.returnCode = PackageManager.INSTALL_FAILED_REPLACE_COULDNT_DELETE; + if (packageName == null) { + Log.w(TAG, "Attempt to delete null packageName."); + return; + } + PackageParser.Package oldPkg; + PackageSetting oldPkgSetting; + synchronized (mPackages) { + oldPkg = mPackages.get(packageName); + oldPkgSetting = mSettings.mPackages.get(packageName); + if((oldPkg == null) || (oldPkg.applicationInfo == null) || + (oldPkgSetting == null)) { + Log.w(TAG, "Could'nt find package:"+packageName+" information"); + return; + } + } + res.removedInfo.uid = oldPkg.applicationInfo.uid; + res.removedInfo.removedPackage = packageName; + // Remove existing system package + removePackageLI(oldPkg, true); + synchronized (mPackages) { + res.removedInfo.removedUid = mSettings.disableSystemPackageLP(packageName); + } + + // Successfully disabled the old package. Now proceed with re-installation + mLastScanError = PackageManager.INSTALL_SUCCEEDED; + pkg.applicationInfo.flags |= ApplicationInfo.FLAG_UPDATED_SYSTEM_APP; + newPackage = scanPackageLI(tmpPackageFile, destPackageFile, + destResourceFile, pkg, parseFlags, + SCAN_MONITOR | SCAN_FORCE_DEX + | SCAN_UPDATE_SIGNATURE + | (forwardLocked ? SCAN_FORWARD_LOCKED : 0)); + if (newPackage == null) { + Log.w(TAG, "Package couldn't be installed in " + destPackageFile); + if ((res.returnCode=mLastScanError) == PackageManager.INSTALL_SUCCEEDED) { + res.returnCode = PackageManager.INSTALL_FAILED_INVALID_APK; + } + } else { + updateSettingsLI(packageName, tmpPackageFile, + destFilePath, destPackageFile, + destResourceFile, pkg, + newPackage, + true, + forwardLocked, + res); + updatedSettings = true; + } + + if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) { + //update signature on the new package setting + //this should always succeed, since we checked the + //signature earlier. + synchronized(mPackages) { + verifySignaturesLP(mSettings.mPackages.get(packageName), pkg, + parseFlags, true); + } + } else { + // Re installation failed. Restore old information + // Remove new pkg information + removePackageLI(newPackage, true); + // Add back the old system package + scanPackageLI(oldPkgSetting.codePath, oldPkgSetting.codePath, + oldPkgSetting.resourcePath, + oldPkg, parseFlags, + SCAN_MONITOR + | SCAN_UPDATE_SIGNATURE + | (forwardLocked ? SCAN_FORWARD_LOCKED : 0)); + // Restore the old system information in Settings + synchronized(mPackages) { + if(updatedSettings) { + mSettings.enableSystemPackageLP(packageName); + } + mSettings.writeLP(); + } + } + } + + private void updateSettingsLI(String pkgName, File tmpPackageFile, + String destFilePath, File destPackageFile, + File destResourceFile, + PackageParser.Package pkg, + PackageParser.Package newPackage, + boolean replacingExistingPackage, + boolean forwardLocked, + PackageInstalledInfo res) { + synchronized (mPackages) { + //write settings. the installStatus will be incomplete at this stage. + //note that the new package setting would have already been + //added to mPackages. It hasn't been persisted yet. + mSettings.setInstallStatus(pkgName, PKG_INSTALL_INCOMPLETE); + mSettings.writeLP(); + } + + int retCode = 0; + if ((pkg.applicationInfo.flags&ApplicationInfo.FLAG_HAS_CODE) != 0) { + retCode = mInstaller.movedex(tmpPackageFile.toString(), + destPackageFile.toString()); + if (retCode != 0) { + Log.e(TAG, "Couldn't rename dex file: " + destPackageFile); + res.returnCode = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE; + return; + } + } + // XXX There are probably some big issues here: upon doing + // the rename, we have reached the point of no return (the + // original .apk is gone!), so we can't fail. Yet... we can. + if (!tmpPackageFile.renameTo(destPackageFile)) { + Log.e(TAG, "Couldn't move package file to: " + destPackageFile); + res.returnCode = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE; + } else { + res.returnCode = setPermissionsLI(pkgName, newPackage, destFilePath, + destResourceFile, + forwardLocked); + if(res.returnCode != PackageManager.INSTALL_SUCCEEDED) { + return; + } else { + Log.d(TAG, "New package installed in " + destPackageFile); + } + } + if(res.returnCode != PackageManager.INSTALL_SUCCEEDED) { + if (mInstaller != null) { + mInstaller.rmdex(tmpPackageFile.getPath()); + } + } + + synchronized (mPackages) { + grantPermissionsLP(newPackage, true); + res.name = pkgName; + res.uid = newPackage.applicationInfo.uid; + res.pkg = newPackage; + mSettings.setInstallStatus(pkgName, PKG_INSTALL_COMPLETE); + res.returnCode = PackageManager.INSTALL_SUCCEEDED; + //to update install status + mSettings.writeLP(); + } + } + + private PackageInstalledInfo installPackageLI(Uri pPackageURI, int pFlags) { File tmpPackageFile = null; - boolean wroteSettings = false; String pkgName = null; - PackageParser.Package newPackage = null; - boolean dataDirExists = false; - PackageParser.Package deletedPackage = null; - PackageRemovedInfo removedInfo = new PackageRemovedInfo(); + boolean forwardLocked = false; + boolean replacingExistingPackage = false; + + // Result object to be returned + PackageInstalledInfo res = new PackageInstalledInfo(); + res.returnCode = PackageManager.INSTALL_SUCCEEDED; + res.uid = -1; + res.pkg = null; + res.removedInfo = new PackageRemovedInfo(); main_flow: try { tmpPackageFile = createTempPackageFile(); if (tmpPackageFile == null) { - returnCode = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE; + res.returnCode = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE; break main_flow; } tmpPackageFile.deleteOnExit(); // paranoia - if (packageURI.getScheme().equals("file")) { - final File srcPackageFile = new File(packageURI.getPath()); + if (pPackageURI.getScheme().equals("file")) { + final File srcPackageFile = new File(pPackageURI.getPath()); // We copy the source package file to a temp file and then rename it to the // destination file in order to eliminate a window where the package directory // scanner notices the new package file but it's not completely copied yet. if (!FileUtils.copyFile(srcPackageFile, tmpPackageFile)) { Log.e(TAG, "Couldn't copy package file to temp file."); - returnCode = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE; + res.returnCode = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE; break main_flow; } - } else if (packageURI.getScheme().equals("content")) { + } else if (pPackageURI.getScheme().equals("content")) { ParcelFileDescriptor fd; try { - fd = mContext.getContentResolver().openFileDescriptor(packageURI, "r"); + fd = mContext.getContentResolver().openFileDescriptor(pPackageURI, "r"); } catch (FileNotFoundException e) { Log.e(TAG, "Couldn't open file descriptor from download service."); - returnCode = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE; + res.returnCode = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE; break main_flow; } if (fd == null) { Log.e(TAG, "Couldn't open file descriptor from download service (null)."); - returnCode = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE; + res.returnCode = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE; break main_flow; } if (Config.LOGV) { @@ -3091,36 +3520,38 @@ class PackageManagerService extends IPackageManager.Stub { // scanner notices the new package file but it's not completely copied yet. if (!FileUtils.copyToFile(dlStream, tmpPackageFile)) { Log.e(TAG, "Couldn't copy package stream to temp file."); - returnCode = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE; + res.returnCode = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE; break main_flow; } } else { - Log.e(TAG, "Package URI is not 'file:' or 'content:' - " + packageURI); - returnCode = PackageManager.INSTALL_FAILED_INVALID_URI; + Log.e(TAG, "Package URI is not 'file:' or 'content:' - " + pPackageURI); + res.returnCode = PackageManager.INSTALL_FAILED_INVALID_URI; break main_flow; - } + } pkgName = PackageParser.parsePackageName( tmpPackageFile.getAbsolutePath(), 0); if (pkgName == null) { Log.e(TAG, "Couldn't find a package name in : " + tmpPackageFile); - returnCode = PackageManager.INSTALL_FAILED_INVALID_APK; + res.returnCode = PackageManager.INSTALL_FAILED_INVALID_APK; break main_flow; } + res.name = pkgName; //initialize some variables before installing pkg final String pkgFileName = pkgName + ".apk"; - final File destDir = ((flags&PackageManager.FORWARD_LOCK_PACKAGE) != 0) + final File destDir = ((pFlags&PackageManager.FORWARD_LOCK_PACKAGE) != 0) ? mDrmAppPrivateInstallDir : mAppInstallDir; final File destPackageFile = new File(destDir, pkgFileName); final String destFilePath = destPackageFile.getAbsolutePath(); File destResourceFile; - if ((flags&PackageManager.FORWARD_LOCK_PACKAGE) != 0) { + if ((pFlags&PackageManager.FORWARD_LOCK_PACKAGE) != 0) { final String publicZipFileName = pkgName + ".zip"; destResourceFile = new File(mAppInstallDir, publicZipFileName); + forwardLocked = true; } else { destResourceFile = destPackageFile; } - //retrieve PackageSettings and parse package + // Retrieve PackageSettings and parse package int parseFlags = PackageParser.PARSE_CHATTY; parseFlags |= mDefParseFlags; PackageParser pp = new PackageParser(tmpPackageFile.getPath()); @@ -3129,204 +3560,79 @@ class PackageManagerService extends IPackageManager.Stub { final PackageParser.Package pkg = pp.parsePackage(tmpPackageFile, destPackageFile.getAbsolutePath(), mMetrics, parseFlags); if (pkg == null) { - returnCode = pp.getParseError(); + res.returnCode = pp.getParseError(); break main_flow; } if (GET_CERTIFICATES && !pp.collectCertificates(pkg, parseFlags)) { - returnCode = pp.getParseError(); + res.returnCode = pp.getParseError(); break main_flow; } - boolean replacingExistingPackage = false; - synchronized (mPackages) { //check if installing already existing package - if ((flags&PackageManager.REPLACE_EXISTING_PACKAGE) != 0 + if ((pFlags&PackageManager.REPLACE_EXISTING_PACKAGE) != 0 && mPackages.containsKey(pkgName)) { replacingExistingPackage = true; - deletedPackage = mPackages.get(pkgName); - if(checkSignaturesLP(pkg, deletedPackage) != PackageManager.SIGNATURE_MATCH) { - returnCode = PackageManager.INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES; - break main_flow; - } - } - } - - if (replacingExistingPackage) { - if (!deletePackageLI(pkgName, false, PackageManager.DONT_DELETE_DATA, - removedInfo)) { - returnCode = PackageManager.INSTALL_FAILED_REPLACE_COULDNT_DELETE; - break main_flow; - } - } else { - if (mPackages.containsKey(pkgName) || mAppDirs.containsKey(destFilePath)) { - // Don't allow installation over an existing package with the same name. - Log.w(TAG, "Attempt to re-install " + pkgName - + " without first uninstalling."); - returnCode = PackageManager.INSTALL_FAILED_ALREADY_EXISTS; - break main_flow; - } - if (destPackageFile.exists()) { - // It's safe to do this because we know (from the above check) that the file - // isn't currently used for an installed package. - destPackageFile.delete(); - } - } - - // Remember this for later, in case we need to rollback this install - dataDirExists = (new File(mAppDataDir, pkgName)).exists(); - mLastScanError = PackageManager.INSTALL_SUCCEEDED; - newPackage = scanPackageLI(tmpPackageFile, destPackageFile, - destResourceFile, pkg, parseFlags, - SCAN_MONITOR | SCAN_FORCE_DEX - | (!replacingExistingPackage ? SCAN_UPDATE_SIGNATURE : 0) - | ((flags&PackageManager.FORWARD_LOCK_PACKAGE) != 0 - ? SCAN_FORWARD_LOCKED : 0)); - if (newPackage == null) { - if (Config.LOGD) { - Log.w(TAG, "Package couldn't be installed in " + destPackageFile); - } - if ((returnCode=mLastScanError) == PackageManager.INSTALL_SUCCEEDED) { - returnCode = PackageManager.INSTALL_FAILED_INVALID_APK; } - break main_flow; } - synchronized (mPackages) { - //write settings. the installStatus will be incomplete at this stage. - //note that the new package setting would have already been - //added to mPackages. It hasn't been persisted yet. - mSettings.setInstallStatus(pkgName, PKG_INSTALL_INCOMPLETE); - mSettings.writeLP(); - wroteSettings = true; - } - - int retCode = 0; - if ((pkg.applicationInfo.flags&ApplicationInfo.FLAG_HAS_CODE) != 0) { - retCode = mInstaller.movedex(tmpPackageFile.toString(), - destPackageFile.toString()); - if (retCode != 0) { - Log.e(TAG, "Couldn't rename dex file: " + destPackageFile); - returnCode = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE; - break main_flow; - } - } - // XXX There are probably some big issues here: upon doing - // the rename, we have reached the point of no return (the - // original .apk is gone!), so we can't fail. Yet... we can. - if (tmpPackageFile.renameTo(destPackageFile)) { - if ((flags&PackageManager.FORWARD_LOCK_PACKAGE) != 0) { - try { - extractPublicFiles(newPackage, destResourceFile); - } catch (IOException e) { - Log.e(TAG, "Couldn't create a new zip file for the public parts of a" + - " forward-locked app."); - returnCode = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE; - break main_flow; - } - if (mInstaller != null) { - retCode = mInstaller.setForwardLockPerm(pkgName, - newPackage.applicationInfo.uid); - } else { - final int filePermissions = - FileUtils.S_IRUSR|FileUtils.S_IWUSR|FileUtils.S_IRGRP; - retCode = FileUtils.setPermissions(destFilePath, filePermissions, -1, - newPackage.applicationInfo.uid); - } - } else { - final int filePermissions = - FileUtils.S_IRUSR|FileUtils.S_IWUSR|FileUtils.S_IRGRP - |FileUtils.S_IROTH; - retCode = FileUtils.setPermissions(destFilePath, filePermissions, -1, -1); - } - if (retCode != 0) { - Log.e(TAG, "Couldn't set new package file permissions for " + destFilePath - + ". The return code was: " + retCode); - } - if (Config.LOGD) { - Log.d(TAG, "New package installed in " + destPackageFile); - } - - synchronized (mPackages) { - grantPermissionsLP(newPackage, true); - installedPackageName = pkgName; - installedPackageUid = newPackage.applicationInfo.uid; - installedPackage = newPackage; - if(replacingExistingPackage) { - //update signature on the new package setting - //this should always succeed, since we checked the - //signature earlier. - verifySignaturesLP(mSettings.mPackages.get(pkgName), pkg, - parseFlags, true); - } - mSettings.setInstallStatus(pkgName, PKG_INSTALL_COMPLETE); - returnCode = PackageManager.INSTALL_SUCCEEDED; - //to update install status - mSettings.writeLP(); - break main_flow; - } + if(replacingExistingPackage) { + replacePackageLI(pkgName, pFlags, + tmpPackageFile, + destFilePath, destPackageFile, destResourceFile, + pkg, forwardLocked, + res); } else { - Log.e(TAG, "Couldn't move package file to: " + destPackageFile); - returnCode = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE; - break main_flow; + installNewPackageLI(pkgName, pFlags, + tmpPackageFile, + destFilePath, destPackageFile, destResourceFile, + pkg, forwardLocked, + res); } } finally { if (tmpPackageFile != null && tmpPackageFile.exists()) { tmpPackageFile.delete(); } - - //if install was successful the pkg's installStatus would have - //been updated and hence needs to be persisted. if not - //the pkg info needs to be cleaned up. - if (returnCode == PackageManager.INSTALL_SUCCEEDED) { - if (deletedPackage != null) { - // If we deleted an exisiting package, the old source and resource files that we - // were keeping around in case we needed them (see below) can now be deleted - final ApplicationInfo deletedPackageAppInfo = deletedPackage.applicationInfo; - final ApplicationInfo installedPackageAppInfo = - installedPackage.applicationInfo; - if (!deletedPackageAppInfo.sourceDir - .equals(installedPackageAppInfo.sourceDir)) { - new File(deletedPackageAppInfo.sourceDir).delete(); - } - if (!deletedPackageAppInfo.publicSourceDir - .equals(installedPackageAppInfo.publicSourceDir)) { - new File(deletedPackageAppInfo.publicSourceDir).delete(); - } - } + return res; + } + } + + private int setPermissionsLI(String pkgName, + PackageParser.Package newPackage, + String destFilePath, + File destResourceFile, + boolean forwardLocked) { + int retCode; + if (forwardLocked) { + try { + extractPublicFiles(newPackage, destResourceFile); + } catch (IOException e) { + Log.e(TAG, "Couldn't create a new zip file for the public parts of a" + + " forward-locked app."); + return PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE; + } finally { + //TODO clean up the extracted public files + } + if (mInstaller != null) { + retCode = mInstaller.setForwardLockPerm(pkgName, + newPackage.applicationInfo.uid); } else { - if (mInstaller != null) { - mInstaller.rmdex(tmpPackageFile.getPath()); - } - if (wroteSettings) { - // remove package from internal structures. Note that we want deletePackageX to - // delete the package data and cache directories that it created in - // scanPackageLocked, unless those directories existed before we even tried to - // install. - deletePackageLI( - pkgName, true, - dataDirExists ? PackageManager.DONT_DELETE_DATA : 0, - new PackageRemovedInfo()); - if (deletedPackage != null) { - // Since we failed to install the new package we need to restore the old - // package that we deleted. - installPackageLI( - Uri.fromFile(new File(deletedPackage.mPath)), - isForwardLocked(deletedPackage) - ? PackageManager.FORWARD_LOCK_PACKAGE - : 0); - } - } + final int filePermissions = + FileUtils.S_IRUSR|FileUtils.S_IWUSR|FileUtils.S_IRGRP; + retCode = FileUtils.setPermissions(destFilePath, filePermissions, -1, + newPackage.applicationInfo.uid); } + } else { + final int filePermissions = + FileUtils.S_IRUSR|FileUtils.S_IWUSR|FileUtils.S_IRGRP + |FileUtils.S_IROTH; + retCode = FileUtils.setPermissions(destFilePath, filePermissions, -1, -1); } - - PackageInstalledInfo res = new PackageInstalledInfo(); - res.name = installedPackageName; - res.uid = installedPackageUid; - res.pkg = installedPackage; - res.returnCode = returnCode; - res.removedInfo = removedInfo; - return res; + if (retCode != 0) { + Log.e(TAG, "Couldn't set new package file permissions for " + destFilePath + + ". The return code was: " + retCode); + } + return PackageManager.INSTALL_SUCCEEDED; } private boolean isForwardLocked(PackageParser.Package deletedPackage) { @@ -3470,11 +3776,6 @@ class PackageManagerService extends IPackageManager.Stub { synchronized (mInstallLock) { res = deletePackageLI(packageName, deleteCodeAndResources, flags, info); - if (res) { - synchronized (mPackages) { - mSettings.writeLP(); - } - } } if(res && sendBroadCast) { @@ -3500,44 +3801,117 @@ class PackageManagerService extends IPackageManager.Stub { } } - private boolean deletePackageLI(String packageName, + /* + * This method deletes the package from internal data structures. If the DONT_DELETE_DATA + * flag is not set, the data directory is removed as well. + * make sure this flag is set for partially installed apps. If not its meaningless to + * delete a partially installed application. + */ + private void removePackageDataLI(PackageParser.Package p, PackageRemovedInfo outInfo, + int flags) { + String packageName = p.packageName; + outInfo.removedPackage = packageName; + removePackageLI(p, true); + // Retrieve object to delete permissions for shared user later on + PackageSetting deletedPs; + synchronized (mPackages) { + deletedPs = mSettings.mPackages.get(packageName); + } + if ((flags&PackageManager.DONT_DELETE_DATA) == 0) { + if (mInstaller != null) { + int retCode = mInstaller.remove(packageName); + if (retCode < 0) { + Log.w(TAG, "Couldn't remove app data or cache directory for package: " + + packageName + ", retcode=" + retCode); + // we don't consider this to be a failure of the core package deletion + } + } else { + //for emulator + PackageParser.Package pkg = mPackages.get(packageName); + File dataDir = new File(pkg.applicationInfo.dataDir); + dataDir.delete(); + } + synchronized (mPackages) { + outInfo.removedUid = mSettings.removePackageLP(packageName); + } + } + synchronized (mPackages) { + if ( (deletedPs != null) && (deletedPs.sharedUser != null)) { + // remove permissions associated with package + mSettings.updateSharedUserPerms (deletedPs); + } + // Save settings now + mSettings.writeLP (); + } + } + + /* + * Tries to delete system package. + */ + private boolean deleteSystemPackageLI(PackageParser.Package p, boolean deleteCodeAndResources, int flags, PackageRemovedInfo outInfo) { - if (packageName == null) { - Log.w(TAG, "Attempt to delete null packageName."); + ApplicationInfo applicationInfo = p.applicationInfo; + //applicable for non-partially installed applications only + if (applicationInfo == null) { + Log.w(TAG, "Package " + p.packageName + " has no applicationInfo."); return false; } - PackageParser.Package p; + PackageSetting ps = null; + // Confirm if the system package has been updated + // An updated system app can be deleted. This will also have to restore + // the system pkg from system partition synchronized (mPackages) { - p = mPackages.get(packageName); + ps = mSettings.getDisabledSystemPkg(p.packageName); } - if (p == null) { - Log.w(TAG, "Package named '" + packageName +"' doesn't exist."); + if (ps == null) { + Log.w(TAG, "Attempt to delete system package "+ p.packageName); return false; + } else { + Log.i(TAG, "Deleting system pkg from data partition"); } - final ApplicationInfo applicationInfo = p.applicationInfo; - if (applicationInfo == null) { - Log.w(TAG, "Package " + packageName + " has no applicationInfo."); + // Delete the updated package + boolean ret = deleteInstalledPackageLI(p, deleteCodeAndResources, flags, outInfo); + if (!ret) { return false; } - - // NB: This is a public nonfinal boolean so it theoretically - // could be altered by anyone. In practice, that can only be - // done from within this same process, and anyway file - // permissions will prevent unauthorized deletion of system - // packages. - if ((applicationInfo.flags&ApplicationInfo.FLAG_SYSTEM) != 0) { - Log.w(TAG, "Attempt to delete system package "+ packageName); + synchronized (mPackages) { + // Reinstate the old system package + mSettings.enableSystemPackageLP(p.packageName); + } + // Install the system package + PackageParser.Package newPkg = scanPackageLI(ps.codePath, ps.codePath, ps.resourcePath, + PackageParser.PARSE_MUST_BE_APK | PackageParser.PARSE_IS_SYSTEM, + SCAN_MONITOR); + + if (newPkg == null) { + Log.w(TAG, "Failed to restore system package:"+p.packageName+" with error:" + mLastScanError); return false; } - final File sourceFile = new File(applicationInfo.sourceDir); + synchronized (mPackages) { + mSettings.writeLP(); + } + return true; + } + + private boolean deleteInstalledPackageLI(PackageParser.Package p, + boolean deleteCodeAndResources, int flags, PackageRemovedInfo outInfo) { + ApplicationInfo applicationInfo = p.applicationInfo; + if (applicationInfo == null) { + Log.w(TAG, "Package " + p.packageName + " has no applicationInfo."); + return false; + } + // Delete application's source directory + File sourceFile = new File(applicationInfo.sourceDir); if (!sourceFile.exists()) { Log.w(TAG, "Package source " + applicationInfo.sourceDir + " does not exist."); return false; } - outInfo.uid = p.applicationInfo.uid; + outInfo.uid = applicationInfo.uid; - outInfo.removedPackage = packageName; - removePackageLI(p, true); + // Delete package data from internal structures and also remove data if flag is set + removePackageDataLI(p, outInfo, flags); + + // Delete application code and resources if (deleteCodeAndResources) { sourceFile.delete(); final File publicSourceFile = new File(applicationInfo.publicSourceDir); @@ -3548,30 +3922,61 @@ class PackageManagerService extends IPackageManager.Stub { int retCode = mInstaller.rmdex(sourceFile.toString()); if (retCode < 0) { Log.w(TAG, "Couldn't remove dex file for package: " - + packageName + ", retcode=" + retCode); + + p.packageName + " at location " + sourceFile.toString() + ", retcode=" + retCode); // we don't consider this to be a failure of the core package deletion } } } - if ((flags&PackageManager.DONT_DELETE_DATA) == 0) { - if (mInstaller != null) { - int retCode = mInstaller.remove(packageName); - if (retCode < 0) { - Log.w(TAG, "Couldn't remove app data or cache directory for package: " - + packageName + ", retcode=" + retCode); - // we don't consider this to be a failure of the core package deletion + return true; + } + + /* + * This method handles package deletion in general + */ + private boolean deletePackageLI(String packageName, + boolean deleteCodeAndResources, int flags, PackageRemovedInfo outInfo) { + if (packageName == null) { + Log.w(TAG, "Attempt to delete null packageName."); + return false; + } + PackageParser.Package p; + boolean dataOnly = false; + synchronized (mPackages) { + p = mPackages.get(packageName); + if (p == null) { + //this retrieves partially installed apps + dataOnly = true; + PackageSetting ps = mSettings.mPackages.get(packageName); + if (ps == null) { + Log.w(TAG, "Package named '" + packageName +"' doesn't exist."); + return false; } - } else { - //for emulator - PackageParser.Package pkg = mPackages.get(packageName); - File dataDir = new File(pkg.applicationInfo.dataDir); - dataDir.delete(); - } - synchronized (mPackages) { - outInfo.removedUid = mSettings.removePackageLP(packageName); + p = ps.pkg; } } - return true; + if (p == null) { + Log.w(TAG, "Package named '" + packageName +"' doesn't exist."); + return false; + } + + if (dataOnly) { + // Delete application data first + removePackageDataLI(p, outInfo, flags); + return true; + } + // At this point the package should have ApplicationInfo associated with it + if (p.applicationInfo == null) { + Log.w(TAG, "Package " + p.packageName + " has no applicationInfo."); + return false; + } + if ( (p.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) { + Log.i(TAG, "Removing system package:"+p.packageName); + // When an updated system application is deleted we delete the existing resources as well and + // fall back to existing code in system partition + return deleteSystemPackageLI(p, true, flags, outInfo); + } + Log.i(TAG, "Removing non-system package:"+p.packageName); + return deleteInstalledPackageLI (p, deleteCodeAndResources, flags, outInfo); } public void clearApplicationUserData(final String packageName, @@ -3582,21 +3987,21 @@ class PackageManagerService extends IPackageManager.Stub { mHandler.post(new Runnable() { public void run() { mHandler.removeCallbacks(this); - final boolean succeded; + final boolean succeeded; synchronized (mInstallLock) { - succeded = clearApplicationUserDataLI(packageName); - } - if(succeded) { - //invoke DeviceMemoryMonitor's update method to clear any notifications - DeviceMemoryMonitorService dmm = (DeviceMemoryMonitorService) - ServiceManager.getService("devicememorymonitor"); - if(dmm!=null) { - dmm.updateMemory(); + succeeded = clearApplicationUserDataLI(packageName); + } + if (succeeded) { + // invoke DeviceStorageMonitor's update method to clear any notifications + DeviceStorageMonitorService dsm = (DeviceStorageMonitorService) + ServiceManager.getService(DeviceStorageMonitorService.SERVICE); + if (dsm != null) { + dsm.updateMemory(); } } if(observer != null) { try { - observer.onRemoveCompleted(packageName, succeded); + observer.onRemoveCompleted(packageName, succeeded); } catch (RemoteException e) { Log.i(TAG, "Observer no longer exists."); } @@ -3611,23 +4016,36 @@ class PackageManagerService extends IPackageManager.Stub { return false; } PackageParser.Package p; + boolean dataOnly = false; synchronized (mPackages) { p = mPackages.get(packageName); + if(p == null) { + dataOnly = true; + PackageSetting ps = mSettings.mPackages.get(packageName); + if((ps == null) || (ps.pkg == null)) { + Log.w(TAG, "Package named '" + packageName +"' doesn't exist."); + return false; + } + p = ps.pkg; + } } - if (p == null) { - Log.w(TAG, "Package named '" + packageName +"' doesn't exist."); - return false; - } - final ApplicationInfo applicationInfo = p.applicationInfo; - if (applicationInfo == null) { - Log.w(TAG, "Package " + packageName + " has no applicationInfo."); - return false; + if(!dataOnly) { + //need to check this only for fully installed applications + if (p == null) { + Log.w(TAG, "Package named '" + packageName +"' doesn't exist."); + return false; + } + final ApplicationInfo applicationInfo = p.applicationInfo; + if (applicationInfo == null) { + Log.w(TAG, "Package " + packageName + " has no applicationInfo."); + return false; + } } if (mInstaller != null) { int retCode = mInstaller.clearUserData(packageName); if (retCode < 0) { Log.w(TAG, "Couldn't remove cache files for package: " - + packageName); + + packageName); return false; } } @@ -3716,22 +4134,31 @@ class PackageManagerService extends IPackageManager.Stub { return false; } PackageParser.Package p; + boolean dataOnly = false; synchronized (mPackages) { p = mPackages.get(packageName); + if(p == null) { + dataOnly = true; + PackageSetting ps = mSettings.mPackages.get(packageName); + if((ps == null) || (ps.pkg == null)) { + Log.w(TAG, "Package named '" + packageName +"' doesn't exist."); + return false; + } + p = ps.pkg; + } } - if (p == null) { - Log.w(TAG, "Package named '" + packageName +"' doesn't exist."); - return false; - } - final ApplicationInfo applicationInfo = p.applicationInfo; - if (applicationInfo == null) { - Log.w(TAG, "Package " + packageName + " has no applicationInfo."); - return false; + String publicSrcDir = null; + if(!dataOnly) { + final ApplicationInfo applicationInfo = p.applicationInfo; + if (applicationInfo == null) { + Log.w(TAG, "Package " + packageName + " has no applicationInfo."); + return false; + } + publicSrcDir = isForwardLocked(p) ? applicationInfo.publicSourceDir : null; } if (mInstaller != null) { int res = mInstaller.getSizeInfo(packageName, p.mPath, - isForwardLocked(p) ? applicationInfo.publicSourceDir : null, - pStats); + publicSrcDir, pStats); if (res < 0) { return false; } else { @@ -4051,7 +4478,7 @@ class PackageManagerService extends IPackageManager.Stub { if (ps.pkg != null) { pw.println(" dataDir=" + ps.pkg.applicationInfo.dataDir); } - pw.println(" timeStamp=" + ps.timeStamp); + pw.println(" timeStamp=" + ps.getTimeStampStr()); pw.println(" signatures=" + ps.signatures); pw.println(" permissionsFixed=" + ps.permissionsFixed + " pkgFlags=0x" + Integer.toHexString(ps.pkgFlags) @@ -4569,8 +4996,8 @@ class PackageManagerService extends IPackageManager.Stub { final String codePathString; final File resourcePath; final String resourcePathString; - long timeStamp; - String timeStampString = "0"; + private long timeStamp; + private String timeStampString = "0"; PackageSignatures signatures = new PackageSignatures(); @@ -4612,6 +5039,14 @@ class PackageManagerService extends IPackageManager.Stub { timeStamp = newStamp; timeStampString = newStampStr; } + + public long getTimeStamp() { + return timeStamp; + } + + public String getTimeStampStr() { + return timeStampString; + } public void copyFrom(PackageSettingBase base) { grantedPermissions = base.grantedPermissions; @@ -4709,6 +5144,10 @@ class PackageManagerService extends IPackageManager.Stub { // First is the most preferred. private final ArrayList mPreferredPackages = new ArrayList(); + // List of replaced system applications + final HashMap mDisabledSysPackages = + new HashMap(); + // The user's preferred activities associated with particular intent // filters. private final IntentResolver mPreferredActivities = @@ -4781,6 +5220,7 @@ class PackageManagerService extends IPackageManager.Stub { final String name = pkg.packageName; PackageSetting p = getPackageLP(name, sharedUser, codePath, resourcePath, pkgFlags, create); + if (p != null) { p.pkg = pkg; } @@ -4836,6 +5276,39 @@ class PackageManagerService extends IPackageManager.Stub { return s; } + int disableSystemPackageLP(String name) { + PackageSetting p = mPackages.get(name); + if(p == null) { + Log.w(TAG, "Package:"+name+" is not an installed package"); + return -1; + } + PackageSetting dp = mDisabledSysPackages.get(name); + // always make sure the system package code and resource paths dont change + if(dp == null) { + if((p.pkg != null) && (p.pkg.applicationInfo != null)) { + p.pkg.applicationInfo.flags |= ApplicationInfo.FLAG_UPDATED_SYSTEM_APP; + } + mDisabledSysPackages.put(name, p); + } + return removePackageLP(name); + } + + PackageSetting enableSystemPackageLP(String name) { + PackageSetting p = mDisabledSysPackages.get(name); + if(p == null) { + Log.w(TAG, "Package:"+name+" is not disabled"); + return null; + } + // Reset flag in ApplicationInfo object + if((p.pkg != null) && (p.pkg.applicationInfo != null)) { + p.pkg.applicationInfo.flags &= ~ApplicationInfo.FLAG_UPDATED_SYSTEM_APP; + } + PackageSetting ret = addPackageLP(name, p.codePath, + p.resourcePath, p.userId, p.pkgFlags); + mDisabledSysPackages.remove(name); + return ret; + } + PackageSetting addPackageLP(String name, File codePath, File resourcePath, int uid, int pkgFlags) { PackageSetting p = mPackages.get(name); @@ -4881,10 +5354,22 @@ class PackageManagerService extends IPackageManager.Stub { PackageSetting p = mPackages.get(name); if (p != null) { if (!p.codePath.equals(codePath)) { - reportSettingsProblem(Log.WARN, - "Package " + name + " codePath changed from " + p.codePath - + " to " + codePath + "; replacing with new"); - p = null; + // Check to see if its a disabled system app + PackageSetting ps = mDisabledSysPackages.get(name); + if((ps != null) && ((ps.pkgFlags & ApplicationInfo.FLAG_SYSTEM) != 0)) { + // Could be a replaced system package + // Note that if the user replaced a system app, the user has to physically + // delete the new one in order to revert to the system app. So even + // if the user updated the system app via an update, the user still + // has to delete the one installed in the data partition in order to pick up the + // new system package. + return p; + } else { + reportSettingsProblem(Log.WARN, + "Package " + name + " codePath changed from " + p.codePath + + " to " + codePath + "; replacing with new"); + p = null; + } } else if (p.sharedUser != sharedUser) { reportSettingsProblem(Log.WARN, "Package " + name + " shared user changed from " @@ -4896,10 +5381,13 @@ class PackageManagerService extends IPackageManager.Stub { } } if (p == null) { + // Create a new PackageSettings entry. this can end up here because + // of code path mismatch or user id mismatch of an updated system partition if (!create) { return null; } p = new PackageSetting(name, codePath, resourcePath, pkgFlags); + p.setTimeStamp(codePath.lastModified()); if (sharedUser != null) { p.userId = sharedUser.userId; } else if (MULTIPLE_APPLICATION_UIDS) { @@ -4935,10 +5423,45 @@ class PackageManagerService extends IPackageManager.Stub { p.sharedUser = sharedUser; p.userId = sharedUser.userId; } - return p; } + private void updateSharedUserPerms (PackageSetting deletedPs) { + if ( (deletedPs == null) || (deletedPs.pkg == null)) { + Log.i(TAG, "Trying to update info for null package. Just ignoring"); + return; + } + // No sharedUserId + if (deletedPs.sharedUser == null) { + return; + } + SharedUserSetting sus = deletedPs.sharedUser; + // Update permissions + for (String eachPerm: deletedPs.pkg.requestedPermissions) { + boolean used = false; + if (!sus.grantedPermissions.contains (eachPerm)) { + continue; + } + for (PackageSetting pkg:sus.packages) { + if (pkg.grantedPermissions.contains (eachPerm)) { + used = true; + break; + } + } + if (!used) { + // can safely delete this permission from list + sus.grantedPermissions.remove(eachPerm); + sus.loadedPermissions.remove(eachPerm); + } + } + // Update gids + int newGids[] = null; + for (PackageSetting pkg:sus.packages) { + newGids = appendInts(newGids, pkg.gids); + } + sus.gids = newGids; + } + private int removePackageLP(String name) { PackageSetting p = mPackages.get(name); if (p != null) { @@ -5047,16 +5570,17 @@ class PackageManagerService extends IPackageManager.Stub { serializer.endTag(null, "permissions"); for (PackageSetting pkg : mPackages.values()) { - serializer.startTag(null, "package"); + writePackage(serializer, pkg); + } + + for (PackageSetting pkg : mDisabledSysPackages.values()) { + serializer.startTag(null, "updated-package"); serializer.attribute(null, "name", pkg.name); serializer.attribute(null, "codePath", pkg.codePathString); + serializer.attribute(null, "ts", pkg.getTimeStampStr()); if (!pkg.resourcePathString.equals(pkg.codePathString)) { serializer.attribute(null, "resourcePath", pkg.resourcePathString); } - serializer.attribute(null, "system", - (pkg.pkgFlags&ApplicationInfo.FLAG_SYSTEM) != 0 - ? "true" : "false"); - serializer.attribute(null, "ts", pkg.timeStampString); if (pkg.sharedUser == null) { serializer.attribute(null, "userId", Integer.toString(pkg.userId)); @@ -5064,50 +5588,9 @@ class PackageManagerService extends IPackageManager.Stub { serializer.attribute(null, "sharedUserId", Integer.toString(pkg.userId)); } - if (pkg.enabled != COMPONENT_ENABLED_STATE_DEFAULT) { - serializer.attribute(null, "enabled", - pkg.enabled == COMPONENT_ENABLED_STATE_ENABLED - ? "true" : "false"); - } - if(pkg.installStatus == PKG_INSTALL_INCOMPLETE) { - serializer.attribute(null, "installStatus", "false"); - } - pkg.signatures.writeXml(serializer, "sigs", mPastSignatures); - if ((pkg.pkgFlags&ApplicationInfo.FLAG_SYSTEM) == 0) { - serializer.startTag(null, "perms"); - if (pkg.sharedUser == null) { - // If this is a shared user, the permissions will - // be written there. We still need to write an - // empty permissions list so permissionsFixed will - // be set. - for (String name : pkg.grantedPermissions) { - serializer.startTag(null, "item"); - serializer.attribute(null, "name", name); - serializer.endTag(null, "item"); - } - } - serializer.endTag(null, "perms"); - } - if (pkg.disabledComponents.size() > 0) { - serializer.startTag(null, "disabled-components"); - for (String name : pkg.disabledComponents) { - serializer.startTag(null, "item"); - serializer.attribute(null, "name", name); - serializer.endTag(null, "item"); - } - serializer.endTag(null, "disabled-components"); - } - if (pkg.enabledComponents.size() > 0) { - serializer.startTag(null, "enabled-components"); - for (String name : pkg.enabledComponents) { - serializer.startTag(null, "item"); - serializer.attribute(null, "name", name); - serializer.endTag(null, "item"); - } - serializer.endTag(null, "enabled-components"); - } - serializer.endTag(null, "package"); + serializer.endTag(null, "updated-package"); } + serializer.startTag(null, "preferred-packages"); int N = mPreferredPackages.size(); @@ -5169,7 +5652,71 @@ class PackageManagerService extends IPackageManager.Stub { //Debug.stopMethodTracing(); } - + + void writePackage(XmlSerializer serializer, final PackageSetting pkg) + throws java.io.IOException { + serializer.startTag(null, "package"); + serializer.attribute(null, "name", pkg.name); + serializer.attribute(null, "codePath", pkg.codePathString); + if (!pkg.resourcePathString.equals(pkg.codePathString)) { + serializer.attribute(null, "resourcePath", pkg.resourcePathString); + } + serializer.attribute(null, "system", + (pkg.pkgFlags&ApplicationInfo.FLAG_SYSTEM) != 0 + ? "true" : "false"); + serializer.attribute(null, "ts", pkg.getTimeStampStr()); + if (pkg.sharedUser == null) { + serializer.attribute(null, "userId", + Integer.toString(pkg.userId)); + } else { + serializer.attribute(null, "sharedUserId", + Integer.toString(pkg.userId)); + } + if (pkg.enabled != COMPONENT_ENABLED_STATE_DEFAULT) { + serializer.attribute(null, "enabled", + pkg.enabled == COMPONENT_ENABLED_STATE_ENABLED + ? "true" : "false"); + } + if(pkg.installStatus == PKG_INSTALL_INCOMPLETE) { + serializer.attribute(null, "installStatus", "false"); + } + pkg.signatures.writeXml(serializer, "sigs", mPastSignatures); + if ((pkg.pkgFlags&ApplicationInfo.FLAG_SYSTEM) == 0) { + serializer.startTag(null, "perms"); + if (pkg.sharedUser == null) { + // If this is a shared user, the permissions will + // be written there. We still need to write an + // empty permissions list so permissionsFixed will + // be set. + for (final String name : pkg.grantedPermissions) { + serializer.startTag(null, "item"); + serializer.attribute(null, "name", name); + serializer.endTag(null, "item"); + } + } + serializer.endTag(null, "perms"); + } + if (pkg.disabledComponents.size() > 0) { + serializer.startTag(null, "disabled-components"); + for (final String name : pkg.disabledComponents) { + serializer.startTag(null, "item"); + serializer.attribute(null, "name", name); + serializer.endTag(null, "item"); + } + serializer.endTag(null, "disabled-components"); + } + if (pkg.enabledComponents.size() > 0) { + serializer.startTag(null, "enabled-components"); + for (final String name : pkg.enabledComponents) { + serializer.startTag(null, "item"); + serializer.attribute(null, "name", name); + serializer.endTag(null, "item"); + } + serializer.endTag(null, "enabled-components"); + } + serializer.endTag(null, "package"); + } + void writePermission(XmlSerializer serializer, BasePermission bp) throws XmlPullParserException, java.io.IOException { if (bp.type != BasePermission.TYPE_BUILTIN @@ -5281,6 +5828,34 @@ class PackageManagerService extends IPackageManager.Stub { readPreferredPackagesLP(parser); } else if (tagName.equals("preferred-activities")) { readPreferredActivitiesLP(parser); + } else if(tagName.equals("updated-package")) { + String name = parser.getAttributeValue(null, "name"); + String codePathStr = parser.getAttributeValue(null, "codePath"); + String resourcePathStr = parser.getAttributeValue(null, "resourcePath"); + if(resourcePathStr == null) { + resourcePathStr = codePathStr; + } + + int pkgFlags = 0; + pkgFlags |= ApplicationInfo.FLAG_SYSTEM; + PackageSetting ps = new PackageSetting(name, + new File(codePathStr), + new File(resourcePathStr), pkgFlags); + String timeStampStr = parser.getAttributeValue(null, "ts"); + if (timeStampStr != null) { + try { + long timeStamp = Long.parseLong(timeStampStr); + ps.setTimeStamp(timeStamp, timeStampStr); + } catch (NumberFormatException e) { + } + } + String idStr = parser.getAttributeValue(null, "userId"); + ps.userId = idStr != null ? Integer.parseInt(idStr) : 0; + if(ps.userId <= 0) { + String sharedIdStr = parser.getAttributeValue(null, "sharedUserId"); + ps.userId = sharedIdStr != null ? Integer.parseInt(sharedIdStr) : 0; + } + mDisabledSysPackages.put(name, ps); } else { Log.w(TAG, "Unknown element under : " + parser.getName()); @@ -5811,6 +6386,13 @@ class PackageManagerService extends IPackageManager.Stub { mUserIds.add(obj); return FIRST_APPLICATION_UID + N; } + + public PackageSetting getDisabledSystemPkg(String name) { + synchronized(mPackages) { + PackageSetting ps = mDisabledSysPackages.get(name); + return ps; + } + } boolean isEnabledLP(ComponentInfo componentInfo, int flags) { final PackageSetting packageSettings = mPackages.get(componentInfo.packageName); diff --git a/services/java/com/android/server/PowerManagerService.java b/services/java/com/android/server/PowerManagerService.java index 4ff0844eab237e10f3f40d76dc390674e148919f..3fa2087f91bf651c53a7d59f60b0f421dbe742c9 100644 --- a/services/java/com/android/server/PowerManagerService.java +++ b/services/java/com/android/server/PowerManagerService.java @@ -17,7 +17,7 @@ package com.android.server; import com.android.internal.app.IBatteryStats; -import com.android.server.am.BatteryStats; +import com.android.server.am.BatteryStatsService; import android.app.ActivityManagerNative; import android.app.IActivityManager; @@ -29,6 +29,7 @@ import android.content.Intent; import android.content.IntentFilter; import android.content.pm.PackageManager; import android.database.Cursor; +import android.os.BatteryStats; import android.os.Binder; import android.os.Handler; import android.os.HandlerThread; @@ -74,11 +75,15 @@ class PowerManagerService extends IPowerManager.Stub implements LocalPowerManage | PowerManager.FULL_WAKE_LOCK; // time since last state: time since last event: - private static final int SHORT_KEYLIGHT_DELAY = 6000; // t+6 sec + // The short keylight delay comes from Gservices; this is the default. + private static final int SHORT_KEYLIGHT_DELAY_DEFAULT = 6000; // t+6 sec private static final int MEDIUM_KEYLIGHT_DELAY = 15000; // t+15 sec private static final int LONG_KEYLIGHT_DELAY = 6000; // t+6 sec private static final int LONG_DIM_TIME = 7000; // t+N-5 sec + // Cached Gservices settings; see updateGservicesValues() + private int mShortKeylightDelay = SHORT_KEYLIGHT_DELAY_DEFAULT; + // flags for setPowerState private static final int SCREEN_ON_BIT = 0x00000001; private static final int SCREEN_BRIGHT_BIT = 0x00000002; @@ -129,7 +134,7 @@ class PowerManagerService extends IPowerManager.Stub implements LocalPowerManage private final int MY_UID; private boolean mDoneBooting = false; - private boolean mStayOnWhilePluggedIn; + private int mStayOnConditions = 0; private int mNotificationQueue = -1; private int mNotificationWhy; private int mPartialCount = 0; @@ -163,7 +168,6 @@ class PowerManagerService extends IPowerManager.Stub implements LocalPowerManage = new BrightnessState(Power.KEYBOARD_LIGHT); private final BrightnessState mButtonBrightness = new BrightnessState(Power.BUTTON_LIGHT); - private ContentResolver mContentResolver; private boolean mIsPowered = false; private IActivityManager mActivityService; private IBatteryStats mBatteryStats; @@ -285,10 +289,20 @@ class PowerManagerService extends IPowerManager.Stub implements LocalPowerManage } } - public void setStayOnSetting(boolean val) { + /** + * Set the setting that determines whether the device stays on when plugged in. + * The argument is a bit string, with each bit specifying a power source that, + * when the device is connected to that source, causes the device to stay on. + * See {@link android.os.BatteryManager} for the list of power sources that + * can be specified. Current values include {@link android.os.BatteryManager#BATTERY_PLUGGED_AC} + * and {@link android.os.BatteryManager#BATTERY_PLUGGED_USB} + * @param val an {@code int} containing the bits that specify which power sources + * should cause the device to stay on. + */ + public void setStayOnSetting(int val) { mContext.enforceCallingOrSelfPermission(android.Manifest.permission.WRITE_SETTINGS, null); Settings.System.putInt(mContext.getContentResolver(), - Settings.System.STAY_ON_WHILE_PLUGGED_IN, val ? 1 : 0); + Settings.System.STAY_ON_WHILE_PLUGGED_IN, val); } private class SettingsObserver implements Observer { @@ -299,7 +313,7 @@ class PowerManagerService extends IPowerManager.Stub implements LocalPowerManage public void update(Observable o, Object arg) { synchronized (mLocks) { // STAY_ON_WHILE_PLUGGED_IN - mStayOnWhilePluggedIn = getInt(STAY_ON_WHILE_PLUGGED_IN) != 0; + mStayOnConditions = getInt(STAY_ON_WHILE_PLUGGED_IN); updateWakeLockLocked(); // SCREEN_OFF_TIMEOUT @@ -337,7 +351,7 @@ class PowerManagerService extends IPowerManager.Stub implements LocalPowerManage void init(Context context, IActivityManager activity, BatteryService battery) { mContext = context; mActivityService = activity; - mBatteryStats = BatteryStats.getService(); + mBatteryStats = BatteryStatsService.getService(); mBatteryService = battery; mHandlerThread = new HandlerThread("PowerManagerService") { @@ -376,10 +390,7 @@ class PowerManagerService extends IPowerManager.Stub implements LocalPowerManage mScreenOffIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); ContentResolver resolver = mContext.getContentResolver(); - mContentResolver = resolver; - - - Cursor settingsCursor = mContentResolver.query(Settings.System.CONTENT_URI, null, + Cursor settingsCursor = resolver.query(Settings.System.CONTENT_URI, null, "(" + Settings.System.NAME + "=?) or (" + Settings.System.NAME + "=?) or (" + Settings.System.NAME + "=?)", @@ -397,6 +408,13 @@ class PowerManagerService extends IPowerManager.Stub implements LocalPowerManage filter.addAction(Intent.ACTION_BATTERY_CHANGED); mContext.registerReceiver(new BatteryReceiver(), filter); + // Listen for Gservices changes + IntentFilter gservicesChangedFilter = + new IntentFilter(Settings.Gservices.CHANGED_ACTION); + mContext.registerReceiver(new GservicesChangedReceiver(), gservicesChangedFilter); + // And explicitly do the initial update of our cached settings + updateGservicesValues(); + // turn everything on setPowerState(ALL_BRIGHT); @@ -444,7 +462,7 @@ class PowerManagerService extends IPowerManager.Stub implements LocalPowerManage } private void updateWakeLockLocked() { - if (mStayOnWhilePluggedIn && mBatteryService.isPowered()) { + if (mStayOnConditions != 0 && mBatteryService.isPowered(mStayOnConditions)) { // keep the device on if we're plugged in and mStayOnWhilePluggedIn is set. mStayOnWhilePluggedInScreenDimLock.acquire(); mStayOnWhilePluggedInPartialLock.acquire(); @@ -758,7 +776,7 @@ class PowerManagerService extends IPowerManager.Stub implements LocalPowerManage pw.println(" mNextTimeout=" + mNextTimeout + " now=" + now + " " + ((mNextTimeout-now)/1000) + "s from now"); pw.println(" mDimScreen=" + mDimScreen - + " mStayOnWhilePluggedIn=" + mStayOnWhilePluggedIn); + + " mStayOnConditions=" + mStayOnConditions); pw.println(" mOffBecauseOfUser=" + mOffBecauseOfUser + " mUserState=" + mUserState); pw.println(" mNotificationQueue=" + mNotificationQueue @@ -1209,7 +1227,7 @@ class PowerManagerService extends IPowerManager.Stub implements LocalPowerManage // was dim steps = (int)(ANIM_STEPS*ratio); } - if (mStayOnWhilePluggedIn && mBatteryService.isPowered()) { + if (mStayOnConditions != 0 && mBatteryService.isPowered(mStayOnConditions)) { // If the "stay on while plugged in" option is // turned on, then the screen will often not // automatically turn off while plugged in. To @@ -1362,7 +1380,8 @@ class PowerManagerService extends IPowerManager.Stub implements LocalPowerManage private int getPreferredBrightness() { try { - final int brightness = Settings.System.getInt(mContentResolver, SCREEN_BRIGHTNESS); + final int brightness = Settings.System.getInt(mContext.getContentResolver(), + SCREEN_BRIGHTNESS); // Don't let applications turn the screen all the way off return Math.max(brightness, Power.BRIGHTNESS_DIM); } catch (SettingNotFoundException snfe) { @@ -1519,7 +1538,7 @@ class PowerManagerService extends IPowerManager.Stub implements LocalPowerManage * */ private void setScreenOffTimeoutsLocked() { if ((mPokey & POKE_LOCK_SHORT_TIMEOUT) != 0) { - mKeylightDelay = SHORT_KEYLIGHT_DELAY; + mKeylightDelay = mShortKeylightDelay; // Configurable via Gservices mDimDelay = -1; mScreenOffDelay = 0; } else if ((mPokey & POKE_LOCK_MEDIUM_TIMEOUT) != 0) { @@ -1553,6 +1572,31 @@ class PowerManagerService extends IPowerManager.Stub implements LocalPowerManage } } + /** + * Refreshes cached Gservices settings. Called once on startup, and + * on subsequent Settings.Gservices.CHANGED_ACTION broadcasts (see + * GservicesChangedReceiver). + */ + private void updateGservicesValues() { + mShortKeylightDelay = Settings.Gservices.getInt( + mContext.getContentResolver(), + Settings.Gservices.SHORT_KEYLIGHT_DELAY_MS, + SHORT_KEYLIGHT_DELAY_DEFAULT); + // Log.i(TAG, "updateGservicesValues(): mShortKeylightDelay now " + mShortKeylightDelay); + } + + /** + * Receiver for the Gservices.CHANGED_ACTION broadcast intent, + * which tells us we need to refresh our cached Gservices settings. + */ + private class GservicesChangedReceiver extends BroadcastReceiver { + @Override + public void onReceive(Context context, Intent intent) { + // Log.i(TAG, "GservicesChangedReceiver.onReceive(): " + intent); + updateGservicesValues(); + } + } + private class LockList extends ArrayList { void addLock(WakeLock wl) diff --git a/services/java/com/android/server/SensorService.java b/services/java/com/android/server/SensorService.java index f4b3f87f75e61fc3cfcff58c8ff6479331345933..f56088c642a78ae5f446fb6d79b3f72c903a5ac0 100644 --- a/services/java/com/android/server/SensorService.java +++ b/services/java/com/android/server/SensorService.java @@ -16,24 +16,20 @@ package com.android.server; -import android.app.Notification; -import android.app.NotificationManager; -import android.app.PendingIntent; import android.content.Context; -import android.content.Intent; import android.hardware.ISensorService; -import android.hardware.SensorManager; import android.os.Binder; import android.os.ParcelFileDescriptor; import android.os.RemoteException; import android.os.IBinder; -import android.os.SystemProperties; import android.util.Config; import android.util.Log; -import com.android.internal.R; import java.util.ArrayList; +import com.android.internal.app.IBatteryStats; +import com.android.server.am.BatteryStatsService; + /** * Class that manages the device's sensors. It register clients and activate @@ -43,46 +39,50 @@ import java.util.ArrayList; */ class SensorService extends ISensorService.Stub { - private static final int SENSOR_NOTIFICATION_ACCURACY_LEVEL = 1; - private static final String TAG = SensorService.class.getSimpleName(); + static final String TAG = SensorService.class.getSimpleName(); private static final boolean DEBUG = false; private static final boolean localLOGV = DEBUG ? Config.LOGD : Config.LOGV; private static final int SENSOR_DISABLE = -1; - private NotificationManager mNotificationManager; - private int mCompassAccuracy = -1; - private final Context mContext; + + /** + * Battery statistics to be updated when sensors are enabled and diabled. + */ + final IBatteryStats mBatteryStats = BatteryStatsService.getService(); private final class Listener implements IBinder.DeathRecipient { - final IBinder mListener; + final IBinder mToken; int mSensors = 0; int mDelay = 0x7FFFFFFF; - Listener(IBinder listener) { - mListener = listener; + Listener(IBinder token) { + mToken = token; } void addSensor(int sensor, int delay) { - mSensors |= sensor; + mSensors |= (1< delay) mDelay = delay; } void removeSensor(int sensor) { - mSensors &= ~sensor; + mSensors &= ~(1< 0; sensor >>>= 1) { + mToken.unlinkToDeath(this, 0); + // go through the lists of sensors used by the listener that + // died and deactivate them. + for (int sensor=0 ; sensor<32 && mSensors!=0 ; sensor++) { if (hasSensor(sensor)) { + removeSensor(sensor); try { deactivateIfUnused(sensor); } catch (RemoteException e) { @@ -95,60 +95,31 @@ class SensorService extends ISensorService.Stub { } } + @SuppressWarnings("unused") public SensorService(Context context) { if (localLOGV) Log.d(TAG, "SensorService startup"); _sensors_control_init(); - mNotificationManager = (NotificationManager)context.getSystemService(Context.NOTIFICATION_SERVICE); - mContext = context; } public ParcelFileDescriptor getDataChanel() throws RemoteException { return _sensors_control_open(); } - public void reportAccuracy(int sensor, int value) { - if ((sensor & (SensorManager.SENSOR_ORIENTATION|SensorManager.SENSOR_ORIENTATION_RAW)) != 0) { - synchronized (mNotificationManager) { - if (value != mCompassAccuracy) { - Log.d(TAG, "Compass needs calibration, accuracy=" + value); - if (!SystemProperties.getBoolean("debug.sensors.notification", false)) { - // don't show the sensors notification by default - return; - } - mCompassAccuracy = value; - if (value == -1) { - mNotificationManager.cancel(0); - } else { - if (value <= SENSOR_NOTIFICATION_ACCURACY_LEVEL) { - long token = Binder.clearCallingIdentity(); - try { - CharSequence banner = mContext.getString(R.string.compass_accuracy_banner); - CharSequence title = mContext.getString(R.string.compass_accuracy_notificaction_title); - CharSequence body = mContext.getString(R.string.compass_accuracy_notificaction_body); - Notification n = new Notification(R.drawable.stat_notify_calibrate_compass, - banner, System.currentTimeMillis()); - Intent bogusIntent = new Intent(mContext, SensorService.class); - PendingIntent contentIntent = PendingIntent.getActivity(mContext, 0, bogusIntent, - PendingIntent.FLAG_CANCEL_CURRENT|PendingIntent.FLAG_ONE_SHOT); - n.setLatestEventInfo(mContext, title, body, contentIntent); - mNotificationManager.notify(0, n); - } finally { - Binder.restoreCallingIdentity(token); - } - } else { - mNotificationManager.cancel(0); - } - } - } - } - } - } - - public boolean enableSensor(IBinder listener, int sensor, int enable) + public boolean enableSensor(IBinder binder, int sensor, int enable) throws RemoteException { if (localLOGV) Log.d(TAG, "enableSensor " + sensor + " " + enable); + + // Inform battery statistics service of status change + int uid = Binder.getCallingUid(); + long identity = Binder.clearCallingIdentity(); + if (enable == SENSOR_DISABLE) { + mBatteryStats.noteStopSensor(uid, sensor); + } else { + mBatteryStats.noteStartSensor(uid, sensor); + } + Binder.restoreCallingIdentity(identity); - if (listener == null) throw new NullPointerException("listener is null in enableSensor"); + if (binder == null) throw new NullPointerException("listener is null in enableSensor"); synchronized(mListeners) { if (enable!=SENSOR_DISABLE && !_sensors_control_activate(sensor, true)) { @@ -156,22 +127,18 @@ class SensorService extends ISensorService.Stub { return false; } - IBinder binder = listener; Listener l = null; - int minDelay = enable; - int size = mListeners.size(); - for (int i = 0; i < size ; i++) { - Listener test = mListeners.get(i); - if (binder.equals(test.mListener)) { - l = test; + for (Listener listener : mListeners) { + if (binder == listener.mToken) { + l = listener; } - if (minDelay > test.mDelay) - minDelay = test.mDelay; + if (minDelay > listener.mDelay) + minDelay = listener.mDelay; } if (l == null && enable!=SENSOR_DISABLE) { - l = new Listener(listener); + l = new Listener(binder); binder.linkToDeath(l, 0); mListeners.add(l); mListeners.notify(); @@ -182,7 +149,7 @@ class SensorService extends ISensorService.Stub { } if (minDelay >= 0) { - _sensors_control_set_delay(minDelay); + _sensors_control_set_delay(minDelay); } if (enable != SENSOR_DISABLE) { @@ -196,24 +163,28 @@ class SensorService extends ISensorService.Stub { mListeners.notify(); } } + + if (mListeners.size() == 0) { + _sensors_control_wake(); + } } return true; } - private void deactivateIfUnused(int sensor) throws RemoteException { + void deactivateIfUnused(int sensor) throws RemoteException { int size = mListeners.size(); - for (int i = 0; i < size ; i++) { + for (int i=0 ; i mListeners = new ArrayList(); + ArrayList mListeners = new ArrayList(); private static native int _sensors_control_init(); private static native ParcelFileDescriptor _sensors_control_open(); private static native boolean _sensors_control_activate(int sensor, boolean activate); private static native int _sensors_control_set_delay(int ms); + private static native int _sensors_control_wake(); } diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java index ff74472ebec4462b924af8b327489eebd5637af8..baf57bccac73233c65ce5e3952828c1dde84c4b5 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -33,11 +33,13 @@ import android.os.IBinder; import android.provider.Settings; import android.provider.Contacts.People; import android.server.BluetoothDeviceService; +import android.server.BluetoothA2dpService; import android.server.checkin.FallbackCheckinService; import android.server.search.SearchManagerService; import android.util.EventLog; import android.util.Log; +import dalvik.system.TouchDex; import dalvik.system.VMRuntime; import com.android.server.am.ActivityManagerService; @@ -46,7 +48,6 @@ import com.android.server.status.StatusBarService; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; - class ServerThread extends Thread { private static final String TAG = "SystemServer"; private final static boolean INCLUDE_DEMO = false; @@ -61,9 +62,9 @@ class ServerThread extends Thread { } @Override public void onChange(boolean selfChange) { - boolean enableAdb = (Settings.System.getInt(mContentResolver, - Settings.System.ADB_ENABLED, 0) > 0); - // setting this system property will start or stop adbd + boolean enableAdb = (Settings.Secure.getInt(mContentResolver, + Settings.Secure.ADB_ENABLED, 0) > 0); + // setting this secure property will start or stop adbd SystemProperties.set("persist.service.adb.enable", enableAdb ? "1" : "0"); } } @@ -83,12 +84,13 @@ class ServerThread extends Thread { String factoryTestStr = SystemProperties.get("ro.factorytest"); int factoryTest = "".equals(factoryTestStr) ? SystemServer.FACTORY_TEST_OFF : Integer.parseInt(factoryTestStr); - + PowerManagerService power = null; IPackageManager pm = null; Context context = null; WindowManagerService wm = null; BluetoothDeviceService bluetooth = null; + BluetoothA2dpService bluetoothA2dp = null; HeadsetObserver headset = null; // Critical services... @@ -96,7 +98,7 @@ class ServerThread extends Thread { Log.i(TAG, "Starting Power Manager."); power = new PowerManagerService(); ServiceManager.addService(Context.POWER_SERVICE, power); - + Log.i(TAG, "Starting Activity Manager."); context = ActivityManagerService.main(factoryTest); @@ -104,43 +106,44 @@ class ServerThread extends Thread { ServiceManager.addService("telephony.registry", new TelephonyRegistry(context)); AttributeCache.init(context); - + Log.i(TAG, "Starting Package Manager."); pm = PackageManagerService.main(context, factoryTest != SystemServer.FACTORY_TEST_OFF); ActivityManagerService.setSystemProcess(); - + mContentResolver = context.getContentResolver(); - + Log.i(TAG, "Starting Content Manager."); ContentService.main(context, factoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL); - + Log.i(TAG, "Starting System Content Providers."); ActivityManagerService.installSystemProviders(); - + Log.i(TAG, "Starting Battery Service."); BatteryService battery = new BatteryService(context); ServiceManager.addService("battery", battery); - // only initialize the power service after we have started the + // only initialize the power service after we have started the // content providers and the batter service. power.init(context, ActivityManagerService.getDefault(), battery); - + Log.i(TAG, "Starting Alarm Manager."); AlarmManagerService alarm = new AlarmManagerService(context); ServiceManager.addService(Context.ALARM_SERVICE, alarm); Watchdog.getInstance().init(context, battery, power, alarm, ActivityManagerService.self()); - + // Sensor Service is needed by Window Manager, so this goes first Log.i(TAG, "Starting Sensor Service."); ServiceManager.addService(Context.SENSOR_SERVICE, new SensorService(context)); Log.i(TAG, "Starting Window Manager."); - wm = WindowManagerService.main(context, power); + wm = WindowManagerService.main(context, power, + factoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL); ServiceManager.addService(Context.WINDOW_SERVICE, wm); ((ActivityManagerService)ServiceManager.getService("activity")) @@ -160,9 +163,12 @@ class ServerThread extends Thread { bluetooth = new BluetoothDeviceService(context); bluetooth.init(); ServiceManager.addService(Context.BLUETOOTH_SERVICE, bluetooth); + bluetoothA2dp = new BluetoothA2dpService(context); + ServiceManager.addService(BluetoothA2dpService.BLUETOOTH_A2DP_SERVICE, + bluetoothA2dp); - int bluetoothOn = Settings.System.getInt(mContentResolver, - Settings.System.BLUETOOTH_ON, 0); + int bluetoothOn = Settings.Secure.getInt(mContentResolver, + Settings.Secure.BLUETOOTH_ON, 0); if (bluetoothOn > 0) { bluetooth.enable(null); } @@ -172,8 +178,10 @@ class ServerThread extends Thread { Log.e("System", "Failure starting core service", e); } + StatusBarService statusBar = null; + InputMethodManagerService imm = null; + if (factoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) { - StatusBarService statusBar = null; try { Log.i(TAG, "Starting Status Bar Service."); statusBar = new StatusBarService(context); @@ -182,7 +190,22 @@ class ServerThread extends Thread { } catch (Throwable e) { Log.e(TAG, "Failure starting StatusBarService", e); } - + + try { + Log.i(TAG, "Starting Clipboard Service."); + ServiceManager.addService("clipboard", new ClipboardService(context)); + } catch (Throwable e) { + Log.e(TAG, "Failure starting Clipboard Service", e); + } + + try { + Log.i(TAG, "Starting Input Method Service."); + imm = new InputMethodManagerService(context, statusBar); + ServiceManager.addService(Context.INPUT_METHOD_SERVICE, imm); + } catch (Throwable e) { + Log.e(TAG, "Failure starting Input Manager Service", e); + } + try { Log.i(TAG, "Starting Hardware Service."); ServiceManager.addService("hardware", new HardwareService(context)); @@ -199,7 +222,7 @@ class ServerThread extends Thread { try { Log.i(TAG, "Starting Connectivity Service."); - ServiceManager.addService(Context.CONNECTIVITY_SERVICE, + ServiceManager.addService(Context.CONNECTIVITY_SERVICE, ConnectivityService.getInstance(context)); } catch (Throwable e) { Log.e(TAG, "Failure starting Connectivity Service", e); @@ -217,25 +240,25 @@ class ServerThread extends Thread { // MountService must start after NotificationManagerService Log.i(TAG, "Starting Mount Service."); ServiceManager.addService("mount", new MountService(context)); - } catch (Throwable e) { Log.e(TAG, "Failure starting Mount Service", e); } try { - Log.i(TAG, "Starting DeviceMemoryMonitor service"); - ServiceManager.addService("devicememorymonitor", new DeviceMemoryMonitorService(context)); + Log.i(TAG, "Starting DeviceStorageMonitor service"); + ServiceManager.addService(DeviceStorageMonitorService.SERVICE, + new DeviceStorageMonitorService(context)); } catch (Throwable e) { - Log.e(TAG, "Failure starting DeviceMemoryMonitor service", e); + Log.e(TAG, "Failure starting DeviceStorageMonitor service", e); } - + try { Log.i(TAG, "Starting Location Manager."); ServiceManager.addService(Context.LOCATION_SERVICE, new LocationManagerService(context)); } catch (Throwable e) { Log.e(TAG, "Failure starting Location Manager", e); } - + try { Log.i(TAG, "Starting Search Service."); ServiceManager.addService( Context.SEARCH_SERVICE, new SearchManagerService(context) ); @@ -243,18 +266,11 @@ class ServerThread extends Thread { Log.e(TAG, "Failure starting Search Service", e); } - try { - Log.i(TAG, "Starting Clipboard Service."); - ServiceManager.addService("clipboard", new ClipboardService(context)); - } catch (Throwable e) { - Log.e(TAG, "Failure starting Clipboard Service", e); - } - if (INCLUDE_DEMO) { Log.i(TAG, "Installing demo data..."); (new DemoThread(context)).start(); } - + try { Log.i(TAG, "Starting Checkin Service"); addService(context, "checkin", "com.google.android.server.checkin.CheckinService", @@ -276,7 +292,7 @@ class ServerThread extends Thread { } catch (Throwable e) { Log.e(TAG, "Failure starting Volume Service", e); } - + try { Log.i(TAG, "Starting HeadsetObserver"); // Listen for wired headset changes @@ -286,30 +302,36 @@ class ServerThread extends Thread { } } - // make sure the ADB_ENABLED setting value matches the system property value - Settings.System.putInt(mContentResolver, Settings.System.ADB_ENABLED, + // make sure the ADB_ENABLED setting value matches the secure property value + Settings.Secure.putInt(mContentResolver, Settings.Secure.ADB_ENABLED, "1".equals(SystemProperties.get("persist.service.adb.enable")) ? 1 : 0); // register observer to listen for settings changes - mContentResolver.registerContentObserver(Settings.System.getUriFor(Settings.System.ADB_ENABLED), + mContentResolver.registerContentObserver(Settings.Secure.getUriFor(Settings.Secure.ADB_ENABLED), false, new AdbSettingsObserver()); // It is now time to start up the app processes... + if (statusBar != null) { + statusBar.systemReady(); + } + if (imm != null) { + imm.systemReady(); + } wm.systemReady(); power.systemReady(); try { pm.systemReady(); } catch (RemoteException e) { } - + // After making the following code, third party code may be running... try { ActivityManagerNative.getDefault().systemReady(); } catch (RemoteException e) { } - + Watchdog.getInstance().start(); - + Looper.loop(); Log.d(TAG, "System ServerThread is exiting!"); } diff --git a/services/java/com/android/server/TelephonyRegistry.java b/services/java/com/android/server/TelephonyRegistry.java index 70ade1da965011dcb3e7dacc1ac4c247e0e0644f..dbaf0869547ac127566ccf97747ea32032d64cbe 100644 --- a/services/java/com/android/server/TelephonyRegistry.java +++ b/services/java/com/android/server/TelephonyRegistry.java @@ -16,19 +16,18 @@ package com.android.server; -import android.app.ActivityManagerNative; import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; -import android.os.Bundle; import android.os.Binder; +import android.os.Bundle; import android.os.IBinder; import android.os.RemoteException; import android.telephony.CellLocation; import android.telephony.PhoneStateListener; import android.telephony.ServiceState; import android.telephony.TelephonyManager; -import android.util.Log; +import android.text.TextUtils; import java.util.ArrayList; import java.io.FileDescriptor; @@ -41,9 +40,6 @@ import com.android.internal.telephony.Phone; import com.android.internal.telephony.PhoneStateIntentReceiver; import com.android.internal.telephony.TelephonyIntents; -import static android.Manifest.permission.READ_PHONE_STATE; -import static android.Manifest.permission.ACCESS_COARSE_LOCATION; - /** * Since phone process can be restarted, this class provides a centralized @@ -408,21 +404,23 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { Bundle data = new Bundle(); state.fillInNotifierBundle(data); intent.putExtras(data); - broadcastStickyIntent(intent); + mContext.sendStickyBroadcast(intent); } private void broadcastSignalStrengthChanged(int asu) { Intent intent = new Intent(TelephonyIntents.ACTION_SIGNAL_STRENGTH_CHANGED); intent.putExtra(PhoneStateIntentReceiver.INTENT_KEY_ASU, asu); - broadcastStickyIntent(intent); + mContext.sendStickyBroadcast(intent); } private void broadcastCallStateChanged(int state, String incomingNumber) { - Intent intent = new Intent(TelephonyIntents.ACTION_PHONE_STATE_CHANGED); + Intent intent = new Intent(TelephonyManager.ACTION_PHONE_STATE_CHANGED); intent.putExtra(Phone.STATE_KEY, DefaultPhoneNotifier.convertCallState(state).toString()); - intent.putExtra(PhoneStateIntentReceiver.INTENT_KEY_NUM, incomingNumber); - broadcastStickyIntent(intent); + if (!TextUtils.isEmpty(incomingNumber)) { + intent.putExtra(TelephonyManager.EXTRA_INCOMING_NUMBER, incomingNumber); + } + mContext.sendBroadcast(intent, android.Manifest.permission.READ_PHONE_STATE); } private void broadcastDataConnectionStateChanged(int state, boolean isDataConnectivityPossible, @@ -437,16 +435,12 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { } intent.putExtra(Phone.DATA_APN_KEY, apn); intent.putExtra(Phone.DATA_IFACE_NAME_KEY, interfaceName); - broadcastStickyIntent(intent); + mContext.sendStickyBroadcast(intent); } private void broadcastDataConnectionFailed(String reason) { Intent intent = new Intent(TelephonyIntents.ACTION_DATA_CONNECTION_FAILED); intent.putExtra(Phone.FAILURE_REASON_KEY, reason); - broadcastStickyIntent(intent); - } - - private static void broadcastStickyIntent(Intent intent) { - ActivityManagerNative.broadcastStickyIntent(intent, null); + mContext.sendStickyBroadcast(intent); } } diff --git a/services/java/com/android/server/Watchdog.java b/services/java/com/android/server/Watchdog.java index 70f54cafe3a979a25e8c9e3319afd5f722bfa28e..70c311013ccd93c432566d4ce3d401bcfd4c753b 100644 --- a/services/java/com/android/server/Watchdog.java +++ b/services/java/com/android/server/Watchdog.java @@ -783,7 +783,15 @@ public class Watchdog extends Thread { c.set(Calendar.SECOND, (int)secondsSinceMidnight - (val*60)); c.set(Calendar.MILLISECOND, 0); - return c.getTimeInMillis(); + long newTime = c.getTimeInMillis(); + if (newTime < curTime) { + // The given time (in seconds since midnight) has already passed for today, so advance + // by one day (due to daylight savings, etc., the delta may differ from 24 hours). + c.add(Calendar.DAY_OF_MONTH, 1); + newTime = c.getTimeInMillis(); + } + + return newTime; } @Override diff --git a/services/java/com/android/server/WifiService.java b/services/java/com/android/server/WifiService.java index 8f69235756bdb12b176e138a4e9aa3e4f1ef6dfb..7a0deffdb86ecf384956dc7b44e28df620b03c42 100644 --- a/services/java/com/android/server/WifiService.java +++ b/services/java/com/android/server/WifiService.java @@ -47,8 +47,8 @@ import android.os.Looper; import android.os.Message; import android.os.PowerManager; import android.os.RemoteException; +import android.os.BatteryManager; import android.provider.Settings; -import android.provider.Settings.Gservices; import android.util.Log; import android.text.TextUtils; @@ -72,7 +72,7 @@ import java.io.PrintWriter; public class WifiService extends IWifiManager.Stub { private static final String TAG = "WifiService"; private static final boolean DBG = false; - private static final Pattern scanResultPattern = Pattern.compile("\t{1,}"); + private static final Pattern scanResultPattern = Pattern.compile("\t+"); private final WifiStateTracker mWifiStateTracker; private Context mContext; @@ -81,15 +81,16 @@ public class WifiService extends IWifiManager.Stub { private AlarmManager mAlarmManager; private PendingIntent mIdleIntent; private static final int IDLE_REQUEST = 0; + private boolean mScreenOff; private boolean mDeviceIdle; - private boolean mChargerAttached; - private final LockList mLocks = new LockList(); + private int mPluggedType; + private final LockList mLocks = new LockList(); /** - * See {@link Gservices#WIFI_IDLE_MS}. This is the default value if a - * Gservices value is not present. + * See {@link Settings.System#WIFI_IDLE_MS}. This is the default value if a + * Settings.System value is not present. */ - private long mIdleMillis = 2 * 60 * 1000; /* 2 minutes */ + private static final long DEFAULT_IDLE_MILLIS = 2 * 60 * 1000; /* 2 minutes */ private static final String WAKELOCK_TAG = "WifiService"; @@ -99,10 +100,11 @@ public class WifiService extends IWifiManager.Stub { * observed to take about 5 seconds under normal circumstances. This * provides a bit of extra margin. *

              - * See {@link Gservices#WIFI_MOBILE_DATA_TRANSITION_WAKELOCK_TIMEOUT_MS}. - * This is the default value if a Gservices value is not present. + * See {@link android.provider.Settings.Secure#WIFI_MOBILE_DATA_TRANSITION_WAKELOCK_TIMEOUT_MS}. + * This is the default value if a Settings.System value is not present. */ - private int mWakelockTimeout = 8000; + private static final int DEFAULT_WAKELOCK_TIMEOUT = 8000; + // Wake lock used by driver-stop operation private static PowerManager.WakeLock mDriverStopWakeLock; // Wake lock used by other operations @@ -151,6 +153,12 @@ public class WifiService extends IWifiManager.Stub { private char[] mScanResultBuffer; private boolean mNeedReconfig; + /** + * Number of allowed radio frequency channels in various regulatory domains. + * This list is sufficient for 802.11b/g networks (2.4GHz range). + */ + private static int[] sValidRegulatoryChannelCounts = new int[] {11, 13, 14}; + private static final String ACTION_DEVICE_IDLE = "com.android.server.WifiManager.action.DEVICE_IDLE"; @@ -164,11 +172,6 @@ public class WifiService extends IWifiManager.Stub { mIsHiddenNetworkPresent = new HashMap(); mNumHiddenNetworkPresent = 0; - ContentResolver contentResolver = context.getContentResolver(); - mIdleMillis = Gservices.getLong(contentResolver, Gservices.WIFI_IDLE_MS, mIdleMillis); - mWakelockTimeout = Gservices.getInt(contentResolver, - Gservices.WIFI_MOBILE_DATA_TRANSITION_WAKELOCK_TIMEOUT_MS, mWakelockTimeout); - mScanResultCache = new LinkedHashMap( SCAN_RESULT_CACHE_SIZE, 0.75f, true) { /* @@ -214,7 +217,7 @@ public class WifiService extends IWifiManager.Stub { Log.d(TAG, "WifiService starting up with Wi-Fi " + (wifiEnabled ? "enabled" : "disabled")); registerForBroadcasts(); - setWifiEnabledBlocking(wifiEnabled); + setWifiEnabledBlocking(wifiEnabled, false); } /** @@ -369,16 +372,16 @@ public class WifiService extends IWifiManager.Stub { private boolean getPersistedWifiEnabled() { final ContentResolver cr = mContext.getContentResolver(); try { - return Settings.System.getInt(cr, Settings.System.WIFI_ON) == 1; + return Settings.Secure.getInt(cr, Settings.Secure.WIFI_ON) == 1; } catch (Settings.SettingNotFoundException e) { - Settings.System.putInt(cr, Settings.System.WIFI_ON, 0); + Settings.Secure.putInt(cr, Settings.Secure.WIFI_ON, 0); return false; } } private void persistWifiEnabled(boolean enabled) { final ContentResolver cr = mContext.getContentResolver(); - Settings.System.putInt(cr, Settings.System.WIFI_ON, enabled ? 1 : 0); + Settings.Secure.putInt(cr, Settings.Secure.WIFI_ON, enabled ? 1 : 0); } NetworkStateTracker getNetworkStateTracker() { @@ -433,9 +436,7 @@ public class WifiService extends IWifiManager.Stub { */ synchronized (mWifiHandler) { mWakeLock.acquire(); - - mWifiHandler.obtainMessage( - enable ? MESSAGE_ENABLE_WIFI : MESSAGE_DISABLE_WIFI).sendToTarget(); + sendEnableMessage(enable, true); } return true; @@ -444,10 +445,11 @@ public class WifiService extends IWifiManager.Stub { /** * Enables/disables Wi-Fi synchronously. * @param enable {@code true} to turn Wi-Fi on, {@code false} to turn it off. + * @param persist {@code true} if the setting should be persisted. * @return {@code true} if the operation succeeds (or if the existing state * is the same as the requested state) */ - private boolean setWifiEnabledBlocking(boolean enable) { + private boolean setWifiEnabledBlocking(boolean enable, boolean persist) { final int eventualWifiState = enable ? WIFI_STATE_ENABLED : WIFI_STATE_DISABLED; if (mWifiState == eventualWifiState) { @@ -501,13 +503,17 @@ public class WifiService extends IWifiManager.Stub { // Success! - persistWifiEnabled(enable); + if (persist) { + persistWifiEnabled(enable); + } updateWifiState(eventualWifiState); /* - * Initiliaze the hidden networs state if the Wi-Fi is being turned on. + * Initialize the hidden networks state and the number of allowed + * radio channels if Wi-Fi is being turned on. */ if (enable) { + mWifiStateTracker.setNumAllowedChannels(); initializeHiddenNetworksState(); } @@ -799,7 +805,7 @@ public class WifiService extends IWifiManager.Stub { */ int netId = config.networkId; boolean newNetwork = netId == -1; - boolean doReconfig = false; + boolean doReconfig; int currentPriority; // networkId of -1 means we want to create a new network if (newNetwork) { @@ -1349,6 +1355,78 @@ public class WifiService extends IWifiManager.Stub { return result; } + /** + * Set the number of radio frequency channels that are allowed to be used + * in the current regulatory domain. This method should be used only + * if the correct number of channels cannot be determined automatically + * for some reason. If the operation is successful, the new value is + * persisted as a System setting. + * @param numChannels the number of allowed channels. Must be greater than 0 + * and less than or equal to 16. + * @return {@code true} if the operation succeeds, {@code false} otherwise, e.g., + * {@code numChannels} is outside the valid range. + */ + public boolean setNumAllowedChannels(int numChannels) { + enforceChangePermission(); + /* + * Validate the argument. We'd like to let the Wi-Fi driver do this, + * but if Wi-Fi isn't currently enabled, that's not possible, and + * we want to persist the setting anyway,so that it will take + * effect when Wi-Fi does become enabled. + */ + boolean found = false; + for (int validChan : sValidRegulatoryChannelCounts) { + if (validChan == numChannels) { + found = true; + break; + } + } + if (!found) { + return false; + } + + Settings.Secure.putInt(mContext.getContentResolver(), + Settings.Secure.WIFI_NUM_ALLOWED_CHANNELS, + numChannels); + mWifiStateTracker.setNumAllowedChannels(numChannels); + return true; + } + + /** + * Return the number of frequency channels that are allowed + * to be used in the current regulatory domain. + * @return the number of allowed channels, or {@code -1} if an error occurs + */ + public int getNumAllowedChannels() { + int numChannels; + + enforceAccessPermission(); + synchronized (mWifiStateTracker) { + /* + * If we can't get the value from the driver (e.g., because + * Wi-Fi is not currently enabled), get the value from + * Settings. + */ + numChannels = WifiNative.getNumAllowedChannelsCommand(); + if (numChannels < 0) { + numChannels = Settings.Secure.getInt(mContext.getContentResolver(), + Settings.Secure.WIFI_NUM_ALLOWED_CHANNELS, + -1); + } + } + return numChannels; + } + + /** + * Return the list of valid values for the number of allowed radio channels + * for various regulatory domains. + * @return the list of channel counts + */ + public int[] getValidChannelCounts() { + enforceAccessPermission(); + return sValidRegulatoryChannelCounts; + } + /** * Return the DHCP-assigned addresses from the last successful DHCP request, * if any. @@ -1364,29 +1442,83 @@ public class WifiService extends IWifiManager.Stub { public void onReceive(Context context, Intent intent) { String action = intent.getAction(); + long idleMillis = Settings.System.getLong(mContext.getContentResolver(), + Settings.System.WIFI_IDLE_MS, DEFAULT_IDLE_MILLIS); + int stayAwakeConditions = + Settings.System.getInt(mContext.getContentResolver(), + Settings.System.STAY_ON_WHILE_PLUGGED_IN, 0); if (action.equals(Intent.ACTION_AIRPLANE_MODE_CHANGED)) { /* do nothing, we'll check isAirplaneModeOn later. */ } else if (action.equals(Intent.ACTION_SCREEN_ON)) { mAlarmManager.cancel(mIdleIntent); mDeviceIdle = false; + mScreenOff = false; } else if (action.equals(Intent.ACTION_SCREEN_OFF)) { - long triggerTime = System.currentTimeMillis() + mIdleMillis; - mAlarmManager.set(AlarmManager.RTC_WAKEUP, triggerTime, mIdleIntent); + mScreenOff = true; + /* + * Set a timer to put Wi-Fi to sleep, but only if the screen is off + * AND the "stay on while plugged in" setting doesn't match the + * current power conditions (i.e, not plugged in, plugged in to USB, + * or plugged in to AC). + */ + if (!shouldStayAwake(stayAwakeConditions, mPluggedType)) { + long triggerTime = System.currentTimeMillis() + idleMillis; + mAlarmManager.set(AlarmManager.RTC_WAKEUP, triggerTime, mIdleIntent); + } /* we can return now -- there's nothing to do until we get the idle intent back */ return; } else if (action.equals(ACTION_DEVICE_IDLE)) { mDeviceIdle = true; } else if (action.equals(Intent.ACTION_BATTERY_CHANGED)) { - int plugged = intent.getIntExtra("plugged", 0); - mChargerAttached = (plugged != 0); + /* + * Set a timer to put Wi-Fi to sleep, but only if the screen is off + * AND we are transitioning from a state in which the device was supposed + * to stay awake and a state in which it is not supposed to stay awake. + * If "stay awake" state is not changing, we do nothing, to avoid resetting + * the already-set timer. + */ + int pluggedType = intent.getIntExtra("plugged", 0); + if (mScreenOff && shouldStayAwake(stayAwakeConditions, mPluggedType) && + !shouldStayAwake(stayAwakeConditions, pluggedType)) { + long triggerTime = System.currentTimeMillis() + idleMillis; + mAlarmManager.set(AlarmManager.RTC_WAKEUP, triggerTime, mIdleIntent); + mPluggedType = pluggedType; + return; + } + mPluggedType = pluggedType; } else { return; } updateWifiState(); } + + /** + * Determine whether the bit value corresponding to {@code pluggedType} is set in + * the bit string {@code stayAwakeConditions}. Because a {@code pluggedType} value + * of {@code 0} isn't really a plugged type, but rather an indication that the + * device isn't plugged in at all, there is no bit value corresponding to a + * {@code pluggedType} value of {@code 0}. That is why we shift by + * {@code pluggedType — 1} instead of by {@code pluggedType}. + * @param stayAwakeConditions a bit string specifying which "plugged types" should + * keep the device (and hence Wi-Fi) awake. + * @param pluggedType the type of plug (USB, AC, or none) for which the check is + * being made + * @return {@code true} if {@code pluggedType} indicates that the device is + * supposed to stay awake, {@code false} otherwise. + */ + private boolean shouldStayAwake(int stayAwakeConditions, int pluggedType) { + return (stayAwakeConditions & pluggedType) != 0; + } }; + private void sendEnableMessage(boolean enable, boolean persist) { + Message msg = Message.obtain(mWifiHandler, + (enable ? MESSAGE_ENABLE_WIFI : MESSAGE_DISABLE_WIFI), + (persist ? 1 : 0), 0); + msg.sendToTarget(); + } + private void updateWifiState() { boolean wifiEnabled = getPersistedWifiEnabled(); boolean airplaneMode = isAirplaneModeOn(); @@ -1399,17 +1531,22 @@ public class WifiService extends IWifiManager.Stub { if (wifiShouldBeEnabled) { if (wifiShouldBeStarted) { mWakeLock.acquire(); - mWifiHandler.obtainMessage(MESSAGE_ENABLE_WIFI).sendToTarget(); + sendEnableMessage(true, false); mWakeLock.acquire(); - mWifiHandler.obtainMessage(MESSAGE_START_WIFI).sendToTarget(); + mWifiHandler.sendEmptyMessage(MESSAGE_START_WIFI); } else { + int wakeLockTimeout = + Settings.Secure.getInt( + mContext.getContentResolver(), + Settings.Secure.WIFI_MOBILE_DATA_TRANSITION_WAKELOCK_TIMEOUT_MS, + DEFAULT_WAKELOCK_TIMEOUT); mDriverStopWakeLock.acquire(); - mWifiHandler.obtainMessage(MESSAGE_STOP_WIFI).sendToTarget(); - mWifiHandler.sendEmptyMessageDelayed(MESSAGE_RELEASE_WAKELOCK, mWakelockTimeout); + mWifiHandler.sendEmptyMessage(MESSAGE_STOP_WIFI); + mWifiHandler.sendEmptyMessageDelayed(MESSAGE_RELEASE_WAKELOCK, wakeLockTimeout); } } else { mWakeLock.acquire(); - mWifiHandler.obtainMessage(MESSAGE_DISABLE_WIFI).sendToTarget(); + sendEnableMessage(false, false); } } } @@ -1454,24 +1591,24 @@ public class WifiService extends IWifiManager.Stub { switch (msg.what) { case MESSAGE_ENABLE_WIFI: { - setWifiEnabledBlocking(true); + setWifiEnabledBlocking(true, msg.arg1 == 1); /* fall through */ } case MESSAGE_START_WIFI: { - WifiNative.startDriverCommand(); + mWifiStateTracker.startDriver(); mWakeLock.release(); break; } case MESSAGE_DISABLE_WIFI: { - setWifiEnabledBlocking(false); + setWifiEnabledBlocking(false, msg.arg1 == 1); mWakeLock.release(); break; } case MESSAGE_STOP_WIFI: { - WifiNative.stopDriverCommand(); + mWifiStateTracker.stopDriver(); // don't release wakelock break; } @@ -1487,7 +1624,7 @@ public class WifiService extends IWifiManager.Stub { } } } - + @Override protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { if (mContext.checkCallingPermission(android.Manifest.permission.DUMP) @@ -1498,6 +1635,9 @@ public class WifiService extends IWifiManager.Stub { return; } pw.println("Wi-Fi is " + stateName(mWifiState)); + pw.println("stay-awake conditions: " + + Settings.System.getInt(mContext.getContentResolver(), + Settings.System.STAY_ON_WHILE_PLUGGED_IN, 0)); pw.println(); pw.println("Latest scan results:"); diff --git a/services/java/com/android/server/WifiWatchdogService.java b/services/java/com/android/server/WifiWatchdogService.java index f9edab4f6abed80937d79b5a1028d6a22eedc0fe..e686bf0b5a7bd416347b8af70d62ca51458c3c34 100644 --- a/services/java/com/android/server/WifiWatchdogService.java +++ b/services/java/com/android/server/WifiWatchdogService.java @@ -31,7 +31,7 @@ import android.os.Handler; import android.os.Looper; import android.os.Message; import android.os.SystemProperties; -import android.provider.Settings.System; +import android.provider.Settings; import android.text.TextUtils; import android.util.Config; import android.util.Log; @@ -139,7 +139,7 @@ public class WifiWatchdogService { private void registerForSettingsChanges() { ContentResolver contentResolver = mContext.getContentResolver(); contentResolver.registerContentObserver( - System.getUriFor(System.WIFI_WATCHDOG_ON), false, + Settings.Secure.getUriFor(Settings.Secure.WIFI_WATCHDOG_ON), false, new ContentObserver(mHandler) { @Override public void onChange(boolean selfChange) { @@ -156,84 +156,90 @@ public class WifiWatchdogService { } /** - * @see System#WIFI_WATCHDOG_ON + * @see android.provider.Settings.Secure#WIFI_WATCHDOG_ON */ private boolean isWatchdogEnabled() { - return System.getInt(mContentResolver, System.WIFI_WATCHDOG_ON, 1) == 1; + return Settings.Secure.getInt(mContentResolver, Settings.Secure.WIFI_WATCHDOG_ON, 1) == 1; } /** - * @see System#WIFI_WATCHDOG_AP_COUNT + * @see android.provider.Settings.Secure#WIFI_WATCHDOG_AP_COUNT */ private int getApCount() { - return System.getInt(mContentResolver, System.WIFI_WATCHDOG_AP_COUNT, 2); + return Settings.Secure.getInt(mContentResolver, + Settings.Secure.WIFI_WATCHDOG_AP_COUNT, 2); } /** - * @see System#WIFI_WATCHDOG_INITIAL_IGNORED_PING_COUNT + * @see android.provider.Settings.Secure#WIFI_WATCHDOG_INITIAL_IGNORED_PING_COUNT */ private int getInitialIgnoredPingCount() { - return System.getInt(mContentResolver, System.WIFI_WATCHDOG_INITIAL_IGNORED_PING_COUNT , 2); + return Settings.Secure.getInt(mContentResolver, + Settings.Secure.WIFI_WATCHDOG_INITIAL_IGNORED_PING_COUNT , 2); } /** - * @see System#WIFI_WATCHDOG_PING_COUNT + * @see android.provider.Settings.Secure#WIFI_WATCHDOG_PING_COUNT */ private int getPingCount() { - return System.getInt(mContentResolver, System.WIFI_WATCHDOG_PING_COUNT, 4); + return Settings.Secure.getInt(mContentResolver, + Settings.Secure.WIFI_WATCHDOG_PING_COUNT, 4); } /** - * @see System#WIFI_WATCHDOG_PING_TIMEOUT_MS + * @see android.provider.Settings.Secure#WIFI_WATCHDOG_PING_TIMEOUT_MS */ private int getPingTimeoutMs() { - return System.getInt(mContentResolver, System.WIFI_WATCHDOG_PING_TIMEOUT_MS, 500); + return Settings.Secure.getInt(mContentResolver, + Settings.Secure.WIFI_WATCHDOG_PING_TIMEOUT_MS, 500); } /** - * @see System#WIFI_WATCHDOG_PING_DELAY_MS + * @see android.provider.Settings.Secure#WIFI_WATCHDOG_PING_DELAY_MS */ private int getPingDelayMs() { - return System.getInt(mContentResolver, System.WIFI_WATCHDOG_PING_DELAY_MS, 250); + return Settings.Secure.getInt(mContentResolver, + Settings.Secure.WIFI_WATCHDOG_PING_DELAY_MS, 250); } /** - * @see System#WIFI_WATCHDOG_ACCEPTABLE_PACKET_LOSS_PERCENTAGE + * @see android.provider.Settings.Secure#WIFI_WATCHDOG_ACCEPTABLE_PACKET_LOSS_PERCENTAGE */ private int getAcceptablePacketLossPercentage() { - return System.getInt(mContentResolver, - System.WIFI_WATCHDOG_ACCEPTABLE_PACKET_LOSS_PERCENTAGE, 25); + return Settings.Secure.getInt(mContentResolver, + Settings.Secure.WIFI_WATCHDOG_ACCEPTABLE_PACKET_LOSS_PERCENTAGE, 25); } /** - * @see System#WIFI_WATCHDOG_MAX_AP_CHECKS + * @see android.provider.Settings.Secure#WIFI_WATCHDOG_MAX_AP_CHECKS */ private int getMaxApChecks() { - return System.getInt(mContentResolver, System.WIFI_WATCHDOG_MAX_AP_CHECKS, 7); + return Settings.Secure.getInt(mContentResolver, + Settings.Secure.WIFI_WATCHDOG_MAX_AP_CHECKS, 7); } /** - * @see System#WIFI_WATCHDOG_BACKGROUND_CHECK_ENABLED + * @see android.provider.Settings.Secure#WIFI_WATCHDOG_BACKGROUND_CHECK_ENABLED */ private boolean isBackgroundCheckEnabled() { - return System.getInt(mContentResolver, System.WIFI_WATCHDOG_BACKGROUND_CHECK_ENABLED, 1) - == 1; + return Settings.Secure.getInt(mContentResolver, + Settings.Secure.WIFI_WATCHDOG_BACKGROUND_CHECK_ENABLED, 1) == 1; } /** - * @see System#WIFI_WATCHDOG_BACKGROUND_CHECK_DELAY_MS + * @see android.provider.Settings.Secure#WIFI_WATCHDOG_BACKGROUND_CHECK_DELAY_MS */ private int getBackgroundCheckDelayMs() { - return System.getInt(mContentResolver, - System.WIFI_WATCHDOG_BACKGROUND_CHECK_DELAY_MS, 5000); + return Settings.Secure.getInt(mContentResolver, + Settings.Secure.WIFI_WATCHDOG_BACKGROUND_CHECK_DELAY_MS, 5000); } /** - * @see System#WIFI_WATCHDOG_BACKGROUND_CHECK_TIMEOUT_MS + * @see android.provider.Settings.Secure#WIFI_WATCHDOG_BACKGROUND_CHECK_TIMEOUT_MS */ private int getBackgroundCheckTimeoutMs() { - return System.getInt(mContentResolver, - System.WIFI_WATCHDOG_BACKGROUND_CHECK_TIMEOUT_MS, 1000); + return Settings.Secure.getInt(mContentResolver, + Settings.Secure.WIFI_WATCHDOG_BACKGROUND_CHECK_TIMEOUT_MS, 1000); } /** @@ -326,7 +332,7 @@ public class WifiWatchdogService { int pingDelay = getPingDelayMs(); int acceptableLoss = getAcceptablePacketLossPercentage(); - /** See {@link System#WIFI_WATCHDOG_INITIAL_IGNORED_PING_COUNT} */ + /** See {@link Secure#WIFI_WATCHDOG_INITIAL_IGNORED_PING_COUNT} */ int ignoredPingCounter = 0; int pingCounter = 0; int successCounter = 0; @@ -959,7 +965,7 @@ public class WifiWatchdogService { * thread will ensure when it sees the message that the state is still * valid for going to sleep. *

              - * For an explanation of sleep, see {@link System#WIFI_WATCHDOG_MAX_AP_CHECKS}. + * For an explanation of sleep, see {@link android.provider.Settings.Secure#WIFI_WATCHDOG_MAX_AP_CHECKS}. */ static final int MESSAGE_SLEEP = 101; /** Disables the watchdog. */ @@ -1166,7 +1172,7 @@ public class WifiWatchdogService { private static class DnsPinger { /** Number of bytes for the query */ - private static final int DNS_QUERY_BASE_SIZE = 12; + private static final int DNS_QUERY_BASE_SIZE = 33; /** The DNS port */ private static final int DNS_PORT = 53; @@ -1227,21 +1233,54 @@ public class WifiWatchdogService { } private static void fillQuery(byte[] buf) { - int i = 0; - // See RFC2929, section 2 + /* + * See RFC2929 (though the bit tables in there are misleading for + * us. For example, the recursion desired bit is the 0th bit for us, + * but looking there it would appear as the 7th bit of the byte + */ + + // Make sure it's all zeroed out + for (int i = 0; i < buf.length; i++) buf[i] = 0; + + // Form a query for www.android.com - // [0-1] bytes are an ID - buf[i++] = (byte) sRandom.nextInt(256); - buf[i++] = (byte) sRandom.nextInt(256); + // [0-1] bytes are an ID, generate random ID for this query + buf[0] = (byte) sRandom.nextInt(256); + buf[1] = (byte) sRandom.nextInt(256); // [2-3] bytes are for flags. - // The Opcode is '2' for server status. It is on bits [1-4] of this byte. - buf[i++] = 4; - buf[i++] = 0; + buf[2] = 1; // Recursion desired + + // [4-5] bytes are for the query count + buf[5] = 1; // One query + + // [6-7] [8-9] [10-11] are all counts of other fields we don't use + + // [12-15] for www + writeString(buf, 12, "www"); - // [4-5] [6-7] [8-9] [10-11] are all counts of other fields we don't use - for (; i <= 11; i++) buf[i] = 0; + // [16-23] for android + writeString(buf, 16, "android"); + + // [24-27] for com + writeString(buf, 24, "com"); + + // [29-30] bytes are for QTYPE, set to 1 + buf[30] = 1; + + // [31-32] bytes are for QCLASS, set to 1 + buf[32] = 1; + } + + private static void writeString(byte[] buf, int startPos, String string) { + int pos = startPos; + + // Write the length first + buf[pos++] = (byte) string.length(); + for (int i = 0; i < string.length(); i++) { + buf[pos++] = (byte) string.charAt(i); + } } } } diff --git a/services/java/com/android/server/WindowManagerService.java b/services/java/com/android/server/WindowManagerService.java index 4ad2c42cae58a5cea63800212b381605bc8c87a2..967174343e63e0e2ffccd6ae5ea266ff97d1923e 100644 --- a/services/java/com/android/server/WindowManagerService.java +++ b/services/java/com/android/server/WindowManagerService.java @@ -25,6 +25,8 @@ import static android.view.WindowManager.LayoutParams.FLAG_BLUR_BEHIND; import static android.view.WindowManager.LayoutParams.FLAG_DIM_BEHIND; import static android.view.WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON; import static android.view.WindowManager.LayoutParams.FLAG_SYSTEM_ERROR; +import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE; +import static android.view.WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM; import static android.view.WindowManager.LayoutParams.LAST_APPLICATION_WINDOW; import static android.view.WindowManager.LayoutParams.LAST_SUB_WINDOW; import static android.view.WindowManager.LayoutParams.MEMORY_TYPE_GPU; @@ -32,11 +34,16 @@ import static android.view.WindowManager.LayoutParams.MEMORY_TYPE_HARDWARE; import static android.view.WindowManager.LayoutParams.MEMORY_TYPE_PUSH_BUFFERS; import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING; import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION; +import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD; +import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG; import com.android.internal.app.IBatteryStats; import com.android.internal.policy.PolicyManager; +import com.android.internal.view.IInputContext; +import com.android.internal.view.IInputMethodClient; +import com.android.internal.view.IInputMethodManager; import com.android.server.KeyInputQueue.QueuedEvent; -import com.android.server.am.BatteryStats; +import com.android.server.am.BatteryStatsService; import android.Manifest; import android.app.ActivityManagerNative; @@ -49,6 +56,7 @@ import android.graphics.Matrix; import android.graphics.PixelFormat; import android.graphics.Rect; import android.graphics.Region; +import android.os.BatteryStats; import android.os.Binder; import android.os.Debug; import android.os.Handler; @@ -84,6 +92,7 @@ import android.view.RawInputEvent; import android.view.Surface; import android.view.SurfaceSession; import android.view.View; +import android.view.ViewTreeObserver; import android.view.WindowManager; import android.view.WindowManagerImpl; import android.view.WindowManagerPolicy; @@ -152,6 +161,16 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo */ static final int MAX_ANIMATION_DURATION = 10*1000; + /** Amount of time (in milliseconds) to animate the dim surface from one + * value to another, when no window animation is driving it. + */ + static final int DEFAULT_DIM_DURATION = 200; + + static final int UPDATE_FOCUS_NORMAL = 0; + static final int UPDATE_FOCUS_WILL_ASSIGN_LAYERS = 1; + static final int UPDATE_FOCUS_PLACING_SURFACES = 2; + static final int UPDATE_FOCUS_WILL_PLACE_SURFACES = 3; + private static final String SYSTEM_SECURE = "ro.secure"; /** @@ -177,6 +196,8 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo final Context mContext; + final boolean mHaveInputMethods; + final WindowManagerPolicy mPolicy = PolicyManager.makeNewWindowManager(); final IActivityManager mActivityManager; @@ -206,6 +227,12 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo */ final ArrayList mTokenList = new ArrayList(); + /** + * Window tokens that are in the process of exiting, but still + * on screen for animations. + */ + final ArrayList mExitingTokens = new ArrayList(); + /** * Z-ordered (bottom-most first) list of all application tokens, for * controlling the ordering of windows in different applications. This @@ -259,9 +286,15 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo */ ArrayList mForceRemoves; + IInputMethodManager mInputMethodManager; + SurfaceSession mFxSession; Surface mDimSurface; boolean mDimShown; + float mDimCurrentAlpha; + float mDimTargetAlpha; + float mDimDeltaPerMs; + long mLastDimAnimTime; Surface mBlurSurface; boolean mBlurShown; @@ -306,13 +339,20 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo WindowState mCurrentFocus = null; WindowState mLastFocus = null; + + // This just indicates the window the input method is on top of, not + // necessarily the window its input is going to. + WindowState mInputMethodTarget = null; + + WindowState mInputMethodWindow = null; + final ArrayList mInputMethodDialogs = new ArrayList(); AppWindowToken mFocusedApp = null; PowerManagerService mPowerManager; float mWindowAnimationScale = 1.0f; - float mTransitionAnimationScale = 0.0f; + float mTransitionAnimationScale = 1.0f; final KeyWaiter mKeyWaiter = new KeyWaiter(); final KeyQ mQueue; @@ -329,9 +369,11 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo private ViewServer mViewServer; - public static WindowManagerService main( - Context context, PowerManagerService pm) { - WMThread thr = new WMThread(context, pm); + final Rect mTempRect = new Rect(); + + public static WindowManagerService main(Context context, + PowerManagerService pm, boolean haveInputMethods) { + WMThread thr = new WMThread(context, pm, haveInputMethods); thr.start(); synchronized (thr) { @@ -351,16 +393,20 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo private final Context mContext; private final PowerManagerService mPM; + private final boolean mHaveInputMethods; - public WMThread(Context context, PowerManagerService pm) { + public WMThread(Context context, PowerManagerService pm, + boolean haveInputMethods) { super("WindowManager"); mContext = context; mPM = pm; + mHaveInputMethods = haveInputMethods; } public void run() { Looper.prepare(); - WindowManagerService s = new WindowManagerService(mContext, mPM); + WindowManagerService s = new WindowManagerService(mContext, mPM, + mHaveInputMethods); android.os.Process.setThreadPriority( android.os.Process.THREAD_PRIORITY_DISPLAY); @@ -407,14 +453,16 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo } } - private WindowManagerService(Context context, PowerManagerService pm) { + private WindowManagerService(Context context, PowerManagerService pm, + boolean haveInputMethods) { mContext = context; + mHaveInputMethods = haveInputMethods; mPowerManager = pm; mPowerManager.setPolicy(mPolicy); mActivityManager = ActivityManagerNative.getDefault(); - mBatteryStats = BatteryStats.getService(); + mBatteryStats = BatteryStatsService.getService(); // Get persisted window scale setting mWindowAnimationScale = Settings.System.getFloat(context.getContentResolver(), @@ -450,7 +498,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo try { return super.onTransact(code, data, reply, flags); } catch (RuntimeException e) { - // The activity manager only throws security exceptions, so let's + // The window manager only throws security exceptions, so let's // log all others. if (!(e instanceof SecurityException)) { Log.e(TAG, "Window Manager Crash", e); @@ -674,9 +722,144 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo } } + int findDesiredInputMethodWindowIndexLocked() { + final ArrayList localmWindows = mWindows; + final int N = localmWindows.size(); + WindowState w = null; + int i = N; + while (i > 0) { + i--; + w = (WindowState)localmWindows.get(i); + final int fl = w.mAttrs.flags + & (FLAG_NOT_FOCUSABLE|FLAG_ALT_FOCUSABLE_IM); + //Log.i(TAG, "Checking window @" + i + " " + w + " fl=0x" + // + Integer.toHexString(fl)); + if (fl == 0 || fl == (FLAG_NOT_FOCUSABLE|FLAG_ALT_FOCUSABLE_IM)) { + //Log.i(TAG, "Putting input method here!"); + if (w.isVisibleOrAdding()) { + break; + } + } + } + //Log.i(TAG, "Placing input method @" + (i+1)); + if (w != null) { + mInputMethodTarget = w; + return i+1; + } + mInputMethodTarget = null; + return -1; + } + + void addInputMethodWindowToListLocked(WindowState win) { + int pos = findDesiredInputMethodWindowIndexLocked(); + if (pos >= 0) { + win.mTargetAppToken = mInputMethodTarget.mAppToken; + mWindows.add(pos, win); + moveInputMethodDialogsLocked(pos+1); + return; + } + win.mTargetAppToken = null; + addWindowToListInOrderLocked(win); + moveInputMethodDialogsLocked(pos); + } + + void moveInputMethodDialogsLocked(int pos) { + ArrayList dialogs = mInputMethodDialogs; + final int N = dialogs.size(); + for (int i=0; i= 0) { + if (wpos < pos) pos--; + mWindows.remove(wpos); + } + } + if (pos >= 0) { + final AppWindowToken targetAppToken = mInputMethodTarget.mAppToken; + WindowState wp = (WindowState)mWindows.get(pos); + if (wp == mInputMethodWindow) { + pos++; + } + for (int i=0; i= 0) { + // In this case, the input method windows are to be placed + // immediately above the window they are targeting. + + WindowState firstImWin = imPos < DN + ? (WindowState)mWindows.get(imPos) : null; + if (imWin != null) { + if (imWin == firstImWin) { + // Already at the correct location! + return false; + } + } else { + if (mInputMethodDialogs.get(0) == firstImWin) { + // Already at the correct location! + return false; + } + } + + if (imWin != null) { + int oldPos = mWindows.indexOf(imWin); + mWindows.remove(oldPos); + if (imPos > oldPos) imPos--; + imWin.mTargetAppToken = mInputMethodTarget.mAppToken; + mWindows.add(imPos, imWin); + if (DN > 0) moveInputMethodDialogsLocked(imPos+1); + } else { + moveInputMethodDialogsLocked(imPos); + } + + } else { + // In this case, the input method windows go in a fixed layer, + // because they aren't currently associated with a focus window. + + if (imWin != null) { + mWindows.remove(imWin); + imWin.mTargetAppToken = null; + addWindowToListInOrderLocked(imWin); + if (DN > 0) moveInputMethodDialogsLocked(-1);; + } else { + moveInputMethodDialogsLocked(-1);; + } + + } + + if (needAssignLayers) { + assignLayersLocked(); + } + + return true; + } + + void adjustInputMethodDialogsLocked() { + moveInputMethodDialogsLocked(findDesiredInputMethodWindowIndexLocked()); + } + public int addWindow(Session session, IWindow client, WindowManager.LayoutParams attrs, int viewVisibility, - Rect outCoveredInsets) { + Rect outContentInsets) { int res = mPolicy.checkAddPermission(attrs); if (res != WindowManagerImpl.ADD_OKAY) { return res; @@ -703,7 +886,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo } if (attrs.type >= FIRST_SUB_WINDOW && attrs.type <= LAST_SUB_WINDOW) { - attachedWindow = windowForClientLocked(session, attrs.token); + attachedWindow = windowForClientLocked(null, attrs.token); if (attachedWindow == null) { Log.w(TAG, "Attempted to add window with token that is not a window: " + attrs.token + ". Aborting."); @@ -726,7 +909,12 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo + attrs.token + ". Aborting."); return WindowManagerImpl.ADD_BAD_APP_TOKEN; } - token = new WindowToken(attrs.token); + if (attrs.type == TYPE_INPUT_METHOD) { + Log.w(TAG, "Attempted to add input method window with unknown token " + + attrs.token + ". Aborting."); + return WindowManagerImpl.ADD_BAD_APP_TOKEN; + } + token = new WindowToken(attrs.token, -1); addToken = true; } else if (attrs.type >= FIRST_APPLICATION_WINDOW && attrs.type <= LAST_APPLICATION_WINDOW) { @@ -746,6 +934,12 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo TAG, "**** NO NEED TO START: " + attrs.getTitle()); return WindowManagerImpl.ADD_STARTING_NOT_NEEDED; } + } else if (attrs.type == TYPE_INPUT_METHOD) { + if (token.windowType != TYPE_INPUT_METHOD) { + Log.w(TAG, "Attempted to add input method window with bad token " + + attrs.token + ". Aborting."); + return WindowManagerImpl.ADD_BAD_APP_TOKEN; + } } win = new WindowState(session, client, token, @@ -783,19 +977,25 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo token.appWindowToken.startingWindow = win; } - addWindowToListInOrderLocked(win); + boolean imMayMove = true; - assignLayersLocked(); - // Don't do layout here, the window must call - // relayout to be displayed, so we'll do it there. + if (attrs.type == TYPE_INPUT_METHOD) { + mInputMethodWindow = win; + addInputMethodWindowToListLocked(win); + imMayMove = false; + } else if (attrs.type == TYPE_INPUT_METHOD_DIALOG) { + mInputMethodDialogs.add(win); + adjustInputMethodDialogsLocked(); + imMayMove = false; + } else { + addWindowToListInOrderLocked(win); + } - //dump(); - Binder.restoreCallingIdentity(origId); win.mEnterAnimationPending = true; - mPolicy.getCoveredInsetHintLw(attrs, outCoveredInsets); + mPolicy.getContentInsetHintLw(attrs, outContentInsets); if (mInTouchMode) { res |= WindowManagerImpl.ADD_FLAG_IN_TOUCH_MODE; @@ -805,9 +1005,21 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo } if (win.canReceiveKeys()) { - updateFocusedWindowLocked(); + if (updateFocusedWindowLocked(UPDATE_FOCUS_WILL_ASSIGN_LAYERS)) { + imMayMove = false; + } + } + + if (imMayMove) { + moveInputMethodWindowsIfNeededLocked(false); } + assignLayersLocked(); + // Don't do layout here, the window must call + // relayout to be displayed, so we'll do it there. + + //dump(); + if (localLOGV) Log.v( TAG, "New client " + client.asBinder() + ": window=" + win); @@ -859,7 +1071,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo if (win.mSurface != null && !mDisplayFrozen) { // If we are not currently running the exit animation, we // need to see about starting one. - if (!win.mExiting && !win.mDrawPending && !win.mCommitDrawPending) { + if (win.isVisible()) { int transit = WindowManagerPolicy.TRANSIT_EXIT; if (win.getAttrs().type == TYPE_APPLICATION_STARTING) { transit = WindowManagerPolicy.TRANSIT_PREVIEW_DONE; @@ -875,8 +1087,8 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo win.mExiting = true; win.mRemoveOnExit = true; mLayoutNeeded = true; + updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES); performLayoutAndPlaceSurfacesLocked(); - updateFocusedWindowLocked(); if (win.mAppToken != null) { win.mAppToken.updateReportedVisibilityLocked(); } @@ -887,7 +1099,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo } removeWindowInnerLocked(session, win); - updateFocusedWindowLocked(); + updateFocusedWindowLocked(UPDATE_FOCUS_NORMAL); Binder.restoreCallingIdentity(origId); } @@ -901,6 +1113,12 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo mWindowMap.remove(win.mClient.asBinder()); mWindows.remove(win); + if (mInputMethodWindow == win) { + mInputMethodWindow = null; + } else if (win.mAttrs.type == TYPE_INPUT_METHOD_DIALOG) { + mInputMethodDialogs.remove(win); + } + final WindowToken token = win.mToken; final AppWindowToken atoken = win.mAppToken; token.windows.remove(win); @@ -967,10 +1185,44 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo } } + void setInsetsWindow(Session session, IWindow client, + int touchableInsets, Rect contentInsets, + Rect visibleInsets) { + long origId = Binder.clearCallingIdentity(); + try { + synchronized (mWindowMap) { + WindowState w = windowForClientLocked(session, client); + if (w != null) { + w.mGivenInsetsPending = false; + w.mGivenContentInsets.set(contentInsets); + w.mGivenVisibleInsets.set(visibleInsets); + w.mTouchableInsets = touchableInsets; + mLayoutNeeded = true; + performLayoutAndPlaceSurfacesLocked(); + } + } + } finally { + Binder.restoreCallingIdentity(origId); + } + } + + public void getWindowDisplayFrame(Session session, IWindow client, + Rect outDisplayFrame) { + synchronized(mWindowMap) { + WindowState win = windowForClientLocked(session, client); + if (win == null) { + outDisplayFrame.setEmpty(); + return; + } + outDisplayFrame.set(win.mDisplayFrame); + } + } - public int relayoutWindow(Session session, IWindow client, WindowManager.LayoutParams attrs, - int requestedWidth, int requestedHeight, int viewVisibility, Rect outFrame, - Rect outCoveredInsets, Surface outSurface) { + public int relayoutWindow(Session session, IWindow client, + WindowManager.LayoutParams attrs, int requestedWidth, + int requestedHeight, int viewVisibility, boolean insetsPending, + Rect outFrame, Rect outContentInsets, Rect outVisibleInsets, + Surface outSurface) { boolean displayed = false; boolean inTouchMode; @@ -988,12 +1240,12 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo mPolicy.adjustWindowParamsLw(attrs); } - boolean windowfocusabilityChanged = attrs != null && - ((attrs.flags & WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE) != - (win.mAttrs.flags & WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE)); - int attrChanges = 0; - if (attrs != null) attrChanges = win.mAttrs.copyFrom(attrs); + int flagChanges = 0; + if (attrs != null) { + flagChanges = win.mAttrs.flags ^= attrs.flags; + attrChanges = win.mAttrs.copyFrom(attrs); + } if (localLOGV) Log.v( TAG, "Relayout given client " + client.asBinder() @@ -1016,10 +1268,16 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo (attrs.height / (float)requestedHeight) : 1.0f; } + boolean imMayMove = (flagChanges&( + WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM | + WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE)) != 0; + boolean focusMayChange = win.mViewVisibility != viewVisibility - || windowfocusabilityChanged + || ((flagChanges&WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE) != 0) || (!win.mRelayoutCalled); + win.mRelayoutCalled = true; + final int oldVisibility = win.mViewVisibility; win.mViewVisibility = viewVisibility; if (viewVisibility == View.VISIBLE && (win.mAppToken == null || !win.mAppToken.clientHidden)) { @@ -1032,6 +1290,9 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo win.mDestroying = false; mDestroySurface.remove(win); } + if (oldVisibility == View.GONE) { + win.mEnterAnimationPending = true; + } if (displayed && win.mSurface != null && !win.mDrawPending && !win.mCommitDrawPending && !mDisplayFrozen) { applyEnterAnimationLocked(win); @@ -1053,7 +1314,13 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo if (displayed) { focusMayChange = true; } + if (win.mAttrs.type == TYPE_INPUT_METHOD + && mInputMethodWindow == null) { + mInputMethodWindow = win; + imMayMove = true; + } } else { + win.mEnterAnimationPending = false; if (win.mSurface != null) { // If we are not currently running the exit animation, we // need to see about starting one. @@ -1064,7 +1331,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo if (win.getAttrs().type == TYPE_APPLICATION_STARTING) { transit = WindowManagerPolicy.TRANSIT_PREVIEW_DONE; } - if (!win.mExiting && !win.mDrawPending && + if (win.isVisible() && applyAnimationLocked(win, transit, false)) { win.mExiting = true; mKeyWaiter.finishedKey(session, client, true, @@ -1078,16 +1345,41 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo } } } + if (mInputMethodWindow == win) { + mInputMethodWindow = null; + } outSurface.clear(); } + boolean assignLayers = false; + + if (focusMayChange) { + //System.out.println("Focus may change: " + win.mAttrs.getTitle()); + if (updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES)) { + assignLayers = true; + imMayMove = false; + } + //System.out.println("Relayout " + win + ": focus=" + mCurrentFocus); + } + + if (imMayMove) { + if (moveInputMethodWindowsIfNeededLocked(false)) { + assignLayers = true; + } + } + mLayoutNeeded = true; + win.mGivenInsetsPending = insetsPending; + if (assignLayers) { + assignLayersLocked(); + } performLayoutAndPlaceSurfacesLocked(); if (win.mAppToken != null) { win.mAppToken.updateReportedVisibilityLocked(); } outFrame.set(win.mFrame); - outCoveredInsets.set(win.mCoveredInsets); + outContentInsets.set(win.mContentInsets); + outVisibleInsets.set(win.mVisibleInsets); if (localLOGV) Log.v( TAG, "Relayout given client " + client.asBinder() + ", requestedWidth=" + requestedWidth @@ -1099,12 +1391,6 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo if (localLOGV || DEBUG_FOCUS) Log.v( TAG, "Relayout of " + win + ": focusMayChange=" + focusMayChange); - if (focusMayChange) { - //System.out.println("Focus may change: " + win.mAttrs.getTitle()); - updateFocusedWindowLocked(); - //System.out.println("Relayout " + win + ": focus=" + mCurrentFocus); - } - inTouchMode = mInTouchMode; } @@ -1348,6 +1634,76 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo return wtoken.appWindowToken; } + public void addWindowToken(IBinder token, int type) { + if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS, + "addWindowToken()")) { + return; + } + + synchronized(mWindowMap) { + WindowToken wtoken = mTokenMap.get(token); + if (wtoken != null) { + Log.w(TAG, "Attempted to add existing input method token: " + token); + return; + } + wtoken = new WindowToken(token, type); + mTokenMap.put(token, wtoken); + mTokenList.add(wtoken); + } + } + + public void removeWindowToken(IBinder token) { + if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS, + "removeWindowToken()")) { + return; + } + + final long origId = Binder.clearCallingIdentity(); + synchronized(mWindowMap) { + WindowToken wtoken = mTokenMap.remove(token); + mTokenList.remove(wtoken); + if (wtoken != null) { + boolean delayed = false; + if (!wtoken.hidden) { + wtoken.hidden = true; + + final int N = wtoken.windows.size(); + boolean changed = false; + + for (int i=0; i

              + * 03-xxxx-xxxx + * 090-xxxx-xxxx + * 0120-xxx-xxx + * +81-3-xxxx-xxxx + * +81-90-xxxx-xxxx + *

              + * + * @param text the number to be formatted, will be modified with + * the formatting + */ + public static void formatJapaneseNumber(Editable text) { + JapanesePhoneNumberFormatter.format(text); + } + // Three and four digit phone numbers for either special services // or from the network (eg carrier-originated SMS messages) should // not match @@ -1040,10 +1145,10 @@ public class PhoneNumberUtils * listed in the ril / sim, then return true, otherwise false. */ public static boolean isEmergencyNumber(String number) { - // Strip the separators from the number before comparing it + // Strip the separators from the number before comparing it // to the list. number = extractNetworkPortion(number); - + // retrieve the list of emergency numbers String numbers = SystemProperties.get("ro.ril.ecclist"); diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java index 529ba31a748c00d45361d8a392bfe7cf21fd2818..374a7032cdd24714c9befd6359fa7f269378be24 100644 --- a/telephony/java/android/telephony/TelephonyManager.java +++ b/telephony/java/android/telephony/TelephonyManager.java @@ -16,20 +16,19 @@ package android.telephony; -import android.content.BroadcastReceiver; +import com.android.internal.telephony.*; + +import java.util.ArrayList; +import java.util.List; + +import android.annotation.SdkConstant.SdkConstantType; +import android.annotation.SdkConstant; import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; import android.os.Bundle; import android.os.RemoteException; -import android.os.SystemProperties; import android.os.ServiceManager; +import android.os.SystemProperties; -import com.android.internal.telephony.*; -import android.telephony.CellLocation; -import android.telephony.ServiceState; - -import java.util.ArrayList; /** * Provides access to information about the telephony services on @@ -73,6 +72,93 @@ public class TelephonyManager { return sInstance; } + + // + // Broadcast Intent actions + // + + /** + * Broadcast intent action indicating that the call state (cellular) + * on the device has changed. + * + *

              + * The {@link #EXTRA_STATE} extra indicates the new call state. + * If the new state is RINGING, a second extra + * {@link #EXTRA_INCOMING_NUMBER} provides the incoming phone number as + * a String. + * + *

              + * Requires the READ_PHONE_STATE permission. + * + *

              + * This was a {@link android.content.Context#sendStickyBroadcast sticky} + * broadcast in version 1.0, but it is no longer sticky. + * Instead, use {@link #getCallState} to synchronously query the current call state. + * + * @see #EXTRA_STATE + * @see #EXTRA_INCOMING_NUMBER + * @see #getCallState + * + * @hide pending API Council approval + */ + @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) + public static final String ACTION_PHONE_STATE_CHANGED = + "android.intent.action.PHONE_STATE"; + + /** + * The lookup key used with the {@link #ACTION_PHONE_STATE_CHANGED} broadcast + * for a String containing the new call state. + * + * @see #EXTRA_STATE_IDLE + * @see #EXTRA_STATE_RINGING + * @see #EXTRA_STATE_OFFHOOK + * + *

              + * Retrieve with + * {@link android.content.Intent#getStringExtra(String)}. + * + * @hide pending API Council approval + */ + public static final String EXTRA_STATE = Phone.STATE_KEY; + + /** + * Value used with {@link #EXTRA_STATE} corresponding to + * {@link #CALL_STATE_IDLE}. + * + * @hide pending API Council approval + */ + public static final String EXTRA_STATE_IDLE = Phone.State.IDLE.toString(); + + /** + * Value used with {@link #EXTRA_STATE} corresponding to + * {@link #CALL_STATE_RINGING}. + * + * @hide pending API Council approval + */ + public static final String EXTRA_STATE_RINGING = Phone.State.RINGING.toString(); + + /** + * Value used with {@link #EXTRA_STATE} corresponding to + * {@link #CALL_STATE_OFFHOOK}. + * + * @hide pending API Council approval + */ + public static final String EXTRA_STATE_OFFHOOK = Phone.State.OFFHOOK.toString(); + + /** + * The lookup key used with the {@link #ACTION_PHONE_STATE_CHANGED} broadcast + * for a String containing the incoming phone number. + * Only valid when the new call state is RINGING. + * + *

              + * Retrieve with + * {@link android.content.Intent#getStringExtra(String)}. + * + * @hide pending API Council approval + */ + public static final String EXTRA_INCOMING_NUMBER = "incoming_number"; + + // // // Device Info @@ -156,6 +242,26 @@ public class TelephonyManager { } } + /** + * Returns the neighboring cell information of the device. + * + * @return List of NeighboringCellInfo or null if info unavailable. + * + *

              Requires Permission: + * (@link android.Manifest.permission#ACCESS_COARSE_UPDATES} + */ + public List getNeighboringCellInfo() { + try { + ITelephony tel = getITelephony(); + if (tel != null) { + return tel.getNeighboringCellInfo(); + } + } catch (RemoteException ex) { + } + return null; + + } + /** * No phone module */ @@ -233,6 +339,7 @@ public class TelephonyManager { /** * Returns a constant indicating the radio technology (network type) * currently in use on the device. + * @return the network type * * @see #NETWORK_TYPE_UNKNOWN * @see #NETWORK_TYPE_GPRS @@ -255,6 +362,26 @@ public class TelephonyManager { } } + /** + * Returns a string representation of the radio technology (network type) + * currently in use on the device. + * @return the name of the radio technology + * + * @hide pending API council review + */ + public String getNetworkTypeName() { + switch (getNetworkType()) { + case NETWORK_TYPE_GPRS: + return "GPRS"; + case NETWORK_TYPE_EDGE: + return "EDGE"; + case NETWORK_TYPE_UMTS: + return "UMTS"; + default: + return "UNKNOWN"; + } + } + // // // SIM Card @@ -562,62 +689,3 @@ public class TelephonyManager { } } } - -/* - * These have not been implemented since they're not used anywhere in the system - * and it's impossible to tell if they're working or not. The comments in SystemProperties - * were wrong in at least one case, so I don't trust them. They claimed that - * PROPERTY_OPERATOR_ISROAMING was "1" if it was true, but it's actually set to "true." - */ - - - /* Set to '1' if voice mail is waiting, otherwise false */ - /* - public boolean isVoiceMailWaiting() { - return "1".equals( - SystemProperties.get(TelephonyProperties.PROPERTY_LINE1_VOICE_MAIL_WAITING)); - } - */ - - /* Set to 'true' if unconditional voice call forwarding is enabled - * Availablity: only if configured in SIM; SIM state must be "READY" - */ - /* - public boolean isCallForwarding() { - SystemProperties.get(TelephonyProperties.PROPERTY_LINE1_VOICE_CALL_FORWARDING); - } - */ - - /* '1' if the current network is the result of a manual network selection. - * Availability: when registered to a network - */ - /* - public boolean isNetworkManual() { - return SystemProperties.get(TelephonyProperties.PROPERTY_OPERATOR_ISMANUAL); - } - */ - - -/* - * These have not been implemented because they're not public IMHO. -joeo - */ - - /* - * Baseband version - * Availability: property is available any time radio is on - */ - /* - public String getBasebandVersion() { - return SystemProperties.get(TelephonyProperties.PROPERTY_BASEBAND_VERSION); - } - */ - - /* - * Radio Interface Layer (RIL) library implementation. - */ - /* - public String getRilLibrary() { - return SystemProperties.get(TelephonyProperties.PROPERTY_RIL_IMPL); - } - */ - diff --git a/telephony/java/android/telephony/gsm/SmsManager.java b/telephony/java/android/telephony/gsm/SmsManager.java index 274c4619049630fd21e0a6f7e701914c95386141..c63b5303309bd1f8adb62ddeb03fbb5187dac089 100644 --- a/telephony/java/android/telephony/gsm/SmsManager.java +++ b/telephony/java/android/telephony/gsm/SmsManager.java @@ -104,11 +104,12 @@ public final class SmsManager { int limit; if (messageCount > 1) { - limit = (encodingType == SmsMessage.ENCODING_7BIT)? - SmsMessage.MAX_USER_DATA_SEPTETS_WITH_HEADER: SmsMessage.MAX_USER_DATA_BYTES_WITH_HEADER; + limit = (encodingType == SmsMessage.ENCODING_7BIT) ? + SmsMessage.MAX_USER_DATA_SEPTETS_WITH_HEADER : + SmsMessage.MAX_USER_DATA_BYTES_WITH_HEADER; } else { - limit = (encodingType == SmsMessage.ENCODING_7BIT)? - SmsMessage.MAX_USER_DATA_SEPTETS: SmsMessage.MAX_USER_DATA_BYTES; + limit = (encodingType == SmsMessage.ENCODING_7BIT) ? + SmsMessage.MAX_USER_DATA_SEPTETS : SmsMessage.MAX_USER_DATA_BYTES; } try { @@ -117,8 +118,7 @@ public final class SmsManager { result.add(text.substring(start, end)); start = end; } - } - catch (EncodeException e) { + } catch (EncodeException e) { // ignore it. } return result; diff --git a/telephony/java/android/telephony/gsm/SmsMessage.java b/telephony/java/android/telephony/gsm/SmsMessage.java index 836a0134bc26f6988bcab54aee35a4992ea69e84..f79b0a0001ee9953e7863f92046213f0ba7599f6 100644 --- a/telephony/java/android/telephony/gsm/SmsMessage.java +++ b/telephony/java/android/telephony/gsm/SmsMessage.java @@ -16,11 +16,12 @@ package android.telephony.gsm; -import android.pim.Time; import android.telephony.PhoneNumberUtils; import android.util.Config; import android.util.Log; import android.telephony.PhoneNumberUtils; +import android.text.format.Time; + import com.android.internal.telephony.gsm.EncodeException; import com.android.internal.telephony.gsm.GsmAlphabet; import com.android.internal.telephony.gsm.SimUtils; @@ -222,7 +223,7 @@ public class SmsMessage { * * @hide pending API Council approval to extend the public API */ - public static final int MAX_USER_DATA_BYTES_WITH_HEADER = 134; + static final int MAX_USER_DATA_BYTES_WITH_HEADER = 134; /** The maximum number of payload septets per message */ public static final int MAX_USER_DATA_SEPTETS = 160; @@ -329,6 +330,9 @@ public class SmsMessage { */ boolean isStatusReportMessage = false; + /** + * This class represents the encoded form of an outgoing SMS. + */ public static class SubmitPdu { public byte[] encodedScAddress; // Null if not applicable. public byte[] encodedMessage; @@ -472,23 +476,25 @@ public class SmsMessage { ret[1] = septets; if (septets > MAX_USER_DATA_SEPTETS) { ret[0] = (septets / MAX_USER_DATA_SEPTETS_WITH_HEADER) + 1; - ret[2] = septets % MAX_USER_DATA_SEPTETS_WITH_HEADER; + ret[2] = MAX_USER_DATA_SEPTETS_WITH_HEADER + - (septets % MAX_USER_DATA_SEPTETS_WITH_HEADER); } else { ret[0] = 1; ret[2] = MAX_USER_DATA_SEPTETS - septets; } ret[3] = ENCODING_7BIT; } catch (EncodeException ex) { - // fall back to USC-2 + // fall back to UCS-2 int octets = messageBody.length() * 2; - ret[1] = octets; + ret[1] = messageBody.length(); if (octets > MAX_USER_DATA_BYTES) { // 6 is the size of the user data header ret[0] = (octets / MAX_USER_DATA_BYTES_WITH_HEADER) + 1; - ret[2] = octets % MAX_USER_DATA_BYTES_WITH_HEADER; + ret[2] = (MAX_USER_DATA_BYTES_WITH_HEADER + - (octets % MAX_USER_DATA_BYTES_WITH_HEADER))/2; } else { ret[0] = 1; - ret[2] = MAX_USER_DATA_BYTES - octets; + ret[2] = (MAX_USER_DATA_BYTES - octets)/2; } ret[3] = ENCODING_16BIT; } @@ -559,8 +565,7 @@ public class SmsMessage { System.arraycopy(header, 0, userData, 0, header.length); System.arraycopy(textPart, 0, userData, header.length, textPart.length); - } - else { + } else { userData = textPart; } @@ -875,7 +880,9 @@ public class SmsMessage { if (dataInSeptets) { // Return the number of septets - return userDataLength - headerSeptets; + int count = userDataLength - headerSeptets; + // If count < 0, return 0 (means UDL was probably incorrect) + return count < 0 ? 0 : count; } else { // Return the number of octets return userData.length; diff --git a/telephony/java/com/android/internal/telephony/CallerInfo.java b/telephony/java/com/android/internal/telephony/CallerInfo.java index 5f630f80b8609a3641bb4a0286855be6fb7b08fc..13b6e5c839d2c84a24f48f6b4005a4e0367e48d2 100644 --- a/telephony/java/com/android/internal/telephony/CallerInfo.java +++ b/telephony/java/com/android/internal/telephony/CallerInfo.java @@ -40,6 +40,33 @@ public class CallerInfo { public static final String UNKNOWN_NUMBER = "-1"; public static final String PRIVATE_NUMBER = "-2"; + /** + * Please note that, any one of these member variables can be null, + * and any accesses to them should be prepared to handle such a case. + * + * Also, it is implied that phoneNumber is more often populated than + * name is, (think of calls being dialed/received using numbers where + * names are not known to the device), so phoneNumber should serve as + * a dependable fallback when name is unavailable. + * + * One other detail here is that this CallerInfo object reflects + * information found on a connection, it is an OUTPUT that serves + * mainly to display information to the user. In no way is this object + * used as input to make a connection, so we can choose to display + * whatever human-readable text makes sense to the user for a + * connection. This is especially relevant for the phone number field, + * since it is the one field that is most likely exposed to the user. + * + * As an example: + * 1. User dials "911" + * 2. Device recognizes that this is an emergency number + * 3. We use the "Emergency Number" string instead of "911" in the + * phoneNumber field. + * + * What we're really doing here is treating phoneNumber as an essential + * field here, NOT name. We're NOT always guaranteed to have a name + * for a connection, but the number should be displayable. + */ public String name; public String phoneNumber; public String phoneLabel; @@ -192,6 +219,9 @@ public class CallerInfo { // shortcut and skip the query. if (PhoneNumberUtils.isEmergencyNumber(number)) { CallerInfo ci = new CallerInfo(); + + // Note we're setting the phone number here (refer to javadoc + // comments at the top of CallerInfo class). ci.phoneNumber = context.getString( com.android.internal.R.string.emergency_call_dialog_number_for_display); return ci; @@ -200,7 +230,10 @@ public class CallerInfo { if (!sSkipVmCheck && PhoneNumberUtils.compare(number, TelephonyManager.getDefault().getVoiceMailNumber())) { CallerInfo ci = new CallerInfo(); - ci.name = TelephonyManager.getDefault().getVoiceMailAlphaTag(); + + // Note we're setting the phone number here (refer to javadoc + // comments at the top of CallerInfo class). + ci.phoneNumber = TelephonyManager.getDefault().getVoiceMailAlphaTag(); // TODO: FIND ANOTHER ICON //info.photoResource = android.R.drawable.badge_voicemail; return ci; @@ -214,7 +247,8 @@ public class CallerInfo { } } - Uri contactUri = Uri.withAppendedPath(Contacts.Phones.CONTENT_FILTER_URL, number); + Uri contactUri = Uri.withAppendedPath(Contacts.Phones.CONTENT_FILTER_URL, + Uri.encode(number)); CallerInfo info = getCallerInfo(context, contactUri); diff --git a/telephony/java/com/android/internal/telephony/CallerInfoAsyncQuery.java b/telephony/java/com/android/internal/telephony/CallerInfoAsyncQuery.java index 6cb829d0d0b4fda77926ea502db0cd217c8e732f..145e5d86098eda2066571f50a915c4e45a2ec94d 100644 --- a/telephony/java/com/android/internal/telephony/CallerInfoAsyncQuery.java +++ b/telephony/java/com/android/internal/telephony/CallerInfoAsyncQuery.java @@ -224,6 +224,8 @@ public class CallerInfoAsyncQuery { // accordingly. if (cw.event == EVENT_EMERGENCY_NUMBER) { mCallerInfo = new CallerInfo(); + // Note we're setting the phone number here (refer to javadoc + // comments at the top of CallerInfo class). mCallerInfo.phoneNumber = mQueryContext.getString(com.android.internal .R.string.emergency_call_dialog_number_for_display); mCallerInfo.photoResource = com.android.internal.R.drawable.picture_emergency; @@ -231,7 +233,10 @@ public class CallerInfoAsyncQuery { } else if (cw.event == EVENT_VOICEMAIL_NUMBER) { mCallerInfo = new CallerInfo(); try { - mCallerInfo.name = TelephonyManager.getDefault().getVoiceMailAlphaTag(); + // Note we're setting the phone number here (refer to javadoc + // comments at the top of CallerInfo class). + mCallerInfo.phoneNumber = + TelephonyManager.getDefault().getVoiceMailAlphaTag(); } catch (SecurityException ex) { // Should never happen: if this process does not have // permission to retrieve VM tag, it should not have diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl index 663fc038043073bdcffa1b924c9835ef416ca465..4957366fbeb813acd37aa88597ba968cb1e4e99d 100644 --- a/telephony/java/com/android/internal/telephony/ITelephony.aidl +++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl @@ -17,6 +17,8 @@ package com.android.internal.telephony; import android.os.Bundle; +import java.util.List; +import android.telephony.NeighboringCellInfo; /** * Interface used to interact with the phone. Mostly this is used by the @@ -43,10 +45,26 @@ interface ITelephony { /** * If there is currently a call in progress, show the call screen. - * Returns true if the call screen was shown. + * The DTMF dialpad may or may not be visible initially, depending on + * whether it was up when the user last exited the InCallScreen. + * + * @return true if the call screen was shown. */ boolean showCallScreen(); - + + /** + * Variation of showCallScreen() that also specifies whether the + * DTMF dialpad should be initially visible when the InCallScreen + * comes up. + * + * @param showDialpad if true, make the dialpad visible initially, + * otherwise hide the dialpad initially. + * @return true if the call screen was shown. + * + * @see showCallScreen + */ + boolean showCallScreenWithDialpad(boolean showDialpad); + /** * End call or go to the Home screen * @@ -157,6 +175,11 @@ interface ITelephony { Bundle getCellLocation(); + /** + * Returns the neighboring cell information of the device. + */ + List getNeighboringCellInfo(); + int getCallState(); int getDataActivity(); int getDataState(); diff --git a/telephony/java/com/android/internal/telephony/PhoneStateIntentReceiver.java b/telephony/java/com/android/internal/telephony/PhoneStateIntentReceiver.java index c558cd15f1d1de9e702daaccd0bdee6da5e23231..61d4c9fe52715d0c7cd3c6b1d6ef7e2ba120b5ec 100644 --- a/telephony/java/com/android/internal/telephony/PhoneStateIntentReceiver.java +++ b/telephony/java/com/android/internal/telephony/PhoneStateIntentReceiver.java @@ -16,15 +16,15 @@ package com.android.internal.telephony; - import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; -import android.util.Log; import android.os.Handler; import android.os.Message; import android.telephony.ServiceState; +import android.telephony.TelephonyManager; +import android.util.Log; /** * @@ -40,7 +40,6 @@ public final class PhoneStateIntentReceiver extends BroadcastReceiver { private static final boolean DBG = false; public static final String INTENT_KEY_ASU = "asu"; - public static final String INTENT_KEY_NUM = "incoming_number"; private static final int NOTIF_PHONE = 1 << 0; private static final int NOTIF_SERVICE = 1 << 1; @@ -49,7 +48,6 @@ public final class PhoneStateIntentReceiver extends BroadcastReceiver { private static final int NOTIF_MAX = 1 << 5; Phone.State mPhoneState = Phone.State.IDLE; - String mIncomingNumber; ServiceState mServiceState = new ServiceState(); int mAsu = -1; private Context mContext; @@ -141,7 +139,7 @@ public final class PhoneStateIntentReceiver extends BroadcastReceiver { public void notifyPhoneCallState(int eventWhat) { mWants |= NOTIF_PHONE; mPhoneStateEventWhat = eventWhat; - mFilter.addAction(TelephonyIntents.ACTION_PHONE_STATE_CHANGED); + mFilter.addAction(TelephonyManager.ACTION_PHONE_STATE_CHANGED); } public boolean getNotifyPhoneCallState() { @@ -189,11 +187,10 @@ public final class PhoneStateIntentReceiver extends BroadcastReceiver { Message message = Message.obtain(mTarget, mAsuEventWhat); mTarget.sendMessage(message); } - } else if (TelephonyIntents.ACTION_PHONE_STATE_CHANGED.equals(action)) { + } else if (TelephonyManager.ACTION_PHONE_STATE_CHANGED.equals(action)) { if (DBG) Log.d(LOG_TAG, "onReceiveIntent: ACTION_PHONE_STATE_CHANGED, state=" + intent.getStringExtra(Phone.STATE_KEY)); String phoneState = intent.getStringExtra(Phone.STATE_KEY); - mIncomingNumber = intent.getStringExtra(INTENT_KEY_NUM); mPhoneState = (Phone.State) Enum.valueOf( Phone.State.class, phoneState); diff --git a/telephony/java/com/android/internal/telephony/TelephonyIntents.java b/telephony/java/com/android/internal/telephony/TelephonyIntents.java index 8519796c223f45f89bb8b79ce789917a3fb97e8d..9219e7aa72d86da8649e5547740d8d4f99d6e00e 100644 --- a/telephony/java/com/android/internal/telephony/TelephonyIntents.java +++ b/telephony/java/com/android/internal/telephony/TelephonyIntents.java @@ -9,26 +9,6 @@ package com.android.internal.telephony; */ public class TelephonyIntents { - /** - *

              Broadcast Action: The phone state has changed. The intent will have the following - * extra values:

              - *
                - *
              • phoneName - A string version of the phone name.
              • - *
              • state - A string version of the new phone state.
              • - *
              - * - *

              - * You can not receive this through components declared - * in manifests, only by exlicitly registering for it with - * {@link android.content.Context#registerReceiver(android.content.BroadcastReceiver, - * android.content.IntentFilter) Context.registerReceiver()}. - * - *

              - * Requires the READ_PHONE_STATE permission. - */ - public static final String ACTION_PHONE_STATE_CHANGED = "android.intent.action.PHONE_STATE"; - - /** * Broadcast Action: The phone service state has changed. The intent will have the following * extra values:

              diff --git a/telephony/java/com/android/internal/telephony/TelephonyProperties.java b/telephony/java/com/android/internal/telephony/TelephonyProperties.java index c19773433aa7768e9f2504fd6193018e37263a08..6aa90f19d01ae5ac21f61b08a4a92397fcd0e815 100644 --- a/telephony/java/com/android/internal/telephony/TelephonyProperties.java +++ b/telephony/java/com/android/internal/telephony/TelephonyProperties.java @@ -53,11 +53,7 @@ public interface TelephonyProperties */ static final String PROPERTY_OPERATOR_ISROAMING = "gsm.operator.isroaming"; - /** '1' if the current network is the result of a manual network selection. - * Availability: when registered to a network - */ - static final String PROPERTY_OPERATOR_ISMANUAL = "gsm.operator.ismanual"; - /** The ISO country code equivilent of the current registered operator's + /** The ISO country code equivalent of the current registered operator's * MCC (Mobile Country Code) * Availability: when registered to a network */ @@ -70,14 +66,6 @@ public interface TelephonyProperties */ static String PROPERTY_SIM_STATE = "gsm.sim.state"; - /** Set to '1' if voice mail is waiting, otherwise false */ - static String PROPERTY_LINE1_VOICE_MAIL_WAITING = "gsm.sim.voice-mail.waiting"; - - /** Set to 'true' if unconditional voice call forwarding is enabled - * Availablity: only if configured in SIM; SIM state must be "READY" - */ - static String PROPERTY_LINE1_VOICE_CALL_FORWARDING = "gsm.sim.line1.cff"; - /** The MCC+MNC (mobile country code+mobile network code) of the * provider of the SIM. 5 or 6 decimal digits. * Availablity: SIM state must be "READY" diff --git a/telephony/java/com/android/internal/telephony/gsm/CallTracker.java b/telephony/java/com/android/internal/telephony/gsm/CallTracker.java index 9821852b7bdd4781726904f2c4c310d75bc4fcae..afd11c47094d11ca0c21a995f4ece02806528209 100644 --- a/telephony/java/com/android/internal/telephony/gsm/CallTracker.java +++ b/telephony/java/com/android/internal/telephony/gsm/CallTracker.java @@ -15,16 +15,32 @@ */ package com.android.internal.telephony.gsm; -import com.android.internal.telephony.*; -import android.os.*; + +import static com.android.internal.telephony.TelephonyProperties.PROPERTY_DATA_NETWORK_TYPE; +import static com.android.internal.telephony.gsm.ServiceStateTracker.DATA_ACCESS_EDGE; +import static com.android.internal.telephony.gsm.ServiceStateTracker.DATA_ACCESS_GPRS; +import static com.android.internal.telephony.gsm.ServiceStateTracker.DATA_ACCESS_UMTS; +import static com.android.internal.telephony.gsm.ServiceStateTracker.DATA_ACCESS_UNKNOWN; import android.os.AsyncResult; -import android.util.Log; -import android.provider.Checkin; +import android.os.Handler; +import android.os.Message; +import android.os.Registrant; +import android.os.RegistrantList; +import android.os.SystemProperties; import android.telephony.PhoneNumberUtils; import android.telephony.ServiceState; +import android.telephony.TelephonyManager; +import android.telephony.gsm.GsmCellLocation; +import android.util.EventLog; +import android.util.Log; + +import com.android.internal.telephony.Call; +import com.android.internal.telephony.CallStateException; +import com.android.internal.telephony.Connection; +import com.android.internal.telephony.Phone; -import java.util.List; import java.util.ArrayList; +import java.util.List; /** * {@hide} @@ -36,6 +52,9 @@ public final class CallTracker extends Handler private static final boolean DBG_POLL = false; + // Event Log Tags + private static final int EVENT_LOG_CALL_DROP = 50106; + //***** Constants static final int POLL_DELAY_MSEC = 250; @@ -165,7 +184,7 @@ public final class CallTracker extends Handler throw new CallStateException("cannot dial in current state"); } - pendingMO = new GSMConnection(dialString, this, foregroundCall); + pendingMO = new GSMConnection(phone.getContext(), dialString, this, foregroundCall); hangupPendingMO = false; if (pendingMO.address == null || pendingMO.address.length() == 0 @@ -503,7 +522,7 @@ public final class CallTracker extends Handler return; } } else { - connections[i] = new GSMConnection(dc, this, i); + connections[i] = new GSMConnection(phone.getContext(), dc, this, i); // it's a ringing call if (connections[i].getCall() == ringingCall) { @@ -540,7 +559,7 @@ public final class CallTracker extends Handler // we were tracking. Assume dropped call and new call droppedDuringPoll.add(conn); - connections[i] = new GSMConnection (dc, this, i); + connections[i] = new GSMConnection (phone.getContext(), dc, this, i); if (connections[i].getCall() == ringingCall) { newRinging = connections[i]; @@ -916,6 +935,22 @@ public final class CallTracker extends Handler } else { causeCode = ((int[])ar.result)[0]; } + // Log the causeCode if its not normal + if (causeCode == CallFailCause.NO_CIRCUIT_AVAIL || + causeCode == CallFailCause.TEMPORARY_FAILURE || + causeCode == CallFailCause.SWITCHING_CONGESTION || + causeCode == CallFailCause.CHANNEL_NOT_AVAIL || + causeCode == CallFailCause.QOS_NOT_AVAIL || + causeCode == CallFailCause.BEARER_NOT_AVAIL || + causeCode == CallFailCause.ERROR_UNSPECIFIED) { + int cid = -1; + GsmCellLocation loc = ((GsmCellLocation)phone.getCellLocation()); + if (loc != null) cid = loc.getCid(); + + EventLog.List val = new EventLog.List(causeCode, cid, + TelephonyManager.getDefault().getNetworkType()); + EventLog.writeEvent(EVENT_LOG_CALL_DROP, val); + } for (int i = 0, s = droppedDuringPoll.size() ; i < s ; i++ diff --git a/telephony/java/com/android/internal/telephony/gsm/CommandsInterface.java b/telephony/java/com/android/internal/telephony/gsm/CommandsInterface.java index ececd7216101f9994344faae6d02deaf8859319b..c7b08d215381bf3c747467a7854350287c809b2f 100644 --- a/telephony/java/com/android/internal/telephony/gsm/CommandsInterface.java +++ b/telephony/java/com/android/internal/telephony/gsm/CommandsInterface.java @@ -212,9 +212,9 @@ public interface CommandsInterface * * AsyncResult.result is an Object[] * ((Object[])AsyncResult.result)[0] is a String containing the NITZ time string - * ((Object[])AsyncResult.result)[0] is an Integer containing - * the UNIX time_t returned by time() when - * this NITZ time was posted. + * ((Object[])AsyncResult.result)[1] is a Long containing the milliseconds since boot as + * returned by elapsedRealtime() when this NITZ time + * was posted. * * Please note that the delivery of this message may be delayed several * seconds on system startup diff --git a/telephony/java/com/android/internal/telephony/gsm/DataConnectionTracker.java b/telephony/java/com/android/internal/telephony/gsm/DataConnectionTracker.java index 63d145edabf4a272590daeb0334da8ab755ec246..b0b8cdca421486b3945cc33561d19077ea52a09b 100644 --- a/telephony/java/com/android/internal/telephony/gsm/DataConnectionTracker.java +++ b/telephony/java/com/android/internal/telephony/gsm/DataConnectionTracker.java @@ -16,8 +16,12 @@ package com.android.internal.telephony.gsm; +import static com.android.internal.telephony.TelephonyProperties.PROPERTY_DATA_NETWORK_TYPE; +import static com.android.internal.telephony.gsm.ServiceStateTracker.DATA_ACCESS_EDGE; +import static com.android.internal.telephony.gsm.ServiceStateTracker.DATA_ACCESS_GPRS; +import static com.android.internal.telephony.gsm.ServiceStateTracker.DATA_ACCESS_UMTS; +import static com.android.internal.telephony.gsm.ServiceStateTracker.DATA_ACCESS_UNKNOWN; import android.app.AlarmManager; -import android.app.IAlarmManager; import android.app.PendingIntent; import android.content.BroadcastReceiver; import android.content.ContentResolver; @@ -40,14 +44,19 @@ import android.provider.Checkin; import android.provider.Settings; import android.provider.Telephony; import android.provider.Settings.SettingNotFoundException; -import com.android.internal.telephony.Phone; -import com.android.internal.telephony.gsm.PdpConnection.PdpFailCause; - import android.telephony.ServiceState; +import android.telephony.TelephonyManager; +import android.telephony.gsm.GsmCellLocation; +import android.text.TextUtils; import android.util.EventLog; import android.util.Log; -import android.text.TextUtils; +import android.util.EventLog.List; +import com.android.internal.telephony.Phone; +import com.android.internal.telephony.gsm.PdpConnection.PdpFailCause; +import android.net.wifi.WifiManager; +import android.net.NetworkInfo; + import java.io.IOException; import java.util.ArrayList; @@ -66,12 +75,14 @@ final class DataConnectionTracker extends Handler * SCANNING: data connection fails with one apn but other apns are available * ready to start data connection on other apns (before INITING) * CONNECTED: IP connection is setup + * DISCONNECTING: PdpConnection.disconnect() has been called, but PDP + * context is not yet deactivated * FAILED: data connection fail for all apns settings * * getDataConnectionState() maps State to DataState * FAILED or IDLE : DISCONNECTED * INITING or CONNECTING or SCANNING: CONNECTING - * CONNECTED : CONNECTED + * CONNECTED : CONNECTED or DISCONNECTING */ enum State { IDLE, @@ -79,6 +90,7 @@ final class DataConnectionTracker extends Handler CONNECTING, SCANNING, CONNECTED, + DISCONNECTING, FAILED } @@ -99,14 +111,7 @@ final class DataConnectionTracker extends Handler @Override public void onChange(boolean selfChange) { - boolean isConnected; - - isConnected = (state != State.IDLE && state != State.FAILED); - // TODO: It'd be nice to only do this if the changed entrie(s) - // match the current operator. - cleanUpConnection(isConnected, Phone.REASON_APN_CHANGED); - createAllApnList(); - sendMessage(obtainMessage(EVENT_TRY_SETUP_DATA)); + sendMessage(obtainMessage(EVENT_APN_CHANGED)); } } @@ -172,6 +177,12 @@ final class DataConnectionTracker extends Handler private boolean[] dataEnabled = new boolean[APN_NUM_TYPES]; + // wifi connection status will be updated by sticky intent + private boolean mIsWifiConnected = false; + + /** Intent sent when the reconnect alarm fires. */ + private PendingIntent mReconnectIntent = null; + //***** Constants // TODO: Increase this to match the max number of simultaneous @@ -183,6 +194,8 @@ final class DataConnectionTracker extends Handler private static final int POLL_PDP_MILLIS = 5 * 1000; private static final int RECONNECT_DELAY_INITIAL_MILLIS = 5 * 1000; + /** Cap out with 1 hour retry interval. */ + private static final int RECONNECT_DELAY_MAX_MILLIS = 60 * 60 * 1000; /** Slow poll when attempting connection recovery. */ private static final int POLL_NETSTAT_SLOW_MILLIS = 5000; @@ -215,13 +228,16 @@ final class DataConnectionTracker extends Handler // represents an invalid IP address private static final String NULL_IP = "0.0.0.0"; - static final String INTENT_RECONNECT_ALARM = "com.android.internal.telephony.gprs-reconnect"; + private static final String INTENT_RECONNECT_ALARM = "com.android.internal.telephony.gprs-reconnect"; + private static final String INTENT_RECONNECT_ALARM_EXTRA_REASON = "reason"; + //***** Tag IDs for EventLog private static final int EVENT_LOG_RADIO_RESET_COUNTDOWN_TRIGGERED = 50101; private static final int EVENT_LOG_RADIO_RESET = 50102; private static final int EVENT_LOG_PDP_RESET = 50103; private static final int EVENT_LOG_REREGISTER_NETWORK = 50104; + private static final int EVENT_LOG_RADIO_PDP_SETUP_FAIL = 50105; //***** Event Codes static final int EVENT_DATA_SETUP_COMPLETE = 1; @@ -244,37 +260,44 @@ final class DataConnectionTracker extends Handler static final int EVENT_GPRS_ATTACHED = 26; static final int EVENT_START_NETSTAT_POLL = 27; static final int EVENT_START_RECOVERY = 28; + static final int EVENT_APN_CHANGED = 29; - BroadcastReceiver screenOnOffReceiver = new BroadcastReceiver () + BroadcastReceiver mIntentReceiver = new BroadcastReceiver () { + @Override public void onReceive(Context context, Intent intent) { - if (intent.getAction().equals(Intent.ACTION_SCREEN_ON)) { + String action = intent.getAction(); + if (action.equals(Intent.ACTION_SCREEN_ON)) { mIsScreenOn = true; stopNetStatPoll(); startNetStatPoll(); - } else if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) { + } else if (action.equals(Intent.ACTION_SCREEN_OFF)) { mIsScreenOn = false; stopNetStatPoll(); startNetStatPoll(); - } else { - Log.w(LOG_TAG, "DataConnectionTracker received unexpected Intent: " + intent.getAction()); - } - } - }; + } else if (action.equals((INTENT_RECONNECT_ALARM))) { + Log.d(LOG_TAG, "GPRS reconnect alarm. Previous state was " + state); - BroadcastReceiver alarmReceiver - = new BroadcastReceiver () { - - public void onReceive(Context context, Intent intent) - { - Log.d(LOG_TAG, "GPRS reconnect alarm. Previous state was " + state); - - if (state == State.FAILED) { - cleanUpConnection(false, null); + String reason = intent.getStringExtra(INTENT_RECONNECT_ALARM_EXTRA_REASON); + if (state == State.FAILED) { + cleanUpConnection(false, reason); + } + trySetupData(reason); + } else if (action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) { + final android.net.NetworkInfo networkInfo = (NetworkInfo) + intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO); + mIsWifiConnected = (networkInfo != null && networkInfo.isConnected()); + } else if (action.equals(WifiManager.WIFI_STATE_CHANGED_ACTION)) { + final boolean enabled = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE, + WifiManager.WIFI_STATE_UNKNOWN) == WifiManager.WIFI_STATE_ENABLED; + + if (!enabled) { + // when wifi got disabeled, the NETWORK_STATE_CHANGED_ACTION + // quit and wont report disconnected til next enalbing. + mIsWifiConnected = false; + } } - - trySetupData(null); } }; @@ -301,13 +324,13 @@ final class DataConnectionTracker extends Handler IntentFilter filter = new IntentFilter(); filter.addAction(INTENT_RECONNECT_ALARM); - phone.getContext().registerReceiver( - alarmReceiver, filter, null, phone.h); + filter.addAction(Intent.ACTION_SCREEN_ON); + filter.addAction(Intent.ACTION_SCREEN_OFF); + filter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION); + filter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION); + + phone.getContext().registerReceiver(mIntentReceiver, filter, null, phone.h); - IntentFilter filterS = new IntentFilter(); - filterS.addAction(Intent.ACTION_SCREEN_ON); - filterS.addAction(Intent.ACTION_SCREEN_OFF); - phone.getContext().registerReceiver(screenOnOffReceiver, filterS); mDataConnectionTracker = this; mResolver = phone.getContext().getContentResolver(); @@ -326,6 +349,7 @@ final class DataConnectionTracker extends Handler } void setState(State s) { + if (DBG) log ("setState: " + s); if (state != s) { if (s == State.INITING) { // request PDP context Checkin.updateStats( @@ -347,6 +371,20 @@ final class DataConnectionTracker extends Handler waitingApns.clear(); // when teardown the connection and set to IDLE } } + + String getStateInString() { + switch (state) { + case IDLE: return "IDLE"; + case INITING: return "INIT"; + case CONNECTING: return "CING"; + case SCANNING: return "SCAN"; + case CONNECTED: return "CNTD"; + case DISCONNECTING: return "DING"; + case FAILED: return "FAIL"; + default: return "ERRO"; + } + } + String[] getActiveApnTypes() { String[] result; if (mActiveApn != null) { @@ -394,7 +432,8 @@ final class DataConnectionTracker extends Handler sendMessageDelayed( obtainMessage(EVENT_RESTORE_DEFAULT_APN), getRestoreDefaultApnDelay()); - return Phone.APN_ALREADY_ACTIVE; + if (state == State.INITING) return Phone.APN_REQUEST_STARTED; + else if (state == State.CONNECTED) return Phone.APN_ALREADY_ACTIVE; } if (!isApnTypeAvailable(type)) { @@ -440,6 +479,27 @@ final class DataConnectionTracker extends Handler return Phone.APN_REQUEST_FAILED; } } + + /** + * The data connection is expected to be setup while device + * 1. has sim card + * 2. registered to gprs service + * 3. user doesn't explicitly disable data service + * 4. wifi is not on + * + * @return false while no data connection if all above requirements are met. + */ + boolean isDataConnectionAsDesired() { + boolean roaming = phone.getServiceState().getRoaming(); + + if (phone.mSIMRecords.getRecordsLoaded() && + phone.mSST.getCurrentGprsState() == ServiceState.STATE_IN_SERVICE && + (!roaming || getDataOnRoamingEnabled()) && + !mIsWifiConnected ) { + return (state == State.CONNECTED); + } + return true; + } private boolean isApnTypeActive(String type) { // TODO: to support simultaneous, mActiveApn can be a List instead. @@ -534,8 +594,8 @@ final class DataConnectionTracker extends Handler // the shared values. If it is not, then update it. public void setDataOnRoamingEnabled(boolean enabled) { if (getDataOnRoamingEnabled() != enabled) { - Settings.System.putInt(phone.getContext().getContentResolver(), - Settings.System.DATA_ROAMING, enabled ? 1 : 0); + Settings.Secure.putInt(phone.getContext().getContentResolver(), + Settings.Secure.DATA_ROAMING, enabled ? 1 : 0); } Message roamingMsg = phone.getServiceState().getRoaming() ? obtainMessage(EVENT_ROAMING_ON) : obtainMessage(EVENT_ROAMING_OFF); @@ -545,8 +605,8 @@ final class DataConnectionTracker extends Handler //Retrieve the data roaming setting from the shared preferences. public boolean getDataOnRoamingEnabled() { try { - return Settings.System.getInt(phone.getContext().getContentResolver(), - Settings.System.DATA_ROAMING) > 0; + return Settings.Secure.getInt(phone.getContext().getContentResolver(), + Settings.Secure.DATA_ROAMING) > 0; } catch (SettingNotFoundException snfe) { return false; } @@ -582,6 +642,10 @@ final class DataConnectionTracker extends Handler startNetStatPoll(); phone.notifyDataConnection(Phone.REASON_GPRS_ATTACHED); } else { + if (state == State.FAILED) { + cleanUpConnection(false, Phone.REASON_GPRS_ATTACHED); + nextReconnectDelay = RECONNECT_DELAY_INITIAL_MILLIS; + } trySetupData(Phone.REASON_GPRS_ATTACHED); } } @@ -651,18 +715,45 @@ final class DataConnectionTracker extends Handler */ private void cleanUpConnection(boolean tearDown, String reason) { if (DBG) log("Clean up connection due to " + reason); + + // Clear the reconnect alarm, if set. + if (mReconnectIntent != null) { + AlarmManager am = + (AlarmManager) phone.getContext().getSystemService(Context.ALARM_SERVICE); + am.cancel(mReconnectIntent); + mReconnectIntent = null; + } + for (PdpConnection pdp : pdpList) { if (tearDown) { - Message msg = obtainMessage(EVENT_DISCONNECT_DONE); + Message msg = obtainMessage(EVENT_DISCONNECT_DONE, reason); pdp.disconnect(msg); } else { pdp.clearSettings(); } } stopNetStatPoll(); - setState(State.IDLE); - phone.notifyDataConnection(reason); - mActiveApn = null; + + /* + * If we've been asked to tear down the connection, + * set the state to DISCONNECTING. However, there's + * a race that can occur if for some reason we were + * already in the IDLE state. In that case, the call + * to pdp.disconnect() above will immediately post + * a message to the handler thread that the disconnect + * is done, and if the handler runs before the code + * below does, the handler will have set the state to + * IDLE before the code below runs. If we didn't check + * for that, future calls to trySetupData would fail, + * and we would never get out of the DISCONNECTING state. + */ + if (!tearDown) { + setState(State.IDLE); + phone.notifyDataConnection(reason); + mActiveApn = null; + } else if (state != State.IDLE) { + setState(State.DISCONNECTING); + } } /** @@ -729,6 +820,7 @@ final class DataConnectionTracker extends Handler Message msg = obtainMessage(); msg.what = EVENT_DATA_SETUP_COMPLETE; + msg.obj = reason; pdp.connect(apn, msg); setState(State.INITING); @@ -788,6 +880,25 @@ final class DataConnectionTracker extends Handler return false; } + /** + * Handles changes to the APN database. + */ + private void onApnChanged() { + boolean isConnected; + + isConnected = (state != State.IDLE && state != State.FAILED); + + // TODO: It'd be nice to only do this if the changed entrie(s) + // match the current operator. + createAllApnList(); + if (state != State.DISCONNECTING) { + cleanUpConnection(isConnected, Phone.REASON_APN_CHANGED); + if (!isConnected) { + trySetupData(Phone.REASON_APN_CHANGED); + } + } + } + /** * @param explicitPoll if true, indicates that *we* polled for this * update while state == CONNECTED rather than having it delivered @@ -822,7 +933,6 @@ final class DataConnectionTracker extends Handler Log.i(LOG_TAG, "PDP connection has dropped. Reconnecting"); cleanUpConnection(true, null); - trySetupData(null); return; } @@ -855,16 +965,15 @@ final class DataConnectionTracker extends Handler + " Reconnecting"); cleanUpConnection(true, null); - trySetupData(null); } } } } - private void notifyDefaultData() { + private void notifyDefaultData(String reason) { setupDnsProperties(); setState(State.CONNECTED); - phone.notifyDataConnection(null); + phone.notifyDataConnection(reason); startNetStatPoll(); // reset reconnect timer nextReconnectDelay = RECONNECT_DELAY_INITIAL_MILLIS; @@ -949,7 +1058,7 @@ final class DataConnectionTracker extends Handler private void startNetStatPoll() { - if (state == State.CONNECTED && mPingTestActive == false) { + if (state == State.CONNECTED && mPingTestActive == false && netStatPollEnabled == false) { Log.d(LOG_TAG, "[DataConnection] Start poll NetStat"); resetPollStats(); netStatPollEnabled = true; @@ -1066,14 +1175,13 @@ final class DataConnectionTracker extends Handler " pkts since last received"); // We've exceeded the threshold. Run ping test as a final check; // it will proceed with recovery if ping fails. - netStatPollEnabled = false; stopNetStatPoll(); Thread pingTest = new Thread() { public void run() { - mPingTestActive = true; runPingTest(); } }; + mPingTestActive = true; pingTest.start(); } } else { @@ -1141,27 +1249,26 @@ final class DataConnectionTracker extends Handler return (shouldPost && cause != PdpConnection.PdpFailCause.UNKNOWN); } - private void - reconnectAfterFail(PdpConnection.PdpFailCause lastFailCauseCode) - { + private void reconnectAfterFail(PdpFailCause lastFailCauseCode, String reason) { if (state == State.FAILED) { Log.d(LOG_TAG, "PDP activate failed. Scheduling next attempt for " + (nextReconnectDelay / 1000) + "s"); - try { - IAlarmManager am = IAlarmManager.Stub.asInterface( - ServiceManager.getService(Context.ALARM_SERVICE)); - PendingIntent sender = PendingIntent.getBroadcast( - phone.getContext(), 0, - new Intent(INTENT_RECONNECT_ALARM), 0); - am.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, - SystemClock.elapsedRealtime() + nextReconnectDelay, - sender); - } catch (RemoteException ex) { - } + AlarmManager am = + (AlarmManager) phone.getContext().getSystemService(Context.ALARM_SERVICE); + Intent intent = new Intent(INTENT_RECONNECT_ALARM); + intent.putExtra(INTENT_RECONNECT_ALARM_EXTRA_REASON, reason); + mReconnectIntent = PendingIntent.getBroadcast( + phone.getContext(), 0, intent, 0); + am.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, + SystemClock.elapsedRealtime() + nextReconnectDelay, + mReconnectIntent); // double it for next time nextReconnectDelay *= 2; + if (nextReconnectDelay > RECONNECT_DELAY_MAX_MILLIS) { + nextReconnectDelay = RECONNECT_DELAY_MAX_MILLIS; + } if (!shouldPostNotification(lastFailCauseCode)) { Log.d(LOG_TAG,"NOT Posting GPRS Unavailable notification " @@ -1202,7 +1309,8 @@ final class DataConnectionTracker extends Handler // cleanUpConnection if it needs to free up a PdpConnection. reason = Phone.REASON_APN_SWITCHED; cleanUpConnection(true, reason); - // Fall through to EVENT_TRY_SETUP_DATA. + break; + case EVENT_TRY_SETUP_DATA: trySetupData(reason); break; @@ -1213,7 +1321,6 @@ final class DataConnectionTracker extends Handler if (!isApnTypeActive(Phone.APN_TYPE_DEFAULT)) { cleanUpConnection(true, Phone.REASON_RESTORE_DEFAULT_APN); mRequestedApnType = Phone.APN_TYPE_DEFAULT; - trySetupData(Phone.REASON_RESTORE_DEFAULT_APN ); } break; @@ -1272,6 +1379,9 @@ final class DataConnectionTracker extends Handler case EVENT_DATA_SETUP_COMPLETE: ar = (AsyncResult) msg.obj; + if (ar.userObj instanceof String) { + reason = (String) ar.userObj; + } if (ar.exception == null) { // everything is setup @@ -1299,7 +1409,7 @@ final class DataConnectionTracker extends Handler } else { SystemProperties.set("gsm.defaultpdpcontext.active", "false"); } - notifyDefaultData(); + notifyDefaultData(reason); // TODO: For simultaneous PDP support, we need to build another // trigger another TRY_SETUP_DATA for the next APN type. (Note @@ -1310,7 +1420,23 @@ final class DataConnectionTracker extends Handler cause = (PdpConnection.PdpFailCause) (ar.result); if(DBG) log("PDP setup failed " + cause); - + // Log this failure to the Event Logs. + if (cause == PdpConnection.PdpFailCause.BAD_APN || + cause == PdpConnection.PdpFailCause.BAD_PAP_SECRET || + cause == PdpConnection.PdpFailCause.BARRED || + cause == PdpConnection.PdpFailCause.RADIO_ERROR_RETRY || + cause == PdpConnection.PdpFailCause.SUSPENED_TEMPORARY || + cause == PdpConnection.PdpFailCause.UNKNOWN || + cause == PdpConnection.PdpFailCause.USER_AUTHENTICATION) { + int cid = -1; + GsmCellLocation loc = ((GsmCellLocation)phone.getCellLocation()); + if (loc != null) cid = loc.getCid(); + + EventLog.List val = new EventLog.List( + cause.ordinal(), cid, + TelephonyManager.getDefault().getNetworkType()); + EventLog.writeEvent(EVENT_LOG_RADIO_PDP_SETUP_FAIL, val); + } // No try for permanent failure if (cause.isPermanentFail()) { notifyNoData(cause); @@ -1320,23 +1446,28 @@ final class DataConnectionTracker extends Handler waitingApns.remove(0); if (waitingApns.isEmpty()) { // No more to try, start delayed retry - notifyNoData(cause); - reconnectAfterFail(cause); + startDelayedRetry(cause, reason); } else { // we still have more apns to try setState(State.SCANNING); - trySetupData(null); + trySetupData(reason); } } else { - notifyNoData(cause); - reconnectAfterFail(cause); + startDelayedRetry(cause, reason); } } break; case EVENT_DISCONNECT_DONE: if(DBG) log("EVENT_DISCONNECT_DONE"); - trySetupData(null); + ar = (AsyncResult) msg.obj; + if (ar.userObj instanceof String) { + reason = (String) ar.userObj; + } + setState(State.IDLE); + phone.notifyDataConnection(reason); + mActiveApn = null; + trySetupData(reason); break; case EVENT_PDP_STATE_CHANGED: @@ -1375,15 +1506,17 @@ final class DataConnectionTracker extends Handler break; case EVENT_VOICE_CALL_ENDED: - // in case data setup was attempted when we were on a voice call - trySetupData(Phone.REASON_VOICE_CALL_ENDED); - if (state == State.CONNECTED && - !phone.mSST.isConcurrentVoiceAndData()) { - startNetStatPoll(); - phone.notifyDataConnection(Phone.REASON_VOICE_CALL_ENDED); + if (state == State.CONNECTED) { + if (!phone.mSST.isConcurrentVoiceAndData()) { + startNetStatPoll(); + phone.notifyDataConnection(Phone.REASON_VOICE_CALL_ENDED); + } else { + // clean slate after call end. + resetPollStats(); + } } else { - // clean slate after call end. - resetPollStats(); + // in case data setup was attempted when we were on a voice call + trySetupData(Phone.REASON_VOICE_CALL_ENDED); } break; @@ -1396,6 +1529,10 @@ final class DataConnectionTracker extends Handler mPingTestActive = false; doRecovery(); break; + + case EVENT_APN_CHANGED: + onApnChanged(); + break; } } @@ -1509,4 +1646,14 @@ final class DataConnectionTracker extends Handler } return result.toString(); } + + private void startDelayedRetry(PdpConnection.PdpFailCause cause, String reason) { + notifyNoData(cause); + if (mRequestedApnType != Phone.APN_TYPE_DEFAULT) { + sendMessage(obtainMessage(EVENT_RESTORE_DEFAULT_APN)); + } + else { + reconnectAfterFail(cause, reason); + } + } } diff --git a/telephony/java/com/android/internal/telephony/gsm/GSMConnection.java b/telephony/java/com/android/internal/telephony/gsm/GSMConnection.java index c316a23f6537c10871100b13ee3c9ac1640afc6f..43930c10d53471dfc4526b1efa3c51f2bf771286 100644 --- a/telephony/java/com/android/internal/telephony/gsm/GSMConnection.java +++ b/telephony/java/com/android/internal/telephony/gsm/GSMConnection.java @@ -16,7 +16,9 @@ package com.android.internal.telephony.gsm; import com.android.internal.telephony.*; +import android.content.Context; import android.os.Handler; +import android.os.PowerManager; import android.os.Registrant; import android.os.Looper; import android.os.Message; @@ -72,6 +74,8 @@ public class GSMConnection extends Connection { Handler h; + private PowerManager.WakeLock mPartialWakeLock; + //***** Event Constants static final int EVENT_DTMF_DONE = 1; @@ -106,8 +110,11 @@ public class GSMConnection extends Connection { /** This is probably an MT call that we first saw in a CLCC response */ /*package*/ - GSMConnection (DriverCall dc, CallTracker ct, int index) + GSMConnection (Context context, DriverCall dc, CallTracker ct, int index) { + createWakeLock(context); + acquireWakeLock(); + owner = ct; h = new MyHandler(owner.getLooper()); @@ -124,8 +131,11 @@ public class GSMConnection extends Connection { /** This is an MO call, created when dialing */ /*package*/ - GSMConnection (String dialString, CallTracker ct, GSMCall parent) + GSMConnection (Context context, String dialString, CallTracker ct, GSMCall parent) { + createWakeLock(context); + acquireWakeLock(); + owner = ct; h = new MyHandler(owner.getLooper()); @@ -412,6 +422,7 @@ public class GSMConnection extends Connection { parent.connectionDisconnected(this); } } + releaseWakeLock(); } // Returns true if state has changed, false if nothing changed @@ -513,6 +524,7 @@ public class GSMConnection extends Connection { // outgoing calls only processNextPostDialChar(); } + releaseWakeLock(); } private void @@ -574,6 +586,21 @@ public class GSMConnection extends Connection { return postDialString.substring(nextPostDialChar); } + @Override + protected void finalize() + { + /** + * It is understood that This finializer is not guaranteed + * to be called and the release lock call is here just in + * case there is some path that doesn't call onDisconnect + * and or onConnectedInOrOut. + */ + if (mPartialWakeLock.isHeld()) { + Log.e(LOG_TAG, "[GSMConn] UNEXPECTED; mPartialWakeLock is held when finalizing."); + } + releaseWakeLock(); + } + private void processNextPostDialChar() { @@ -672,6 +699,28 @@ public class GSMConnection extends Connection { } } + private void + createWakeLock(Context context) { + PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE); + mPartialWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, LOG_TAG); + } + + private void + acquireWakeLock() { + log("acquireWakeLock"); + mPartialWakeLock.acquire(); + } + + private void + releaseWakeLock() { + synchronized(mPartialWakeLock) { + if (mPartialWakeLock.isHeld()) { + log("releaseWakeLock"); + mPartialWakeLock.release(); + } + } + } + private void log(String msg) { Log.d(LOG_TAG, "[GSMConn] " + msg); } diff --git a/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java b/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java index f2e57999797cdfccb2d188cd7829434cecebdd9b..3f4bb5ca7d72e78bf04638fc80f881d87fc0d638 100644 --- a/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java +++ b/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java @@ -16,29 +16,58 @@ package com.android.internal.telephony.gsm; -import android.content.*; +import static com.android.internal.telephony.TelephonyProperties.PROPERTY_BASEBAND_VERSION; +import static com.android.internal.telephony.gsm.CommandsInterface.CF_ACTION_DISABLE; +import static com.android.internal.telephony.gsm.CommandsInterface.CF_ACTION_ENABLE; +import static com.android.internal.telephony.gsm.CommandsInterface.CF_ACTION_ERASURE; +import static com.android.internal.telephony.gsm.CommandsInterface.CF_ACTION_REGISTRATION; +import static com.android.internal.telephony.gsm.CommandsInterface.CF_REASON_ALL; +import static com.android.internal.telephony.gsm.CommandsInterface.CF_REASON_ALL_CONDITIONAL; +import static com.android.internal.telephony.gsm.CommandsInterface.CF_REASON_BUSY; +import static com.android.internal.telephony.gsm.CommandsInterface.CF_REASON_NOT_REACHABLE; +import static com.android.internal.telephony.gsm.CommandsInterface.CF_REASON_NO_REPLY; +import static com.android.internal.telephony.gsm.CommandsInterface.CF_REASON_UNCONDITIONAL; +import static com.android.internal.telephony.gsm.CommandsInterface.SERVICE_CLASS_VOICE; +import android.content.ContentValues; +import android.content.Context; +import android.content.SharedPreferences; import android.database.SQLException; -import android.os.*; +import android.net.Uri; +import android.os.AsyncResult; +import android.os.Handler; +import android.os.Looper; +import android.os.Message; +import android.os.Registrant; +import android.os.RegistrantList; +import android.os.SystemProperties; import android.preference.PreferenceManager; import android.provider.Telephony; -import com.android.internal.telephony.*; -import com.android.internal.telephony.gsm.stk.Service; -import static com.android.internal.telephony.gsm.CommandsInterface.*; - -import com.android.internal.telephony.test.SimulatedRadioControl; -import android.text.TextUtils; -import android.util.Log; -import static com.android.internal.telephony.TelephonyProperties.*; -import android.net.Uri; -import android.telephony.PhoneNumberUtils; import android.telephony.CellLocation; +import android.telephony.PhoneNumberUtils; import android.telephony.ServiceState; +import android.telephony.TelephonyManager; +import android.text.TextUtils; +import android.util.Log; + +import com.android.internal.telephony.Call; +import com.android.internal.telephony.CallStateException; +import com.android.internal.telephony.Connection; +import com.android.internal.telephony.MmiCode; +import com.android.internal.telephony.Phone; +import com.android.internal.telephony.PhoneBase; +import com.android.internal.telephony.PhoneNotifier; +import com.android.internal.telephony.PhoneSubInfo; +import com.android.internal.telephony.SimCard; +import com.android.internal.telephony.gsm.SimException; +import com.android.internal.telephony.gsm.stk.Service; +import com.android.internal.telephony.test.SimulatedRadioControl; import java.io.IOException; import java.net.InetSocketAddress; import java.net.ServerSocket; import java.net.Socket; -import java.util.*; +import java.util.ArrayList; +import java.util.List; /** * {@hide} @@ -58,7 +87,10 @@ public class GSMPhone extends PhoneBase { public static final String CIPHERING_KEY = "ciphering_key"; // Key used to read/write current CLIR setting public static final String CLIR_KEY = "clir_key"; - + // Key used to read/write voice mail number + public static final String VM_NUMBER = "vm_number_key"; + // Key used to read/write the SIM IMSI used for storing the voice mail + public static final String VM_SIM_IMSI = "vm_sim_imsi_key"; //***** Instance Variables @@ -91,6 +123,7 @@ public class GSMPhone extends PhoneBase { private String mImei; private String mImeiSv; + private String mVmNumber; //***** Event Constants @@ -115,6 +148,7 @@ public class GSMPhone extends PhoneBase { static final int EVENT_SET_NETWORK_AUTOMATIC_COMPLETE = 16; static final int EVENT_SET_CLIR_COMPLETE = 17; static final int EVENT_REGISTERED_TO_NETWORK = 18; + static final int EVENT_SET_VM_NUMBER_DONE = 19; //***** Constructors @@ -275,11 +309,13 @@ public class GSMPhone extends PhoneBase { break; case CONNECTED: + case DISCONNECTING: if ( mCT.state != Phone.State.IDLE - && !mSST.isConcurrentVoiceAndData()) + && !mSST.isConcurrentVoiceAndData()) { ret = DataState.SUSPENDED; - else + } else { ret = DataState.CONNECTED; + } break; case INITING: @@ -731,8 +767,10 @@ public class GSMPhone extends PhoneBase { if (handleInCallMmiCommands(newDialString)) { return null; } - - GsmMmiCode mmi = GsmMmiCode.newFromDialString(newDialString, this); + + // Only look at the Network portion for mmi + String networkPortion = PhoneNumberUtils.extractNetworkPortion(newDialString); + GsmMmiCode mmi = GsmMmiCode.newFromDialString(networkPortion, this); if (LOCAL_DEBUG) Log.d(LOG_TAG, "dialing w/ mmi '" + mmi + "'..."); @@ -802,11 +840,36 @@ public class GSMPhone extends PhoneBase { mSST.setRadioPower(power); } + private void storeVoiceMailNumber(String number) { + SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getContext()); + SharedPreferences.Editor editor = sp.edit(); + editor.putString(VM_NUMBER, number); + editor.commit(); + setVmSimImsi(getSubscriberId()); + } public String getVoiceMailNumber() { - return mSIMRecords.getVoiceMailNumber(); + // Read from the SIM. If its null, try reading from the shared preference area. + String number = mSIMRecords.getVoiceMailNumber(); + if (TextUtils.isEmpty(number)) { + SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getContext()); + number = sp.getString(VM_NUMBER, null); + } + return number; + } + + private String getVmSimImsi() { + SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getContext()); + return sp.getString(VM_SIM_IMSI, null); } + private void setVmSimImsi(String imsi) { + SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getContext()); + SharedPreferences.Editor editor = sp.edit(); + editor.putString(VM_SIM_IMSI, imsi); + editor.commit(); + } + public String getVoiceMailAlphaTag() { String ret; @@ -860,7 +923,11 @@ public class GSMPhone extends PhoneBase { public void setVoiceMailNumber(String alphaTag, String voiceMailNumber, Message onComplete) { - mSIMRecords.setVoiceMailNumber(alphaTag, voiceMailNumber, onComplete); + + Message resp; + mVmNumber = voiceMailNumber; + resp = h.obtainMessage(EVENT_SET_VM_NUMBER_DONE, 0, 0, onComplete); + mSIMRecords.setVoiceMailNumber(alphaTag, mVmNumber, resp); } private boolean isValidCommandInterfaceCFReason (int commandInterfaceCFReason) { @@ -1301,6 +1368,13 @@ public class GSMPhone extends PhoneBase { } catch (SQLException e) { Log.e(LOG_TAG, "Can't store current operator", e); } + // Check if this is a different SIM than the previous one. If so unset the + // voice mail number. + String imsi = getVmSimImsi(); + if (imsi != null && !getSubscriberId().equals(imsi)) { + storeVoiceMailNumber(null); + setVmSimImsi(null); + } break; @@ -1380,7 +1454,21 @@ public class GSMPhone extends PhoneBase { onComplete.sendToTarget(); } break; + + case EVENT_SET_VM_NUMBER_DONE: + ar = (AsyncResult)msg.obj; + if (SimVmNotSupportedException.class.isInstance(ar.exception)) { + storeVoiceMailNumber(mVmNumber); + ar.exception = null; + } + onComplete = (Message) ar.userObj; + if (onComplete != null) { + AsyncResult.forMessage(onComplete, ar.result, ar.exception); + onComplete.sendToTarget(); + } + break; + case EVENT_GET_CALL_FORWARD_DONE: ar = (AsyncResult)msg.obj; if (ar.exception == null) { diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmAlphabet.java b/telephony/java/com/android/internal/telephony/gsm/GsmAlphabet.java index 7baaecaa434eb4f5e307c7246e5edc435417a1f4..59a94223b93dd001acae55318c0c02810c7c6ed7 100644 --- a/telephony/java/com/android/internal/telephony/gsm/GsmAlphabet.java +++ b/telephony/java/com/android/internal/telephony/gsm/GsmAlphabet.java @@ -495,7 +495,7 @@ public class GsmAlphabet countGsmSeptets(char c) { try { - return countGsmSeptets(c, true); + return countGsmSeptets(c, false); } catch (EncodeException ex) { // This should never happen. return 0; @@ -535,7 +535,7 @@ public class GsmAlphabet countGsmSeptets(String s) { try { - return countGsmSeptets(s, true); + return countGsmSeptets(s, false); } catch (EncodeException ex) { // this should never happen return 0; diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmMmiCode.java b/telephony/java/com/android/internal/telephony/gsm/GsmMmiCode.java index c85fb7c98b26d8e1d1f19f8d79d427767ee62dcb..ce6c1860d4cb5c6babee050d616aa9ea283e9e31 100644 --- a/telephony/java/com/android/internal/telephony/gsm/GsmMmiCode.java +++ b/telephony/java/com/android/internal/telephony/gsm/GsmMmiCode.java @@ -197,7 +197,7 @@ public final class GsmMmiCode extends Handler implements MmiCode ret = new GsmMmiCode(phone); ret.dialingNumber = dialString; } - + return ret; } @@ -621,21 +621,21 @@ public final class GsmMmiCode extends Handler implements MmiCode throw new RuntimeException ("invalid action"); } - int isSettingUnconditionalVoice = ( - (reason == CommandsInterface.CF_REASON_UNCONDITIONAL) && - ((serviceClass & CommandsInterface.SERVICE_CLASS_VOICE) != 0) - ) ? 1 : 0; + int isSettingUnconditionalVoice = + ((reason == CommandsInterface.CF_REASON_UNCONDITIONAL) && + (((serviceClass & CommandsInterface.SERVICE_CLASS_VOICE) != 0) || + (serviceClass == CommandsInterface.SERVICE_CLASS_NONE))) ? 1 : 0; int isEnableDesired = - ((cfAction == CommandsInterface.CF_ACTION_ENABLE) - || (cfAction == CommandsInterface.CF_ACTION_REGISTRATION)) ? 1 : 0; - - phone.mCM.setCallForward(cfAction, reason, - serviceClass, dialingNumber, time, - obtainMessage(EVENT_SET_CFF_COMPLETE, - isSettingUnconditionalVoice, - isEnableDesired, - this)); + ((cfAction == CommandsInterface.CF_ACTION_ENABLE) || + (cfAction == CommandsInterface.CF_ACTION_REGISTRATION)) ? 1 : 0; + + Log.d(LOG_TAG, "is CF setCallForward"); + phone.mCM.setCallForward(cfAction, reason, serviceClass, + dialingNumber, time, obtainMessage( + EVENT_SET_CFF_COMPLETE, + isSettingUnconditionalVoice, + isEnableDesired, this)); } } else if (isServiceCodeCallBarring(sc)) { // sia = password @@ -711,6 +711,10 @@ public final class GsmMmiCode extends Handler implements MmiCode } else if (pinLen < 4 || pinLen > 8 ) { // invalid length handlePasswordError(com.android.internal.R.string.invalidPin); + } else if (sc.equals(SC_PIN) && + phone.mSimCard.getState() == SimCard.State.PUK_REQUIRED ) { + // Sim is puk-locked + handlePasswordError(com.android.internal.R.string.needPuk); } else { // pre-checks OK if (sc.equals(SC_PIN)) { diff --git a/telephony/java/com/android/internal/telephony/gsm/MccTable.java b/telephony/java/com/android/internal/telephony/gsm/MccTable.java index 57aa01261ff81098381ddbd46fa23511de6ab29e..8f6b22edc3486438c433f3fe7291e432eea63084 100644 --- a/telephony/java/com/android/internal/telephony/gsm/MccTable.java +++ b/telephony/java/com/android/internal/telephony/gsm/MccTable.java @@ -33,12 +33,23 @@ public final class MccTable int mcc; String iso; int smallestDigitsMnc; + String timezone; + String language; - MccEntry(int mnc, String iso, int smallestDigitsMCC) - { + MccEntry(int mnc, String iso, int smallestDigitsMCC) { + this(mnc, iso, smallestDigitsMCC, null); + } + + MccEntry(int mnc, String iso, int smallestDigitsMCC, String timezone) { + this(mnc, iso, smallestDigitsMCC, timezone, null); + } + + MccEntry(int mnc, String iso, int smallestDigitsMCC, String timezone, String language) { this.mcc = mnc; this.iso = iso; this.smallestDigitsMnc = smallestDigitsMCC; + this.timezone = timezone; + this.language = language; } public int compareTo(MccEntry o) @@ -65,6 +76,23 @@ public final class MccTable } } + /** + * Returns a default time zone ID for the given MCC. + * @param mcc Mobile Country Code + * @return default TimeZone ID, or null if not specified + */ + /* package */ static String defaultTimeZoneForMcc(int mcc) { + MccEntry entry; + + entry = entryForMcc(mcc); + + if (entry == null) { + return null; + } else { + return entry.timezone; + } + } + /** * Given a GSM Mobile Country Code, returns * an ISO two-character country code if available. @@ -84,6 +112,22 @@ public final class MccTable } } + /** + * Given a GSM Mobile Country Code, returns + * an ISO 2-3 character language code if available. + * Returns null if unavailable. + */ + /* package */ static String defaultLanguageForMcc(int mcc) { + MccEntry entry; + + entry = entryForMcc(mcc); + + if (entry == null) { + return null; + } else { + return entry.language; + } + } /** * Given a GSM Mobile Country Code, returns @@ -125,7 +169,7 @@ public final class MccTable */ table.add(new MccEntry(202,"gr",2)); //Greece - table.add(new MccEntry(204,"nl",2)); //Netherlands (Kingdom of the) + table.add(new MccEntry(204,"nl",2,"Europe/Amsterdam")); //Netherlands (Kingdom of the) table.add(new MccEntry(206,"be",2)); //Belgium table.add(new MccEntry(208,"fr",2)); //France table.add(new MccEntry(212,"mc",2)); //Monaco (Principality of) @@ -139,11 +183,11 @@ public final class MccTable table.add(new MccEntry(225,"va",2)); //Vatican City State table.add(new MccEntry(226,"ro",2)); //Romania table.add(new MccEntry(228,"ch",2)); //Switzerland (Confederation of) - table.add(new MccEntry(230,"cz",2)); //Czech Republic + table.add(new MccEntry(230,"cz",2,"Europe/Prague")); //Czech Republic table.add(new MccEntry(231,"sk",2)); //Slovak Republic - table.add(new MccEntry(232,"at",2)); //Austria - table.add(new MccEntry(234,"gb",2)); //United Kingdom of Great Britain and Northern Ireland - table.add(new MccEntry(235,"gb",2)); //United Kingdom of Great Britain and Northern Ireland + table.add(new MccEntry(232,"at",2,"Europe/Vienna","de")); //Austria + table.add(new MccEntry(234,"gb",2,"Europe/London","en")); //United Kingdom of Great Britain and Northern Ireland + table.add(new MccEntry(235,"gb",2,"Europe/London","en")); //United Kingdom of Great Britain and Northern Ireland table.add(new MccEntry(238,"dk",2)); //Denmark table.add(new MccEntry(240,"se",2)); //Sweden table.add(new MccEntry(242,"no",2)); //Norway @@ -155,8 +199,8 @@ public final class MccTable table.add(new MccEntry(255,"ua",2)); //Ukraine table.add(new MccEntry(257,"by",2)); //Belarus (Republic of) table.add(new MccEntry(259,"md",2)); //Moldova (Republic of) - table.add(new MccEntry(260,"pl",2)); //Poland (Republic of) - table.add(new MccEntry(262,"de",2)); //Germany (Federal Republic of) + table.add(new MccEntry(260,"pl",2,"Europe/Warsaw")); //Poland (Republic of) + table.add(new MccEntry(262,"de",2,"Europe/Berlin","de")); //Germany (Federal Republic of) table.add(new MccEntry(266,"gi",2)); //Gibraltar table.add(new MccEntry(268,"pt",2)); //Portugal table.add(new MccEntry(270,"lu",2)); //Luxembourg @@ -177,13 +221,13 @@ public final class MccTable table.add(new MccEntry(295,"li",2)); //Liechtenstein (Principality of) table.add(new MccEntry(302,"ca",2)); //Canada table.add(new MccEntry(308,"pm",2)); //Saint Pierre and Miquelon (Collectivit territoriale de la Rpublique franaise) - table.add(new MccEntry(310,"us",3)); //United States of America - table.add(new MccEntry(311,"us",3)); //United States of America - table.add(new MccEntry(312,"us",3)); //United States of America - table.add(new MccEntry(313,"us",3)); //United States of America - table.add(new MccEntry(314,"us",3)); //United States of America - table.add(new MccEntry(315,"us",3)); //United States of America - table.add(new MccEntry(316,"us",3)); //United States of America + table.add(new MccEntry(310,"us",3,"","en")); //United States of America + table.add(new MccEntry(311,"us",3,"","en")); //United States of America + table.add(new MccEntry(312,"us",3,"","en")); //United States of America + table.add(new MccEntry(313,"us",3,"","en")); //United States of America + table.add(new MccEntry(314,"us",3,"","en")); //United States of America + table.add(new MccEntry(315,"us",3,"","en")); //United States of America + table.add(new MccEntry(316,"us",3,"","en")); //United States of America table.add(new MccEntry(330,"pr",2)); //Puerto Rico table.add(new MccEntry(332,"vi",2)); //United States Virgin Islands table.add(new MccEntry(334,"mx",3)); //Mexico @@ -254,12 +298,12 @@ public final class MccTable table.add(new MccEntry(470,"bd",2)); //Bangladesh (People's Republic of) table.add(new MccEntry(472,"mv",2)); //Maldives (Republic of) table.add(new MccEntry(502,"my",2)); //Malaysia - table.add(new MccEntry(505,"au",2)); //Australia + table.add(new MccEntry(505,"au",2,"Australia/Sydney","en")); //Australia table.add(new MccEntry(510,"id",2)); //Indonesia (Republic of) table.add(new MccEntry(514,"tl",2)); //Democratic Republic of Timor-Leste table.add(new MccEntry(515,"ph",2)); //Philippines (Republic of the) table.add(new MccEntry(520,"th",2)); //Thailand - table.add(new MccEntry(525,"sg",2)); //Singapore (Republic of) + table.add(new MccEntry(525,"sg",2,"Singapore","en")); //Singapore (Republic of) table.add(new MccEntry(528,"bn",2)); //Brunei Darussalam table.add(new MccEntry(530,"nz",2)); //New Zealand table.add(new MccEntry(534,"mp",2)); //Northern Mariana Islands (Commonwealth of the) diff --git a/telephony/java/com/android/internal/telephony/gsm/PdpConnection.java b/telephony/java/com/android/internal/telephony/gsm/PdpConnection.java index 79e48f9c49cbd7b087b3d452889e363dde0c93db..6428f7047c6fa03c1187f73a5c96da9ece297b31 100644 --- a/telephony/java/com/android/internal/telephony/gsm/PdpConnection.java +++ b/telephony/java/com/android/internal/telephony/gsm/PdpConnection.java @@ -19,10 +19,12 @@ package com.android.internal.telephony.gsm; import android.os.*; import android.database.Cursor; import android.provider.Telephony; +import android.text.util.Regex; import android.util.EventLog; import android.util.Log; import java.util.ArrayList; +import com.android.internal.telephony.Phone; /** * {@hide} @@ -204,6 +206,9 @@ public class PdpConnection extends Handler { } } else if (state == PdpState.ACTIVATING) { receivedDisconnectReq = true; + } else { + // state == INACTIVE. Nothing to do, so notify immediately. + notifyDisconnect(msg); } } @@ -395,6 +400,8 @@ public class PdpConnection extends Handler { // Don't bother reporting success if there's already a // pending disconnect request, since DataConnectionTracker // has already updated its state. + // Set ACTIVE so that disconnect does the right thing. + state = PdpState.ACTIVE; disconnect(onDisconnect); } else { String[] response = ((String[]) ar.result); @@ -416,10 +423,16 @@ public class PdpConnection extends Handler { if (NULL_IP.equals(dnsServers[0]) && NULL_IP.equals(dnsServers[1])) { // Work around a race condition where QMI does not fill in DNS: // Deactivate PDP and let DataConnectionTracker retry. - EventLog.writeEvent(EVENT_LOG_BAD_DNS_ADDRESS, dnsServers[0]); - phone.mCM.deactivateDefaultPDP(cid, - obtainMessage(EVENT_FORCE_RETRY)); - break; + // Do not apply the race condition workaround for MMS APN + // if Proxy is an IP-address. + // Otherwise, the default APN will not be restored anymore. + if (!apn.types[0].equals(Phone.APN_TYPE_MMS) + || !isIpAddress(apn.mmsProxy)) { + EventLog.writeEvent(EVENT_LOG_BAD_DNS_ADDRESS, dnsServers[0]); + phone.mCM.deactivateDefaultPDP(cid, + obtainMessage(EVENT_FORCE_RETRY)); + break; + } } } @@ -470,4 +483,10 @@ public class PdpConnection extends Handler { break; } } + + private boolean isIpAddress(String address) { + if (address == null) return false; + + return Regex.IP_ADDRESS_PATTERN.matcher(apn.mmsProxy).matches(); + } } diff --git a/telephony/java/com/android/internal/telephony/gsm/RIL.java b/telephony/java/com/android/internal/telephony/gsm/RIL.java index 6739fba7a9a85a83252ade12d41fa8304101bd91..45000ba0b531f9e9fa258d30e0858be4ab2aabe9 100644 --- a/telephony/java/com/android/internal/telephony/gsm/RIL.java +++ b/telephony/java/com/android/internal/telephony/gsm/RIL.java @@ -16,32 +16,32 @@ package com.android.internal.telephony.gsm; +import static com.android.internal.telephony.gsm.RILConstants.*; +import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; -import android.content.BroadcastReceiver; -import com.android.internal.telephony.*; -import android.os.Parcel; -import java.io.IOException; -import android.os.Message; -import android.os.Handler; -import android.net.LocalSocketAddress; import android.net.LocalSocket; -import com.android.internal.os.HandlerThread; -import android.os.HandlerInterface; -import java.util.ArrayList; -import java.util.Collections; -import java.io.InputStream; +import android.net.LocalSocketAddress; +import android.os.AsyncResult; +import android.os.Handler; +import android.os.HandlerThread; +import android.os.Looper; +import android.os.Message; +import android.os.Parcel; +import android.os.PowerManager; +import android.os.PowerManager.WakeLock; import android.telephony.PhoneNumberUtils; import android.telephony.gsm.SmsManager; import android.telephony.gsm.SmsMessage; -import android.util.Log; +import android.telephony.NeighboringCellInfo; import android.util.Config; -import android.os.AsyncResult; -import android.os.PowerManager; -import android.os.PowerManager.WakeLock; +import android.util.Log; -import static com.android.internal.telephony.gsm.RILConstants.*; +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.Collections; /** * {@hide} @@ -160,7 +160,7 @@ class RILRequest ex = CommandException.fromRilErrno(error); - if (RIL.RILJ_LOG) Log.d(LOG_TAG, serialString() + "< " + if (RIL.RILJ_LOGD) Log.d(LOG_TAG, serialString() + "< " + RIL.requestToString(mRequest) + " error: " + ex); @@ -186,15 +186,15 @@ class RILRequest public final class RIL extends BaseCommands implements CommandsInterface { static final String LOG_TAG = "RILJ"; - private static final boolean DBG = true; - static final boolean RILJ_LOG = true; + private static final boolean DBG = false; + static final boolean RILJ_LOGD = Config.LOGD; + static final boolean RILJ_LOGV = DBG ? Config.LOGD : Config.LOGV; static int WAKE_LOCK_TIMEOUT = 5000; //***** Instance Variables LocalSocket mSocket; - HandlerThread mSenderThread; - Handler mSenderH; + HandlerThread mSenderThread; RILSender mSender; Thread mReceiverThread; RILReceiver mReceiver; @@ -239,8 +239,12 @@ public final class RIL extends BaseCommands implements CommandsInterface } }; - class RILSender implements HandlerInterface,Runnable + class RILSender extends Handler implements Runnable { + public RILSender(Looper looper) { + super(looper); + } + // Only allocated once byte[] dataLength = new byte[4]; @@ -341,7 +345,7 @@ public final class RIL extends BaseCommands implements CommandsInterface // TODO should we clean up mRequestList and mRequestPending synchronized (mWakeLock) { if (mWakeLock.isHeld()) { - if (DBG) { + if (RILJ_LOGD) { synchronized (mRequestsList) { int count = mRequestsList.size(); Log.d(LOG_TAG, "WAKE_LOCK_TIMEOUT " + @@ -512,7 +516,8 @@ public final class RIL extends BaseCommands implements CommandsInterface Log.i(LOG_TAG, "'" + SOCKET_NAME_RIL + "' socket closed", ex); } catch (Throwable tr) { - Log.e(LOG_TAG, "Uncaught exception read length=" + length, tr); + Log.e(LOG_TAG, "Uncaught exception read length=" + length + + "Exception:" + tr.toString()); } Log.i(LOG_TAG, "Disconnected from '" + SOCKET_NAME_RIL @@ -559,9 +564,13 @@ public final class RIL extends BaseCommands implements CommandsInterface mRequestMessagesPending = 0; mContext = context; - mSender = new RILSender(); - mSenderThread = new HandlerThread(mSender, mSender, "RILSender"); - mSenderH = mSenderThread.getHandler(); + + mSenderThread = new HandlerThread("RILSender"); + mSenderThread.start(); + + Looper looper = mSenderThread.getLooper(); + mSender = new RILSender(looper); + mReceiver = new RILReceiver(); mReceiverThread = new Thread(mReceiver, "RILReceiver"); mReceiverThread.start(); @@ -593,7 +602,7 @@ public final class RIL extends BaseCommands implements CommandsInterface { RILRequest rr = RILRequest.obtain(RIL_REQUEST_GET_SIM_STATUS, result); - if (RILJ_LOG) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); + if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); send(rr); } @@ -603,7 +612,7 @@ public final class RIL extends BaseCommands implements CommandsInterface { RILRequest rr = RILRequest.obtain(RIL_REQUEST_ENTER_SIM_PIN, result); - if (RILJ_LOG) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); + if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); rr.mp.writeInt(1); rr.mp.writeString(pin); @@ -616,7 +625,7 @@ public final class RIL extends BaseCommands implements CommandsInterface { RILRequest rr = RILRequest.obtain(RIL_REQUEST_ENTER_SIM_PUK, result); - if (RILJ_LOG) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); + if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); rr.mp.writeInt(2); rr.mp.writeString(puk); @@ -630,7 +639,7 @@ public final class RIL extends BaseCommands implements CommandsInterface { RILRequest rr = RILRequest.obtain(RIL_REQUEST_ENTER_SIM_PIN2, result); - if (RILJ_LOG) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); + if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); rr.mp.writeInt(1); rr.mp.writeString(pin); @@ -643,7 +652,7 @@ public final class RIL extends BaseCommands implements CommandsInterface { RILRequest rr = RILRequest.obtain(RIL_REQUEST_ENTER_SIM_PUK2, result); - if (RILJ_LOG) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); + if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); rr.mp.writeInt(2); rr.mp.writeString(puk); @@ -657,7 +666,7 @@ public final class RIL extends BaseCommands implements CommandsInterface { RILRequest rr = RILRequest.obtain(RIL_REQUEST_CHANGE_SIM_PIN, result); - if (RILJ_LOG) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); + if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); rr.mp.writeInt(2); rr.mp.writeString(oldPin); @@ -671,7 +680,7 @@ public final class RIL extends BaseCommands implements CommandsInterface { RILRequest rr = RILRequest.obtain(RIL_REQUEST_CHANGE_SIM_PIN2, result); - if (RILJ_LOG) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); + if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); rr.mp.writeInt(2); rr.mp.writeString(oldPin2); @@ -685,7 +694,7 @@ public final class RIL extends BaseCommands implements CommandsInterface { RILRequest rr = RILRequest.obtain(RIL_REQUEST_CHANGE_BARRING_PASSWORD, result); - if (RILJ_LOG) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); + if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); rr.mp.writeInt(3); rr.mp.writeString(facility); @@ -700,7 +709,7 @@ public final class RIL extends BaseCommands implements CommandsInterface { RILRequest rr = RILRequest.obtain(RIL_REQUEST_ENTER_NETWORK_DEPERSONALIZATION, result); - if (RILJ_LOG) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); + if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); rr.mp.writeInt(1); rr.mp.writeString(netpin); @@ -713,7 +722,7 @@ public final class RIL extends BaseCommands implements CommandsInterface { RILRequest rr = RILRequest.obtain(RIL_REQUEST_GET_CURRENT_CALLS, result); - if (RILJ_LOG) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); + if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); send(rr); } @@ -723,7 +732,7 @@ public final class RIL extends BaseCommands implements CommandsInterface { RILRequest rr = RILRequest.obtain(RIL_REQUEST_PDP_CONTEXT_LIST, result); - if (RILJ_LOG) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); + if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); send(rr); } @@ -736,7 +745,7 @@ public final class RIL extends BaseCommands implements CommandsInterface rr.mp.writeString(address); rr.mp.writeInt(clirMode); - if (RILJ_LOG) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); + if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); send(rr); } @@ -746,7 +755,7 @@ public final class RIL extends BaseCommands implements CommandsInterface { RILRequest rr = RILRequest.obtain(RIL_REQUEST_GET_IMSI, result); - if (RILJ_LOG) riljLog(rr.serialString() + "> getIMSI:RIL_REQUEST_GET_IMSI " + RIL_REQUEST_GET_IMSI + " " + requestToString(rr.mRequest)); + if (RILJ_LOGD) riljLog(rr.serialString() + "> getIMSI:RIL_REQUEST_GET_IMSI " + RIL_REQUEST_GET_IMSI + " " + requestToString(rr.mRequest)); send(rr); } @@ -756,7 +765,7 @@ public final class RIL extends BaseCommands implements CommandsInterface { RILRequest rr = RILRequest.obtain(RIL_REQUEST_GET_IMEI, result); - if (RILJ_LOG) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); + if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); send(rr); } @@ -766,7 +775,7 @@ public final class RIL extends BaseCommands implements CommandsInterface { RILRequest rr = RILRequest.obtain(RIL_REQUEST_GET_IMEISV, result); - if (RILJ_LOG) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); + if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); send(rr); } @@ -775,11 +784,11 @@ public final class RIL extends BaseCommands implements CommandsInterface public void hangupConnection (int gsmIndex, Message result) { - if (RILJ_LOG) riljLog("hangupConnection: gsmIndex=" + gsmIndex); + if (RILJ_LOGD) riljLog("hangupConnection: gsmIndex=" + gsmIndex); RILRequest rr = RILRequest.obtain(RIL_REQUEST_HANGUP, result); - if (RILJ_LOG) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest) + " " + gsmIndex); + if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest) + " " + gsmIndex); rr.mp.writeInt(1); rr.mp.writeInt(gsmIndex); @@ -793,7 +802,7 @@ public final class RIL extends BaseCommands implements CommandsInterface RILRequest rr = RILRequest.obtain(RIL_REQUEST_HANGUP_WAITING_OR_BACKGROUND, result); - if (RILJ_LOG) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); + if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); send(rr); } @@ -805,7 +814,7 @@ public final class RIL extends BaseCommands implements CommandsInterface = RILRequest.obtain( RIL_REQUEST_HANGUP_FOREGROUND_RESUME_BACKGROUND, result); - if (RILJ_LOG) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); + if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); send(rr); } @@ -817,7 +826,7 @@ public final class RIL extends BaseCommands implements CommandsInterface = RILRequest.obtain( RIL_REQUEST_SWITCH_WAITING_OR_HOLDING_AND_ACTIVE, result); - if (RILJ_LOG) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); + if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); send(rr); } @@ -828,7 +837,7 @@ public final class RIL extends BaseCommands implements CommandsInterface RILRequest rr = RILRequest.obtain(RIL_REQUEST_CONFERENCE, result); - if (RILJ_LOG) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); + if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); send(rr); } @@ -840,7 +849,7 @@ public final class RIL extends BaseCommands implements CommandsInterface RILRequest rr = RILRequest.obtain(RIL_REQUEST_SEPARATE_CONNECTION, result); - if (RILJ_LOG) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest) + if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest) + " " + gsmIndex); rr.mp.writeInt(1); @@ -855,7 +864,7 @@ public final class RIL extends BaseCommands implements CommandsInterface RILRequest rr = RILRequest.obtain(RIL_REQUEST_ANSWER, result); - if (RILJ_LOG) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); + if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); send(rr); } @@ -866,7 +875,7 @@ public final class RIL extends BaseCommands implements CommandsInterface RILRequest rr = RILRequest.obtain(RIL_REQUEST_UDUB, result); - if (RILJ_LOG) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); + if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); send(rr); } @@ -877,7 +886,7 @@ public final class RIL extends BaseCommands implements CommandsInterface RILRequest rr = RILRequest.obtain(RIL_REQUEST_EXPLICIT_CALL_TRANSFER, result); - if (RILJ_LOG) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); + if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); send(rr); } @@ -888,7 +897,7 @@ public final class RIL extends BaseCommands implements CommandsInterface RILRequest rr = RILRequest.obtain(RIL_REQUEST_LAST_CALL_FAIL_CAUSE, result); - if (RILJ_LOG) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); + if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); send(rr); } @@ -899,7 +908,7 @@ public final class RIL extends BaseCommands implements CommandsInterface RILRequest rr = RILRequest.obtain(RIL_REQUEST_LAST_PDP_FAIL_CAUSE, result); - if (RILJ_LOG) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); + if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); send(rr); } @@ -910,7 +919,7 @@ public final class RIL extends BaseCommands implements CommandsInterface RILRequest rr = RILRequest.obtain(RIL_REQUEST_SET_MUTE, response); - if (RILJ_LOG) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest) + if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest) + " " + enableMute); rr.mp.writeInt(1); @@ -925,7 +934,7 @@ public final class RIL extends BaseCommands implements CommandsInterface RILRequest rr = RILRequest.obtain(RIL_REQUEST_GET_MUTE, response); - if (RILJ_LOG) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); + if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); send(rr); } @@ -936,7 +945,7 @@ public final class RIL extends BaseCommands implements CommandsInterface RILRequest rr = RILRequest.obtain(RIL_REQUEST_SIGNAL_STRENGTH, result); - if (RILJ_LOG) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); + if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); send(rr); } @@ -947,7 +956,7 @@ public final class RIL extends BaseCommands implements CommandsInterface RILRequest rr = RILRequest.obtain(RIL_REQUEST_REGISTRATION_STATE, result); - if (RILJ_LOG) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); + if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); send(rr); } @@ -958,7 +967,7 @@ public final class RIL extends BaseCommands implements CommandsInterface RILRequest rr = RILRequest.obtain(RIL_REQUEST_GPRS_REGISTRATION_STATE, result); - if (RILJ_LOG) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); + if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); send(rr); } @@ -969,7 +978,7 @@ public final class RIL extends BaseCommands implements CommandsInterface RILRequest rr = RILRequest.obtain(RIL_REQUEST_OPERATOR, result); - if (RILJ_LOG) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); + if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); send(rr); } @@ -980,7 +989,7 @@ public final class RIL extends BaseCommands implements CommandsInterface RILRequest rr = RILRequest.obtain(RIL_REQUEST_DTMF, result); - if (RILJ_LOG) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); + if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); rr.mp.writeString(Character.toString(c)); @@ -992,7 +1001,7 @@ public final class RIL extends BaseCommands implements CommandsInterface RILRequest rr = RILRequest.obtain(RIL_REQUEST_DTMF_START, result); - if (RILJ_LOG) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); + if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); rr.mp.writeString(Character.toString(c)); @@ -1004,7 +1013,7 @@ public final class RIL extends BaseCommands implements CommandsInterface RILRequest rr = RILRequest.obtain(RIL_REQUEST_DTMF_STOP, result); - if (RILJ_LOG) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); + if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); send(rr); } @@ -1020,7 +1029,7 @@ public final class RIL extends BaseCommands implements CommandsInterface rr.mp.writeString(smscPDU); rr.mp.writeString(pdu); - if (RILJ_LOG) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); + if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); send(rr); } @@ -1032,9 +1041,9 @@ public final class RIL extends BaseCommands implements CommandsInterface rr.mp.writeInt(1); rr.mp.writeInt(index); - if (Config.LOGD) { - if (RILJ_LOG) riljLog(rr.serialString() + "> " - + requestToString(rr.mRequest) + if (RILJ_LOGD) { + riljLog(rr.serialString() + "> " + + requestToString(rr.mRequest) + " " + index); } @@ -1051,8 +1060,8 @@ public final class RIL extends BaseCommands implements CommandsInterface rr.mp.writeString(pdu); rr.mp.writeString(smsc); - if (Config.LOGD) { - if (RILJ_LOG) riljLog(rr.serialString() + "> " + if (RILJ_LOGD) { + riljLog(rr.serialString() + "> " + requestToString(rr.mRequest) + " " + status); } @@ -1091,7 +1100,7 @@ public final class RIL extends BaseCommands implements CommandsInterface rr.mp.writeString(user); rr.mp.writeString(password); - if (RILJ_LOG) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest) + " " + if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest) + " " + apn); send(rr); @@ -1106,7 +1115,7 @@ public final class RIL extends BaseCommands implements CommandsInterface rr.mp.writeInt(1); rr.mp.writeString(Integer.toString(cid)); - if (RILJ_LOG) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest) + " " + cid); + if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest) + " " + cid); send(rr); } @@ -1120,7 +1129,7 @@ public final class RIL extends BaseCommands implements CommandsInterface rr.mp.writeInt(1); rr.mp.writeInt(on ? 1 : 0); - if (RILJ_LOG) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); + if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); send(rr); } @@ -1134,10 +1143,8 @@ public final class RIL extends BaseCommands implements CommandsInterface rr.mp.writeInt(1); rr.mp.writeInt(enable ? 1 : 0); - if (Config.LOGD) { - if (RILJ_LOG) riljLog(rr.serialString() + "> " + if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); - } send(rr); } @@ -1151,7 +1158,7 @@ public final class RIL extends BaseCommands implements CommandsInterface rr.mp.writeInt(1); rr.mp.writeInt(success ? 1 : 0); - if (RILJ_LOG) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); + if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); send(rr); } @@ -1172,7 +1179,7 @@ public final class RIL extends BaseCommands implements CommandsInterface rr.mp.writeString(data); rr.mp.writeString(pin2); - if (RILJ_LOG) riljLog(rr.serialString() + "> simIO: " + requestToString(rr.mRequest) + if (RILJ_LOGD) riljLog(rr.serialString() + "> simIO: " + requestToString(rr.mRequest) + " 0x" + Integer.toHexString(command) + " 0x" + Integer.toHexString(fileid) + " " + p1 + "," + p2 + "," + p3); @@ -1186,7 +1193,7 @@ public final class RIL extends BaseCommands implements CommandsInterface RILRequest rr = RILRequest.obtain(RIL_REQUEST_GET_CLIR, result); - if (RILJ_LOG) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); + if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); send(rr); } @@ -1202,7 +1209,7 @@ public final class RIL extends BaseCommands implements CommandsInterface rr.mp.writeInt(clirMode); - if (RILJ_LOG) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest) + if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest) + " " + clirMode); send(rr); @@ -1217,7 +1224,7 @@ public final class RIL extends BaseCommands implements CommandsInterface rr.mp.writeInt(1); rr.mp.writeInt(serviceClass); - if (RILJ_LOG) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest) + if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest) + " " + serviceClass); send(rr); @@ -1233,7 +1240,7 @@ public final class RIL extends BaseCommands implements CommandsInterface rr.mp.writeInt(enable ? 1 : 0); rr.mp.writeInt(serviceClass); - if (RILJ_LOG) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest) + if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest) + " " + enable + ", " + serviceClass); send(rr); @@ -1246,7 +1253,7 @@ public final class RIL extends BaseCommands implements CommandsInterface = RILRequest.obtain(RIL_REQUEST_SET_NETWORK_SELECTION_AUTOMATIC, response); - if (RILJ_LOG) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); + if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); send(rr); } @@ -1258,7 +1265,7 @@ public final class RIL extends BaseCommands implements CommandsInterface = RILRequest.obtain(RIL_REQUEST_SET_NETWORK_SELECTION_MANUAL, response); - if (RILJ_LOG) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest) + if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest) + " " + operatorNumeric); rr.mp.writeString(operatorNumeric); @@ -1273,7 +1280,7 @@ public final class RIL extends BaseCommands implements CommandsInterface = RILRequest.obtain(RIL_REQUEST_QUERY_NETWORK_SELECTION_MODE, response); - if (RILJ_LOG) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); + if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); send(rr); } @@ -1285,7 +1292,7 @@ public final class RIL extends BaseCommands implements CommandsInterface = RILRequest.obtain(RIL_REQUEST_QUERY_AVAILABLE_NETWORKS, response); - if (RILJ_LOG) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); + if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); send(rr); } @@ -1304,7 +1311,7 @@ public final class RIL extends BaseCommands implements CommandsInterface rr.mp.writeString(number); rr.mp.writeInt (timeSeconds); - if (RILJ_LOG) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest) + if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest) + " " + action + " " + cfReason + " " + serviceClass + timeSeconds); @@ -1325,7 +1332,7 @@ public final class RIL extends BaseCommands implements CommandsInterface rr.mp.writeString(number); rr.mp.writeInt (0); - if (RILJ_LOG) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest) + if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest) + " " + cfReason + " " + serviceClass); send(rr); @@ -1337,7 +1344,7 @@ public final class RIL extends BaseCommands implements CommandsInterface RILRequest rr = RILRequest.obtain(RIL_REQUEST_QUERY_CLIP, response); - if (RILJ_LOG) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); + if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); send(rr); } @@ -1349,7 +1356,7 @@ public final class RIL extends BaseCommands implements CommandsInterface RILRequest rr = RILRequest.obtain(RIL_REQUEST_BASEBAND_VERSION, response); - if (RILJ_LOG) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); + if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); send(rr); } @@ -1360,7 +1367,7 @@ public final class RIL extends BaseCommands implements CommandsInterface { RILRequest rr = RILRequest.obtain(RIL_REQUEST_QUERY_FACILITY_LOCK, response); - if (RILJ_LOG) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); + if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); // count strings rr.mp.writeInt(3); @@ -1381,7 +1388,7 @@ public final class RIL extends BaseCommands implements CommandsInterface RILRequest rr = RILRequest.obtain(RIL_REQUEST_SET_FACILITY_LOCK, response); - if (RILJ_LOG) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); + if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); // count strings rr.mp.writeInt(4); @@ -1402,7 +1409,7 @@ public final class RIL extends BaseCommands implements CommandsInterface RILRequest rr = RILRequest.obtain(RIL_REQUEST_SEND_USSD, response); - if (RILJ_LOG) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest) + if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest) + " " + ussdString); rr.mp.writeString(ussdString); @@ -1415,7 +1422,7 @@ public final class RIL extends BaseCommands implements CommandsInterface RILRequest rr = RILRequest.obtain(RIL_REQUEST_CANCEL_USSD, response); - if (RILJ_LOG) riljLog(rr.serialString() + if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); send(rr); @@ -1427,7 +1434,7 @@ public final class RIL extends BaseCommands implements CommandsInterface RILRequest rr = RILRequest.obtain(RIL_REQUEST_RESET_RADIO, result); - if (RILJ_LOG) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); + if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); send(rr); } @@ -1437,7 +1444,7 @@ public final class RIL extends BaseCommands implements CommandsInterface RILRequest rr = RILRequest.obtain(RIL_REQUEST_OEM_HOOK_RAW, response); - if (RILJ_LOG) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest) + if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest) + "[" + SimUtils.bytesToHexString(data) + "]"); rr.mp.writeByteArray(data); @@ -1451,7 +1458,7 @@ public final class RIL extends BaseCommands implements CommandsInterface RILRequest rr = RILRequest.obtain(RIL_REQUEST_OEM_HOOK_STRINGS, response); - if (RILJ_LOG) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); + if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); rr.mp.writeStringArray(strings); @@ -1471,7 +1478,7 @@ public final class RIL extends BaseCommands implements CommandsInterface rr.mp.writeInt(1); rr.mp.writeInt(bandMode); - if (RILJ_LOG) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest) + if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest) + " " + bandMode); send(rr); @@ -1489,7 +1496,7 @@ public final class RIL extends BaseCommands implements CommandsInterface = RILRequest.obtain(RIL_REQUEST_QUERY_AVAILABLE_BAND_MODE, response); - if (RILJ_LOG) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); + if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); send(rr); } @@ -1501,7 +1508,7 @@ public final class RIL extends BaseCommands implements CommandsInterface RILRequest rr = RILRequest.obtain( RILConstants.RIL_REQUEST_STK_SEND_TERMINAL_RESPONSE, response); - if (RILJ_LOG) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); + if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); rr.mp.writeString(contents); send(rr); @@ -1514,7 +1521,7 @@ public final class RIL extends BaseCommands implements CommandsInterface RILRequest rr = RILRequest.obtain( RILConstants.RIL_REQUEST_STK_SEND_ENVELOPE_COMMAND, response); - if (RILJ_LOG) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); + if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); rr.mp.writeString(contents); send(rr); @@ -1530,7 +1537,7 @@ public final class RIL extends BaseCommands implements CommandsInterface RILConstants.RIL_REQUEST_STK_HANDLE_CALL_SETUP_REQUESTED_FROM_SIM, response); - if (RILJ_LOG) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); + if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); int[] param = new int[1]; param[0] = accept ? 1 : 0; @@ -1548,7 +1555,7 @@ public final class RIL extends BaseCommands implements CommandsInterface rr.mp.writeInt(1); rr.mp.writeInt(networkType); - if (RILJ_LOG) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest) + if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest) + " : " + networkType); send(rr); @@ -1561,7 +1568,7 @@ public final class RIL extends BaseCommands implements CommandsInterface RILRequest rr = RILRequest.obtain( RILConstants.RIL_REQUEST_GET_PREFERRED_NETWORK_TYPE, response); - if (RILJ_LOG) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); + if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); send(rr); } @@ -1573,7 +1580,7 @@ public final class RIL extends BaseCommands implements CommandsInterface RILRequest rr = RILRequest.obtain( RILConstants.RIL_REQUEST_GET_NEIGHBORING_CELL_IDS, response); - if (RILJ_LOG) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); + if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); send(rr); } @@ -1586,7 +1593,7 @@ public final class RIL extends BaseCommands implements CommandsInterface rr.mp.writeInt(1); rr.mp.writeInt(enable ? 1 : 0); - if (RILJ_LOG) riljLog(rr.serialString() + "> " + if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest) + ": " + enable); send(rr); @@ -1600,7 +1607,7 @@ public final class RIL extends BaseCommands implements CommandsInterface rr.mp.writeInt(1); rr.mp.writeInt(on ? 1 : 0); - if (RILJ_LOG) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest) + ": " + on); + if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest) + ": " + on); send(rr); } @@ -1640,7 +1647,7 @@ public final class RIL extends BaseCommands implements CommandsInterface * (eg, if it or the runtime crashed) without the RIL * and/or radio knowing. */ - if (DBG) Log.d(LOG_TAG, "Radio ON @ init; reset to OFF"); + if (RILJ_LOGD) Log.d(LOG_TAG, "Radio ON @ init; reset to OFF"); setRadioPower(false, null); return; } @@ -1665,9 +1672,9 @@ public final class RIL extends BaseCommands implements CommandsInterface mWakeLock.acquire(); mRequestMessagesPending++; - mSenderH.removeMessages(EVENT_WAKE_LOCK_TIMEOUT); - Message msg = mSenderH.obtainMessage(EVENT_WAKE_LOCK_TIMEOUT); - mSenderH.sendMessageDelayed(msg, WAKE_LOCK_TIMEOUT); + mSender.removeMessages(EVENT_WAKE_LOCK_TIMEOUT); + Message msg = mSender.obtainMessage(EVENT_WAKE_LOCK_TIMEOUT); + mSender.sendMessageDelayed(msg, WAKE_LOCK_TIMEOUT); } } @@ -1678,7 +1685,7 @@ public final class RIL extends BaseCommands implements CommandsInterface if (mWakeLock.isHeld() && (mRequestMessagesPending == 0) && (mRequestsList.size() == 0)) { - mSenderH.removeMessages(EVENT_WAKE_LOCK_TIMEOUT); + mSender.removeMessages(EVENT_WAKE_LOCK_TIMEOUT); mWakeLock.release(); } } @@ -1689,7 +1696,7 @@ public final class RIL extends BaseCommands implements CommandsInterface { Message msg; - msg = mSenderH.obtainMessage(EVENT_SEND, rr); + msg = mSender.obtainMessage(EVENT_SEND, rr); acquireWakeLock(); @@ -1837,7 +1844,7 @@ public final class RIL extends BaseCommands implements CommandsInterface case RIL_REQUEST_EXPLICIT_CALL_TRANSFER: ret = responseVoid(p); break; case RIL_REQUEST_SET_PREFERRED_NETWORK_TYPE: ret = responseVoid(p); break; case RIL_REQUEST_GET_PREFERRED_NETWORK_TYPE: ret = responseInts(p); break; - case RIL_REQUEST_GET_NEIGHBORING_CELL_IDS: ret = responseStrings(p); break; + case RIL_REQUEST_GET_NEIGHBORING_CELL_IDS: ret = responseCellList(p); break; case RIL_REQUEST_SET_LOCATION_UPDATES: ret = responseVoid(p); break; default: @@ -1857,7 +1864,7 @@ public final class RIL extends BaseCommands implements CommandsInterface return; } - if (RILJ_LOG) riljLog(rr.serialString() + "< " + requestToString(rr.mRequest) + if (RILJ_LOGD) riljLog(rr.serialString() + "< " + requestToString(rr.mRequest) + " " + retToString(rr.mRequest, ret)); if (rr.mResult != null) { @@ -1916,6 +1923,14 @@ public final class RIL extends BaseCommands implements CommandsInterface sb.append("[").append(dc).append("] "); } s = sb.toString(); + } else if (req == RIL_REQUEST_GET_NEIGHBORING_CELL_IDS) { + ArrayList cells; + cells = (ArrayList) ret; + sb = new StringBuilder(" "); + for (NeighboringCellInfo cell : cells) { + sb.append(cell).append(" "); + } + s = sb.toString(); } else { s = ret.toString(); } @@ -1959,8 +1974,8 @@ public final class RIL extends BaseCommands implements CommandsInterface throw new RuntimeException("Unrecognized unsol response: " + response); //break; (implied) }} catch (Throwable tr) { - Log.e(LOG_TAG, "Exception processing unsol response: " - + response, tr); + Log.e(LOG_TAG, "Exception processing unsol response: " + response + + "Exception:" + tr.toString()); return; } @@ -1969,22 +1984,22 @@ public final class RIL extends BaseCommands implements CommandsInterface /* has bonus radio state int */ setRadioStateFromRILInt(p.readInt()); - if (RILJ_LOG) riljLog("[UNSL]< RADIO_STATE_CHANGED " +mState); + if (RILJ_LOGD) unsljLogMore(response, mState.toString()); break; case RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED: - if (RILJ_LOG) riljLog("[UNSL]< CALL_STATE_CHANGED"); + if (RILJ_LOGD) unsljLog(response); mCallStateRegistrants .notifyRegistrants(new AsyncResult(null, null, null)); break; case RIL_UNSOL_RESPONSE_NETWORK_STATE_CHANGED: - if (RILJ_LOG) riljLog("[UNSL]< NETWORK_STATE_CHANGED"); + if (RILJ_LOGD) unsljLog(response); mNetworkStateRegistrants .notifyRegistrants(new AsyncResult(null, null, null)); break; case RIL_UNSOL_RESPONSE_NEW_SMS: { - if (RILJ_LOG) riljLog("[UNSL]< NEW_SMS"); + if (RILJ_LOGD) unsljLog(response); // FIXME this should move up a layer String a[] = new String[2]; @@ -2001,9 +2016,7 @@ public final class RIL extends BaseCommands implements CommandsInterface break; } case RIL_UNSOL_RESPONSE_NEW_SMS_STATUS_REPORT: - if (Config.LOGD) { - if (RILJ_LOG) riljLog("[UNSL]< NEW_SMS_STATUS_REPORT " + ret); - } + if (RILJ_LOGD) unsljLogRet(response, ret); if (mSmsStatusRegistrant != null) { mSmsStatusRegistrant.notifyRegistrant( @@ -2011,7 +2024,7 @@ public final class RIL extends BaseCommands implements CommandsInterface } break; case RIL_UNSOL_RESPONSE_NEW_SMS_ON_SIM: - if (RILJ_LOG) riljLog("[UNSL]< NEW_SMS_ON_SIM" + retToString(response, ret)); + if (RILJ_LOGD) unsljLogRet(response, ret); int[] smsIndex = (int[])ret; @@ -2021,7 +2034,7 @@ public final class RIL extends BaseCommands implements CommandsInterface notifyRegistrant(new AsyncResult(null, smsIndex, null)); } } else { - if (RILJ_LOG) riljLog(" NEW_SMS_ON_SIM ERROR with wrong length " + if (RILJ_LOGD) riljLog(" NEW_SMS_ON_SIM ERROR with wrong length " + smsIndex.length); } break; @@ -2033,23 +2046,23 @@ public final class RIL extends BaseCommands implements CommandsInterface resp[0] = ((String[])ret)[0]; resp[1] = null; } - if (RILJ_LOG) riljLog("[UNSL]< ON_USSD " + resp[0]); + if (RILJ_LOGD) unsljLogMore(response, resp[0]); if (mUSSDRegistrant != null) { mUSSDRegistrant.notifyRegistrant( new AsyncResult (null, resp, null)); } break; case RIL_UNSOL_NITZ_TIME_RECEIVED: - if (RILJ_LOG) riljLog("[UNSL]< NITZ_TIME_RECEIVED " + retToString(response, ret)); + if (RILJ_LOGD) unsljLogRet(response, ret); - // has bonus int containing time_t that the NITZ + // has bonus long containing milliseconds since boot that the NITZ // time was received - int nitzReceiveTime = p.readInt(); + long nitzReceiveTime = p.readLong(); Object[] result = new Object[2]; result[0] = ret; - result[1] = Integer.valueOf(nitzReceiveTime); + result[1] = Long.valueOf(nitzReceiveTime); if (mNITZTimeRegistrant != null) { @@ -2064,8 +2077,7 @@ public final class RIL extends BaseCommands implements CommandsInterface case RIL_UNSOL_SIGNAL_STRENGTH: // Note this is set to "verbose" because it happens // frequently - if (Config.LOGV) Log.v(LOG_TAG, "[UNSL]< SIGNAL_STRENGTH " - + retToString(response, ret)); + if (RILJ_LOGV) unsljLogvRet(response, ret); if (mSignalStrengthRegistrant != null) { mSignalStrengthRegistrant.notifyRegistrant( @@ -2073,17 +2085,14 @@ public final class RIL extends BaseCommands implements CommandsInterface } break; case RIL_UNSOL_PDP_CONTEXT_LIST_CHANGED: - if (RILJ_LOG) riljLog("[UNSL]< PDP_CONTEXT_CHANGED " + retToString(response, ret)); + if (RILJ_LOGD) unsljLogRet(response, ret); mPDPRegistrants .notifyRegistrants(new AsyncResult(null, ret, null)); break; case RIL_UNSOL_SUPP_SVC_NOTIFICATION: - if (Config.LOGD) { - if (RILJ_LOG) riljLog("[UNSL]< SUPP_SVC_NOTIFICATION " - + retToString(response, ret)); - } + if (RILJ_LOGD) unsljLogRet(response, ret); if (mSsnRegistrant != null) { mSsnRegistrant.notifyRegistrant( @@ -2092,9 +2101,7 @@ public final class RIL extends BaseCommands implements CommandsInterface break; case RIL_UNSOL_STK_SESSION_END: - if (Config.LOGD) { - if (RILJ_LOG) riljLog("[UNSL]< STK_SESSION_END"); - } + if (RILJ_LOGD) unsljLog(response); if (mStkSessionEndRegistrant != null) { mStkSessionEndRegistrant.notifyRegistrant( @@ -2103,10 +2110,7 @@ public final class RIL extends BaseCommands implements CommandsInterface break; case RIL_UNSOL_STK_PROACTIVE_COMMAND: - if (Config.LOGD) { - if (RILJ_LOG) riljLog("[UNSL]< STK_PROACTIVE_COMMAND " - + retToString(response, ret)); - } + if (RILJ_LOGD) unsljLogRet(response, ret); if (mStkProCmdRegistrant != null) { mStkProCmdRegistrant.notifyRegistrant( @@ -2115,10 +2119,7 @@ public final class RIL extends BaseCommands implements CommandsInterface break; case RIL_UNSOL_STK_EVENT_NOTIFY: - if (Config.LOGD) { - if (RILJ_LOG) riljLog("[UNSL]< STK_EVENT_NOTIFY " - + retToString(response, ret)); - } + if (RILJ_LOGD) unsljLogRet(response, ret); if (mStkEventRegistrant != null) { mStkEventRegistrant.notifyRegistrant( @@ -2127,10 +2128,7 @@ public final class RIL extends BaseCommands implements CommandsInterface break; case RIL_UNSOL_STK_CALL_SETUP: - if (Config.LOGD) { - if (RILJ_LOG) riljLog("[UNSL]< STK_CALL_SETUP " - + retToString(response, ret)); - } + if (RILJ_LOGD) unsljLogRet(response, ret); if (mStkCallSetUpRegistrant != null) { mStkCallSetUpRegistrant.notifyRegistrant( @@ -2139,9 +2137,7 @@ public final class RIL extends BaseCommands implements CommandsInterface break; case RIL_UNSOL_SIM_SMS_STORAGE_FULL: - if (Config.LOGD) { - if (RILJ_LOG) riljLog("[UNSL]< SIM_SMS_STORAGE_FULL"); - } + if (RILJ_LOGD) unsljLog(response); if (mSimSmsFullRegistrant != null) { mSimSmsFullRegistrant.notifyRegistrant(); @@ -2149,9 +2145,7 @@ public final class RIL extends BaseCommands implements CommandsInterface break; case RIL_UNSOL_SIM_REFRESH: - if (Config.LOGD) { - if (RILJ_LOG) riljLog("[UNSL]< SIM_REFRESH " + retToString(response, ret)); - } + if (RILJ_LOGD) unsljLogRet(response, ret); if (mSimRefreshRegistrant != null) { mSimRefreshRegistrant.notifyRegistrant( @@ -2160,9 +2154,7 @@ public final class RIL extends BaseCommands implements CommandsInterface break; case RIL_UNSOL_CALL_RING: - if (Config.LOGD) { - if (RILJ_LOG) riljLog("[UNSL]< CALL_RING "); - } + if (RILJ_LOGD) unsljLog(response); if (mRingRegistrant != null) { mRingRegistrant.notifyRegistrant(); @@ -2410,6 +2402,29 @@ public final class RIL extends BaseCommands implements CommandsInterface return ret; } + private Object + responseCellList(Parcel p) + { + int num; + ArrayList response; + NeighboringCellInfo cell; + + num = p.readInt(); + response = new ArrayList(num); + + for (int i = 0 ; i < num ; i++) { + try { + int rssi = p.readInt(); + int cid = Integer.valueOf(p.readString(), 16); + cell = new NeighboringCellInfo(rssi, cid); + response.add(cell); + } catch ( Exception e) { + } + } + + return response; + } + static String requestToString(int request) @@ -2434,7 +2449,7 @@ public final class RIL extends BaseCommands implements CommandsInterface case RIL_REQUEST_HANGUP: return "HANGUP"; case RIL_REQUEST_HANGUP_WAITING_OR_BACKGROUND: return "HANGUP_WAITING_OR_BACKGROUND"; case RIL_REQUEST_HANGUP_FOREGROUND_RESUME_BACKGROUND: return "HANGUP_FOREGROUND_RESUME_BACKGROUND"; - case RIL_REQUEST_SWITCH_WAITING_OR_HOLDING_AND_ACTIVE: return "RIL_REQUEST_SWITCH_WAITING_OR_HOLDING_AND_ACTIVE"; + case RIL_REQUEST_SWITCH_WAITING_OR_HOLDING_AND_ACTIVE: return "REQUEST_SWITCH_WAITING_OR_HOLDING_AND_ACTIVE"; case RIL_REQUEST_CONFERENCE: return "CONFERENCE"; case RIL_REQUEST_UDUB: return "UDUB"; case RIL_REQUEST_LAST_CALL_FAIL_CAUSE: return "LAST_CALL_FAIL_CAUSE"; @@ -2486,21 +2501,74 @@ public final class RIL extends BaseCommands implements CommandsInterface case RIL_REQUEST_DELETE_SMS_ON_SIM: return "DELETE_SMS_ON_SIM"; case RIL_REQUEST_SET_BAND_MODE: return "SET_BAND_MODE"; case RIL_REQUEST_QUERY_AVAILABLE_BAND_MODE: return "QUERY_AVAILABLE_BAND_MODE"; - case RIL_REQUEST_STK_GET_PROFILE: return "RIL_REQUEST_STK_GET_PROFILE"; - case RIL_REQUEST_STK_SET_PROFILE: return "RIL_REQUEST_STK_SET_PROFILE"; - case RIL_REQUEST_STK_SEND_ENVELOPE_COMMAND: return "RIL_REQUEST_STK_SEND_ENVELOPE_COMMAND"; - case RIL_REQUEST_STK_SEND_TERMINAL_RESPONSE: return "RIL_REQUEST_STK_SEND_TERMINAL_RESPONSE"; - case RIL_REQUEST_STK_HANDLE_CALL_SETUP_REQUESTED_FROM_SIM: return "RIL_REQUEST_STK_HANDLE_CALL_SETUP_REQUESTED_FROM_SIM"; - case RIL_REQUEST_EXPLICIT_CALL_TRANSFER: return "RIL_REQUEST_EXPLICIT_CALL_TRANSFER"; - case RIL_REQUEST_SET_PREFERRED_NETWORK_TYPE: return "RIL_REQUEST_SET_PREFERRED_NETWORK_TYPE"; - case RIL_REQUEST_GET_PREFERRED_NETWORK_TYPE: return "RIL_REQUEST_GET_PREFERRED_NETWORK_TYPE"; - case RIL_REQUEST_GET_NEIGHBORING_CELL_IDS: return "RIL_REQUEST_GET_NEIGHBORING_CELL_IDS"; - case RIL_REQUEST_SET_LOCATION_UPDATES: return "RIL_REQUEST_SET_LOCATION_UPDATES"; + case RIL_REQUEST_STK_GET_PROFILE: return "REQUEST_STK_GET_PROFILE"; + case RIL_REQUEST_STK_SET_PROFILE: return "REQUEST_STK_SET_PROFILE"; + case RIL_REQUEST_STK_SEND_ENVELOPE_COMMAND: return "REQUEST_STK_SEND_ENVELOPE_COMMAND"; + case RIL_REQUEST_STK_SEND_TERMINAL_RESPONSE: return "REQUEST_STK_SEND_TERMINAL_RESPONSE"; + case RIL_REQUEST_STK_HANDLE_CALL_SETUP_REQUESTED_FROM_SIM: return "REQUEST_STK_HANDLE_CALL_SETUP_REQUESTED_FROM_SIM"; + case RIL_REQUEST_EXPLICIT_CALL_TRANSFER: return "REQUEST_EXPLICIT_CALL_TRANSFER"; + case RIL_REQUEST_SET_PREFERRED_NETWORK_TYPE: return "REQUEST_SET_PREFERRED_NETWORK_TYPE"; + case RIL_REQUEST_GET_PREFERRED_NETWORK_TYPE: return "REQUEST_GET_PREFERRED_NETWORK_TYPE"; + case RIL_REQUEST_GET_NEIGHBORING_CELL_IDS: return "REQUEST_GET_NEIGHBORING_CELL_IDS"; + case RIL_REQUEST_SET_LOCATION_UPDATES: return "REQUEST_SET_LOCATION_UPDATES"; default: return ""; } } + static String + responseToString(int request) + { +/* + cat libs/telephony/ril_unsol_commands.h \ + | egrep "^ *{RIL_" \ + | sed -re 's/\{RIL_([^,]+),[^,]+,([^}]+).+/case RIL_\1: return "\1";/' +*/ + switch(request) { + case RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED: return "UNSOL_RESPONSE_RADIO_STATE_CHANGED"; + case RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED: return "UNSOL_RESPONSE_CALL_STATE_CHANGED"; + case RIL_UNSOL_RESPONSE_NETWORK_STATE_CHANGED: return "UNSOL_RESPONSE_NETWORK_STATE_CHANGED"; + case RIL_UNSOL_RESPONSE_NEW_SMS: return "UNSOL_RESPONSE_NEW_SMS"; + case RIL_UNSOL_RESPONSE_NEW_SMS_STATUS_REPORT: return "UNSOL_RESPONSE_NEW_SMS_STATUS_REPORT"; + case RIL_UNSOL_RESPONSE_NEW_SMS_ON_SIM: return "UNSOL_RESPONSE_NEW_SMS_ON_SIM"; + case RIL_UNSOL_ON_USSD: return "UNSOL_ON_USSD"; + case RIL_UNSOL_ON_USSD_REQUEST: return "UNSOL_ON_USSD_REQUEST"; + case RIL_UNSOL_NITZ_TIME_RECEIVED: return "UNSOL_NITZ_TIME_RECEIVED"; + case RIL_UNSOL_SIGNAL_STRENGTH: return "UNSOL_SIGNAL_STRENGTH"; + case RIL_UNSOL_PDP_CONTEXT_LIST_CHANGED: return "UNSOL_PDP_CONTEXT_LIST_CHANGED"; + case RIL_UNSOL_SUPP_SVC_NOTIFICATION: return "UNSOL_SUPP_SVC_NOTIFICATION"; + case RIL_UNSOL_STK_SESSION_END: return "UNSOL_STK_SESSION_END"; + case RIL_UNSOL_STK_PROACTIVE_COMMAND: return "UNSOL_STK_PROACTIVE_COMMAND"; + case RIL_UNSOL_STK_EVENT_NOTIFY: return "UNSOL_STK_EVENT_NOTIFY"; + case RIL_UNSOL_STK_CALL_SETUP: return "UNSOL_STK_CALL_SETUP"; + case RIL_UNSOL_SIM_SMS_STORAGE_FULL: return "UNSOL_SIM_SMS_STORAGE_FULL"; + case RIL_UNSOL_SIM_REFRESH: return "UNSOL_SIM_REFRESH"; + case RIL_UNSOL_CALL_RING: return "UNSOL_CALL_RING"; + default: return ""; + } + } + private void riljLog(String msg) { Log.d(LOG_TAG, msg); } + + private void riljLogv(String msg) { + Log.v(LOG_TAG, msg); + } + + private void unsljLog(int response) { + riljLog("[UNSL]< " + responseToString(response)); + } + + private void unsljLogMore(int response, String more) { + riljLog("[UNSL]< " + responseToString(response) + " " + more); + } + + private void unsljLogRet(int response, Object ret) { + riljLog("[UNSL]< " + responseToString(response) + " " + retToString(response, ret)); + } + + private void unsljLogvRet(int response, Object ret) { + riljLogv("[UNSL]< " + responseToString(response) + " " + retToString(response, ret)); + } + } diff --git a/telephony/java/com/android/internal/telephony/gsm/SIMRecords.java b/telephony/java/com/android/internal/telephony/gsm/SIMRecords.java index ebbf501986a06e8331967dd25fa0e0e3320a8686..75f56a35b87e9c0f44015af8104ca09784f0a65e 100644 --- a/telephony/java/com/android/internal/telephony/gsm/SIMRecords.java +++ b/telephony/java/com/android/internal/telephony/gsm/SIMRecords.java @@ -16,14 +16,21 @@ package com.android.internal.telephony.gsm; +import android.app.AlarmManager; +import android.content.Context; import android.os.AsyncResult; import android.os.RegistrantList; import android.os.Registrant; import android.os.Handler; import android.os.Message; +import android.os.SystemProperties; import android.telephony.gsm.SmsMessage; import android.util.Log; import java.util.ArrayList; +import android.app.ActivityManagerNative; +import android.app.IActivityManager; +import java.util.Locale; +import android.content.res.Configuration; import static com.android.internal.telephony.TelephonyProperties.*; import com.android.internal.telephony.SimCard; @@ -149,6 +156,8 @@ public final class SIMRecords extends Handler implements SimConstants private static final int EVENT_SIM_REFRESH = 31; private static final int EVENT_GET_CFIS_DONE = 32; + private static final String TIMEZONE_PROPERTY = "persist.sys.timezone"; + //***** Constructor SIMRecords(GSMPhone phone) @@ -199,7 +208,6 @@ public final class SIMRecords extends Handler implements SimConstants adnCache.reset(); - phone.setSystemProperty(PROPERTY_LINE1_VOICE_MAIL_WAITING, null); phone.setSystemProperty(PROPERTY_SIM_OPERATOR_NUMERIC, null); phone.setSystemProperty(PROPERTY_SIM_OPERATOR_ALPHA, null); phone.setSystemProperty(PROPERTY_SIM_OPERATOR_ISO_COUNTRY, null); @@ -309,7 +317,7 @@ public final class SIMRecords extends Handler implements SimConstants Message onComplete) { if (isVoiceMailFixed) { AsyncResult.forMessage((onComplete)).exception = - new SimException("Voicemail number is fixed by operator"); + new SimVmFixedException("Voicemail number is fixed by operator"); onComplete.sendToTarget(); return; } @@ -331,9 +339,9 @@ public final class SIMRecords extends Handler implements SimConstants EF_EXT1, 1, null, obtainMessage(EVENT_SET_CPHS_MAILBOX_DONE, onComplete)); - } else { + }else { AsyncResult.forMessage((onComplete)).exception = - new SimException("Update SIM voice mailbox error"); + new SimVmNotSupportedException("Update SIM voice mailbox error"); onComplete.sendToTarget(); } } @@ -369,9 +377,6 @@ public final class SIMRecords extends Handler implements SimConstants countVoiceMessages = countWaiting; - phone.setSystemProperty(PROPERTY_LINE1_VOICE_MAIL_WAITING, - (countVoiceMessages != 0) ? "true" : "false"); - phone.notifyMessageWaitingIndicator(); try { @@ -437,9 +442,6 @@ public final class SIMRecords extends Handler implements SimConstants callForwardingEnabled = enable; - phone.setSystemProperty(PROPERTY_LINE1_VOICE_CALL_FORWARDING, - (callForwardingEnabled ? "true" : "false")); - phone.notifyCallForwardingIndicator(); try { @@ -528,6 +530,73 @@ public final class SIMRecords extends Handler implements SimConstants } } + /** + * If the timezone is not already set, set it based on the MCC of the SIM. + * @param mcc Mobile Country Code of the SIM + */ + private void setTimezoneFromMccIfNeeded(int mcc) { + String timezone = SystemProperties.get(TIMEZONE_PROPERTY); + if (timezone == null || timezone.length() == 0) { + String zoneId = MccTable.defaultTimeZoneForMcc(mcc); + + if (zoneId != null && zoneId.length() > 0) { + // Set time zone based on MCC + AlarmManager alarm = + (AlarmManager) phone.getContext().getSystemService(Context.ALARM_SERVICE); + alarm.setTimeZone(zoneId); + } + } + } + + /** + * If the locale is not already set, set it based on the MCC of the SIM. + * @param mcc Mobile Country Code of the SIM + */ + private void setLocaleFromMccIfNeeded(int mcc) { + String language = SystemProperties.get("persist.sys.language"); + String country = SystemProperties.get("persist.sys.country"); + Log.d(LOG_TAG,"setLocaleFromMcc"); + if((language == null || language.length() == 0) && (country == null || country.length() == 0)) { + try { + language = MccTable.defaultLanguageForMcc(mcc); + country = MccTable.countryCodeForMcc(mcc).toUpperCase(); + // try to find a good match + String[] locales = phone.getContext().getAssets().getLocales(); + final int N = locales.length; + String bestMatch = null; + for(int i = 0; i < N; i++) { + Log.d(LOG_TAG," trying "+locales[i]); + if(locales[i]!=null && locales[i].length() >= 2 && + locales[i].substring(0,2).equals(language)) { + if(locales[i].length() >= 5 && + locales[i].substring(3,5).equals(country)) { + bestMatch = locales[i]; + break; + } else if(bestMatch == null) { + bestMatch = locales[i]; + } + } + } + Log.d(LOG_TAG," got bestmatch = "+bestMatch); + if(bestMatch != null) { + IActivityManager am = ActivityManagerNative.getDefault(); + Configuration config = am.getConfiguration(); + + if(bestMatch.length() >= 5) { + config.locale = new Locale(bestMatch.substring(0,2), + bestMatch.substring(3,5)); + } else { + config.locale = new Locale(bestMatch.substring(0,2)); + } + config.userSetLocale = true; + am.updateConfiguration(config); + } + } catch (Exception e) { + // Intentionally left blank + } + } + } + //***** Overridden from Handler public void handleMessage(Message msg) { @@ -554,7 +623,7 @@ public final class SIMRecords extends Handler implements SimConstants ar = (AsyncResult)msg.obj; if (ar.exception != null) { - Log.e(LOG_TAG, "Exception querying IMSI", ar.exception); + Log.e(LOG_TAG, "Exception querying IMSI, Exception:" + ar.exception); break; } @@ -571,6 +640,10 @@ public final class SIMRecords extends Handler implements SimConstants phone.mSimCard.updateImsiConfiguration(imsi); phone.mSimCard.broadcastSimStateChangedIntent( SimCard.INTENT_VALUE_SIM_IMSI, null); + + int mcc = Integer.parseInt(imsi.substring(0, 3)); + setTimezoneFromMccIfNeeded(mcc); + setLocaleFromMccIfNeeded(mcc); break; case EVENT_GET_MBI_DONE: @@ -716,8 +789,6 @@ public final class SIMRecords extends Handler implements SimConstants countVoiceMessages = -1; } - phone.setSystemProperty(PROPERTY_LINE1_VOICE_MAIL_WAITING, - voiceMailWaiting ? "true" : "false"); phone.notifyMessageWaitingIndicator(); break; @@ -747,9 +818,6 @@ public final class SIMRecords extends Handler implements SimConstants countVoiceMessages = 0; } - phone.setSystemProperty(PROPERTY_LINE1_VOICE_MAIL_WAITING, - countVoiceMessages != 0 - ? "true" : "false"); phone.notifyMessageWaitingIndicator(); } break; @@ -831,9 +899,6 @@ public final class SIMRecords extends Handler implements SimConstants callForwardingEnabled = ((data[0] & CFF_LINE1_MASK) == CFF_UNCONDITIONAL_ACTIVE); - phone.setSystemProperty(PROPERTY_LINE1_VOICE_CALL_FORWARDING, - (callForwardingEnabled ? "true" : "false")); - phone.notifyCallForwardingIndicator(); } break; @@ -1010,6 +1075,7 @@ public final class SIMRecords extends Handler implements SimConstants case EVENT_SIM_REFRESH: isRecordLoadResponse = false; ar = (AsyncResult)msg.obj; + if (DBG) log("Sim REFRESH with exception: " + ar.exception); if (ar.exception == null) { handleSimRefresh((int[])(ar.result)); } @@ -1032,9 +1098,6 @@ public final class SIMRecords extends Handler implements SimConstants // Refer TS 51.011 Section 10.3.46 for the content description callForwardingEnabled = ((data[1] & 0x01) != 0); - phone.setSystemProperty(PROPERTY_LINE1_VOICE_CALL_FORWARDING, - (callForwardingEnabled ? "true" : "false")); - phone.notifyCallForwardingIndicator(); break; @@ -1071,22 +1134,27 @@ public final class SIMRecords extends Handler implements SimConstants } } - private void handleSimRefresh(int[] result) { + private void handleSimRefresh(int[] result) { if (result == null || result.length == 0) { + if (DBG) log("handleSimRefresh without input"); return; } - + switch ((result[0])) { case CommandsInterface.SIM_REFRESH_FILE_UPDATED: - // result[1] contains the EFID of the updated file. + if (DBG) log("handleSimRefresh with SIM_REFRESH_FILE_UPDATED"); + // result[1] contains the EFID of the updated file. int efid = result[1]; handleFileUpdate(efid); break; case CommandsInterface.SIM_REFRESH_INIT: + if (DBG) log("handleSimRefresh with SIM_REFRESH_INIT"); // need to reload all files (that we care about) + adnCache.reset(); fetchSimRecords(); break; case CommandsInterface.SIM_REFRESH_RESET: + if (DBG) log("handleSimRefresh with SIM_REFRESH_RESET"); phone.mCM.setRadioPower(false, null); /* Note: no need to call setRadioPower(true). Assuming the desired * radio power state is still ON (as tracked by ServiceStateTracker), @@ -1098,6 +1166,7 @@ public final class SIMRecords extends Handler implements SimConstants break; default: // unknown refresh operation + if (DBG) log("handleSimRefresh with unknown operation"); break; } } diff --git a/telephony/java/com/android/internal/telephony/gsm/SMSDispatcher.java b/telephony/java/com/android/internal/telephony/gsm/SMSDispatcher.java index 258c05815a84c0e3effce801867b53f230da0640..daf4b9cac920107c622eddeda2be7230769315d3 100644 --- a/telephony/java/com/android/internal/telephony/gsm/SMSDispatcher.java +++ b/telephony/java/com/android/internal/telephony/gsm/SMSDispatcher.java @@ -33,6 +33,7 @@ import android.os.AsyncResult; import android.os.Handler; import android.os.Message; import android.provider.Telephony; +import android.provider.Settings; import android.provider.Telephony.Sms.Intents; import android.telephony.gsm.SmsMessage; import android.telephony.gsm.SmsManager; @@ -56,7 +57,7 @@ final class SMSDispatcher extends Handler { private static final int DEFAULT_SMS_CHECK_PERIOD = 3600000; /** Default number of SMS sent in checking period without uesr permit */ - private static final int DEFAULT_SMS_MAX_ALLOWED = 100; + private static final int DEFAULT_SMS_MAX_COUNT = 100; /** Default timeout for SMS sent query */ private static final int DEFAULT_SMS_TIMOUEOUT = 6000; @@ -199,8 +200,14 @@ final class SMSDispatcher extends Handler { mResolver = mContext.getContentResolver(); mCm = phone.mCM; mSTracker = null; - mCounter = new SmsCounter(DEFAULT_SMS_MAX_ALLOWED, + + int check_period = Settings.Gservices.getInt(mResolver, + Settings.Gservices.SMS_OUTGOING_CEHCK_INTERVAL_MS, DEFAULT_SMS_CHECK_PERIOD); + int max_count = Settings.Gservices.getInt(mResolver, + Settings.Gservices.SMS_OUTGOING_CEHCK_MAX_COUNT, + DEFAULT_SMS_MAX_COUNT); + mCounter = new SmsCounter(max_count, check_period); mCm.setOnNewSMS(this, EVENT_NEW_SMS, null); mCm.setOnSmsStatus(this, EVENT_NEW_SMS_STATUS_REPORT, null); @@ -245,8 +252,7 @@ final class SMSDispatcher extends Handler { } if (ar.exception != null) { - Log.e(TAG, "Exception processing incoming SMS", - ar.exception); + Log.e(TAG, "Exception processing incoming SMS. Exception:" + ar.exception); return; } diff --git a/telephony/java/com/android/internal/telephony/gsm/ServiceStateTracker.java b/telephony/java/com/android/internal/telephony/gsm/ServiceStateTracker.java index 1c337f9c6a83e9fb2e91584f7c0bc727b2f99e69..a4b8b476844932ef4d72bcb277739a83a21f1201 100644 --- a/telephony/java/com/android/internal/telephony/gsm/ServiceStateTracker.java +++ b/telephony/java/com/android/internal/telephony/gsm/ServiceStateTracker.java @@ -18,7 +18,6 @@ package com.android.internal.telephony.gsm; import static com.android.internal.telephony.TelephonyProperties.PROPERTY_DATA_NETWORK_TYPE; import static com.android.internal.telephony.TelephonyProperties.PROPERTY_OPERATOR_ALPHA; -import static com.android.internal.telephony.TelephonyProperties.PROPERTY_OPERATOR_ISMANUAL; import static com.android.internal.telephony.TelephonyProperties.PROPERTY_OPERATOR_ISO_COUNTRY; import static com.android.internal.telephony.TelephonyProperties.PROPERTY_OPERATOR_ISROAMING; import static com.android.internal.telephony.TelephonyProperties.PROPERTY_OPERATOR_NUMERIC; @@ -45,8 +44,10 @@ import android.provider.Telephony.Intents; import android.telephony.gsm.GsmCellLocation; import android.telephony.ServiceState; import android.text.TextUtils; +import android.util.Config; import android.util.Log; import android.util.TimeUtils; +import android.util.EventLog; import java.util.Arrays; import java.util.Calendar; @@ -130,6 +131,12 @@ final class ServiceStateTracker extends Handler // SIMRecords object may not be instantiated yet. private boolean mNeedToRegForSimLoaded; + // Started the recheck process after finding gprs should registerd but not + private boolean mStartedGprsRegCheck = false; + // Already sent the event-log for no gprs register + private boolean mReportedGprsNoReg = false; + + // Keep track of SPN display rules, so we only broadcast intent if something changes. private String curSpn = null; private String curPlmn = null; @@ -143,6 +150,9 @@ final class ServiceStateTracker extends Handler // signal strength poll rate static final int POLL_PERIOD_MILLIS = 20 * 1000; + // waiting period before recheck gprs and voice registration + static final int DEFAULT_GPRS_CHECK_PERIOD_MILLIS = 60 * 1000; + //***** Events static final int EVENT_RADIO_STATE_CHANGED = 1; @@ -163,7 +173,11 @@ final class ServiceStateTracker extends Handler static final int EVENT_GET_PREFERRED_NETWORK_TYPE = 19; static final int EVENT_SET_PREFERRED_NETWORK_TYPE = 20; static final int EVENT_RESET_PREFERRED_NETWORK_TYPE = 21; + static final int EVENT_CHECK_REPORT_GPRS = 22; + // Event Log Tags + private static final int EVENT_LOG_CGREG_FAIL = 50107; + private static final int EVENT_DATA_STATE_RADIO_OFF = 50108; //***** Time Zones @@ -460,7 +474,7 @@ final class ServiceStateTracker extends Handler ar = (AsyncResult) msg.obj; String nitzString = (String)((Object[])ar.result)[0]; - int nitzReceiveTime = ((Integer)((Object[])ar.result)[1]).intValue(); + long nitzReceiveTime = ((Long)((Object[])ar.result)[1]).longValue(); setTimeFromNITZString(nitzString, nitzReceiveTime); break; @@ -523,6 +537,23 @@ final class ServiceStateTracker extends Handler cm.setPreferredNetworkType(toggledNetworkType, message); break; + case EVENT_CHECK_REPORT_GPRS: + if (ss != null && !isGprsConsistant(gprsState, ss.getState())) { + + // Can't register data sevice while voice service is ok + // i.e. CREG is ok while CGREG is not + // possible a network or baseband side error + int cid = -1; + GsmCellLocation loc = ((GsmCellLocation)phone.getCellLocation()); + if (loc != null) cid = loc.getCid(); + + EventLog.List val = new EventLog.List(ss.getOperatorNumeric(), cid); + EventLog.writeEvent(EVENT_LOG_CGREG_FAIL, val); + mReportedGprsNoReg = true; + } + mStartedGprsRegCheck = false; + break; + } } @@ -561,6 +592,14 @@ final class ServiceStateTracker extends Handler ) { cm.setRadioPower(true, null); } else if (!mDesiredPowerState && cm.getRadioState().isOn()) { + DataConnectionTracker dcTracker = phone.mDataConnection; + if (! dcTracker.isDataConnectionAsDesired()) { + + EventLog.List val = new EventLog.List( + dcTracker.getStateInString(), + (dcTracker.getAnyDataEnabled() ? 1 : 0) ); + EventLog.writeEvent(EVENT_DATA_STATE_RADIO_OFF, val); + } // If it's on and available and we want it off.. cm.setRadioPower(false, null); } // Otherwise, we're in the desired state @@ -609,7 +648,7 @@ final class ServiceStateTracker extends Handler if (err != CommandException.Error.OP_NOT_ALLOWED_BEFORE_REG_NW && err != CommandException.Error.OP_NOT_ALLOWED_BEFORE_REG_NW) { Log.e(LOG_TAG, - "RIL implementation has returned an error where it must succeed", + "RIL implementation has returned an error where it must succeed" + ar.exception); } } else try { @@ -882,8 +921,7 @@ final class ServiceStateTracker extends Handler // need adjust time to reflect default timezone setting long tzOffset; tzOffset = zone.getOffset(System.currentTimeMillis()); - SystemClock.setCurrentTimeMillis( - System.currentTimeMillis() - tzOffset); + setAndBroadcastNetworkSetTime(System.currentTimeMillis() - tzOffset); } else if (iso.equals("")){ // Country code not found. This is likely a test network. // Get a TimeZone based only on the NITZ parameters (best guess). @@ -896,10 +934,8 @@ final class ServiceStateTracker extends Handler mNeedFixZone = false; if (zone != null) { - Context context = phone.getContext(); if (getAutoTime()) { - AlarmManager alarm = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); - alarm.setTimeZone(zone.getID()); + setAndBroadcastNetworkSetTimeZone(zone.getID()); } saveNitzTimeZone(zone.getID()); } @@ -908,8 +944,6 @@ final class ServiceStateTracker extends Handler phone.setSystemProperty(PROPERTY_OPERATOR_ISROAMING, ss.getRoaming() ? "true" : "false"); - phone.setSystemProperty(PROPERTY_OPERATOR_ISMANUAL, - ss.getIsManualSelection() ? "true" : "false"); updateSpnDisplay(); phone.notifyServiceStateChanged(ss); @@ -938,8 +972,35 @@ final class ServiceStateTracker extends Handler if (hasLocationChanged) { phone.notifyLocationChanged(); } + + if (! isGprsConsistant(gprsState, ss.getState())) { + if (!mStartedGprsRegCheck && !mReportedGprsNoReg) { + mStartedGprsRegCheck = true; + + int check_period = Settings.Gservices.getInt( + phone.getContext().getContentResolver(), + Settings.Gservices.GPRS_REGISTER_CHECK_PERIOD_MS, + DEFAULT_GPRS_CHECK_PERIOD_MILLIS); + sendMessageDelayed(obtainMessage(EVENT_CHECK_REPORT_GPRS), + check_period); + } + } else { + mReportedGprsNoReg = false; + } } - + + /** + * Check if GPRS got registred while voice is registered + * + * @param gprsState for GPRS registration state, i.e. CGREG in GSM + * @param serviceState for voice registration state, i.e. CREG in GSM + * @return false if device only register to voice but not gprs + */ + private boolean isGprsConsistant (int gprsState, int serviceState) { + return !((serviceState == ServiceState.STATE_IN_SERVICE) && + (gprsState != ServiceState.STATE_IN_SERVICE)); + } + /** * Returns a TimeZone object based only on parameters from the NITZ string. */ @@ -1162,13 +1223,14 @@ final class ServiceStateTracker extends Handler */ private - void setTimeFromNITZString (String nitz, int nitzReceiveTime) + void setTimeFromNITZString (String nitz, long nitzReceiveTime) { // "yy/mm/dd,hh:mm:ss(+/-)tz" // tz is in number of quarter-hours - Log.i(LOG_TAG, "setTimeFromNITZString: " + - nitz + "," + nitzReceiveTime); + long start = SystemClock.elapsedRealtime(); + Log.i(LOG_TAG, "NITZ: " + nitz + "," + nitzReceiveTime + + " start=" + start + " delay=" + (start - nitzReceiveTime)); try { /* NITZ time (hour:min:sec) will be in UTC but it supplies the timezone @@ -1257,57 +1319,57 @@ final class ServiceStateTracker extends Handler } if (zone != null) { - Context context = phone.getContext(); if (getAutoTime()) { - AlarmManager alarm = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); - alarm.setTimeZone(zone.getID()); + setAndBroadcastNetworkSetTimeZone(zone.getID()); } saveNitzTimeZone(zone.getID()); } - - long millisSinceNitzReceived - = System.currentTimeMillis() - (nitzReceiveTime * 1000L); - - if (millisSinceNitzReceived < 0) { - // Sanity check: something is wrong - Log.i(LOG_TAG, "NITZ: not setting time, clock has rolled " - + "backwards since NITZ time received, " - + nitz); - return; - } - - if (millisSinceNitzReceived > (1000L * 1000L)) { - // If the time is this far off, something is wrong - Log.i(LOG_TAG, "NITZ: not setting time, more than 1000 seconds " - + " have elapsed since time received, " - + nitz); - - return; - } - - // Note: with range checks above, cast to int is safe - c.add(Calendar.MILLISECOND, (int)millisSinceNitzReceived); - + String ignore = SystemProperties.get("gsm.ignore-nitz"); if (ignore != null && ignore.equals("yes")) { - Log.i(LOG_TAG, - "Not setting clock because gsm.ignore-nitz is set"); + Log.i(LOG_TAG, "NITZ: Not setting clock because gsm.ignore-nitz is set"); return; } if (getAutoTime()) { - Log.i(LOG_TAG, "Setting time of day to " + c.getTime() + long millisSinceNitzReceived + = SystemClock.elapsedRealtime() - nitzReceiveTime; + + if (millisSinceNitzReceived < 0) { + // Sanity check: something is wrong + Log.i(LOG_TAG, "NITZ: not setting time, clock has rolled " + + "backwards since NITZ time was received, " + + nitz); + return; + } + + if (millisSinceNitzReceived > Integer.MAX_VALUE) { + // If the time is this far off, something is wrong > 24 days! + Log.i(LOG_TAG, "NITZ: not setting time, processing has taken " + + (millisSinceNitzReceived / (1000 * 60 * 60 * 24)) + + " days"); + return; + } + + // Note: with range checks above, cast to int is safe + c.add(Calendar.MILLISECOND, (int)millisSinceNitzReceived); + + Log.i(LOG_TAG, "NITZ: Setting time of day to " + c.getTime() + " NITZ receive delay(ms): " + millisSinceNitzReceived + " gained(ms): " + (c.getTimeInMillis() - System.currentTimeMillis()) + " from " + nitz); - SystemClock.setCurrentTimeMillis(c.getTimeInMillis()); + setAndBroadcastNetworkSetTime(c.getTimeInMillis()); } SystemProperties.set("gsm.nitz.time", String.valueOf(c.getTimeInMillis())); saveNitzTime(c.getTimeInMillis()); + if (Config.LOGV) { + long end = SystemClock.elapsedRealtime(); + Log.v(LOG_TAG, "NITZ: end=" + end + " dur=" + (end - start)); + } } catch (RuntimeException ex) { - Log.e(LOG_TAG, "Parsing NITZ time " + nitz, ex); + Log.e(LOG_TAG, "NITZ: Parsing NITZ time " + nitz, ex); } } @@ -1319,26 +1381,44 @@ final class ServiceStateTracker extends Handler return true; } } - + private void saveNitzTimeZone(String zoneId) { mSavedTimeZone = zoneId; - // Send out a sticky broadcast so the system can determine if - // the timezone was set by the carrier... - Intent intent = new Intent(TelephonyIntents.ACTION_NETWORK_SET_TIMEZONE); - intent.putExtra("time-zone", zoneId); - phone.getContext().sendStickyBroadcast(intent); } - + private void saveNitzTime(long time) { mSavedTime = time; mSavedAtTime = SystemClock.elapsedRealtime(); - // Send out a sticky broadcast so the system can determine if - // the time was set by the carrier... + } + + /** + * Set the timezone and send out a sticky broadcast so the system can + * determine if the timezone was set by the carrier. + * + * @param zoneId timezone set by carrier + */ + private void setAndBroadcastNetworkSetTimeZone(String zoneId) { + AlarmManager alarm = + (AlarmManager) phone.getContext().getSystemService(Context.ALARM_SERVICE); + alarm.setTimeZone(zoneId); + Intent intent = new Intent(TelephonyIntents.ACTION_NETWORK_SET_TIMEZONE); + intent.putExtra("time-zone", zoneId); + phone.getContext().sendStickyBroadcast(intent); + } + + /** + * Set the time and Send out a sticky broadcast so the system can determine + * if the time was set by the carrier. + * + * @param time time set by network + */ + private void setAndBroadcastNetworkSetTime(long time) { + SystemClock.setCurrentTimeMillis(time); Intent intent = new Intent(TelephonyIntents.ACTION_NETWORK_SET_TIME); intent.putExtra("time", time); phone.getContext().sendStickyBroadcast(intent); } - + private void revertToNitz() { if (Settings.System.getInt(phone.getContext().getContentResolver(), Settings.System.AUTO_TIME, 0) == 0) { @@ -1348,10 +1428,8 @@ final class ServiceStateTracker extends Handler + "' mSavedTime=" + mSavedTime + " mSavedAtTime=" + mSavedAtTime); if (mSavedTimeZone != null && mSavedTime != 0 && mSavedAtTime != 0) { - AlarmManager alarm = - (AlarmManager) phone.getContext().getSystemService(Context.ALARM_SERVICE); - alarm.setTimeZone(mSavedTimeZone); - SystemClock.setCurrentTimeMillis(mSavedTime + setAndBroadcastNetworkSetTimeZone(mSavedTimeZone); + setAndBroadcastNetworkSetTime(mSavedTime + (SystemClock.elapsedRealtime() - mSavedAtTime)); } } diff --git a/telephony/java/com/android/internal/telephony/gsm/SimException.java b/telephony/java/com/android/internal/telephony/gsm/SimException.java index 4a9d2661852e79db2322691896aa6bd682811b2e..1c0daba45a1072c06054d38ff55ea03f49a03d1b 100644 --- a/telephony/java/com/android/internal/telephony/gsm/SimException.java +++ b/telephony/java/com/android/internal/telephony/gsm/SimException.java @@ -31,3 +31,28 @@ public class SimException extends Exception super(s); } } + +final class SimVmFixedException extends SimException { + SimVmFixedException() + { + + } + + SimVmFixedException(String s) + { + super(s); + } +} + +final class SimVmNotSupportedException extends SimException { + SimVmNotSupportedException() + { + + } + + SimVmNotSupportedException(String s) + { + super(s); + } +} + diff --git a/telephony/java/com/android/internal/telephony/gsm/SimUtils.java b/telephony/java/com/android/internal/telephony/gsm/SimUtils.java index 5cd5a90d9f2ffc40b4df59c57e814e130423d2bf..2eecdba06f52b774e1ecb528b1fdb46efec92be4 100644 --- a/telephony/java/com/android/internal/telephony/gsm/SimUtils.java +++ b/telephony/java/com/android/internal/telephony/gsm/SimUtils.java @@ -326,4 +326,151 @@ public class SimUtils return ret; } + + /** + * Convert a TS 131.102 image instance of code scheme '11' into Bitmap + * @param data The raw data + * @param length The length of image body + * @return The bitmap + */ + public static Bitmap parseToBnW(byte[] data, int length){ + int valueIndex = 0; + int width = data[valueIndex++] & 0xFF; + int height = data[valueIndex++] & 0xFF; + int numOfPixels = width*height; + + int[] pixels = new int[numOfPixels]; + + int pixelIndex = 0; + int bitIndex = 7; + byte currentByte = 0x00; + while (pixelIndex < numOfPixels) { + // reassign data and index for every byte (8 bits). + if (pixelIndex % 8 == 0) { + currentByte = data[valueIndex++]; + bitIndex = 7; + } + pixels[pixelIndex++] = bitToRGB((currentByte >> bitIndex-- ) & 0x01); + }; + + if (pixelIndex != numOfPixels) { + Log.e(LOG_TAG, "parse end and size error"); + } + return Bitmap.createBitmap(pixels, width, height, Bitmap.Config.ARGB_8888); + } + + private static int bitToRGB(int bit){ + if(bit == 1){ + return Color.WHITE; + } else { + return Color.BLACK; + } + } + + /** + * a TS 131.102 image instance of code scheme '11' into color Bitmap + * + * @param data The raw data + * @param length the length of image body + * @param transparency with or without transparency + * @return The color bitmap + */ + public static Bitmap parseToRGB(byte[] data, int length, + boolean transparency) { + int valueIndex = 0; + int width = data[valueIndex++] & 0xFF; + int height = data[valueIndex++] & 0xFF; + int bits = data[valueIndex++] & 0xFF; + int colorNumber = data[valueIndex++] & 0xFF; + int clutOffset = ((data[valueIndex++] & 0xFF) << 8) + | data[valueIndex++]; + length = length - 6; + + int[] colorIndexArray = getCLUT(data, clutOffset, colorNumber); + if (true == transparency) { + colorIndexArray[colorNumber - 1] = Color.TRANSPARENT; + } + + int[] resultArray = null; + if (0 == (8 % bits)) { + resultArray = mapTo2OrderBitColor(data, valueIndex, + (width * height), colorIndexArray, bits); + } else { + resultArray = mapToNon2OrderBitColor(data, valueIndex, + (width * height), colorIndexArray, bits); + } + + return Bitmap.createBitmap(resultArray, width, height, + Bitmap.Config.RGB_565); + } + + private static int[] mapTo2OrderBitColor(byte[] data, int valueIndex, + int length, int[] colorArray, int bits) { + if (0 != (8 % bits)) { + Log.e(LOG_TAG, "not event number of color"); + return mapToNon2OrderBitColor(data, valueIndex, length, colorArray, + bits); + } + + int mask = 0x01; + switch (bits) { + case 1: + mask = 0x01; + break; + case 2: + mask = 0x03; + break; + case 4: + mask = 0x0F; + break; + case 8: + mask = 0xFF; + break; + } + + int[] resultArray = new int[length]; + int resultIndex = 0; + int run = 8 / bits; + while (resultIndex < length) { + byte tempByte = data[valueIndex++]; + for (int runIndex = 0; runIndex < run; ++runIndex) { + int offset = run - runIndex - 1; + resultArray[resultIndex++] = colorArray[(tempByte >> (offset * bits)) + & mask]; + } + } + return resultArray; + } + + private static int[] mapToNon2OrderBitColor(byte[] data, int valueIndex, + int length, int[] colorArray, int bits) { + if (0 == (8 % bits)) { + Log.e(LOG_TAG, "not odd number of color"); + return mapTo2OrderBitColor(data, valueIndex, length, colorArray, + bits); + } + + int[] resultArray = new int[length]; + // TODO fix me: + return resultArray; + } + + private static int[] getCLUT(byte[] rawData, int offset, int number) { + if (null == rawData) { + return null; + } + + int[] result = new int[number]; + int endIndex = offset + (number * 3); // 1 color use 3 bytes + int valueIndex = offset; + int colorIndex = 0; + int alpha = 0xff << 24; + do { + result[colorIndex++] = alpha + | ((rawData[valueIndex++] & 0xFF) << 16) + | ((rawData[valueIndex++] & 0xFF) << 8) + | ((rawData[valueIndex++] & 0xFF)); + } while (valueIndex < endIndex); + return result; + } } diff --git a/telephony/java/com/android/internal/telephony/gsm/stk/AppInterface.java b/telephony/java/com/android/internal/telephony/gsm/stk/AppInterface.java index a43e32fea7260c4a14b8864f92bbb35beef1afe4..c00272993259aa796d5538f7c02c24ba8e7b3cab 100644 --- a/telephony/java/com/android/internal/telephony/gsm/stk/AppInterface.java +++ b/telephony/java/com/android/internal/telephony/gsm/stk/AppInterface.java @@ -17,241 +17,74 @@ package com.android.internal.telephony.gsm.stk; /** - * Interface for communication from Apps to STK Service + * Interface for communication between STK App and STK Telephony * * {@hide} */ public interface AppInterface { - /** - * STK state - */ - public enum State { - /** - * Idle state - */ - IDLE, - /** - * Idle but main menu exists. Menu selection should be done by calling {@code - * notifyMenuSelection()}. - */ - MAIN_MENU, - /** - * Waiting for a key input. Key input should be notified by calling - * {@code notifyInkey()}. - */ - GET_INKEY, - /** - * Waiting for a user input. Text input should be notified by calling - * {@code notifyInput()}. - */ - GET_INPUT, - /** - * Waiting for a user selection. The selection should be notified by - * calling {@code notifySelectedItem()}. - */ - SELECT_ITEM, - /** - * Waiting for the user to accept or reject a call. It should be - * notified by calling {@code acceptOrRejectCall()}. - */ - CALL_SETUP, - /** - * Waiting for user to confirm Display Text message. - * notified by calling {@code notifyDisplayTextEnded()}. - */ - DISPLAY_TEXT, - /** - * Waiting for user to confirm launching the browser. - * notified by calling {@code notifyLaunchedBrowserConfirmed()}. - */ - LAUNCH_BROWSER, - /** - * Waiting for the application to play the requested tone. - */ - PLAY_TONE - } - - /** - * Sets the {@link CommandListener CommandListener} object that is used for - * notifying of proactive commands or events from the SIM/RIL. - * - * @param l CommandListener object that handles the proactive commands and - * events from the SIM/RIL. - */ - void setCommandListener(CommandListener l); - /** - * Gets the current state of STK service. - * @return The current state. + /* + * Intent's actions which are broadcasted by the Telephony once a new STK + * proactive command, session end arrive. */ - State getState(); - - /** - * Gets the main menu that has been setup by the SIM. - * - * @return The main menu that has been setup by the SIM. It can be null. - */ - Menu getCurrentMenu(); - - /** - * Notifies the SIM of the menu selection among a set of menu options - * supplied by the SIM using SET UP MENU. - * - * @param menuId ID of the selected menu item. It can be between 1 and - * 255. - * @param helpRequired True if just help information is requested on a menu - * item rather than menu selection. False if the menu item - * is actually selected. - */ - void notifyMenuSelection(int menuId, boolean helpRequired); - - /** - * Notifies the SIM that a user activity has occurred. It is actually sent - * to the SIM when it has registered to be notified of this event via SET - * UP EVENT LIST command. - */ - void notifyUserActivity(); - - /** - * Notifies the SIM that the idle screen is available. It is actually sent - * to the SIM when it has registered to be notified of this event via SET - * UP EVENT LIST command. - */ - void notifyIdleScreenAvailable(); - - /** - * Notifies the SIM that the currently used language has changed. It is - * actually sent to the SIM when it has registered to be notified of this - * event via SET UP EVENT LIST command. - * - * @param langCode Language code of the currently selected language. - * Language code is defined in ISO 639. This must be a - * string of two characters. - */ - void notifyLanguageSelection(String langCode); - - /** - * Notifies the SIM that the browser is terminated. It is actually sent to - * the SIM when it has registered to be notified of this event via SET UP - * EVENT LIST command. - * - * @param isErrorTermination True if the cause is "Error Termination", - * false if the cause is "User Termination". - */ - void notifyBrowserTermination(boolean isErrorTermination); - - /** - * Notifies the SIM about the launch browser confirmation. This method - * should be called only after the application gets notified by {@code - * CommandListener.onLaunchBrowser()} or inside that method. - * - * @param userConfirmed True if user choose to confirm browser launch, - * False if user choose not to confirm browser launch. - */ - void notifyLaunchBrowser(boolean userConfirmed); - - /** - * Notifies the SIM that a tone had been played. This method should be called - * only after the application gets notified by {@code - * CommandListener.onPlayTone()} or inside that method. - * - */ - void notifyToneEnded(); - - /** - * Notifies the SIM that the user input a text. This method should be - * called only after the application gets notified by {@code - * CommandListener.onGetInput()} or inside that method. - * - * @param input The text string that the user has typed. - * @param helpRequired True if just help information is requested on a menu - * item rather than menu selection. False if the menu - * item is actually selected. - */ - void notifyInput(String input, boolean helpRequired); - - /** - * Notifies the SIM that the user input a key in Yes/No scenario. - * This method should be called only after the application gets notified by - * {@code CommandListener.onGetInkey()} or inside that method. - * - * @param yesNoResponse User's choice for Yes/No scenario. - * @param helpRequired True if just help information is requested on a menu - * item rather than menu selection. False if the menu - * item is actually selected. - */ - void notifyInkey(boolean yesNoResponse, boolean helpRequired); - - /** - * Notifies the SIM that the user input a key. This method should be called - * only after the application gets notified by {@code - * CommandListener.onGetInkey()} or inside that method. - * - * @param key The key that the user has typed. If the SIM required - * @param helpRequired True if just help information is requested on a menu - * item rather than menu selection. False if the menu - * item is actually selected. - */ - void notifyInkey(char key, boolean helpRequired); - - /** - * Notifies the SIM that no response was received from the user. - */ - void notifyNoResponse(); - - /** - * Send terminal response for backward move in the proactive SIM session - * requested by the user - * - * Only available when responding following proactive commands - * DISPLAY_TEXT(0x21), - * GET_INKEY(0x22), - * GET_INPUT(0x23), - * SET_UP_MENU(0x25); - * - * @return true if stk can send backward move response - */ - boolean backwardMove(); - - /** - * Send terminal response for proactive SIM session terminated by the user - * - * Only available when responding following proactive commands - * DISPLAY_TEXT(0x21), - * GET_INKEY(0x22), - * GET_INPUT(0x23), - * PLAY_TONE(0x20), - * SET_UP_MENU(0x25); - * - * @return true if stk can send terminate session response - */ - boolean terminateSession(); - - /** - * Notifies the SIM that the user selected an item. This method should be - * called only after the application gets notified by {@code - * CommandListener.onSelectItem()} or inside that method. - * - * @param id The menu item that the user has selected. - * @param wantsHelp Indicates if the user requested help for the id item. - */ - void notifySelectedItem(int id, boolean wantsHelp); + public static final String STK_CMD_ACTION = + "android.intent.action.stk.command"; + public static final String STK_SESSION_END_ACTION = + "android.intent.action.stk.session_end"; - /** - * Notifies the SIM that No response was received from the user for display - * text message dialog. - * - * * @param terminationCode indication for display text termination. Uses - * {@code ResultCode } values. - */ - public void notifyDisplayTextEnded(ResultCode terminationCode); + /* + * Callback function from app to telephony to pass a result code and user's + * input back to the SIM. + */ + void onCmdResponse(StkResponseMessage resMsg); + + /* + * Enumeration for representing "Type of Command" of proactive commands. + * Those are the only commands which are supported by the Telephony. Any app + * implementation should support those. + */ + public static enum CommandType { + DISPLAY_TEXT(0x21), + GET_INKEY(0x22), + GET_INPUT(0x23), + LAUNCH_BROWSER(0x15), + PLAY_TONE(0x20), + REFRESH(0x01), + SELECT_ITEM(0x24), + SEND_SS(0x11), + SEND_USSD(0x12), + SEND_SMS(0x13), + SEND_DTMF(0x14), + SET_UP_EVENT_LIST(0x05), + SET_UP_IDLE_MODE_TEXT(0x28), + SET_UP_MENU(0x25), + SET_UP_CALL(0x10); + + private int mValue; + + CommandType(int value) { + mValue = value; + } + + public int value() { + return mValue; + } - /** - * Notifies the SIM whether the user accepted the call or not. This method - * should be called only after the application gets notified by {@code - * CommandListener.onCallSetup()} or inside that method. - * - * @param accept True if the user has accepted the call, false if not. - */ - void acceptOrRejectCall(boolean accept); + /** + * Create a CommandType object. + * + * @param value Integer value to be converted to a CommandType object. + * @return CommandType object whose "Type of Command" value is {@code + * value}. If no CommandType object has that value, null is + * returned. + */ + public static CommandType fromInt(int value) { + for (CommandType e : CommandType.values()) { + if (e.mValue == value) { + return e; + } + } + return null; + } + } } diff --git a/telephony/java/com/android/internal/telephony/gsm/stk/BerTlv.java b/telephony/java/com/android/internal/telephony/gsm/stk/BerTlv.java index f5268e535f7f6b8e8f0cb206eb76d4b7c6f83cd7..26c2175b78ad1a3626837b8e4614b9d9e36c30a6 100644 --- a/telephony/java/com/android/internal/telephony/gsm/stk/BerTlv.java +++ b/telephony/java/com/android/internal/telephony/gsm/stk/BerTlv.java @@ -72,20 +72,7 @@ class BerTlv { try { /* tag */ tag = data[curIndex++] & 0xff; - if (tag != BER_PROACTIVE_COMMAND_TAG) { - // If the buffer doesn't contain proactive command tag, but - // start with a command details tlv object ==> skip the length - // parsing and look for tlv objects. - ComprehensionTlv ctlv = ComprehensionTlv.decode(data, - curIndex--); - if (ctlv.getTag() == ComprehensionTlvTag.COMMAND_DETAILS.value()) { - tag = BER_UNKNOWN_TAG; - curIndex--; - } else { - throw new ResultException(ResultCode.CMD_DATA_NOT_UNDERSTOOD); - } - } else { - + if (tag == BER_PROACTIVE_COMMAND_TAG) { /* length */ int temp = data[curIndex++] & 0xff; if (temp < 0x80) { @@ -101,8 +88,12 @@ class BerTlv { throw new ResultException( ResultCode.CMD_DATA_NOT_UNDERSTOOD); } + } else { + if (ComprehensionTlvTag.COMMAND_DETAILS.value() == (tag & ~0x80)) { + tag = BER_UNKNOWN_TAG; + curIndex = 0; + } } - } catch (IndexOutOfBoundsException e) { throw new ResultException(ResultCode.REQUIRED_VALUES_MISSING); } catch (ResultException e) { diff --git a/telephony/java/com/android/internal/telephony/gsm/stk/CommandDetails.java b/telephony/java/com/android/internal/telephony/gsm/stk/CommandDetails.java new file mode 100644 index 0000000000000000000000000000000000000000..168361aead1da62f4612620ed425a0d85852b091 --- /dev/null +++ b/telephony/java/com/android/internal/telephony/gsm/stk/CommandDetails.java @@ -0,0 +1,106 @@ +/* + * Copyright (C) 2007 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.android.internal.telephony.gsm.stk; + +import android.os.Parcel; +import android.os.Parcelable; + +abstract class ValueObject { + abstract ComprehensionTlvTag getTag(); +} + +/** + * Class for Command Detailes object of proactive commands from SIM. + * {@hide} + */ +class CommandDetails extends ValueObject implements Parcelable { + public boolean compRequired; + public int commandNumber; + public int typeOfCommand; + public int commandQualifier; + + public ComprehensionTlvTag getTag() { + return ComprehensionTlvTag.COMMAND_DETAILS; + } + + CommandDetails() { + } + + public boolean compareTo(CommandDetails other) { + return (this.compRequired == other.compRequired && + this.commandNumber == other.commandNumber && + this.commandQualifier == other.commandQualifier && + this.typeOfCommand == other.typeOfCommand); + } + + public CommandDetails(Parcel in) { + compRequired = true; + commandNumber = in.readInt(); + typeOfCommand = in.readInt(); + commandQualifier = in.readInt(); + } + + public void writeToParcel(Parcel dest, int flags) { + dest.writeInt(commandNumber); + dest.writeInt(typeOfCommand); + dest.writeInt(commandQualifier); + } + + public static final Parcelable.Creator CREATOR = + new Parcelable.Creator() { + public CommandDetails createFromParcel(Parcel in) { + return new CommandDetails(in); + } + + public CommandDetails[] newArray(int size) { + return new CommandDetails[size]; + } + }; + + public int describeContents() { + return 0; + } +} + +class DeviceIdentities extends ValueObject { + public int sourceId; + public int destinationId; + + ComprehensionTlvTag getTag() { + return ComprehensionTlvTag.DEVICE_IDENTITIES; + } +} + +// Container class to hold icon identifier value. +class IconId extends ValueObject { + int recordNumber; + boolean selfExplanatory; + + ComprehensionTlvTag getTag() { + return ComprehensionTlvTag.ICON_ID; + } +} + +// Container class to hold item icon identifier list value. +class ItemsIconId extends ValueObject { + int [] recordNumbers; + boolean selfExplanatory; + + ComprehensionTlvTag getTag() { + return ComprehensionTlvTag.ITEM_ICON_ID_LIST; + } +} \ No newline at end of file diff --git a/telephony/java/com/android/internal/telephony/gsm/stk/CommandListener.java b/telephony/java/com/android/internal/telephony/gsm/stk/CommandListener.java deleted file mode 100644 index 5c9a3e9ad626da352a9f066688c07714aa093a6c..0000000000000000000000000000000000000000 --- a/telephony/java/com/android/internal/telephony/gsm/stk/CommandListener.java +++ /dev/null @@ -1,187 +0,0 @@ -/* - * Copyright (C) 2006 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.android.internal.telephony.gsm.stk; - -import android.graphics.Bitmap; - -import java.util.BitSet; -import java.util.List; - - -/** - * Interface for command notification from STK Service to Apps - * - * {@hide} - */ -public interface CommandListener { - - /** - * Call back function to be called when the session with the SIM ends. - * Application must go back to the main SIM Toolkit application screen when - * this is called. - */ - void onSessionEnd(); - - /** - * Call back function to be called when the SIM wants a call to be set up. - * Application must call {@code AppInterface.acceptOrRejectCall()} after - * this method returns or inside this method. - * - * @param confirmMsg User confirmation phase message. - * @param textAttrs List of text attributes to be applied. Can be null. - * @param callMsg Call set up phase message. - */ - void onCallSetup(String confirmMsg, List textAttrs, - String callMsg); - - /** - * Call back function to be called for handling DISPLAY_TEXT proactive - * commands. - * @param text A text to be displayed - * @param textAttrs List of text attributes to be applied. Can be null. - * @param isHighPriority High priority - * @param userClear Wait for user to clear message if true, clear - * message after a delay if false. - */ - void onDisplayText(String text, List textAttrs, - boolean isHighPriority, boolean userClear, boolean responseNeeded, - Bitmap icon); - - /** - * Call back function to be called for handling SET_UP_MENU proactive - * commands. The menu can be retrieved by calling {@code - * AppInterface.getMainMenu}. - * - * @param menu application main menu. - */ - void onSetUpMenu(Menu menu); - - /** - * Call back function to be called for handling GET_INKEY proactive - * commands. - * Application must call {@code AppInterface.notifyInkey()} after this - * method returns or inside this method. - * - * @param text A text to be used as a prompt. - * @param textAttrs List of text attributes to be applied. Can be null. - * @param yesNo "Yes/No" response is requested if true. When this is - * true, {@code digitOnly} and {@code ucs2} are ignored. - * @param digitOnly Digits (0 to 9, *, # and +) only if true. Alphabet set - * if false. - * @param ucs2 UCS2 alphabet if true, SMS default alphabet if false. - * @param immediateResponse An immediate digit response (0 to 9, * and #) - * is required if true. User response shall be displayed - * and the terminal may allow alteration and/or - * confirmation if false. - * @param helpAvailable Help information available. - */ - void onGetInkey(String text, List textAttrs, boolean yesNo, boolean digitOnly, - boolean ucs2, boolean immediateResponse, boolean helpAvailable); - /** - * Call back function to be called for handling GET_INPUT proactive - * commands. Application must call {@code AppInterface.notifyInput()} after - * this method returns or inside this method. - * - * @param text A text to be used as a prompt - * @param defaultText A text to be used as a default input - * @param minLen Mininum length of response (0 indicates there is no mininum - * length requirement). - * @param maxLen Maximum length of response (between 0 and 0xfe). - * @param noMaxLimit If true, there is no limit in maximum length of - * response. - * @param textAttrs List of text attributes to be applied. Can be null. - * @param digitOnly Digits (0 to 9, *, # and +) only if true. Alphabet set - * if false. - * @param ucs2 UCS2 alphabet if true, SMS default alphabet if false. - * @param echo Terminal may echo user input on the display if true. User - * input shall not be revealed in any way if false. - * @param helpAvailable Help information available. - */ - void onGetInput(String text, String defaultText, int minLen, int maxLen, - boolean noMaxLimit, List textAttrs, - boolean digitOnly, boolean ucs2, boolean echo, boolean helpAvailable); - - /** - * Call back function to be called for handling SELECT_ITEM proactive - * commands. - * Application must call {@code AppInterface.notifySelectedItem()} after - * this method returns or inside this method. - * - * @param menu Items menu. - * @param presentationType Presentation type of the choices. - */ - void onSelectItem(Menu menu, PresentationType presentationType); - - /** - * Call back function to be called for handling SET_UP_EVENT_LIST proactive - * commands. - * @param events BitSet object each bit of which represents an event - * that UICC wants the terminal to monitor. - *
                - *
              • 0x00: MT call - *
              • 0x01: Call connected - *
              • 0x02: Call disconnected - *
              • 0x03: Location status - *
              • 0x04: User activity - *
              • 0x05: Idle screen available - *
              • 0x06: Card reader status - *
              • 0x07: Language selection - *
              • 0x08: Browser termination - *
              • 0x09: Data available - *
              • 0x0A: Channel status - *
              • 0x0B: Access Technology Change - *
              • 0x0C: Display parameters changed - *
              • 0x0D: Local connection - *
              • 0x0E: Network Search Mode Change - *
              • 0x0F: Browsing status - *
              • 0x10: Frames Information Change - *
              • 0x11: reserved for 3GPP (I-WLAN Access Status) - *
              - * These values are defined in Service as UICC_EVENT_*. - * @throws ResultException must be BEYOND_TERMINAL_CAPABILITY - * if the ME is not able to successfully accept all events - */ - void onSetUpEventList(BitSet events) throws ResultException; - - /** - * Call back function to be called for handling LAUNCH_BROWSER proactive - * commands. - * - * @param useDefaultUrl If true, use the system default URL, otherwise use - * {@code url} as the URL. - * @param confirmMsg A text to be used as the user confirmation message. Can - * be null. - * @param confirmMsgAttrs List of text attributes to be applied to {code - * confirmMsgAttrs}. Can be null. - * @param mode Launch mode. - */ - void onLaunchBrowser(String url, String confirmMsg, - List confirmMsgAttrs, LaunchBrowserMode mode); - - /** - * Call back function to be called for handling PLAY_TONE proactive - * commands. - * - * @param tone Tone to be played - * @param text A text to be displayed. Can be null. - * @param textAttrs List of text attributes to be applied. Can be null. - * @param duration Time duration to play the tone. - * @throws ResultException - */ - void onPlayTone(Tone tone, String text, List textAttrs, - Duration duration) throws ResultException; -} diff --git a/telephony/java/com/android/internal/telephony/gsm/stk/CommandParams.java b/telephony/java/com/android/internal/telephony/gsm/stk/CommandParams.java index d39ad7b4ff36e55d5e6c1c1e62f88f99060590ec..60e8148b6fe5f514937b7ae2fbeb20911168d6a2 100644 --- a/telephony/java/com/android/internal/telephony/gsm/stk/CommandParams.java +++ b/telephony/java/com/android/internal/telephony/gsm/stk/CommandParams.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006 The Android Open Source Project + * Copyright (C) 2007 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. @@ -18,102 +18,152 @@ package com.android.internal.telephony.gsm.stk; import android.graphics.Bitmap; -import java.util.List; - /** * Container class for proactive command parameters. * */ class CommandParams { - public CtlvCommandDetails cmdDet; + CommandDetails cmdDet; - CommandParams(CtlvCommandDetails cmdDet) { + CommandParams(CommandDetails cmdDet) { this.cmdDet = cmdDet; } + + AppInterface.CommandType getCommandType() { + return AppInterface.CommandType.fromInt(cmdDet.typeOfCommand); + } + + boolean setIcon(Bitmap icon) { return true; } } -class CommonUIParams extends CommandParams { - String mText; - Bitmap mIcon; - boolean mIconSelfExplanatory; - TextAttribute mTextAttrs; +class DisplayTextParams extends CommandParams { + TextMessage textMsg; - CommonUIParams(CtlvCommandDetails cmdDet, String text, - TextAttribute textAttrs) { + DisplayTextParams(CommandDetails cmdDet, TextMessage textMsg) { super(cmdDet); + this.textMsg = textMsg; + } - mText = text; - mTextAttrs = textAttrs; - mIconSelfExplanatory = false; - mIcon = null; + boolean setIcon(Bitmap icon) { + if (icon != null && textMsg != null) { + textMsg.icon = icon; + return true; + } + return false; } +} + +class LaunchBrowserParams extends CommandParams { + TextMessage confirmMsg; + LaunchBrowserMode mode; + String url; - void setIcon(Bitmap icon) { - mIcon = icon; + LaunchBrowserParams(CommandDetails cmdDet, TextMessage confirmMsg, + String url, LaunchBrowserMode mode) { + super(cmdDet); + this.confirmMsg = confirmMsg; + this.mode = mode; + this.url = url; } - void setIconSelfExplanatory(boolean iconSelfExplanatory) { - mIconSelfExplanatory = iconSelfExplanatory; + boolean setIcon(Bitmap icon) { + if (icon != null && confirmMsg != null) { + confirmMsg.icon = icon; + return true; + } + return false; } } -class DisplayTextParams extends CommandParams { - String text = null; - Bitmap icon = null; - List textAttrs = null; - boolean immediateResponse = false; - boolean userClear = false; - boolean isHighPriority = false; - - DisplayTextParams(CtlvCommandDetails cmdDet) { +class PlayToneParams extends CommandParams { + TextMessage textMsg; + ToneSettings settings; + + PlayToneParams(CommandDetails cmdDet, TextMessage textMsg, + Tone tone, Duration duration, boolean vibrate) { super(cmdDet); + this.textMsg = textMsg; + this.settings = new ToneSettings(duration, tone, vibrate); + } + + boolean setIcon(Bitmap icon) { + if (icon != null && textMsg != null) { + textMsg.icon = icon; + return true; + } + return false; } } -class GetInkeyParams extends CommandParams { - boolean isYesNo; - boolean isUcs2; +class CallSetupParams extends CommandParams { + TextMessage confirmMsg; + TextMessage callMsg; - GetInkeyParams(CtlvCommandDetails cmdDet, boolean isYesNo, - boolean isUcs2) { + CallSetupParams(CommandDetails cmdDet, TextMessage confirmMsg, + TextMessage callMsg) { super(cmdDet); + this.confirmMsg = confirmMsg; + this.callMsg = callMsg; + } - this.isYesNo = isYesNo; - this.isUcs2 = isUcs2; + boolean setIcon(Bitmap icon) { + if (icon == null) { + return false; + } + if (confirmMsg != null && confirmMsg.icon == null) { + confirmMsg.icon = icon; + return true; + } else if (callMsg != null && callMsg.icon == null) { + callMsg.icon = icon; + return true; + } + return false; } } -class GetInputParams extends CommandParams { - boolean isUcs2; - boolean isPacked; +class SelectItemParams extends CommandParams { + Menu menu = null; + boolean loadTitleIcon = false; - GetInputParams(CtlvCommandDetails cmdDet, boolean isUcs2, - boolean isPacked) { + SelectItemParams(CommandDetails cmdDet, Menu menu, boolean loadTitleIcon) { super(cmdDet); + this.menu = menu; + this.loadTitleIcon = loadTitleIcon; + } - this.isUcs2 = isUcs2; - this.isPacked = isPacked; + boolean setIcon(Bitmap icon) { + if (icon != null && menu != null) { + if (loadTitleIcon && menu.titleIcon == null) { + menu.titleIcon = icon; + } else { + for (Item item : menu.items) { + if (item.icon != null) { + continue; + } + item.icon = icon; + break; + } + } + return true; + } + return false; } } -class SelectItemParams extends CommandParams { - Menu mMenu = null; - PresentationType mPresentationType; - int mIconLoadState = LOAD_NO_ICON; - - // loading icons state parameters. - static final int LOAD_NO_ICON = 0; - static final int LOAD_TITLE_ICON = 1; - static final int LOAD_ITEMS_ICONS = 2; - static final int LOAD_TITLE_ITEMS_ICONS = 3; - - SelectItemParams(CtlvCommandDetails cmdDet, Menu menu, - PresentationType presentationType, int iconLoadState) { +class GetInputParams extends CommandParams { + Input input = null; + + GetInputParams(CommandDetails cmdDet, Input input) { super(cmdDet); + this.input = input; + } - mMenu = menu; - mPresentationType = presentationType; - mIconLoadState = iconLoadState; + boolean setIcon(Bitmap icon) { + if (icon != null && input != null) { + input.icon = icon; + } + return true; } } + diff --git a/telephony/java/com/android/internal/telephony/gsm/stk/CommandParamsFactory.java b/telephony/java/com/android/internal/telephony/gsm/stk/CommandParamsFactory.java new file mode 100644 index 0000000000000000000000000000000000000000..2d2f9ae272439fcb069acafa3f0bf818b6d7284d --- /dev/null +++ b/telephony/java/com/android/internal/telephony/gsm/stk/CommandParamsFactory.java @@ -0,0 +1,870 @@ +/* + * Copyright (C) 2007 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.android.internal.telephony.gsm.stk; + +import android.graphics.Bitmap; +import android.os.Handler; +import android.os.Message; + +import com.android.internal.telephony.gsm.GsmAlphabet; +import com.android.internal.telephony.gsm.SIMFileHandler; + +import java.util.Iterator; +import java.util.List; + +/** + * Factory class, used for decoding raw byte arrays, received from baseband, + * into a CommandParams object. + * + */ +class CommandParamsFactory extends Handler { + private static CommandParamsFactory sInstance = null; + private IconLoader mIconLoader; + private CommandParams mCmdParams = null; + private int mIconLoadState = LOAD_NO_ICON; + private Handler mCaller = null; + + // constants + static final int MSG_ID_LOAD_ICON_DONE = 1; + + // loading icons state parameters. + static final int LOAD_NO_ICON = 0; + static final int LOAD_SINGLE_ICON = 1; + static final int LOAD_MULTI_ICONS = 2; + + // Command Qualifier values for refresh command + static final int REFRESH_NAA_INIT_AND_FULL_FILE_CHANGE = 0x00; + static final int REFRESH_NAA_INIT_AND_FILE_CHANGE = 0x02; + static final int REFRESH_NAA_INIT = 0x03; + static final int REFRESH_UICC_RESET = 0x04; + + private static final String TAG = "CmdParamsFactory"; + + static synchronized CommandParamsFactory getInstance(Handler caller, + SIMFileHandler fh) { + if (sInstance != null) { + return sInstance; + } + if (fh != null) { + return new CommandParamsFactory(caller, fh); + } + return null; + } + + private CommandParamsFactory(Handler caller, SIMFileHandler fh) { + mCaller = caller; + mIconLoader = IconLoader.getInstance(this, fh); + } + + private CommandDetails processCommandDetails(List ctlvs) { + CommandDetails cmdDet = null; + + if (ctlvs != null) { + // Search for the Command Details object. + ComprehensionTlv ctlvCmdDet = searchForTag( + ComprehensionTlvTag.COMMAND_DETAILS, ctlvs); + if (ctlvCmdDet != null) { + try { + cmdDet = ValueParser.retrieveCommandDetails(ctlvCmdDet); + } catch (ResultException e) { + StkLog.d(this, "Failed to procees command details"); + } + } + } + return cmdDet; + } + + void make(BerTlv berTlv) { + if (berTlv == null) { + return; + } + // reset global state parameters. + mCmdParams = null; + mIconLoadState = LOAD_NO_ICON; + // only proactive command messages are processed. + if (berTlv.getTag() != BerTlv.BER_PROACTIVE_COMMAND_TAG) { + sendCmdParams(ResultCode.CMD_TYPE_NOT_UNDERSTOOD); + return; + } + boolean cmdPending = false; + List ctlvs = berTlv.getComprehensionTlvs(); + // process command dtails from the tlv list. + CommandDetails cmdDet = processCommandDetails(ctlvs); + if (cmdDet == null) { + sendCmdParams(ResultCode.CMD_TYPE_NOT_UNDERSTOOD); + return; + } + + // extract command type enumeration from the raw value stored inside + // the Command Details object. + AppInterface.CommandType cmdType = AppInterface.CommandType + .fromInt(cmdDet.typeOfCommand); + if (cmdType == null) { + sendCmdParams(ResultCode.CMD_TYPE_NOT_UNDERSTOOD); + return; + } + + try { + switch (cmdType) { + case SET_UP_MENU: + cmdPending = processSelectItem(cmdDet, ctlvs); + break; + case SELECT_ITEM: + cmdPending = processSelectItem(cmdDet, ctlvs); + break; + case DISPLAY_TEXT: + cmdPending = processDisplayText(cmdDet, ctlvs); + break; + case SET_UP_IDLE_MODE_TEXT: + cmdPending = processSetUpIdleModeText(cmdDet, ctlvs); + break; + case GET_INKEY: + cmdPending = processGetInkey(cmdDet, ctlvs); + break; + case GET_INPUT: + cmdPending = processGetInput(cmdDet, ctlvs); + break; + case SEND_DTMF: + case SEND_SMS: + case SEND_SS: + case SEND_USSD: + cmdPending = processEventNotify(cmdDet, ctlvs); + break; + case SET_UP_CALL: + cmdPending = processSetupCall(cmdDet, ctlvs); + break; + case REFRESH: + processRefresh(cmdDet, ctlvs); + cmdPending = false; + break; + case LAUNCH_BROWSER: + cmdPending = processLaunchBrowser(cmdDet, ctlvs); + break; + case PLAY_TONE: + cmdPending = processPlayTone(cmdDet, ctlvs); + break; + default: + // unsupported proactive commands + mCmdParams = new CommandParams(cmdDet); + sendCmdParams(ResultCode.CMD_TYPE_NOT_UNDERSTOOD); + return; + } + } catch (ResultException e) { + mCmdParams = new CommandParams(cmdDet); + sendCmdParams(e.result()); + return; + } + if (!cmdPending) { + sendCmdParams(ResultCode.OK); + } + } + + public void handleMessage(Message msg) { + switch (msg.what) { + case MSG_ID_LOAD_ICON_DONE: + sendCmdParams(setIcons(msg.obj)); + break; + } + } + + private ResultCode setIcons(Object data) { + Bitmap[] icons = null; + int iconIndex = 0; + + if (data == null) { + return ResultCode.PRFRMD_ICON_NOT_DISPLAYED; + } + switch(mIconLoadState) { + case LOAD_SINGLE_ICON: + mCmdParams.setIcon((Bitmap) data); + break; + case LOAD_MULTI_ICONS: + icons = (Bitmap[]) data; + // set each item icon. + for (Bitmap icon : icons) { + mCmdParams.setIcon(icon); + } + break; + } + return ResultCode.OK; + } + + private void sendCmdParams(ResultCode resCode) { + Message msg = mCaller.obtainMessage(RilMessageDecoder.CMD_PARAMS_READY); + msg.arg1 = resCode.value(); + msg.obj = mCmdParams; + msg.sendToTarget(); + } + + /** + * Search for a COMPREHENSION-TLV object with the given tag from a list + * + * @param tag A tag to search for + * @param ctlvs List of ComprehensionTlv objects used to search in + * + * @return A ComprehensionTlv object that has the tag value of {@code tag}. + * If no object is found with the tag, null is returned. + */ + private ComprehensionTlv searchForTag(ComprehensionTlvTag tag, + List ctlvs) { + Iterator iter = ctlvs.iterator(); + return searchForNextTag(tag, iter); + } + + /** + * Search for the next COMPREHENSION-TLV object with the given tag from a + * list iterated by {@code iter}. {@code iter} points to the object next to + * the found object when this method returns. Used for searching the same + * list for similar tags, usually item id. + * + * @param tag A tag to search for + * @param iter Iterator for ComprehensionTlv objects used for search + * + * @return A ComprehensionTlv object that has the tag value of {@code tag}. + * If no object is found with the tag, null is returned. + */ + private ComprehensionTlv searchForNextTag(ComprehensionTlvTag tag, + Iterator iter) { + int tagValue = tag.value(); + while (iter.hasNext()) { + ComprehensionTlv ctlv = iter.next(); + if (ctlv.getTag() == tagValue) { + return ctlv; + } + } + return null; + } + + /** + * Processes DISPLAY_TEXT proactive command from the SIM card. + * + * @param cmdDet Command Details container object. + * @param ctlvs List of ComprehensionTlv objects following Command Details + * object and Device Identities object within the proactive command + * @return true if the command is processing is pending and additional + * asynchronous processing is required. + * @throws ResultException + */ + private boolean processDisplayText(CommandDetails cmdDet, + List ctlvs) + throws ResultException { + + StkLog.d(this, "process DisplayText"); + + TextMessage textMsg = new TextMessage(); + IconId iconId = null; + + ComprehensionTlv ctlv = searchForTag(ComprehensionTlvTag.TEXT_STRING, + ctlvs); + if (ctlv != null) { + textMsg.text = ValueParser.retrieveTextString(ctlv); + } + // If the tlv object doesn't exist or the it is a null object reply + // with command not understood. + if (textMsg.text == null) { + throw new ResultException(ResultCode.CMD_DATA_NOT_UNDERSTOOD); + } + + ctlv = searchForTag(ComprehensionTlvTag.IMMEDIATE_RESPONSE, ctlvs); + if (ctlv != null) { + textMsg.responseNeeded = false; + } + // parse icon identifier + ctlv = searchForTag(ComprehensionTlvTag.ICON_ID, ctlvs); + if (ctlv != null) { + iconId = ValueParser.retrieveIconId(ctlv); + textMsg.iconSelfExplanatory = iconId.selfExplanatory; + } + // parse tone duration + ctlv = searchForTag(ComprehensionTlvTag.DURATION, ctlvs); + if (ctlv != null) { + textMsg.duration = ValueParser.retrieveDuration(ctlv); + } + + // Parse command qualifier parameters. + textMsg.isHighPriority = (cmdDet.commandQualifier & 0x01) != 0; + textMsg.userClear = (cmdDet.commandQualifier & 0x80) != 0; + + mCmdParams = new DisplayTextParams(cmdDet, textMsg); + + if (iconId != null) { + mIconLoadState = LOAD_SINGLE_ICON; + mIconLoader.loadIcon(iconId.recordNumber, this + .obtainMessage(MSG_ID_LOAD_ICON_DONE)); + return true; + } + return false; + } + + /** + * Processes SET_UP_IDLE_MODE_TEXT proactive command from the SIM card. + * + * @param cmdDet Command Details container object. + * @param ctlvs List of ComprehensionTlv objects following Command Details + * object and Device Identities object within the proactive command + * @return true if the command is processing is pending and additional + * asynchronous processing is required. + * @throws ResultException + */ + private boolean processSetUpIdleModeText(CommandDetails cmdDet, + List ctlvs) throws ResultException { + + StkLog.d(this, "process SetUpIdleModeText"); + + TextMessage textMsg = new TextMessage(); + IconId iconId = null; + + ComprehensionTlv ctlv = searchForTag(ComprehensionTlvTag.TEXT_STRING, + ctlvs); + if (ctlv != null) { + textMsg.text = ValueParser.retrieveTextString(ctlv); + } + // load icons only when text exist. + if (textMsg.text != null) { + ctlv = searchForTag(ComprehensionTlvTag.ICON_ID, ctlvs); + if (ctlv != null) { + iconId = ValueParser.retrieveIconId(ctlv); + textMsg.iconSelfExplanatory = iconId.selfExplanatory; + } + } + + mCmdParams = new DisplayTextParams(cmdDet, textMsg); + + if (iconId != null) { + mIconLoadState = LOAD_SINGLE_ICON; + mIconLoader.loadIcon(iconId.recordNumber, this + .obtainMessage(MSG_ID_LOAD_ICON_DONE)); + return true; + } + return false; + } + + /** + * Processes GET_INKEY proactive command from the SIM card. + * + * @param cmdDet Command Details container object. + * @param ctlvs List of ComprehensionTlv objects following Command Details + * object and Device Identities object within the proactive command + * @return true if the command is processing is pending and additional + * asynchronous processing is required. + * @throws ResultException + */ + private boolean processGetInkey(CommandDetails cmdDet, + List ctlvs) throws ResultException { + + StkLog.d(this, "process GetInkey"); + + Input input = new Input(); + IconId iconId = null; + + ComprehensionTlv ctlv = searchForTag(ComprehensionTlvTag.TEXT_STRING, + ctlvs); + if (ctlv != null) { + input.text = ValueParser.retrieveTextString(ctlv); + } else { + throw new ResultException(ResultCode.REQUIRED_VALUES_MISSING); + } + // parse icon identifier + ctlv = searchForTag(ComprehensionTlvTag.ICON_ID, ctlvs); + if (ctlv != null) { + iconId = ValueParser.retrieveIconId(ctlv); + } + + input.minLen = 1; + input.maxLen = 1; + + input.digitOnly = (cmdDet.commandQualifier & 0x01) == 0; + input.ucs2 = (cmdDet.commandQualifier & 0x02) != 0; + input.yesNo = (cmdDet.commandQualifier & 0x04) != 0; + input.helpAvailable = (cmdDet.commandQualifier & 0x80) != 0; + + mCmdParams = new GetInputParams(cmdDet, input); + + if (iconId != null) { + mIconLoadState = LOAD_SINGLE_ICON; + mIconLoader.loadIcon(iconId.recordNumber, this + .obtainMessage(MSG_ID_LOAD_ICON_DONE)); + return true; + } + return false; + } + + /** + * Processes GET_INPUT proactive command from the SIM card. + * + * @param cmdDet Command Details container object. + * @param ctlvs List of ComprehensionTlv objects following Command Details + * object and Device Identities object within the proactive command + * @return true if the command is processing is pending and additional + * asynchronous processing is required. + * @throws ResultException + */ + private boolean processGetInput(CommandDetails cmdDet, + List ctlvs) throws ResultException { + + StkLog.d(this, "process GetInput"); + + Input input = new Input(); + IconId iconId = null; + + ComprehensionTlv ctlv = searchForTag(ComprehensionTlvTag.TEXT_STRING, + ctlvs); + if (ctlv != null) { + input.text = ValueParser.retrieveTextString(ctlv); + } else { + throw new ResultException(ResultCode.REQUIRED_VALUES_MISSING); + } + + ctlv = searchForTag(ComprehensionTlvTag.RESPONSE_LENGTH, ctlvs); + if (ctlv != null) { + try { + byte[] rawValue = ctlv.getRawValue(); + int valueIndex = ctlv.getValueIndex(); + input.minLen = rawValue[valueIndex] & 0xff; + input.maxLen = rawValue[valueIndex + 1] & 0xff; + } catch (IndexOutOfBoundsException e) { + throw new ResultException(ResultCode.CMD_DATA_NOT_UNDERSTOOD); + } + } else { + throw new ResultException(ResultCode.REQUIRED_VALUES_MISSING); + } + + ctlv = searchForTag(ComprehensionTlvTag.DEFAULT_TEXT, ctlvs); + if (ctlv != null) { + input.defaultText = ValueParser.retrieveTextString(ctlv); + } + // parse icon identifier + ctlv = searchForTag(ComprehensionTlvTag.ICON_ID, ctlvs); + if (ctlv != null) { + iconId = ValueParser.retrieveIconId(ctlv); + } + + input.digitOnly = (cmdDet.commandQualifier & 0x01) == 0; + input.ucs2 = (cmdDet.commandQualifier & 0x02) != 0; + input.echo = (cmdDet.commandQualifier & 0x04) == 0; + input.packed = (cmdDet.commandQualifier & 0x08) != 0; + input.helpAvailable = (cmdDet.commandQualifier & 0x80) != 0; + + mCmdParams = new GetInputParams(cmdDet, input); + + if (iconId != null) { + mIconLoadState = LOAD_SINGLE_ICON; + mIconLoader.loadIcon(iconId.recordNumber, this + .obtainMessage(MSG_ID_LOAD_ICON_DONE)); + return true; + } + return false; + } + + /** + * Processes REFRESH proactive command from the SIM card. + * + * @param cmdDet Command Details container object. + * @param ctlvs List of ComprehensionTlv objects following Command Details + * object and Device Identities object within the proactive command + */ + private boolean processRefresh(CommandDetails cmdDet, + List ctlvs) { + + StkLog.d(this, "process Refresh"); + + // REFRESH proactive command is rerouted by the baseband and handled by + // the telephony layer. IDLE TEXT should be removed for a REFRESH command + // with "initialization" or "reset" + switch (cmdDet.commandQualifier) { + case REFRESH_NAA_INIT_AND_FULL_FILE_CHANGE: + case REFRESH_NAA_INIT_AND_FILE_CHANGE: + case REFRESH_NAA_INIT: + case REFRESH_UICC_RESET: + mCmdParams = new DisplayTextParams(cmdDet, null); + break; + } + return false; + } + + /** + * Processes SELECT_ITEM proactive command from the SIM card. + * + * @param cmdDet Command Details container object. + * @param ctlvs List of ComprehensionTlv objects following Command Details + * object and Device Identities object within the proactive command + * @return true if the command is processing is pending and additional + * asynchronous processing is required. + * @throws ResultException + */ + private boolean processSelectItem(CommandDetails cmdDet, + List ctlvs) throws ResultException { + + StkLog.d(this, "process SelectItem"); + + Menu menu = new Menu(); + IconId titleIconId = null; + ItemsIconId itemsIconId = null; + Iterator iter = ctlvs.iterator(); + + ComprehensionTlv ctlv = searchForTag(ComprehensionTlvTag.ALPHA_ID, + ctlvs); + if (ctlv != null) { + menu.title = ValueParser.retrieveAlphaId(ctlv); + } + + while (true) { + ctlv = searchForNextTag(ComprehensionTlvTag.ITEM, iter); + if (ctlv != null) { + menu.items.add(ValueParser.retrieveItem(ctlv)); + } else { + break; + } + } + + // We must have at least one menu item. + if (menu.items.size() == 0) { + throw new ResultException(ResultCode.REQUIRED_VALUES_MISSING); + } + + ctlv = searchForTag(ComprehensionTlvTag.ITEM_ID, ctlvs); + if (ctlv != null) { + // STK items are listed 1...n while list start at 0, need to + // subtract one. + menu.defaultItem = ValueParser.retrieveItemId(ctlv) - 1; + } + + ctlv = searchForTag(ComprehensionTlvTag.ICON_ID, ctlvs); + if (ctlv != null) { + mIconLoadState = LOAD_SINGLE_ICON; + titleIconId = ValueParser.retrieveIconId(ctlv); + menu.titleIconSelfExplanatory = titleIconId.selfExplanatory; + } + + ctlv = searchForTag(ComprehensionTlvTag.ITEM_ICON_ID_LIST, ctlvs); + if (ctlv != null) { + mIconLoadState = LOAD_MULTI_ICONS; + itemsIconId = ValueParser.retrieveItemsIconId(ctlv); + menu.itemsIconSelfExplanatory = itemsIconId.selfExplanatory; + } + + boolean presentTypeSpecified = (cmdDet.commandQualifier & 0x01) != 0; + if (presentTypeSpecified) { + if ((cmdDet.commandQualifier & 0x02) == 0) { + menu.presentationType = PresentationType.DATA_VALUES; + } else { + menu.presentationType = PresentationType.NAVIGATION_OPTIONS; + } + } + menu.softKeyPreferred = (cmdDet.commandQualifier & 0x04) != 0; + menu.helpAvailable = (cmdDet.commandQualifier & 0x80) != 0; + + mCmdParams = new SelectItemParams(cmdDet, menu, titleIconId != null); + + // Load icons data if needed. + switch(mIconLoadState) { + case LOAD_NO_ICON: + return false; + case LOAD_SINGLE_ICON: + mIconLoader.loadIcon(titleIconId.recordNumber, this + .obtainMessage(MSG_ID_LOAD_ICON_DONE)); + break; + case LOAD_MULTI_ICONS: + int[] recordNumbers = itemsIconId.recordNumbers; + if (titleIconId != null) { + // Create a new array for all the icons (title and items). + recordNumbers = new int[itemsIconId.recordNumbers.length + 1]; + recordNumbers[0] = titleIconId.recordNumber; + System.arraycopy(itemsIconId.recordNumbers, 0, recordNumbers, + 1, itemsIconId.recordNumbers.length); + } + mIconLoader.loadIcons(recordNumbers, this + .obtainMessage(MSG_ID_LOAD_ICON_DONE)); + break; + } + return true; + } + + /** + * Processes EVENT_NOTIFY message from baseband. + * + * @param cmdDet Command Details container object. + * @param ctlvs List of ComprehensionTlv objects following Command Details + * object and Device Identities object within the proactive command + * @return true if the command is processing is pending and additional + * asynchronous processing is required. + */ + private boolean processEventNotify(CommandDetails cmdDet, + List ctlvs) throws ResultException { + + StkLog.d(this, "process EventNotify"); + + TextMessage textMsg = new TextMessage(); + IconId iconId = null; + + ComprehensionTlv ctlv = searchForTag(ComprehensionTlvTag.ALPHA_ID, + ctlvs); + if (ctlv != null) { + textMsg.text = ValueParser.retrieveAlphaId(ctlv); + } else { + throw new ResultException(ResultCode.REQUIRED_VALUES_MISSING); + } + + ctlv = searchForTag(ComprehensionTlvTag.ICON_ID, ctlvs); + if (ctlv != null) { + iconId = ValueParser.retrieveIconId(ctlv); + textMsg.iconSelfExplanatory = iconId.selfExplanatory; + } + + textMsg.responseNeeded = false; + mCmdParams = new DisplayTextParams(cmdDet, textMsg); + + if (iconId != null) { + mIconLoadState = LOAD_SINGLE_ICON; + mIconLoader.loadIcon(iconId.recordNumber, this + .obtainMessage(MSG_ID_LOAD_ICON_DONE)); + return true; + } + return false; + } + + /** + * Processes SET_UP_EVENT_LIST proactive command from the SIM card. + * + * @param cmdDet Command Details object retrieved. + * @param ctlvs List of ComprehensionTlv objects following Command Details + * object and Device Identities object within the proactive command + * @return true if the command is processing is pending and additional + * asynchronous processing is required. + */ + private boolean processSetUpEventList(CommandDetails cmdDet, + List ctlvs) { + + StkLog.d(this, "process SetUpEventList"); + // + // ComprehensionTlv ctlv = searchForTag(ComprehensionTlvTag.EVENT_LIST, + // ctlvs); + // if (ctlv != null) { + // try { + // byte[] rawValue = ctlv.getRawValue(); + // int valueIndex = ctlv.getValueIndex(); + // int valueLen = ctlv.getLength(); + // + // } catch (IndexOutOfBoundsException e) {} + // } + return true; + } + + /** + * Processes LAUNCH_BROWSER proactive command from the SIM card. + * + * @param cmdDet Command Details container object. + * @param ctlvs List of ComprehensionTlv objects following Command Details + * object and Device Identities object within the proactive command + * @return true if the command is processing is pending and additional + * asynchronous processing is required. + * @throws ResultException + */ + private boolean processLaunchBrowser(CommandDetails cmdDet, + List ctlvs) throws ResultException { + + StkLog.d(this, "process LaunchBrowser"); + + TextMessage confirmMsg = new TextMessage(); + IconId iconId = null; + String url = null; + + ComprehensionTlv ctlv = searchForTag(ComprehensionTlvTag.URL, ctlvs); + if (ctlv != null) { + try { + byte[] rawValue = ctlv.getRawValue(); + int valueIndex = ctlv.getValueIndex(); + int valueLen = ctlv.getLength(); + if (valueLen > 0) { + url = GsmAlphabet.gsm8BitUnpackedToString(rawValue, + valueIndex, valueLen); + } else { + url = null; + } + } catch (IndexOutOfBoundsException e) { + throw new ResultException(ResultCode.CMD_DATA_NOT_UNDERSTOOD); + } + } + + // parse alpha identifier. + ctlv = searchForTag(ComprehensionTlvTag.ALPHA_ID, ctlvs); + if (ctlv != null) { + confirmMsg.text = ValueParser.retrieveAlphaId(ctlv); + } + // parse icon identifier + ctlv = searchForTag(ComprehensionTlvTag.ICON_ID, ctlvs); + if (ctlv != null) { + iconId = ValueParser.retrieveIconId(ctlv); + confirmMsg.iconSelfExplanatory = iconId.selfExplanatory; + } + + // parse command qualifier value. + LaunchBrowserMode mode; + switch (cmdDet.commandQualifier) { + case 0x00: + default: + mode = LaunchBrowserMode.LAUNCH_IF_NOT_ALREADY_LAUNCHED; + break; + case 0x02: + mode = LaunchBrowserMode.USE_EXISTING_BROWSER; + break; + case 0x03: + mode = LaunchBrowserMode.LAUNCH_NEW_BROWSER; + break; + } + + mCmdParams = new LaunchBrowserParams(cmdDet, confirmMsg, url, mode); + + if (iconId != null) { + mIconLoadState = LOAD_SINGLE_ICON; + mIconLoader.loadIcon(iconId.recordNumber, this + .obtainMessage(MSG_ID_LOAD_ICON_DONE)); + return true; + } + return false; + } + + /** + * Processes PLAY_TONE proactive command from the SIM card. + * + * @param cmdDet Command Details container object. + * @param ctlvs List of ComprehensionTlv objects following Command Details + * object and Device Identities object within the proactive command + * @return true if the command is processing is pending and additional + * asynchronous processing is required.t + * @throws ResultException + */ + private boolean processPlayTone(CommandDetails cmdDet, + List ctlvs) throws ResultException { + + StkLog.d(TAG, "process PlayTone"); + + Tone tone = null; + TextMessage textMsg = new TextMessage(); + Duration duration = null; + IconId iconId = null; + + ComprehensionTlv ctlv = searchForTag(ComprehensionTlvTag.TONE, ctlvs); + if (ctlv != null) { + // Nothing to do for null objects. + if (ctlv.getLength() > 0) { + try { + byte[] rawValue = ctlv.getRawValue(); + int valueIndex = ctlv.getValueIndex(); + int toneVal = rawValue[valueIndex]; + tone = Tone.fromInt(toneVal); + } catch (IndexOutOfBoundsException e) { + throw new ResultException( + ResultCode.CMD_DATA_NOT_UNDERSTOOD); + } + } + } + // parse alpha identifier + ctlv = searchForTag(ComprehensionTlvTag.ALPHA_ID, ctlvs); + if (ctlv != null) { + textMsg.text = ValueParser.retrieveAlphaId(ctlv); + } + // parse tone duration + ctlv = searchForTag(ComprehensionTlvTag.DURATION, ctlvs); + if (ctlv != null) { + duration = ValueParser.retrieveDuration(ctlv); + } + // parse icon identifier + ctlv = searchForTag(ComprehensionTlvTag.ICON_ID, ctlvs); + if (ctlv != null) { + iconId = ValueParser.retrieveIconId(ctlv); + textMsg.iconSelfExplanatory = iconId.selfExplanatory; + } + + boolean vibrate = (cmdDet.commandQualifier & 0x01) != 0x00; + + textMsg.responseNeeded = false; + mCmdParams = new PlayToneParams(cmdDet, textMsg, tone, duration, vibrate); + + if (iconId != null) { + mIconLoadState = LOAD_SINGLE_ICON; + mIconLoader.loadIcon(iconId.recordNumber, this + .obtainMessage(MSG_ID_LOAD_ICON_DONE)); + return true; + } + return false; + } + + /** + * Processes SETUP_CALL proactive command from the SIM card. + * + * @param cmdDet Command Details object retrieved from the proactive command + * object + * @param ctlvs List of ComprehensionTlv objects following Command Details + * object and Device Identities object within the proactive command + * @return true if the command is processing is pending and additional + * asynchronous processing is required. + */ + private boolean processSetupCall(CommandDetails cmdDet, + List ctlvs) throws ResultException { + StkLog.d(TAG, "process SetupCall"); + + Iterator iter = ctlvs.iterator(); + ComprehensionTlv ctlv = null; + // User confirmation phase message. + TextMessage confirmMsg = new TextMessage(); + // Call set up phase message. + TextMessage callMsg = new TextMessage(); + IconId confirmIconId = null; + IconId callIconId = null; + + // get confirmation message string. + ctlv = searchForNextTag(ComprehensionTlvTag.ALPHA_ID, iter); + if (ctlv != null) { + confirmMsg.text = ValueParser.retrieveAlphaId(ctlv); + } + + ctlv = searchForTag(ComprehensionTlvTag.ICON_ID, ctlvs); + if (ctlv != null) { + confirmIconId = ValueParser.retrieveIconId(ctlv); + confirmMsg.iconSelfExplanatory = confirmIconId.selfExplanatory; + } + + // get call set up message string. + ctlv = searchForNextTag(ComprehensionTlvTag.ALPHA_ID, iter); + if (ctlv != null) { + callMsg.text = ValueParser.retrieveAlphaId(ctlv); + } + + ctlv = searchForTag(ComprehensionTlvTag.ICON_ID, ctlvs); + if (ctlv != null) { + callIconId = ValueParser.retrieveIconId(ctlv); + callMsg.iconSelfExplanatory = callIconId.selfExplanatory; + } + + mCmdParams = new CallSetupParams(cmdDet, confirmMsg, callMsg); + + if (confirmIconId != null || callIconId != null) { + mIconLoadState = LOAD_MULTI_ICONS; + int[] recordNumbers = new int[2]; + recordNumbers[0] = confirmIconId != null + ? confirmIconId.recordNumber : -1; + recordNumbers[1] = callIconId != null ? callIconId.recordNumber + : -1; + + mIconLoader.loadIcons(recordNumbers, this + .obtainMessage(MSG_ID_LOAD_ICON_DONE)); + return true; + } + return false; + } +} \ No newline at end of file diff --git a/telephony/java/com/android/internal/telephony/gsm/stk/ComprehensionTlv.java b/telephony/java/com/android/internal/telephony/gsm/stk/ComprehensionTlv.java index 3cf8ca67a5c623863b3818e86b203ccb51ade2f7..833ff3cfffb04bf0710df437c015b0ebeb183b1f 100644 --- a/telephony/java/com/android/internal/telephony/gsm/stk/ComprehensionTlv.java +++ b/telephony/java/com/android/internal/telephony/gsm/stk/ComprehensionTlv.java @@ -33,7 +33,7 @@ class ComprehensionTlv { private int mLength; private int mValueIndex; private byte[] mRawValue; - + /** * Constructor. Private on purpose. Use * {@link #decodeMany(byte[], int) decodeMany} or @@ -45,7 +45,7 @@ class ComprehensionTlv { * @param data Byte array containing the value * @param valueIndex Index in data at which the value starts */ - private ComprehensionTlv(int tag, boolean cr, int length, byte[] data, + protected ComprehensionTlv(int tag, boolean cr, int length, byte[] data, int valueIndex) { mTag = tag; mCr = cr; @@ -165,9 +165,9 @@ class ComprehensionTlv { } else { throw new ResultException(ResultCode.CMD_DATA_NOT_UNDERSTOOD); } - + return new ComprehensionTlv(tag, cr, length, data, curIndex); - + } catch (IndexOutOfBoundsException e) { throw new ResultException(ResultCode.CMD_DATA_NOT_UNDERSTOOD); } diff --git a/telephony/java/com/android/internal/telephony/gsm/stk/Duration.java b/telephony/java/com/android/internal/telephony/gsm/stk/Duration.java index 9ca8fb53aa62f69b40444cd6249ff7f1b7ca549d..9d8cc974f762254bb6d63bbc4b393aa407038229 100644 --- a/telephony/java/com/android/internal/telephony/gsm/stk/Duration.java +++ b/telephony/java/com/android/internal/telephony/gsm/stk/Duration.java @@ -16,13 +16,16 @@ package com.android.internal.telephony.gsm.stk; +import android.os.Parcel; +import android.os.Parcelable; + /** * Class for representing "Duration" object for STK. * * {@hide} */ -public class Duration { +public class Duration implements Parcelable { public int timeInterval; public TimeUnit timeUnit; @@ -49,4 +52,28 @@ public class Duration { this.timeInterval = timeInterval; this.timeUnit = timeUnit; } + + private Duration(Parcel in) { + timeInterval = in.readInt(); + timeUnit = TimeUnit.values()[in.readInt()]; + } + + public void writeToParcel(Parcel dest, int flags) { + dest.writeInt(timeInterval); + dest.writeInt(timeUnit.ordinal()); + } + + public int describeContents() { + return 0; + } + + public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { + public Duration createFromParcel(Parcel in) { + return new Duration(in); + } + + public Duration[] newArray(int size) { + return new Duration[size]; + } + }; } diff --git a/telephony/java/com/android/internal/telephony/gsm/stk/IconLoader.java b/telephony/java/com/android/internal/telephony/gsm/stk/IconLoader.java index ee9154191bcee590d5fb64cad5562946c6a0abf4..2219f58159df712e35e5d54fd34ecafba93388e3 100644 --- a/telephony/java/com/android/internal/telephony/gsm/stk/IconLoader.java +++ b/telephony/java/com/android/internal/telephony/gsm/stk/IconLoader.java @@ -27,6 +27,8 @@ import android.os.Looper; import android.os.Message; import android.util.Log; +import java.util.HashMap; + /** * Class for loading icons from the SIM card. Has two states: single, for loading * one icon. Multi, for loading icons list. @@ -34,17 +36,18 @@ import android.util.Log; */ class IconLoader extends Handler { // members - int mState = STATE_SINGLE_ICON; - ImageDescriptor mId = null; - Bitmap mCurrentIcon = null; - int mRecordNumber; - SIMFileHandler mSimFH = null; - Message mEndMsg = null; - byte[] mIconData = null; + private int mState = STATE_SINGLE_ICON; + private ImageDescriptor mId = null; + private Bitmap mCurrentIcon = null; + private int mRecordNumber; + private SIMFileHandler mSimFH = null; + private Message mEndMsg = null; + private byte[] mIconData = null; // multi icons state members - int[] mRecordNumbers = null; - int mCurrentRecordIndex = 0; - Bitmap[] mIcons = null; + private int[] mRecordNumbers = null; + private int mCurrentRecordIndex = 0; + private Bitmap[] mIcons = null; + private HashMap mIconsCache = null; private static IconLoader sLoader = null; @@ -69,14 +72,16 @@ class IconLoader extends Handler { private IconLoader(Looper looper , SIMFileHandler fh) { super(looper); mSimFH = fh; + + mIconsCache = new HashMap(50); } - static IconLoader getInstance(Handler caller , SIMFileHandler fh) { + static IconLoader getInstance(Handler caller, SIMFileHandler fh) { if (sLoader != null) { return sLoader; } if (fh != null) { - HandlerThread thread = new HandlerThread("Stk Icon Laoder"); + HandlerThread thread = new HandlerThread("Stk Icon Loader"); thread.start(); return new IconLoader(thread.getLooper(), fh); } @@ -104,7 +109,7 @@ class IconLoader extends Handler { mState = STATE_SINGLE_ICON; startLoadingIcon(recordNumber); } - + private void startLoadingIcon(int recordNumber) { // Reset the load variables. mId = null; @@ -112,6 +117,13 @@ class IconLoader extends Handler { mCurrentIcon = null; mRecordNumber = recordNumber; + // make sure the icon was not already loaded and saved in the local cache. + if (mIconsCache.containsKey(recordNumber)) { + mCurrentIcon = mIconsCache.get(recordNumber); + postIcon(); + return; + } + // start the first phase ==> loading Image Descriptor. readId(); } @@ -134,6 +146,7 @@ class IconLoader extends Handler { byte[] rawData = ((byte[]) ar.result); if (mId.codingScheme == ImageDescriptor.CODING_SCHEME_BASIC) { mCurrentIcon = parseToBnW(rawData, rawData.length); + mIconsCache.put(mRecordNumber, mCurrentIcon); postIcon(); } else if (mId.codingScheme == ImageDescriptor.CODING_SCHEME_COLOUR) { mIconData = rawData; @@ -145,6 +158,7 @@ class IconLoader extends Handler { byte [] clut = ((byte[]) ar.result); mCurrentIcon = parseToRGB(mIconData, mIconData.length, false, clut); + mIconsCache.put(mRecordNumber, mCurrentIcon); postIcon(); break; } @@ -181,6 +195,11 @@ class IconLoader extends Handler { // Start reading Image Descriptor from SIM card. private void readId() { + if (mRecordNumber < 0) { + mCurrentIcon = null; + postIcon(); + return; + } Message msg = this.obtainMessage(EVENT_READ_EF_IMG_RECOED_DONE); mSimFH.loadEFImgLinearFixed(mRecordNumber, msg); } diff --git a/telephony/java/com/android/internal/telephony/gsm/stk/Input.java b/telephony/java/com/android/internal/telephony/gsm/stk/Input.java new file mode 100644 index 0000000000000000000000000000000000000000..1f0d9711b7055067214069db227fd212b2e6bab0 --- /dev/null +++ b/telephony/java/com/android/internal/telephony/gsm/stk/Input.java @@ -0,0 +1,97 @@ +/* + * Copyright (C) 2007 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.android.internal.telephony.gsm.stk; + +import android.graphics.Bitmap; +import android.os.Parcel; +import android.os.Parcelable; + +/** + * Container class for STK GET INPUT, GET IN KEY commands parameters. + * + */ +public class Input implements Parcelable { + public String text; + public String defaultText; + public Bitmap icon; + public int minLen; + public int maxLen; + public boolean ucs2; + public boolean packed; + public boolean digitOnly; + public boolean echo; + public boolean yesNo; + public boolean helpAvailable; + + Input() { + text = ""; + defaultText = null; + icon = null; + minLen = 0; + maxLen = 1; + ucs2 = false; + packed = false; + digitOnly = false; + echo = false; + yesNo = false; + helpAvailable = false; + } + + private Input(Parcel in) { + text = in.readString(); + defaultText = in.readString(); + icon = in.readParcelable(null); + minLen = in.readInt(); + maxLen = in.readInt(); + ucs2 = in.readInt() == 1 ? true : false; + packed = in.readInt() == 1 ? true : false; + digitOnly = in.readInt() == 1 ? true : false; + echo = in.readInt() == 1 ? true : false; + yesNo = in.readInt() == 1 ? true : false; + helpAvailable = in.readInt() == 1 ? true : false; + } + + public int describeContents() { + return 0; + } + + public void writeToParcel(Parcel dest, int flags) { + dest.writeString(text); + dest.writeString(defaultText); + dest.writeParcelable(icon, 0); + dest.writeInt(minLen); + dest.writeInt(maxLen); + dest.writeInt(ucs2 ? 1 : 0); + dest.writeInt(packed ? 1 : 0); + dest.writeInt(digitOnly ? 1 : 0); + dest.writeInt(echo ? 1 : 0); + dest.writeInt(yesNo ? 1 : 0); + dest.writeInt(helpAvailable ? 1 : 0); + } + + public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { + public Input createFromParcel(Parcel in) { + return new Input(in); + } + + public Input[] newArray(int size) { + return new Input[size]; + } + }; + + boolean setIcon(Bitmap Icon) { return true; } +} \ No newline at end of file diff --git a/telephony/java/com/android/internal/telephony/gsm/stk/Item.java b/telephony/java/com/android/internal/telephony/gsm/stk/Item.java index 0122c86b61c3ae8d783158181361b3cfc95cee1a..b2f338c19d609cf943d5cebc93686b769a467ea5 100644 --- a/telephony/java/com/android/internal/telephony/gsm/stk/Item.java +++ b/telephony/java/com/android/internal/telephony/gsm/stk/Item.java @@ -42,6 +42,7 @@ public class Item implements Parcelable { public Item(Parcel in) { id = in.readInt(); text = in.readString(); + icon = in.readParcelable(null); } public int describeContents() { @@ -51,6 +52,7 @@ public class Item implements Parcelable { public void writeToParcel(Parcel dest, int flags) { dest.writeInt(id); dest.writeString(text); + dest.writeParcelable(icon, flags); } public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { diff --git a/telephony/java/com/android/internal/telephony/gsm/stk/Menu.java b/telephony/java/com/android/internal/telephony/gsm/stk/Menu.java index 5f9de15072c46c1f10bb28520efd3db13f9a6857..40a6b378df8c0291391dcd8e6dc5852f732f8217 100644 --- a/telephony/java/com/android/internal/telephony/gsm/stk/Menu.java +++ b/telephony/java/com/android/internal/telephony/gsm/stk/Menu.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006 The Android Open Source Project + * Copyright (C) 2007 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. @@ -23,10 +23,15 @@ import android.os.Parcelable; import java.util.ArrayList; import java.util.List; +/** + * Container class for STK menu (SET UP MENU, SELECT ITEM) parameters. + * + */ public class Menu implements Parcelable { public List items; - public String title; public List titleAttrs; + public PresentationType presentationType; + public String title; public Bitmap titleIcon; public int defaultItem; public boolean softKeyPreferred; @@ -36,28 +41,22 @@ public class Menu implements Parcelable { public Menu() { // Create an empty list. - this.items = new ArrayList(); - this.title = null; - this.titleAttrs = null; - this.defaultItem = 0; - this.softKeyPreferred = false; - this.helpAvailable = false; - this.titleIconSelfExplanatory = false; - this.titleIcon = null; - } - - public Menu(List items, String title, List titleAttrs, - boolean softKeyPreferred, boolean helpAvailable, int defaultItem) { - this.items = items; - this.title = title; - this.titleAttrs = titleAttrs; - this.defaultItem = defaultItem; - this.softKeyPreferred = softKeyPreferred; - this.helpAvailable = helpAvailable; + items = new ArrayList(); + title = null; + titleAttrs = null; + defaultItem = 0; + softKeyPreferred = false; + helpAvailable = false; + titleIconSelfExplanatory = false; + itemsIconSelfExplanatory = false; + titleIcon = null; + // set default style to be navigation menu. + presentationType = PresentationType.NAVIGATION_OPTIONS; } private Menu(Parcel in) { title = in.readString(); + titleIcon = in.readParcelable(null); // rebuild items list. items = new ArrayList(); int size = in.readInt(); @@ -68,6 +67,9 @@ public class Menu implements Parcelable { defaultItem = in.readInt(); softKeyPreferred = in.readInt() == 1 ? true : false; helpAvailable = in.readInt() == 1 ? true : false; + titleIconSelfExplanatory = in.readInt() == 1 ? true : false; + itemsIconSelfExplanatory = in.readInt() == 1 ? true : false; + presentationType = PresentationType.values()[in.readInt()]; } public int describeContents() { @@ -76,6 +78,7 @@ public class Menu implements Parcelable { public void writeToParcel(Parcel dest, int flags) { dest.writeString(title); + dest.writeParcelable(titleIcon, flags); // write items list to the parcel. int size = items.size(); dest.writeInt(size); @@ -85,6 +88,9 @@ public class Menu implements Parcelable { dest.writeInt(defaultItem); dest.writeInt(softKeyPreferred ? 1 : 0); dest.writeInt(helpAvailable ? 1 : 0); + dest.writeInt(titleIconSelfExplanatory ? 1 : 0); + dest.writeInt(itemsIconSelfExplanatory ? 1 : 0); + dest.writeInt(presentationType.ordinal()); } public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { diff --git a/telephony/java/com/android/internal/telephony/gsm/stk/ResponseData.java b/telephony/java/com/android/internal/telephony/gsm/stk/ResponseData.java new file mode 100644 index 0000000000000000000000000000000000000000..9afa063891c6b30222a90ca32a19d9836edc3c63 --- /dev/null +++ b/telephony/java/com/android/internal/telephony/gsm/stk/ResponseData.java @@ -0,0 +1,140 @@ +/* + * Copyright (C) 2006-2007 Google Inc. + * + * 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.android.internal.telephony.gsm.stk; + +import com.android.internal.telephony.gsm.EncodeException; +import com.android.internal.telephony.gsm.GsmAlphabet; + +import java.io.ByteArrayOutputStream; +import java.io.UnsupportedEncodingException; + +abstract class ResponseData { + /** + * Format the data appropriate for TERMINAL RESPONSE and write it into + * the ByteArrayOutputStream object. + */ + public abstract void format(ByteArrayOutputStream buf); +} + +class SelectItemResponseData extends ResponseData { + // members + private int id; + + public SelectItemResponseData(int id) { + super(); + this.id = id; + } + + @Override + public void format(ByteArrayOutputStream buf) { + // Item identifier object + int tag = 0x80 | ComprehensionTlvTag.ITEM_ID.value(); + buf.write(tag); // tag + buf.write(1); // length + buf.write(id); // identifier of item chosen + } +} + +class GetInkeyInputResponseData extends ResponseData { + // members + private boolean mIsUcs2; + private boolean mIsPacked; + private boolean mIsYesNo; + private boolean mYesNoResponse; + public String mInData; + + // GetInKey Yes/No response characters constants. + protected static final byte GET_INKEY_YES = 0x01; + protected static final byte GET_INKEY_NO = 0x00; + + public GetInkeyInputResponseData(String inData, boolean ucs2, boolean packed) { + super(); + this.mIsUcs2 = ucs2; + this.mIsPacked = packed; + this.mInData = inData; + this.mIsYesNo = false; + } + + public GetInkeyInputResponseData(boolean yesNoResponse) { + super(); + this.mIsUcs2 = false; + this.mIsPacked = false; + this.mInData = ""; + this.mIsYesNo = true; + this.mYesNoResponse = yesNoResponse; + } + + @Override + public void format(ByteArrayOutputStream buf) { + if (buf == null) { + return; + } + + // Text string object + int tag = 0x80 | ComprehensionTlvTag.TEXT_STRING.value(); + buf.write(tag); // tag + + byte[] data; + + if (mIsYesNo) { + data = new byte[1]; + data[0] = mYesNoResponse ? GET_INKEY_YES : GET_INKEY_NO; + } else if (mInData != null && mInData.length() > 0) { + try { + if (mIsUcs2) { + data = mInData.getBytes("UTF-16"); + } else if (mIsPacked) { + int size = mInData.length(); + + byte[] tempData = GsmAlphabet + .stringToGsm7BitPacked(mInData); + data = new byte[size]; + // Since stringToGsm7BitPacked() set byte 0 in the + // returned byte array to the count of septets used... + // copy to a new array without byte 0. + System.arraycopy(tempData, 1, data, 0, size); + } else { + data = GsmAlphabet.stringToGsm8BitPacked(mInData); + } + } catch (UnsupportedEncodingException e) { + data = new byte[0]; + } catch (EncodeException e) { + data = new byte[0]; + } + } else { + data = new byte[0]; + } + + // length - one more for data coding scheme. + buf.write(data.length + 1); + + // data coding scheme + if (mIsUcs2) { + buf.write(0x08); // UCS2 + } else if (mIsPacked) { + buf.write(0x00); // 7 bit packed + } else { + buf.write(0x04); // 8 bit unpacked + } + + for (byte b : data) { + buf.write(b); + } + } +} + + diff --git a/telephony/java/com/android/internal/telephony/gsm/stk/ResultCode.java b/telephony/java/com/android/internal/telephony/gsm/stk/ResultCode.java index 6559c737f2251dce6e081d3da6b6ddfb01e09f95..b96a5244d233ad8e722440d984b205c70d0c7aba 100644 --- a/telephony/java/com/android/internal/telephony/gsm/stk/ResultCode.java +++ b/telephony/java/com/android/internal/telephony/gsm/stk/ResultCode.java @@ -171,7 +171,16 @@ public enum ResultCode { * Retrieves the actual result code that this object represents. * @return Actual result code */ - public int code() { + public int value() { return mCode; } + + public static ResultCode fromInt(int value) { + for (ResultCode r : ResultCode.values()) { + if (r.mCode == value) { + return r; + } + } + return null; + } } diff --git a/telephony/java/com/android/internal/telephony/gsm/stk/RilMessageDecoder.java b/telephony/java/com/android/internal/telephony/gsm/stk/RilMessageDecoder.java new file mode 100644 index 0000000000000000000000000000000000000000..746b1f1255c73cb63a5051b71848eb5cc1765235 --- /dev/null +++ b/telephony/java/com/android/internal/telephony/gsm/stk/RilMessageDecoder.java @@ -0,0 +1,145 @@ +/* + * Copyright (C) 2007 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.android.internal.telephony.gsm.stk; + +import com.android.internal.telephony.gsm.SIMFileHandler; +import com.android.internal.telephony.gsm.SimUtils; + +import android.os.Handler; +import android.os.HandlerThread; +import android.os.Looper; +import android.os.Message; + +import java.util.concurrent.BlockingQueue; + +/** + * Class used for queuing raw ril messages, decoding them into CommanParams + * objects and sending the result back to the STK Service. + * + */ +class RilMessageDecoder extends Handler { + + // members + private final BlockingQueue mInQueue; + private static RilMessageDecoder sInstance = null; + private CommandParamsFactory mCmdParamsFactory = null; + private RilMessage mCurrentRilMessage = null; + private Handler mCaller = null; + + // constants + static final int START = 1; + static final int CMD_PARAMS_READY = 2; + + static RilMessageDecoder getInstance(BlockingQueue inQ, + Handler caller, SIMFileHandler fh) { + if (sInstance != null) { + return sInstance; + } + if (inQ != null) { + HandlerThread thread = new HandlerThread("Stk RIL Messages decoder"); + thread.start(); + return new RilMessageDecoder(thread.getLooper(), inQ, caller, fh); + } + return null; + } + + private RilMessageDecoder(Looper looper, BlockingQueue inQ, + Handler caller, SIMFileHandler fh) { + super(looper); + mInQueue = inQ; + mCaller = caller; + mCmdParamsFactory = CommandParamsFactory.getInstance(this, fh); + } + + public void handleMessage(Message msg) { + switch(msg.what) { + case START: + start(); + break; + case CMD_PARAMS_READY: + mCurrentRilMessage.mResCode = ResultCode.fromInt(msg.arg1); + mCurrentRilMessage.mData = msg.obj; + sendCmdForExecution(); + break; + } + } + + private void start() { + boolean interrupted = false; + try { + while (true) { + try { + mCurrentRilMessage = mInQueue.take(); + StkLog.d(this, "Decoding new message"); + break; + } catch (InterruptedException e) { + interrupted = true; + // fall through and retry + } + } + } finally { + if (interrupted) { + Thread.currentThread().interrupt(); + } + if (mCurrentRilMessage != null) { + decodeMessage(mCurrentRilMessage); + } + } + } + + private void decodeMessage(RilMessage msg) { + switch(msg.mId) { + case Service.MSG_ID_SESSION_END: + case Service.MSG_ID_CALL_SETUP: + mCurrentRilMessage.mResCode = ResultCode.OK; + sendCmdForExecution(); + break; + case Service.MSG_ID_PROACTIVE_COMMAND: + case Service.MSG_ID_EVENT_NOTIFY: + case Service.MSG_ID_REFRESH: + byte[] rawData = null; + try { + rawData = SimUtils.hexStringToBytes((String) msg.mData); + } catch (Exception e) { + // zombie messages are dropped + getNextMessage(); + return; + } + try { + // Start asynch parsing of the command parameters. + mCmdParamsFactory.make(BerTlv.decode(rawData)); + } catch (ResultException e) { + // send to Service for proper RIL communication. + mCurrentRilMessage.mResCode = e.result(); + sendCmdForExecution(); + } + break; + } + } + + private void sendCmdForExecution() { + Message msg = mCaller.obtainMessage(Service.MSG_ID_RIL_MSG_DECODED, + new RilMessage(mCurrentRilMessage)); + msg.sendToTarget(); + getNextMessage(); + } + + private void getNextMessage() { + Message nextMsg = this.obtainMessage(START); + nextMsg.sendToTarget(); + } +} \ No newline at end of file diff --git a/telephony/java/com/android/internal/telephony/gsm/stk/Service.java b/telephony/java/com/android/internal/telephony/gsm/stk/Service.java index e002202c9d95ecd1f3fa17b93a2a2448173a0bee..aae9b300b14496d0117fa562bed98a6a04430d0d 100644 --- a/telephony/java/com/android/internal/telephony/gsm/stk/Service.java +++ b/telephony/java/com/android/internal/telephony/gsm/stk/Service.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006 The Android Open Source Project + * Copyright (C) 2007 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. @@ -16,41 +16,24 @@ package com.android.internal.telephony.gsm.stk; -import android.app.Notification; -import android.app.NotificationManager; -import android.app.PendingIntent; import android.content.Context; import android.content.Intent; -import android.content.IntentFilter; import android.os.AsyncResult; import android.os.Handler; +import android.os.HandlerThread; import android.os.Message; -import android.graphics.Bitmap; -import android.graphics.drawable.Drawable; import com.android.internal.telephony.gsm.CommandsInterface; -import com.android.internal.telephony.gsm.EncodeException; -import com.android.internal.telephony.gsm.GsmAlphabet; import com.android.internal.telephony.gsm.GsmSimCard; import com.android.internal.telephony.gsm.SIMFileHandler; import com.android.internal.telephony.gsm.SIMRecords; import com.android.internal.telephony.gsm.SimUtils; -import com.android.internal.telephony.gsm.stk.Duration.TimeUnit; import android.util.Config; -import android.util.Log; -import android.view.Gravity; -import android.view.LayoutInflater; -import android.view.View; -import android.widget.RemoteViews; -import android.widget.TextView; -import android.widget.Toast; import java.io.ByteArrayOutputStream; -import java.io.UnsupportedEncodingException; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.LinkedBlockingQueue; /** * Enumeration for representing the tag value of COMPREHENSION-TLV objects. If @@ -93,51 +76,12 @@ enum ComprehensionTlvTag { * * @return Actual tag value of this object */ - public int value() { - return mValue; - } -} - -/** - * Enumeration for representing "Type of Command" of proactive commands. If you - * want to create a CommandType object, call the static method {@link - * #fromInt(int) fromInt}. - * - * {@hide} - */ -enum CommandType { - DISPLAY_TEXT(0x21), - GET_INKEY(0x22), - GET_INPUT(0x23), - LAUNCH_BROWSER(0x15), - PLAY_TONE(0x20), - REFRESH(0x01), - SELECT_ITEM(0x24), - SEND_SS(0x11), - SEND_USSD(0x12), - SEND_SMS(0x13), - SEND_DTMF(0x14), - SET_UP_EVENT_LIST(0x05), - SET_UP_IDLE_MODE_TEXT(0x28), - SET_UP_MENU(0x25), - SET_UP_CALL(0x10); - - private int mValue; - - CommandType(int value) { - mValue = value; - } + public int value() { + return mValue; + } - /** - * Create a CommandType object. - * - * @param value Integer value to be converted to a CommandType object. - * @return CommandType object whose "Type of Command" value is {@code - * value}. If no CommandType object has that value, null is - * returned. - */ - public static CommandType fromInt(int value) { - for (CommandType e : CommandType.values()) { + public static ComprehensionTlvTag fromInt(int value) { + for (ComprehensionTlvTag e : ComprehensionTlvTag.values()) { if (e.mValue == value) { return e; } @@ -146,8 +90,26 @@ enum CommandType { } } +class RilMessage { + int mId; + Object mData; + ResultCode mResCode; + + RilMessage(int msgId, String rawData) { + mId = msgId; + mData = rawData; + } + + RilMessage(RilMessage other) { + this.mId = other.mId; + this.mData = other.mData; + this.mResCode = other.mResCode; + } +} + /** - * Main class that implements SIM Toolkit Service. + * Class that implements SIM Toolkit Telephony Service. Interacts with the RIL + * and application. * * {@hide} */ @@ -158,30 +120,26 @@ public class Service extends Handler implements AppInterface { private CommandsInterface mCmdIf; private SIMRecords mSimRecords; private Context mContext; - private GsmSimCard mSimCard; - private CommandListener mCmdListener; - private Object mCmdListenerLock = new Object(); - private CommandParams mCmdParams = null; - private CommandParams mNextCmdParams = null; - private State mState = State.IDLE; - private Menu mMainMenu = null; - private String mServiceName = ""; - private NotificationManager mNm = null; - private int mAppIndicator = APP_INDICATOR_PRE_BOOT; - private int mInstallIndicator = APP_INDICATOR_UNINSTALLED; - private IconLoader mIconLoader = null; - - private static final String TAG = "STK"; + private StkCmdMessage mCurrntCmd = null; + private StkCmdMessage mMenuCmd = null; + + private BlockingQueue mRilMessagesQ = null; + private RilMessageDecoder mMsgDecoder = null; + + public static final String TAG = "STK"; // Service constants. - private static final int EVENT_SESSION_END = 1; - private static final int EVENT_PROACTIVE_COMMAND = 2; - private static final int EVENT_EVENT_NOTIFY = 3; - private static final int EVENT_CALL_SETUP = 4; + static final int MSG_ID_SESSION_END = 1; + static final int MSG_ID_PROACTIVE_COMMAND = 2; + static final int MSG_ID_EVENT_NOTIFY = 3; + static final int MSG_ID_CALL_SETUP = 4; + static final int MSG_ID_REFRESH = 5; + static final int MSG_ID_RESPONSE = 6; + + static final int MSG_ID_RIL_MSG_DECODED = 10; + // Events to signal SIM presence or absent in the device. - private static final int EVENT_SIM_LOADED = 12; - private static final int EVENT_SIM_ABSENT = 13; - static final int EVENT_LOAD_ICON_DONE = 14; + private static final int MSG_ID_SIM_LOADED = 20; private static final int DEV_ID_KEYPAD = 0x01; private static final int DEV_ID_DISPLAY = 0x02; @@ -190,64 +148,6 @@ public class Service extends Handler implements AppInterface { private static final int DEV_ID_TERMINAL = 0x82; private static final int DEV_ID_NETWORK = 0x83; - // Event value for Event List COMPREHENSION-TLV object - public static final int UICC_EVENT_MT_CALL = 0x00; - public static final int UICC_EVENT_CALL_CONNECTED = 0x01; - public static final int UICC_EVENT_CALL_DISCONNECTED = 0x02; - public static final int UICC_EVENT_LOCATION_STATUS = 0x03; - public static final int UICC_EVENT_USER_ACTIVITY = 0x04; - public static final int UICC_EVENT_IDLE_SCREEN_AVAILABLE = 0x05; - public static final int UICC_EVENT_CARD_READER_STATUS = 0x06; - public static final int UICC_EVENT_LANGUAGE_SELECTION = 0x07; - public static final int UICC_EVENT_BROWSER_TERMINATION = 0x08; - public static final int UICC_EVENT_DATA_AVAILABLE = 0x09; - public static final int UICC_EVENT_CHANNEL_STATUS = 0x0a; - public static final int UICC_EVENT_ACCESS_TECH_CHANGE = 0x0b; - public static final int UICC_EVENT_DISPLAY_PARAMS_CHANGE = 0x0c; - public static final int UICC_EVENT_LOCAL_CONNECTION = 0x0d; - public static final int UICC_EVENT_NETWORK_SEARCH_MODE_CHANGE = 0x0e; - public static final int UICC_EVENT_BROWSING_STATUS = 0x0f; - public static final int UICC_EVENT_FRAMES_INFO_CHANGE = 0x10; - public static final int UICC_EVENT_I_WLAN_ACESS_STATUS = 0x11; - - // Command Qualifier values - static final int REFRESH_NAA_INIT_AND_FULL_FILE_CHANGE = 0x00; - static final int REFRESH_NAA_INIT_AND_FILE_CHANGE = 0x02; - static final int REFRESH_NAA_INIT = 0x03; - static final int REFRESH_UICC_RESET = 0x04; - - // GetInKey Yes/No response characters constants. - private static final byte GET_INKEY_YES = 0x01; - private static final byte GET_INKEY_NO = 0x00; - - // Notification id used to display Idle Mode text in NotificationManager. - static final int STK_NOTIFICATION_ID = 333; - - private static String APP_PACKAGE_NAME = "com.android.stk"; - private static String APP_FULL_NAME = APP_PACKAGE_NAME + ".StkActivity"; - - // Application indicators constants - static final int APP_INDICATOR_PRE_BOOT = 0; - static final int APP_INDICATOR_UNINSTALLED = 1; - static final int APP_INDICATOR_INSTALLED_NORMAL = 2; - static final int APP_INDICATOR_INSTALLED_SPECIAL = 3; - private static final int APP_INDICATOR_LAUNCHED = 4; - // Use setAppIndication(APP_INSTALL_INDICATOR) to go back for the original - // install indication. - private static final int APP_INSTALL_INDICATOR = 5; - - // Container class to hold temporary icon identifier TLV object info. - class IconId { - int recordNumber; - boolean selfExplanatory; - } - - // Container class to hold temporary item icon identifier list TLV object info. - class ItemsIconId { - int [] recordNumbers; - boolean selfExplanatory; - } - /* Intentionally private for singleton */ private Service(CommandsInterface ci, SIMRecords sr, Context context, SIMFileHandler fh, GsmSimCard sc) { @@ -259,108 +159,200 @@ public class Service extends Handler implements AppInterface { mCmdIf = ci; mContext = context; - mCmdIf.setOnStkSessionEnd(this, EVENT_SESSION_END, null); - mCmdIf.setOnStkProactiveCmd(this, EVENT_PROACTIVE_COMMAND, null); - mCmdIf.setOnStkEvent(this, EVENT_EVENT_NOTIFY, null); - mCmdIf.setOnStkCallSetUp(this, EVENT_CALL_SETUP, null); - - mSimRecords = sr; + // Initialize a blocking queue to be used for ril messages, and a + // RilMessagesDecoder for decoding the messages into a CommandParams. + // Each CommandParams is put into a SynchronousQueue and pulled by the + // Service take() when its ready to handle the next command. + mRilMessagesQ = new LinkedBlockingQueue(); + mMsgDecoder = RilMessageDecoder.getInstance(mRilMessagesQ, this, fh); - mSimCard = sc; - mNm = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); - mIconLoader = IconLoader.getInstance(this, fh); + // Register ril events handling. + mCmdIf.setOnStkSessionEnd(this, MSG_ID_SESSION_END, null); + mCmdIf.setOnStkProactiveCmd(this, MSG_ID_PROACTIVE_COMMAND, null); + mCmdIf.setOnStkEvent(this, MSG_ID_EVENT_NOTIFY, null); + mCmdIf.setOnStkCallSetUp(this, MSG_ID_CALL_SETUP, null); + //mCmdIf.setOnSimRefresh(this, MSG_ID_REFRESH, null); - // Register a receiver for install/unistall application. - StkAppStateReceiver receiver = new StkAppStateReceiver(); - IntentFilter filter = new IntentFilter(); - filter.addAction(StkAppInstaller.STK_APP_INSTALL_ACTION); - filter.addAction(StkAppInstaller.STK_APP_UNINSTALL_ACTION); - mContext.registerReceiver(receiver, filter); + mSimRecords = sr; // Register for SIM ready event. - mSimRecords.registerForRecordsLoaded(this, EVENT_SIM_LOADED, null); - mSimCard.registerForAbsent(this, EVENT_SIM_ABSENT, null); + mSimRecords.registerForRecordsLoaded(this, MSG_ID_SIM_LOADED, null); + // start decoding ril messages. + mMsgDecoder.obtainMessage(RilMessageDecoder.START).sendToTarget(); } - /** - * Used for retrieving the only Service object in the system. There is only - * one Service object. - * - * @param ci CommandsInterface object - * @param sr SIMRecords object - * @return The only Service object in the system - */ - public static Service getInstance(CommandsInterface ci, SIMRecords sr, - Context context, SIMFileHandler fh, GsmSimCard sc) { - if (sInstance == null) { - if (ci == null || sr == null || context == null || fh == null - || sc == null) { - return null; + private void handleRilMsg(RilMessage rilMsg) { + if (rilMsg == null) { + return; + } + + // dispatch messages + CommandParams cmdParams = null; + switch (rilMsg.mId) { + case MSG_ID_EVENT_NOTIFY: + if (rilMsg.mResCode == ResultCode.OK) { + cmdParams = (CommandParams) rilMsg.mData; + if (cmdParams != null) { + handleProactiveCommand(cmdParams); + } } - sInstance = new Service(ci, sr, context, fh, sc); + break; + case MSG_ID_PROACTIVE_COMMAND: + cmdParams = (CommandParams) rilMsg.mData; + if (cmdParams != null) { + if (rilMsg.mResCode == ResultCode.OK) { + handleProactiveCommand(cmdParams); + } else { + // for proactive commands that couldn't be decoded + // successfully respond with the code generated by the + // message decoder. + sendTerminalResponse(cmdParams.cmdDet, rilMsg.mResCode, + false, 0, null); + } + } + break; + case MSG_ID_REFRESH: + cmdParams = (CommandParams) rilMsg.mData; + if (cmdParams != null) { + handleProactiveCommand(cmdParams); + } + break; + case MSG_ID_SESSION_END: + handleSessionEnd(); + break; + case MSG_ID_CALL_SETUP: + // prior event notify command supplied all the information + // needed for set up call processing. + break; } - return sInstance; } /** - * Used for retrieving the only Service object in the system. There is only - * one Service object. + * Handles RIL_UNSOL_STK_PROACTIVE_COMMAND unsolicited command from RIL. + * Sends valid proactive command data to the application using intents. * - * @return The only Service object in the system */ - public static Service getInstance() { - return getInstance(null, null, null, null, null); - } + private void handleProactiveCommand(CommandParams cmdParams) { + StkLog.d(this, cmdParams.getCommandType().name()); - /** - * {@inheritDoc} - */ - public void setCommandListener(CommandListener l) { - synchronized (mCmdListenerLock) { - mCmdListener = l; - if (mCmdListener != null) { - setAppIndication(APP_INDICATOR_LAUNCHED); + StkCmdMessage cmdMsg = new StkCmdMessage(cmdParams); + switch (cmdParams.getCommandType()) { + case SET_UP_MENU: + if (removeMenu(cmdMsg.getMenu())) { + mMenuCmd = null; } else { - setAppIndication(APP_INSTALL_INDICATOR); + mMenuCmd = cmdMsg; } - } - } - - synchronized void setAppIndication(int indication) { - switch(indication) { - case APP_INDICATOR_PRE_BOOT: - case APP_INDICATOR_UNINSTALLED: - case APP_INDICATOR_INSTALLED_NORMAL: - case APP_INDICATOR_INSTALLED_SPECIAL: - case APP_INDICATOR_LAUNCHED: - mAppIndicator = indication; + sendTerminalResponse(cmdParams.cmdDet, ResultCode.OK, false, 0, + null); + break; + case DISPLAY_TEXT: + // when application is not required to respond, send an immediate + // response. + if (!cmdMsg.geTextMessage().responseNeeded) { + sendTerminalResponse(cmdParams.cmdDet, ResultCode.OK, false, + 0, null); + } + break; + case REFRESH: + // ME side only handles refresh commands which meant to remove IDLE + // MODE TEXT. + cmdParams.cmdDet.typeOfCommand = CommandType.SET_UP_IDLE_MODE_TEXT + .value(); + break; + case SET_UP_IDLE_MODE_TEXT: + sendTerminalResponse(cmdParams.cmdDet, ResultCode.OK, false, + 0, null); break; - case APP_INSTALL_INDICATOR: - mAppIndicator = mInstallIndicator; + case LAUNCH_BROWSER: + case SELECT_ITEM: + case GET_INPUT: + case GET_INKEY: + case SEND_DTMF: + case SEND_SMS: + case SEND_SS: + case SEND_USSD: + case PLAY_TONE: + case SET_UP_CALL: + // nothing to do on telephony! break; default: - throw new NullPointerException("Trying to set wrong app indication"); + StkLog.d(this, "Unsupported command"); + return; } - } - - public synchronized int getAppIndication() { - return mAppIndicator; + mCurrntCmd = cmdMsg; + Intent intent = new Intent(AppInterface.STK_CMD_ACTION); + intent.putExtra("STK CMD", cmdMsg); + mContext.sendBroadcast(intent); } /** - * {@inheritDoc} + * Handles RIL_UNSOL_STK_SESSION_END unsolicited command from RIL. + * */ - public State getState() { - return mState; + private void handleSessionEnd() { + StkLog.d(this, "SESSION END"); + + mCurrntCmd = mMenuCmd; + Intent intent = new Intent(AppInterface.STK_SESSION_END_ACTION); + mContext.sendBroadcast(intent); } - /** - * {@inheritDoc} - */ - public void notifyMenuSelection(int menuId, boolean helpRequired) { - if (mState != State.MAIN_MENU) { + private void sendTerminalResponse(CommandDetails cmdDet, + ResultCode resultCode, boolean includeAdditionalInfo, + int additionalInfo, ResponseData resp) { + + if (cmdDet == null) { return; } + ByteArrayOutputStream buf = new ByteArrayOutputStream(); + + // command details + int tag = ComprehensionTlvTag.COMMAND_DETAILS.value(); + if (cmdDet.compRequired) { + tag |= 0x80; + } + buf.write(tag); + buf.write(0x03); // length + buf.write(cmdDet.commandNumber); + buf.write(cmdDet.typeOfCommand); + buf.write(cmdDet.commandQualifier); + + // device identities + tag = 0x80 | ComprehensionTlvTag.DEVICE_IDENTITIES.value(); + buf.write(tag); + buf.write(0x02); // length + buf.write(DEV_ID_TERMINAL); // source device id + buf.write(DEV_ID_UICC); // destination device id + + // result + tag = 0x80 | ComprehensionTlvTag.RESULT.value(); + buf.write(tag); + int length = includeAdditionalInfo ? 2 : 1; + buf.write(length); + buf.write(resultCode.value()); + + // additional info + if (includeAdditionalInfo) { + buf.write(additionalInfo); + } + + // Fill optional data for each corresponding command + if (resp != null) { + resp.format(buf); + } + + byte[] rawData = buf.toByteArray(); + String hexString = SimUtils.bytesToHexString(rawData); + if (Config.LOGD) { + StkLog.d(this, "TERMINAL RESPONSE: " + hexString); + } + + mCmdIf.sendTerminalResponse(hexString, null); + } + + + private void sendMenuSelection(int menuId, boolean helpRequired) { ByteArrayOutputStream buf = new ByteArrayOutputStream(); @@ -402,112 +394,6 @@ public class Service extends Handler implements AppInterface { mCmdIf.sendEnvelope(hexString, null); } - /** - * {@inheritDoc} - */ - public void notifyUserActivity() { - eventDownload(UICC_EVENT_USER_ACTIVITY, DEV_ID_TERMINAL, DEV_ID_UICC, - null, true); - } - - /** - * {@inheritDoc} - */ - public void notifyDisplayTextEnded(ResultCode terminationCode) { - if (mState != State.DISPLAY_TEXT) { - return; - } - ResultCode rc = ResultCode.OK; - - switch (terminationCode) { - case OK: - case BACKWARD_MOVE_BY_USER: - case NO_RESPONSE_FROM_USER: - rc = terminationCode; - break; - default: - Log.d(TAG, "Invalid termination code for Display Text"); - return; - } - sendTerminalResponse(mCmdParams.cmdDet, rc, false, 0, null); - } - - /** - * {@inheritDoc} - */ - public void notifyToneEnded() { - if (mState != State.PLAY_TONE) { - return; - } - - sendTerminalResponse(mCmdParams.cmdDet, ResultCode.OK, false, 0, - null); - } - - /** - * {@inheritDoc} - */ - public void notifyIdleScreenAvailable() { - eventDownload(UICC_EVENT_IDLE_SCREEN_AVAILABLE, DEV_ID_DISPLAY, - DEV_ID_UICC, null, true); - } - - /** - * {@inheritDoc} - */ - public void notifyLanguageSelection(String langCode) { - assert langCode.length() == 2 : "Language code must be two characters"; - - byte[] lang = GsmAlphabet.stringToGsm8BitPacked(langCode); - ByteArrayOutputStream buf = new ByteArrayOutputStream(); - - // language - int tag = 0x80 | ComprehensionTlvTag.LANGUAGE.value(); - buf.write(tag); - buf.write(0x02); // length - buf.write(lang[0]); - buf.write(lang[1]); - - byte[] info = buf.toByteArray(); - - eventDownload(UICC_EVENT_LANGUAGE_SELECTION, DEV_ID_TERMINAL, - DEV_ID_UICC, info, false); - } - - /** - * {@inheritDoc} - */ - public void notifyBrowserTermination(boolean isErrorTermination) { - ByteArrayOutputStream buf = new ByteArrayOutputStream(); - - int cause = isErrorTermination ? 1 : 0; - - // browser termination cause - int tag = 0x80 | ComprehensionTlvTag.BROWSER_TERMINATION_CAUSE.value(); - buf.write(tag); - buf.write(0x01); // length - buf.write(cause); - - byte[] info = buf.toByteArray(); - - eventDownload(UICC_EVENT_BROWSER_TERMINATION, DEV_ID_TERMINAL, - DEV_ID_UICC, info, true); - } - - /** - * {@inheritDoc} - */ - public void notifyLaunchBrowser(boolean userConfirmed) { - - if (mState != State.LAUNCH_BROWSER) { - return; - } - - ResultCode rc = userConfirmed ? ResultCode.OK - : ResultCode.TERMINAL_CRNTLY_UNABLE_TO_PROCESS; - sendTerminalResponse(mCmdParams.cmdDet, rc, false, 0, null); - } - private void eventDownload(int event, int sourceId, int destinationId, byte[] additionalInfo, boolean oneShot) { @@ -552,1916 +438,170 @@ public class Service extends Handler implements AppInterface { } /** - * {@inheritDoc} + * Used for instantiating the Service from the GsmPhone constructor. + * + * @param ci CommandsInterface object + * @param sr SIMRecords object + * @param context phone app context + * @param fh SIM file handler + * @param sc GSM SIM card + * @return The only Service object in the system */ - public void notifyInkey(char key, boolean helpRequired) { - if (mState != State.GET_INKEY) { - return; - } - - GetInkeyInputResponseData resp = null; - ResultCode result = ResultCode.OK; - GetInkeyParams request = (GetInkeyParams) mCmdParams; - if (helpRequired) { - result = ResultCode.HELP_INFO_REQUIRED; - } else { - resp = new GetInkeyInputResponseData(Character.toString(key), - request.isUcs2, false); + public static Service getInstance(CommandsInterface ci, SIMRecords sr, + Context context, SIMFileHandler fh, GsmSimCard sc) { + if (sInstance == null) { + if (ci == null || sr == null || context == null || fh == null + || sc == null) { + return null; + } + HandlerThread thread = new HandlerThread("Stk Telephony service"); + thread.start(); + sInstance = new Service(ci, sr, context, fh, sc); } - - sendTerminalResponse(request.cmdDet, result, false, 0, resp); + return sInstance; } /** - * {@inheritDoc} + * Used by application to get an AppInterface object. + * + * @return The only Service object in the system */ - public void notifyInkey(boolean yesNoResponse, boolean helpRequired) { - if (mState != State.GET_INKEY) { - return; - } - - GetInkeyInputResponseData resp = null; - ResultCode result = ResultCode.OK; - GetInkeyParams cmdParams = (GetInkeyParams) mCmdParams; - if (!cmdParams.isYesNo) { - // Illegal use of this call. - return; - } - if (helpRequired) { - result = ResultCode.HELP_INFO_REQUIRED; - } else { - resp = new GetInkeyInputResponseData(yesNoResponse); - } - - sendTerminalResponse(cmdParams.cmdDet, result, false, 0, resp); + public static AppInterface getInstance() { + return getInstance(null, null, null, null, null); } /** * {@inheritDoc} */ - public void notifyInput(String input, boolean helpRequired) { - if (mState != State.GET_INPUT) { - return; - } - - GetInkeyInputResponseData resp = null; - GetInputParams cmdParams = (GetInputParams) mCmdParams; - ResultCode result = ResultCode.OK; + public void handleMessage(Message msg) { - if (helpRequired) { - result = ResultCode.HELP_INFO_REQUIRED; - } else { - resp = new GetInkeyInputResponseData(input, cmdParams.isUcs2, - cmdParams.isPacked); + switch (msg.what) { + case MSG_ID_SESSION_END: + case MSG_ID_PROACTIVE_COMMAND: + case MSG_ID_EVENT_NOTIFY: + case MSG_ID_REFRESH: + StkLog.d(this, "ril message arrived"); + String data = null; + if (msg.obj != null) { + AsyncResult ar = (AsyncResult) msg.obj; + if (ar != null && ar.result != null) { + try { + data = (String) ar.result; + } catch (ClassCastException e) { + break; + } + } + } + mRilMessagesQ.add(new RilMessage(msg.what, data)); + break; + case MSG_ID_CALL_SETUP: + mRilMessagesQ.add(new RilMessage(msg.what, null)); + break; + case MSG_ID_SIM_LOADED: + break; + case MSG_ID_RIL_MSG_DECODED: + handleRilMsg((RilMessage) msg.obj); + break; + case MSG_ID_RESPONSE: + handleCmdResponse((StkResponseMessage) msg.obj); + break; + default: + throw new AssertionError("Unrecognized STK command: " + msg.what); } - sendTerminalResponse(cmdParams.cmdDet, result, false, 0, resp); } - /** - * {@inheritDoc} - */ - public void notifySelectedItem(int id, boolean helpRequired) { - if (mState != State.SELECT_ITEM) { + public synchronized void onCmdResponse(StkResponseMessage resMsg) { + if (resMsg == null) { return; } + // queue a response message. + Message msg = this.obtainMessage(MSG_ID_RESPONSE, resMsg); + msg.sendToTarget(); + } - SelectItemResponseData resp = new SelectItemResponseData(id); - ResultCode result = helpRequired ? ResultCode.HELP_INFO_REQUIRED - : ResultCode.OK; - - sendTerminalResponse(mCmdParams.cmdDet, result, false, 0, resp); + private boolean validateResponse(StkResponseMessage resMsg) { + if (mCurrntCmd != null) { + return (resMsg.cmdDet.compareTo(mCurrntCmd.mCmdDet)); + } + return false; } - /** - * {@inheritDoc} - */ - public void notifyNoResponse() { - CtlvCommandDetails cmdDet = getCurrentCmdDet(); - if (cmdDet == null) { - // Unable to continue; - return; - } - sendTerminalResponse(cmdDet, ResultCode.NO_RESPONSE_FROM_USER, false, - 0, null); - } - - /** - * {@inheritDoc} - */ - public void acceptOrRejectCall(boolean accept) { - if (mState != State.CALL_SETUP) { - return; - } - mCmdIf.handleCallSetupRequestFromSim(accept, null); - } - - /** - * Indicates if STK is supported by the SIM card. - */ - public boolean isStkSupported() { - switch (getAppIndication()) { - case APP_INDICATOR_PRE_BOOT: - case APP_INDICATOR_UNINSTALLED: - return false; - } - - return true; - } - - /** - * Returns the unique service name for STK. - */ - public String getServiceName() { - return mServiceName; - } - - /** - * {@inheritDoc} - */ - public void handleMessage(Message msg) { - AsyncResult ar; - - switch (msg.what) { - case EVENT_SESSION_END: - ar = (AsyncResult) msg.obj; - handleSessionEnd(ar.result); - break; - case EVENT_PROACTIVE_COMMAND: - ar = (AsyncResult) msg.obj; - handleProactiveCommand((String) ar.result); - break; - case EVENT_EVENT_NOTIFY: - ar = (AsyncResult) msg.obj; - handleEventNotify((String) ar.result); - break; - case EVENT_CALL_SETUP: - mState = State.CALL_SETUP; - break; - case EVENT_SIM_LOADED: - case EVENT_SIM_ABSENT: - if (!isStkSupported()) { - setAppState(false); - } - break; - case EVENT_LOAD_ICON_DONE: - handleProactiveCommandIcons(msg.obj); - break; - default: - throw new AssertionError("Unrecognized STK command: " + msg.what); - } - } - - /** - * Send terminal response for backward move in the proactive SIM session - * requested by the user - * - * Only available when responding following proactive commands - * DISPLAY_TEXT(0x21), - * GET_INKEY(0x22), - * GET_INPUT(0x23), - * SET_UP_MENU(0x25); - * - * @return true if stk can send backward move response - * - */ - public boolean backwardMove() { - CtlvCommandDetails cmdDet = null; - - cmdDet = getCurrentCmdDet(); - - if (cmdDet == null) { - return false; - } - - sendTerminalResponse(cmdDet, ResultCode.BACKWARD_MOVE_BY_USER, false, - 0, null); - return true; - } - - /** - * Send terminal response for proactive SIM session terminated by the user - * - * Only available when responding following proactive commands - * DISPLAY_TEXT(0x21), - * GET_INKEY(0x22), - * GET_INPUT(0x23), - * PLAY_TONE(0x20), - * SET_UP_MENU(0x25); - * - * @return true if stk can send terminate session response - */ - public boolean terminateSession() { - CtlvCommandDetails cmdDet = null; - - cmdDet = getCurrentCmdDet(); - - if (cmdDet == null) { - return false; - } - - sendTerminalResponse(cmdDet, ResultCode.UICC_SESSION_TERM_BY_USER, - false, 0, null); - mState = State.MAIN_MENU; - return true; - } - - private CtlvCommandDetails getCurrentCmdDet() { - CtlvCommandDetails cmdDet = null; - - if (mCmdParams != null) { - cmdDet = mCmdParams.cmdDet; - } - - return cmdDet; - } - - /** - * Handles RIL_UNSOL_STK_SESSION_END unsolicited command from RIL. - * - * @param data Null object. Do not use this. - */ - private void handleSessionEnd(Object data) { - if (Config.LOGD) { - Log.d(TAG, "handleSessionEnd begins"); - } - switch (mInstallIndicator) { - case APP_INDICATOR_INSTALLED_NORMAL: - mState = State.MAIN_MENU; - break; - case APP_INDICATOR_INSTALLED_SPECIAL: - case APP_INDICATOR_UNINSTALLED: - mState = State.IDLE; - break; - default: - Log.d(TAG, "Can't set service state"); - } - synchronized (mCmdListenerLock) { - if (mCmdListener != null) { - mCmdListener.onSessionEnd(); - } - } - } - - class CtlvDeviceIdentities { - public int sourceId; - public int destinationId; - } - - abstract class ResponseData { - /** - * Format the data appropriate for TERMINAL RESPONSE and write it into - * the ByteArrayOutputStream object. - */ - public abstract void format(ByteArrayOutputStream buf); - } - - class GetInkeyInputResponseData extends ResponseData { - private boolean mIsUcs2; - private boolean mIsPacked; - private boolean mIsYesNo; - private boolean mYesNoResponse; - public String mInData; - - public GetInkeyInputResponseData(String inData, boolean ucs2, - boolean packed) { - super(); - this.mIsUcs2 = ucs2; - this.mIsPacked = packed; - this.mInData = inData; - this.mIsYesNo = false; - } - - public GetInkeyInputResponseData(boolean yesNoResponse) { - super(); - this.mIsUcs2 = false; - this.mIsPacked = false; - this.mInData = ""; - this.mIsYesNo = true; - this.mYesNoResponse = yesNoResponse; - } - - @Override - public void format(ByteArrayOutputStream buf) { - if (buf == null) { - return; - } - - // Text string object - int tag = 0x80 | ComprehensionTlvTag.TEXT_STRING.value(); - buf.write(tag); // tag - - byte[] data; - - if (mIsYesNo) { - data = new byte[1]; - data[0] = mYesNoResponse ? GET_INKEY_YES : GET_INKEY_NO; - } else if (mInData != null && mInData.length() > 0) { - try { - if (mIsUcs2) { - data = mInData.getBytes("UTF-16"); - } else if (mIsPacked) { - int size = mInData.length(); - - byte[] tempData = GsmAlphabet - .stringToGsm7BitPacked(mInData); - data = new byte[size]; - // Since stringToGsm7BitPacked() set byte 0 in the - // returned byte array to the count of septets used... - // copy to a new array without byte 0. - System.arraycopy(tempData, 1, data, 0, size); - } else { - data = GsmAlphabet.stringToGsm8BitPacked(mInData); - } - } catch (UnsupportedEncodingException e) { - data = new byte[0]; - } catch (EncodeException e) { - data = new byte[0]; - } - } else { - data = new byte[0]; - } - - // length - one more for data coding scheme. - buf.write(data.length + 1); - - // data coding scheme - if (mIsUcs2) { - buf.write(0x08); // UCS2 - } else if (mIsPacked) { - buf.write(0x00); // 7 bit packed - } else { - buf.write(0x04); // 8 bit unpacked - } - - for (byte b : data) { - buf.write(b); + private boolean removeMenu(Menu menu) { + try { + if (menu.items.size() == 1 && menu.items.get(0) == null) { + return true; } + } catch (NullPointerException e) { + StkLog.d(this, "Unable to get Menu's items size"); + return true; } + return false; } - class SelectItemResponseData extends ResponseData { - private int id; - - public SelectItemResponseData(int id) { - super(); - this.id = id; - } - - @Override - public void format(ByteArrayOutputStream buf) { - // Item identifier object - int tag = 0x80 | ComprehensionTlvTag.ITEM_ID.value(); - buf.write(tag); // tag - buf.write(1); // length - buf.write(id); // identifier of item chosen - } - } - - /** - * Handles RIL_UNSOL_STK_PROACTIVE_COMMAND unsolicited command from RIL. - * This method parses the data transmitted from the SIM card, and handles - * the command according to the "Type of Command". Each proactive command is - * handled by a corresponding handleXXX() method. - * - * @param data String containing SAT/USAT proactive command in hexadecimal - * format starting with command tag - */ - private void handleProactiveCommand(String data) { - if (Config.LOGD) { - Log.d(TAG, "handleProactiveCommand begins"); - } - // If commands arrives before the SIM loaded/SIM absent events have - // arrived post a message for a delayed processing in 2 seconds. - if (getAppIndication() == APP_INDICATOR_PRE_BOOT) { - Message installMsg = this.obtainMessage(EVENT_PROACTIVE_COMMAND); - AsyncResult.forMessage(installMsg, data, null); - sendMessageDelayed(installMsg, 2000); + private void handleCmdResponse(StkResponseMessage resMsg) { + // make sure the response details match the last valid command. + if (!validateResponse(resMsg)) { return; } + ResponseData resp = null; + boolean helpRequired = false; + CommandDetails cmdDet = resMsg.getCmdDetails(); - CtlvCommandDetails cmdDet = null; - try { - byte[] rawData = SimUtils.hexStringToBytes(data); - BerTlv berTlv = BerTlv.decode(rawData); - - List ctlvs = berTlv.getComprehensionTlvs(); - cmdDet = retrieveCommandDetails(ctlvs); - - CommandType cmdType = CommandType.fromInt(cmdDet.typeOfCommand); - if (cmdType == null) { - throw new ResultException(ResultCode.BEYOND_TERMINAL_CAPABILITY); - } - - // SET UP MENU & SET up IDLE MODE TEXT commands should not trigger - // the special install & launch sequence. - if (cmdType != CommandType.SET_UP_MENU - && cmdType != CommandType.SET_UP_IDLE_MODE_TEXT) { - switch (getAppIndication()) { - case APP_INDICATOR_UNINSTALLED: - setAppState(true); - setAppIndication(APP_INDICATOR_INSTALLED_SPECIAL); - mInstallIndicator = APP_INDICATOR_INSTALLED_SPECIAL; - Message installMsg = this - .obtainMessage(EVENT_PROACTIVE_COMMAND); - AsyncResult.forMessage(installMsg, data, null); - sendMessageDelayed(installMsg, 20); - return; - case APP_INDICATOR_INSTALLED_SPECIAL: - case APP_INDICATOR_INSTALLED_NORMAL: - Intent intent = new Intent(Intent.ACTION_MAIN); - intent.setClassName("com.android.stk", - "com.android.stk.StkActivity"); - intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - mContext.startActivity(intent); - Message launchMsg = this - .obtainMessage(EVENT_PROACTIVE_COMMAND); - AsyncResult.forMessage(launchMsg, data, null); - sendMessageDelayed(launchMsg, 2000); - return; - } - } - - CtlvDeviceIdentities devIds = retrieveDeviceIdentities(ctlvs); - boolean cmdPending = false; - boolean responseNeeded = false; - - switch (cmdType) { - case DISPLAY_TEXT: - cmdPending = processDisplayText(cmdDet, devIds, ctlvs); - responseNeeded = true; - break; + switch (resMsg.resCode) { + case HELP_INFO_REQUIRED: + helpRequired = true; + case OK: + case PRFRMD_WITH_PARTIAL_COMPREHENSION: + case PRFRMD_WITH_MISSING_INFO: + case PRFRMD_WITH_ADDITIONAL_EFS_READ: + case PRFRMD_ICON_NOT_DISPLAYED: + case PRFRMD_MODIFIED_BY_NAA: + case PRFRMD_LIMITED_SERVICE: + case PRFRMD_WITH_MODIFICATION: + case PRFRMD_NAA_NOT_ACTIVE: + case PRFRMD_TONE_NOT_PLAYED: + switch (AppInterface.CommandType.fromInt(cmdDet.typeOfCommand)) { case SET_UP_MENU: - cmdPending = processSetUpMenu(cmdDet, devIds, ctlvs); - responseNeeded = true; - break; - case SET_UP_IDLE_MODE_TEXT: - cmdPending = processSetUpIdleModeText(cmdDet, devIds, ctlvs); - responseNeeded = true; - break; - case GET_INKEY: - cmdPending = processGetInkey(cmdDet, devIds, ctlvs); + helpRequired = resMsg.resCode == ResultCode.HELP_INFO_REQUIRED; + sendMenuSelection(resMsg.usersMenuSelection, helpRequired); + return; + case SELECT_ITEM: + resp = new SelectItemResponseData(resMsg.usersMenuSelection); break; case GET_INPUT: - cmdPending = processGetInput(cmdDet, devIds, ctlvs); - break; - case REFRESH: - processRefresh(cmdDet, devIds, ctlvs); - responseNeeded = true; - break; - case SELECT_ITEM: - cmdPending = processSelectItem(cmdDet, devIds, ctlvs); + case GET_INKEY: + Input input = mCurrntCmd.geInput(); + if (!input.yesNo) { + // when help is requested there is no need to send the text + // string object. + if (!helpRequired) { + resp = new GetInkeyInputResponseData(resMsg.usersInput, + input.ucs2, input.packed); + } + } else { + resp = new GetInkeyInputResponseData( + resMsg.usersYesNoSelection); + } break; + case DISPLAY_TEXT: case LAUNCH_BROWSER: - cmdPending = processLaunchBrowser(cmdDet, devIds, ctlvs); - break; - case PLAY_TONE: - cmdPending = processPlayTone(cmdDet, devIds, ctlvs); - break; - default: - // This should never be reached! - throw new AssertionError( - "Add case statements for the newly added " - + "command types!"); - } - if (!cmdPending) { - callStkApp(cmdType); - } - if (responseNeeded) { - sendTerminalResponse(cmdDet, ResultCode.OK, false, 0, null); - } - } catch (ResultException e) { - sendTerminalResponse(cmdDet, e.result(), e.hasAdditionalInfo(), e - .additionalInfo(), null); - } - } - - private void handleProactiveCommandIcons(Object data) { - CommandType cmdType = CommandType - .fromInt(mNextCmdParams.cmdDet.typeOfCommand); - boolean needsResponse = false; - Bitmap[] icons = null; - int iconIndex = 0; - - switch (cmdType) { - case SET_UP_IDLE_MODE_TEXT: - ((CommonUIParams) mNextCmdParams).mIcon = (Bitmap) (data); - callStkApp(CommandType.SET_UP_IDLE_MODE_TEXT); - break; - case DISPLAY_TEXT: - ((DisplayTextParams) mNextCmdParams).icon = (Bitmap) (data); - callStkApp(CommandType.DISPLAY_TEXT); - break; - case SELECT_ITEM: - - SelectItemParams params = ((SelectItemParams) mNextCmdParams); - Menu menu = params.mMenu; - switch(params.mIconLoadState) { - case SelectItemParams.LOAD_TITLE_ICON: - menu.titleIcon = (Bitmap) data; break; - case SelectItemParams.LOAD_ITEMS_ICONS: - icons = (Bitmap[]) data; - // set each item icon. - for (Item item : menu.items) { - item.icon = icons[iconIndex++]; - } - break; - case SelectItemParams.LOAD_TITLE_ITEMS_ICONS: - icons = (Bitmap[]) data; - // set title icon - menu.titleIcon = icons[iconIndex++]; - // set each item icon. - for (Item item : menu.items) { - item.icon = icons[iconIndex++]; + case SET_UP_CALL: + mCmdIf.handleCallSetupRequestFromSim(resMsg.usersConfirm, null); + if (!resMsg.usersConfirm) { + resMsg.resCode = ResultCode.USER_NOT_ACCEPT; } } - callStkApp(CommandType.SELECT_ITEM); + break; + case NO_RESPONSE_FROM_USER: + case UICC_SESSION_TERM_BY_USER: + case BACKWARD_MOVE_BY_USER: + resp = null; break; default: - // This should never be reached! - throw new AssertionError("Add case statements for the newly added " - + "command types!"); - } - } - - private void callStkApp(CommandType cmdType) { - boolean needsResponse = false; - mCmdParams = mNextCmdParams; - - synchronized (mCmdListenerLock) { - switch (cmdType) { - case SET_UP_IDLE_MODE_TEXT: - if (mNm == null) { - break; - } - CommonUIParams i = (CommonUIParams) mCmdParams; - if (i.mText == null) { - mNm.cancel(STK_NOTIFICATION_ID); - } else { - Notification notification = new Notification(); - RemoteViews contentView = new RemoteViews( - mContext.getPackageName(), - com.android.internal.R.layout.status_bar_latest_event_content); - - // Set text and icon for the status bar. - notification.icon = com.android.internal.R.drawable.stat_notify_sim_toolkit; - notification.tickerText = i.mText; - notification.flags |= Notification.FLAG_NO_CLEAR; - - // Set text and icon for the notification body. - if (!i.mIconSelfExplanatory) { - contentView.setTextViewText( - com.android.internal.R.id.text, i.mText); - } - if (i.mIcon != null) { - contentView.setImageViewBitmap( - com.android.internal.R.id.icon, i.mIcon); - } else { - contentView - .setImageViewResource( - com.android.internal.R.id.icon, - com.android.internal.R.drawable.stat_notify_sim_toolkit); - } - notification.contentView = contentView; - - mNm.notify(STK_NOTIFICATION_ID, notification); - } - case SET_UP_MENU: - needsResponse = true; - break; - case SELECT_ITEM: - mState = State.SELECT_ITEM; - SelectItemParams s = (SelectItemParams) mCmdParams; - mCmdListener.onSelectItem(s.mMenu, s.mPresentationType); - needsResponse = false; - break; - case DISPLAY_TEXT: - mState = State.DISPLAY_TEXT; - DisplayTextParams d = (DisplayTextParams) mCmdParams; - mCmdListener.onDisplayText(d.text, d.textAttrs, d.isHighPriority, - d.userClear, !d.immediateResponse, d.icon); - - needsResponse = d.immediateResponse; - break; - default: - // This should never be reached! - throw new AssertionError( - "Add case statements for the newly added " - + "command types!"); - } - } - - if (needsResponse) { - sendTerminalResponse(mCmdParams.cmdDet, ResultCode.OK, false, 0, null); - } - } - - private void sendTerminalResponse(CtlvCommandDetails cmdDet, - ResultCode resultCode, boolean includeAdditionalInfo, - int additionalInfo, ResponseData resp) { - - if (cmdDet == null) { return; } - ByteArrayOutputStream buf = new ByteArrayOutputStream(); - - // command details - int tag = ComprehensionTlvTag.COMMAND_DETAILS.value(); - if (cmdDet.compRequired) { - tag |= 0x80; - } - buf.write(tag); - buf.write(0x03); // length - buf.write(cmdDet.commandNumber); - buf.write(cmdDet.typeOfCommand); - buf.write(cmdDet.commandQualifier); - - // device identities - tag = 0x80 | ComprehensionTlvTag.DEVICE_IDENTITIES.value(); - buf.write(tag); - buf.write(0x02); // length - buf.write(DEV_ID_TERMINAL); // source device id - buf.write(DEV_ID_UICC); // destination device id - - // result - tag = 0x80 | ComprehensionTlvTag.RESULT.value(); - buf.write(tag); - int length = includeAdditionalInfo ? 2 : 1; - buf.write(length); - buf.write(resultCode.code()); - - // additional info - if (includeAdditionalInfo) { - buf.write(additionalInfo); - } - - // Fill optional data for each corresponding command - if (resp != null) { - resp.format(buf); - } - - byte[] rawData = buf.toByteArray(); - String hexString = SimUtils.bytesToHexString(rawData); - if (Config.LOGD) { - Log.d(TAG, "TERMINAL RESPONSE: " + hexString); - } - - mCmdIf.sendTerminalResponse(hexString, null); - } - - /** - * Search for a COMPREHENSION-TLV object with the given tag from a list - * - * @param tag A tag to search for - * @param ctlvs List of ComprehensionTlv objects used to search in - * - * @return A ComprehensionTlv object that has the tag value of {@code tag}. - * If no object is found with the tag, null is returned. - */ - private ComprehensionTlv searchForTag(ComprehensionTlvTag tag, - List ctlvs) { - Iterator iter = ctlvs.iterator(); - return searchForNextTag(tag, iter); - } - - /** - * Search for the next COMPREHENSION-TLV object with the given tag from a - * list iterated by {@code iter}. {@code iter} points to the object next to - * the found object when this method returns. Used for searching the same - * list for similar tags, usually item id. - * - * @param tag A tag to search for - * @param iter Iterator for ComprehensionTlv objects used for search - * - * @return A ComprehensionTlv object that has the tag value of {@code tag}. - * If no object is found with the tag, null is returned. - */ - private ComprehensionTlv searchForNextTag(ComprehensionTlvTag tag, - Iterator iter) { - int tagValue = tag.value(); - while (iter.hasNext()) { - ComprehensionTlv ctlv = iter.next(); - if (ctlv.getTag() == tagValue) { - return ctlv; - } - } - return null; - } - - /** - * Search for a Command Details object from a list. - * - * @param ctlvs List of ComprehensionTlv objects used for search - * @return An CtlvCommandDetails object found from the objects. If no - * Command Details object is found, ResultException is thrown. - * @throws ResultException - */ - private CtlvCommandDetails retrieveCommandDetails( - List ctlvs) throws ResultException { - - ComprehensionTlv ctlv = searchForTag( - ComprehensionTlvTag.COMMAND_DETAILS, ctlvs); - if (ctlv != null) { - CtlvCommandDetails cmdDet = new CtlvCommandDetails(); - byte[] rawValue = ctlv.getRawValue(); - int valueIndex = ctlv.getValueIndex(); - try { - cmdDet.compRequired = ctlv.isComprehensionRequired(); - cmdDet.commandNumber = rawValue[valueIndex] & 0xff; - cmdDet.typeOfCommand = rawValue[valueIndex + 1] & 0xff; - cmdDet.commandQualifier = rawValue[valueIndex + 2] & 0xff; - return cmdDet; - } catch (IndexOutOfBoundsException e) { - throw new ResultException(ResultCode.CMD_DATA_NOT_UNDERSTOOD); - } - } else { - throw new ResultException(ResultCode.REQUIRED_VALUES_MISSING); - } - } - - /** - * Search for a Device Identities object from a list. - * - * @param ctlvs List of ComprehensionTlv objects used for search - * @return An CtlvDeviceIdentities object found from the objects. If no - * Command Details object is found, ResultException is thrown. - * @throws ResultException - */ - private CtlvDeviceIdentities retrieveDeviceIdentities( - List ctlvs) throws ResultException { - - ComprehensionTlv ctlv = searchForTag( - ComprehensionTlvTag.DEVICE_IDENTITIES, ctlvs); - if (ctlv != null) { - CtlvDeviceIdentities devIds = new CtlvDeviceIdentities(); - byte[] rawValue = ctlv.getRawValue(); - int valueIndex = ctlv.getValueIndex(); - try { - devIds.sourceId = rawValue[valueIndex] & 0xff; - devIds.destinationId = rawValue[valueIndex + 1] & 0xff; - return devIds; - } catch (IndexOutOfBoundsException e) { - throw new ResultException(ResultCode.REQUIRED_VALUES_MISSING); - } - } else { - throw new ResultException(ResultCode.REQUIRED_VALUES_MISSING); - } - } - - /** - * Processes SETUP_CALL proactive command from the SIM card. - * - * @param cmdDet Command Details object retrieved from the proactive command - * object - * @param devIds Device Identities object retrieved from the proactive - * command object - * @param ctlvs List of ComprehensionTlv objects following Command Details - * object and Device Identities object within the proactive command - * @return true if the command is processing is pending and additional - * asynchronous processing is required. - */ - private void processSetupCall(CtlvCommandDetails cmdDet, - CtlvDeviceIdentities devIds, List ctlvs) { - if (Config.LOGD) { - Log.d(TAG, "processSetupCall begins"); - } - - // User confirmation phase message. - String confirmMsg = null; - // Call set up phase message. - String callMsg = null; - List textAttrs = null; - Iterator iter = ctlvs.iterator(); - ComprehensionTlv ctlv = null; - - try { - // get confirmation message string. - ctlv = searchForNextTag(ComprehensionTlvTag.ALPHA_ID, iter); - if (ctlv != null) { - confirmMsg = retrieveAlphaId(ctlv); - } else { - // No message to show. - throw new ResultException(ResultCode.REQUIRED_VALUES_MISSING); - } - // get call set up message string. - ctlv = searchForNextTag(ComprehensionTlvTag.ALPHA_ID, iter); - if (ctlv != null) { - callMsg = retrieveAlphaId(ctlv); - } - - ctlv = searchForTag(ComprehensionTlvTag.TEXT_ATTRIBUTE, ctlvs); - if (ctlv != null) { - textAttrs = retrieveTextAttribute(ctlv); - } - } catch (ResultException e) { - // Unable to process command. Send terminal response when service is - // in call state. - while (mState != State.CALL_SETUP) { - Thread.yield(); - } - sendTerminalResponse(cmdDet, ResultCode.REQUIRED_VALUES_MISSING, - false, 0, null); - return; - } - - synchronized (mCmdListenerLock) { - if (mCmdListener != null) { - mCmdListener.onCallSetup(confirmMsg, textAttrs, callMsg); - } - } - } - - /** - * Processes DISPLAY_TEXT proactive command from the SIM card. - * - * @param cmdDet Command Details object retrieved from the proactive command - * object - * @param devIds Device Identities object retrieved from the proactive - * command object - * @param ctlvs List of ComprehensionTlv objects following Command Details - * object and Device Identities object within the proactive command - * @return true if the command is processing is pending and additional - * asynchronous processing is required. - * @throws ResultException - */ - private boolean processDisplayText(CtlvCommandDetails cmdDet, - CtlvDeviceIdentities devIds, List ctlvs) - throws ResultException { - - if (Config.LOGD) { - Log.d(TAG, "processDisplayText begins"); - } - - DisplayTextParams params = new DisplayTextParams(cmdDet); - IconId iconId = null; - - ComprehensionTlv ctlv = searchForTag(ComprehensionTlvTag.TEXT_STRING, - ctlvs); - if (ctlv != null) { - params.text = retrieveTextString(ctlv); - } - // If the tlv object doesn't exist or the it is a null object reply - // with command not understood. - if (params.text == null) { - throw new ResultException(ResultCode.CMD_DATA_NOT_UNDERSTOOD); - } - - ctlv = searchForTag(ComprehensionTlvTag.TEXT_ATTRIBUTE, ctlvs); - if (ctlv != null) { - params.textAttrs = retrieveTextAttribute(ctlv); - } - - ctlv = searchForTag(ComprehensionTlvTag.IMMEDIATE_RESPONSE, ctlvs); - if (ctlv != null) { - params.immediateResponse = true; - } - - ctlv = searchForTag(ComprehensionTlvTag.ICON_ID, ctlvs); - if (ctlv != null) { - iconId = retrieveIconId(ctlv); - } - - // Parse command qualifier parameters. - params.isHighPriority = (cmdDet.commandQualifier & 0x01) != 0; - params.userClear = (cmdDet.commandQualifier & 0x80) != 0; - - mNextCmdParams = params; - - // If there's no icon to load call stk application. - if (iconId != null) { - mIconLoader.loadIcon(iconId.recordNumber, this - .obtainMessage(EVENT_LOAD_ICON_DONE)); - return true; - } - return false; - } - - /** - * Processes SET_UP_MENU proactive command from the SIM card. - * - * @param cmdDet Command Details object retrieved from the proactive command - * object - * @param devIds Device Identities object retrieved from the proactive - * command object - * @param ctlvs Iterator for ComprehensionTlv objects following Command - * Details object and Device Identities object within the proactive - * command - * @return true if the command is processing is pending and additional - * asynchronous processing is required. - * @throws ResultException - */ - private boolean processSetUpMenu(CtlvCommandDetails cmdDet, - CtlvDeviceIdentities devIds, List ctlvs) - throws ResultException { - - if (Config.LOGD) { - Log.d(TAG, "processSetUpMenu begins"); - } - - Menu menu = new Menu(); - boolean first = true; - boolean removeExistingMenu = false; - Iterator iter = ctlvs.iterator(); - - ComprehensionTlv ctlv = searchForTag(ComprehensionTlvTag.ALPHA_ID, - ctlvs); - if (ctlv != null) { - menu.title = retrieveAlphaId(ctlv); - } - - ctlv = searchForTag(ComprehensionTlvTag.TEXT_ATTRIBUTE, ctlvs); - if (ctlv != null) { - menu.titleAttrs = retrieveTextAttribute(ctlv); - } - - while (true) { - ctlv = searchForNextTag(ComprehensionTlvTag.ITEM, iter); - if (ctlv != null) { - Item item = retrieveItem(ctlv); - // If the first item is a "null" object, it means that - // the existing menu should be removed. - if (first && item == null) { - removeExistingMenu = true; - break; - } - menu.items.add(retrieveItem(ctlv)); - first = false; - } else { - break; - } - } - - // Extract command details. - menu.softKeyPreferred = (cmdDet.commandQualifier & 0x01) != 0; - menu.helpAvailable = (cmdDet.commandQualifier & 0x80) != 0; - - // We must have at least one menu item. - if (menu.items.size() == 0 && !removeExistingMenu) { - if (Config.LOGD) { - Log.d(TAG, "processSetUpMenu: Need at least one menu item"); - } - throw new ResultException(ResultCode.REQUIRED_VALUES_MISSING); - } - mCmdParams = new CommandParams(cmdDet); - if (removeExistingMenu) { - mState = State.IDLE; - mMainMenu = null; - setAppState(false); - } else { - Menu currentMenu = mMainMenu; - mState = State.MAIN_MENU; - mMainMenu = menu; - if (!isStkSupported()) { - setAppState(true); - setAppIndication(APP_INDICATOR_INSTALLED_NORMAL); - mInstallIndicator = APP_INDICATOR_INSTALLED_NORMAL; - } - } - return true; - } - - private void setAppState(boolean installed) { - if (installed) { - StkAppInstaller.installApp(mContext); - } else { - setAppIndication(APP_INDICATOR_UNINSTALLED); - mInstallIndicator = APP_INDICATOR_UNINSTALLED; - StkAppInstaller.unInstallApp(mContext); - } - } - - public Menu getCurrentMenu() { - Menu menu = null; - switch(mState) { - case MAIN_MENU: - menu = mMainMenu; - break; - case SELECT_ITEM: - menu = ((SelectItemParams) mCmdParams).mMenu; - break; - } - return menu; - } - - /** - * Processes SET_UP_IDLE_MODE_TEXT proactive command from the SIM card. - * - * @param cmdDet Command Details object retrieved from the proactive command - * object - * @param devIds Device Identities object retrieved from the proactive - * command object - * @param ctlvs List of ComprehensionTlv objects following Command Details - * object and Device Identities object within the proactive command - * @return true if the command is processing is pending and additional - * asynchronous processing is required. - * @throws ResultException - */ - private boolean processSetUpIdleModeText(CtlvCommandDetails cmdDet, - CtlvDeviceIdentities devIds, List ctlvs) - throws ResultException { - - if (Config.LOGD) { - Log.d(TAG, "processSetUpIdleModeText begins"); - } - - if (mNm == null) { - throw new ResultException(ResultCode.TERMINAL_CRNTLY_UNABLE_TO_PROCESS); - } - - String text = null; - IconId iconId = null; - List textAttrs = null; - - ComprehensionTlv ctlv = searchForTag(ComprehensionTlvTag.TEXT_STRING, - ctlvs); - if (ctlv != null) { - text = retrieveTextString(ctlv); - } else { - throw new ResultException(ResultCode.REQUIRED_VALUES_MISSING); - } - - ctlv = searchForTag(ComprehensionTlvTag.ICON_ID, ctlvs); - if (ctlv != null) { - iconId = retrieveIconId(ctlv); - } - - ctlv = searchForTag(ComprehensionTlvTag.TEXT_ATTRIBUTE, ctlvs); - if (ctlv != null) { - textAttrs = retrieveTextAttribute(ctlv); - } - - CommonUIParams params = new CommonUIParams(cmdDet, text, null); - mNextCmdParams = params; - if (iconId != null) { - params.mIconSelfExplanatory = iconId.selfExplanatory; - mIconLoader.loadIcon(iconId.recordNumber, this - .obtainMessage(EVENT_LOAD_ICON_DONE)); - return true; - } - return false; - } - - /** - * Processes GET_INKEY proactive command from the SIM card. - * - * @param cmdDet Command Details object retrieved from the proactive command - * object - * @param devIds Device Identities object retrieved from the proactive - * command object - * @param ctlvs List of ComprehensionTlv objects following Command Details - * object and Device Identities object within the proactive command - * @return true if the command is processing is pending and additional - * asynchronous processing is required. - * @throws ResultException - */ - private boolean processGetInkey(CtlvCommandDetails cmdDet, - CtlvDeviceIdentities devIds, List ctlvs) - throws ResultException { - - if (Config.LOGD) { - Log.d(TAG, "processGetInkey begins"); - } - - String text = null; - List textAttrs = null; - - ComprehensionTlv ctlv = searchForTag(ComprehensionTlvTag.TEXT_STRING, - ctlvs); - if (ctlv != null) { - text = retrieveTextString(ctlv); - } else { - throw new ResultException(ResultCode.REQUIRED_VALUES_MISSING); - } - - ctlv = searchForTag(ComprehensionTlvTag.TEXT_ATTRIBUTE, ctlvs); - if (ctlv != null) { - textAttrs = retrieveTextAttribute(ctlv); - } - - boolean digitOnly = (cmdDet.commandQualifier & 0x01) == 0; - boolean ucs2 = (cmdDet.commandQualifier & 0x02) != 0; - boolean yesNo = (cmdDet.commandQualifier & 0x04) != 0; - boolean immediateResponse = (cmdDet.commandQualifier & 0x08) != 0; - boolean helpAvailable = (cmdDet.commandQualifier & 0x80) != 0; - - synchronized (mCmdListenerLock) { - if (mCmdListener != null) { - mCmdParams = new GetInkeyParams(cmdDet, yesNo, ucs2); - mState = State.GET_INKEY; - - mCmdListener.onGetInkey(text, textAttrs, yesNo, digitOnly, - ucs2, immediateResponse, helpAvailable); - return true; - } else { - // '0' means "No specific cause can be given" - throw new ResultException( - ResultCode.TERMINAL_CRNTLY_UNABLE_TO_PROCESS, 0); - } - } - } - - /** - * Processes GET_INPUT proactive command from the SIM card. - * - * @param cmdDet Command Details object retrieved from the proactive command - * object - * @param devIds Device Identities object retrieved from the proactive - * command object - * @param ctlvs List of ComprehensionTlv objects following Command Details - * object and Device Identities object within the proactive command - * @return true if the command is processing is pending and additional - * asynchronous processing is required. - * @throws ResultException - */ - private boolean processGetInput(CtlvCommandDetails cmdDet, - CtlvDeviceIdentities devIds, List ctlvs) - throws ResultException { - - if (Config.LOGD) { - Log.d(TAG, "processGetInput begins"); - } - - String text = null; - String defaultText = null; - int minLen, maxLen; - List textAttrs = null; - - ComprehensionTlv ctlv = searchForTag(ComprehensionTlvTag.TEXT_STRING, - ctlvs); - if (ctlv != null) { - text = retrieveTextString(ctlv); - } else { - throw new ResultException(ResultCode.REQUIRED_VALUES_MISSING); - } - - ctlv = searchForTag(ComprehensionTlvTag.RESPONSE_LENGTH, ctlvs); - if (ctlv != null) { - try { - byte[] rawValue = ctlv.getRawValue(); - int valueIndex = ctlv.getValueIndex(); - minLen = rawValue[valueIndex] & 0xff; - maxLen = rawValue[valueIndex + 1] & 0xff; - } catch (IndexOutOfBoundsException e) { - throw new ResultException(ResultCode.CMD_DATA_NOT_UNDERSTOOD); - } - } else { - throw new ResultException(ResultCode.REQUIRED_VALUES_MISSING); - } - - ctlv = searchForTag(ComprehensionTlvTag.TEXT_ATTRIBUTE, ctlvs); - if (ctlv != null) { - textAttrs = retrieveTextAttribute(ctlv); - } - - ctlv = searchForTag(ComprehensionTlvTag.DEFAULT_TEXT, ctlvs); - if (ctlv != null) { - defaultText = retrieveTextString(ctlv); - } - - boolean digitOnly = (cmdDet.commandQualifier & 0x01) == 0; - boolean ucs2 = (cmdDet.commandQualifier & 0x02) != 0; - boolean echo = (cmdDet.commandQualifier & 0x04) == 0; - boolean packed = (cmdDet.commandQualifier & 0x08) != 0; - boolean helpAvailable = (cmdDet.commandQualifier & 0x80) != 0; - - synchronized (mCmdListenerLock) { - if (mCmdListener != null) { - mCmdParams = new GetInputParams(cmdDet, ucs2, packed); - mState = State.GET_INPUT; - - boolean noMaxLimit = maxLen == 0xff; - mCmdListener.onGetInput(text, defaultText, minLen, maxLen, - noMaxLimit, textAttrs, digitOnly, ucs2, echo, - helpAvailable); - return true; - } else { - // '0' means "No specific cause can be given" - throw new ResultException( - ResultCode.TERMINAL_CRNTLY_UNABLE_TO_PROCESS, 0); - } - } - } - - /** - * Processes REFRESH proactive command from the SIM card. - * - * @param cmdDet Command Details object retrieved from the proactive command - * object - * @param devIds Device Identities object retrieved from the proactive - * command object - * @param ctlvs List of ComprehensionTlv objects following Command Details - * object and Device Identities object within the proactive command - * @throws ResultException - */ - private void processRefresh(CtlvCommandDetails cmdDet, - CtlvDeviceIdentities devIds, List ctlvs) - throws ResultException { - - if (Config.LOGD) { - Log.d(TAG, "processRefresh begins"); - } - - // REFRESH proactive command is rerouted by the baseband and handled by - // the telephony layer. IDLE TEXT should be removed for a REFRESH command - // with "initialization" or "reset" - - if (mNm == null) { - throw new ResultException(ResultCode.TERMINAL_CRNTLY_UNABLE_TO_PROCESS); - } - - boolean removeIdleText = false; - - switch (cmdDet.commandQualifier) { - case REFRESH_NAA_INIT_AND_FULL_FILE_CHANGE: - case REFRESH_NAA_INIT_AND_FILE_CHANGE: - case REFRESH_NAA_INIT: - case REFRESH_UICC_RESET: - removeIdleText = true; - } - if (removeIdleText) { - mNm.cancel(STK_NOTIFICATION_ID); - } - } - - /** - * Processes SELECT_ITEM proactive command from the SIM card. - * - * @param cmdDet Command Details object retrieved from the proactive command - * object - * @param devIds Device Identities object retrieved from the proactive - * command object - * @param ctlvs List of ComprehensionTlv objects following Command Details - * object and Device Identities object within the proactive command - * @return true if the command is processing is pending and additional - * asynchronous processing is required. - * @throws ResultException - */ - private boolean processSelectItem(CtlvCommandDetails cmdDet, - CtlvDeviceIdentities devIds, List ctlvs) - throws ResultException { - - if (Config.LOGD) { - Log.d(TAG, "processSelectItem begins"); - } - - Menu menu = new Menu(); - IconId titleIconId = null; - ItemsIconId itemsIconId = null; - int iconLoadState = SelectItemParams.LOAD_NO_ICON; - PresentationType presentType = PresentationType.NOT_SPECIFIED; - Iterator iter = ctlvs.iterator(); - - ComprehensionTlv ctlv = searchForTag(ComprehensionTlvTag.ALPHA_ID, - ctlvs); - if (ctlv != null) { - menu.title = retrieveAlphaId(ctlv); - } - - ctlv = searchForTag(ComprehensionTlvTag.TEXT_ATTRIBUTE, ctlvs); - if (ctlv != null) { - menu.titleAttrs = retrieveTextAttribute(ctlv); - } - - while (true) { - ctlv = searchForNextTag(ComprehensionTlvTag.ITEM, iter); - if (ctlv != null) { - menu.items.add(retrieveItem(ctlv)); - } else { - break; - } - } - - // We must have at least one menu item. - if (menu.items.size() == 0) { - throw new ResultException(ResultCode.REQUIRED_VALUES_MISSING); - } - - ctlv = searchForTag(ComprehensionTlvTag.ITEM_ID, ctlvs); - if (ctlv != null) { - // STK items are listed 1...n while list start at 0, need to - // subtract one. - menu.defaultItem = retrieveItemId(ctlv) - 1; - } - - ctlv = searchForTag(ComprehensionTlvTag.ICON_ID, ctlvs); - if (ctlv != null) { - iconLoadState = SelectItemParams.LOAD_TITLE_ICON; - titleIconId = retrieveIconId(ctlv); - menu.titleIconSelfExplanatory = titleIconId.selfExplanatory; - } - - ctlv = searchForTag(ComprehensionTlvTag.ITEM_ICON_ID_LIST, ctlvs); - if (ctlv != null) { - if (iconLoadState == SelectItemParams.LOAD_TITLE_ICON) { - iconLoadState = SelectItemParams.LOAD_TITLE_ITEMS_ICONS; - } else { - iconLoadState = SelectItemParams.LOAD_ITEMS_ICONS; - } - itemsIconId = retrieveItemsIconId(ctlv); - menu.itemsIconSelfExplanatory = itemsIconId.selfExplanatory; - } - - boolean presentTypeSpecified = (cmdDet.commandQualifier & 0x01) != 0; - if (presentTypeSpecified) { - if ((cmdDet.commandQualifier & 0x02) == 0) { - presentType = PresentationType.DATA_VALUES; - } else { - presentType = PresentationType.NAVIGATION_OPTIONS; - } - } - menu.softKeyPreferred = (cmdDet.commandQualifier & 0x04) != 0; - menu.helpAvailable = (cmdDet.commandQualifier & 0x80) != 0; - - mNextCmdParams = new SelectItemParams(cmdDet, menu, presentType, - iconLoadState); - - // Load icons data if needed. - switch(iconLoadState) { - case SelectItemParams.LOAD_NO_ICON: - return false; - case SelectItemParams.LOAD_TITLE_ICON: - mIconLoader.loadIcon(titleIconId.recordNumber, this - .obtainMessage(EVENT_LOAD_ICON_DONE)); - break; - case SelectItemParams.LOAD_ITEMS_ICONS: - mIconLoader.loadIcons(itemsIconId.recordNumbers, this - .obtainMessage(EVENT_LOAD_ICON_DONE)); - break; - case SelectItemParams.LOAD_TITLE_ITEMS_ICONS: - // Create a new array for all the icons (title and items). - int[] recordNumbers = new int[itemsIconId.recordNumbers.length + 1]; - recordNumbers[0] = titleIconId.recordNumber; - System.arraycopy(itemsIconId.recordNumbers, 0, recordNumbers, 1, - itemsIconId.recordNumbers.length); - mIconLoader.loadIcons(recordNumbers, this - .obtainMessage(EVENT_LOAD_ICON_DONE)); - break; - } - return true; - } - - /** - * Processes EVENT_NOTIFY message from baseband. - * - * @param cmdDet Command Details object retrieved from the proactive command - * object - * @param devIds Device Identities object retrieved from the proactive - * command object - * @param ctlvs List of ComprehensionTlv objects following Command Details - * object and Device Identities object within the proactive command - */ - synchronized private void processEventNotify(CtlvCommandDetails cmdDet, - CtlvDeviceIdentities devIds, List ctlvs) { - - if (Config.LOGD) { - Log.d(TAG, "processEventNotify begins"); - } - - String text = null; - List textAttrs = null; - - try { - ComprehensionTlv ctlv = searchForTag(ComprehensionTlvTag.ALPHA_ID, - ctlvs); - if (ctlv != null) { - text = retrieveAlphaId(ctlv); - } else { - // No message to show. - throw new ResultException(ResultCode.REQUIRED_VALUES_MISSING); - } - - ctlv = searchForTag(ComprehensionTlvTag.TEXT_ATTRIBUTE, ctlvs); - if (ctlv != null) { - textAttrs = retrieveTextAttribute(ctlv); - } - } catch (ResultException e) { - // Unable to process command. - return; - } - - Toast toast = Toast.makeText(mContext.getApplicationContext(), text, - Toast.LENGTH_LONG); - toast.setGravity(Gravity.BOTTOM, 0, 0); - toast.show(); - } - - /** - * Processes SET_UP_EVENT_LIST proactive command from the SIM card. - * - * @param cmdDet Command Details object retrieved from the proactive command - * object - * @param devIds Device Identities object retrieved from the proactive - * command object - * @param ctlvs List of ComprehensionTlv objects following Command Details - * object and Device Identities object within the proactive command - * @return true if the command is processing is pending and additional - * asynchronous processing is required. - */ - private boolean processSetUpEventList(CtlvCommandDetails cmdDet, - CtlvDeviceIdentities devIds, List ctlvs) { - - if (Config.LOGD) { - Log.d(TAG, "processSetUpEventList begins"); - } - - ComprehensionTlv ctlv = searchForTag(ComprehensionTlvTag.EVENT_LIST, - ctlvs); - if (ctlv != null) { - try { - byte[] rawValue = ctlv.getRawValue(); - int valueIndex = ctlv.getValueIndex(); - int valueLen = ctlv.getLength(); - - } catch (IndexOutOfBoundsException e) {} - } - return true; - } - - /** - * Processes LAUNCH_BROWSER proactive command from the SIM card. - * - * @param cmdDet Command Details object retrieved from the proactive command - * object - * @param devIds Device Identities object retrieved from the proactive - * command object - * @param ctlvs List of ComprehensionTlv objects following Command Details - * object and Device Identities object within the proactive command - * @return true if the command is processing is pending and additional - * asynchronous processing is required. - * @throws ResultException - */ - private boolean processLaunchBrowser(CtlvCommandDetails cmdDet, - CtlvDeviceIdentities devIds, List ctlvs) - throws ResultException { - - if (Config.LOGD) { - Log.d(TAG, "processLaunchBrowser begins"); - } - - String url = null; - String confirmMsg = null; - List confirmMsgAttrs = null; - - ComprehensionTlv ctlv = searchForTag(ComprehensionTlvTag.URL, ctlvs); - if (ctlv != null) { - try { - byte[] rawValue = ctlv.getRawValue(); - int valueIndex = ctlv.getValueIndex(); - int valueLen = ctlv.getLength(); - if (valueLen > 0) { - url = GsmAlphabet.gsm8BitUnpackedToString(rawValue, - valueIndex, valueLen); - } else { - url = null; - } - } catch (IndexOutOfBoundsException e) { - throw new ResultException(ResultCode.CMD_DATA_NOT_UNDERSTOOD); - } - } - - ctlv = searchForTag(ComprehensionTlvTag.ALPHA_ID, ctlvs); - if (ctlv != null) { - confirmMsg = retrieveAlphaId(ctlv); - } - - ctlv = searchForTag(ComprehensionTlvTag.TEXT_ATTRIBUTE, ctlvs); - if (ctlv != null) { - confirmMsgAttrs = retrieveTextAttribute(ctlv); - } - - LaunchBrowserMode mode; - switch (cmdDet.commandQualifier) { - case 0x00: - default: - mode = LaunchBrowserMode.LAUNCH_IF_NOT_ALREADY_LAUNCHED; - break; - case 0x02: - mode = LaunchBrowserMode.USE_EXISTING_BROWSER; - break; - case 0x03: - mode = LaunchBrowserMode.LAUNCH_NEW_BROWSER; - break; - } - - synchronized (mCmdListenerLock) { - if (mCmdListener != null) { - mCmdParams = new CommandParams(cmdDet); - mState = State.LAUNCH_BROWSER; - - mCmdListener.onLaunchBrowser(url, confirmMsg, confirmMsgAttrs, - mode); - return true; - } else { - // '0' means "No specific cause can be given" - throw new ResultException( - ResultCode.TERMINAL_CRNTLY_UNABLE_TO_PROCESS, 0); - } - } - } - - /** - * Processes PLAY_TONE proactive command from the SIM card. - * - * @param cmdDet Command Details object retrieved from the proactive command - * object - * @param devIds Device Identities object retrieved from the proactive - * command object - * @param ctlvs List of ComprehensionTlv objects following Command Details - * object and Device Identities object within the proactive command - * @return true if the command is processing is pending and additional - * asynchronous processing is required.t - * @throws ResultException - */ - private boolean processPlayTone(CtlvCommandDetails cmdDet, - CtlvDeviceIdentities devIds, List ctlvs) - throws ResultException { - - if (Config.LOGD) { - Log.d(TAG, "processPlayTone begins"); - } - - Tone tone = null; - String text = null; - List textAttrs = null; - Duration duration = null; - - ComprehensionTlv ctlv = searchForTag(ComprehensionTlvTag.TONE, ctlvs); - if (ctlv != null) { - // Nothing to do for null objects. - if (ctlv.getLength() > 0) { - try { - byte[] rawValue = ctlv.getRawValue(); - int valueIndex = ctlv.getValueIndex(); - int toneVal = rawValue[valueIndex]; - tone = Tone.fromInt(toneVal); - } catch (IndexOutOfBoundsException e) { - throw new ResultException( - ResultCode.CMD_DATA_NOT_UNDERSTOOD); - } - } - } - ctlv = searchForTag(ComprehensionTlvTag.ALPHA_ID, ctlvs); - if (ctlv != null) { - text = retrieveAlphaId(ctlv); - } - - ctlv = searchForTag(ComprehensionTlvTag.TEXT_ATTRIBUTE, ctlvs); - if (ctlv != null) { - textAttrs = retrieveTextAttribute(ctlv); - } - - ctlv = searchForTag(ComprehensionTlvTag.DURATION, ctlvs); - if (ctlv != null) { - duration = retrieveDuration(ctlv); - } - - synchronized (mCmdListenerLock) { - if (mCmdListener != null) { - mState = State.PLAY_TONE; - mCmdParams = new CommandParams(cmdDet); - mCmdListener.onPlayTone(tone, text, textAttrs, duration); - return true; - } else { - // '0' means "No specific cause can be given" - throw new ResultException( - ResultCode.TERMINAL_CRNTLY_UNABLE_TO_PROCESS, 0); - } - } - } - - /** - * Retrieves text from the Text COMPREHENSION-TLV object, and decodes it - * into a {@link java.lang.String}. - * - * @param ctlv A Text COMPREHENSION-TLV object - * @return A {@link java.lang.String} object decoded from the Text object - * @throws ResultException - */ - private String retrieveTextString(ComprehensionTlv ctlv) - throws ResultException { - byte[] rawValue = ctlv.getRawValue(); - int valueIndex = ctlv.getValueIndex(); - byte codingScheme = 0x00; - String text = null; - int textLen = ctlv.getLength(); - - // In case the text length is 0, return a null string. - if (textLen == 0) { - return text; - } else { - // one byte is coding scheme - textLen -= 1; - } - - try { - codingScheme = (byte) (rawValue[valueIndex] & 0x0c); - - if (codingScheme == 0x00) { // GSM 7-bit packed - text = GsmAlphabet.gsm7BitPackedToString(rawValue, - valueIndex + 1, (textLen * 8) / 7); - } else if (codingScheme == 0x04) { // GSM 8-bit unpacked - text = GsmAlphabet.gsm8BitUnpackedToString(rawValue, - valueIndex + 1, textLen); - } else if (codingScheme == 0x08) { // UCS2 - text = new String(rawValue, valueIndex + 1, textLen, "UTF-16"); - } else { - throw new ResultException(ResultCode.CMD_DATA_NOT_UNDERSTOOD); - } - - return text; - } catch (IndexOutOfBoundsException e) { - throw new ResultException(ResultCode.CMD_DATA_NOT_UNDERSTOOD); - } catch (UnsupportedEncodingException e) { - // This should never happen. - throw new ResultException(ResultCode.CMD_DATA_NOT_UNDERSTOOD); - } - } - - /** - * Retrieves Duration information from the Duration COMPREHENSION-TLV - * object. - * - * @param ctlv A Text Attribute COMPREHENSION-TLV object - * @return A Duration object - * @throws ResultException - */ - private Duration retrieveDuration(ComprehensionTlv ctlv) - throws ResultException { - int timeInterval = 0; - TimeUnit timeUnit = TimeUnit.SECOND; - - byte[] rawValue = ctlv.getRawValue(); - int valueIndex = ctlv.getValueIndex(); - - try { - timeUnit = TimeUnit.values()[(rawValue[valueIndex] & 0xff)]; - timeInterval = rawValue[valueIndex + 1] & 0xff; - } catch (IndexOutOfBoundsException e) { - throw new ResultException(ResultCode.CMD_DATA_NOT_UNDERSTOOD); - } - return new Duration(timeInterval, timeUnit); - } - - /** - * Retrieves Item information from the COMPREHENSION-TLV object. - * - * @param ctlv A Text Attribute COMPREHENSION-TLV object - * @return An Item - * @throws ResultException - */ - private Item retrieveItem(ComprehensionTlv ctlv) throws ResultException { - Item item = null; - - byte[] rawValue = ctlv.getRawValue(); - int valueIndex = ctlv.getValueIndex(); - int length = ctlv.getLength(); - - if (length != 0) { - int textLen = length - 1; - - try { - int id = rawValue[valueIndex] & 0xff; - String text = SimUtils.adnStringFieldToString(rawValue, - valueIndex + 1, textLen); - item = new Item(id, text); - } catch (IndexOutOfBoundsException e) { - throw new ResultException(ResultCode.CMD_DATA_NOT_UNDERSTOOD); - } - } - - return item; - } - - /** - * Retrieves Item id information from the COMPREHENSION-TLV object. - * - * @param ctlv A Text Attribute COMPREHENSION-TLV object - * @return An Item id - * @throws ResultException - */ - private int retrieveItemId(ComprehensionTlv ctlv) throws ResultException { - int id = 0; - - byte[] rawValue = ctlv.getRawValue(); - int valueIndex = ctlv.getValueIndex(); - - try { - id = rawValue[valueIndex] & 0xff; - } catch (IndexOutOfBoundsException e) { - throw new ResultException(ResultCode.CMD_DATA_NOT_UNDERSTOOD); - } - - return id; - } - - /** - * Retrieves icon id from an Icon Identifier COMPREHENSION-TLV object - * - * @param ctlv An Icon Identifier COMPREHENSION-TLV object - * @return IconId instance - * @throws ResultException - */ - private IconId retrieveIconId(ComprehensionTlv ctlv) throws ResultException { - IconId id = new IconId(); - - byte[] rawValue = ctlv.getRawValue(); - int valueIndex = ctlv.getValueIndex(); - try { - id.selfExplanatory = (rawValue[valueIndex++] & 0xff) == 0x00; - id.recordNumber = rawValue[valueIndex] & 0xff; - } catch (IndexOutOfBoundsException e) { - throw new ResultException(ResultCode.CMD_DATA_NOT_UNDERSTOOD); - } - - return id; - } - - /** - * Retrieves item icons id from an Icon Identifier List COMPREHENSION-TLV object - * - * @param ctlv An Item Icon List Identifier COMPREHENSION-TLV object - * @return ItemsIconId instance - * @throws ResultException - */ - private ItemsIconId retrieveItemsIconId(ComprehensionTlv ctlv) - throws ResultException{ - Log.d(TAG, "retrieveIconIdList:"); - ItemsIconId id = new ItemsIconId(); - - byte[] rawValue = ctlv.getRawValue(); - int valueIndex = ctlv.getValueIndex(); - int numOfItems = ctlv.getLength() - 1; - id.recordNumbers = new int[numOfItems]; - - try { - // get icon self-explanatory - id.selfExplanatory = (rawValue[valueIndex++] & 0xff) == 0x00; - - for (int index = 0; index < numOfItems;) { - id.recordNumbers[index++] = rawValue[valueIndex++]; - } - } catch (IndexOutOfBoundsException e) { - throw new ResultException(ResultCode.CMD_DATA_NOT_UNDERSTOOD); - } - return id; - } - - /** - * Retrieves text attribute information from the Text Attribute - * COMPREHENSION-TLV object. - * - * @param ctlv A Text Attribute COMPREHENSION-TLV object - * @return A list of TextAttribute objects - * @throws ResultException - */ - private List retrieveTextAttribute(ComprehensionTlv ctlv) - throws ResultException { - ArrayList lst = new ArrayList(); - - byte[] rawValue = ctlv.getRawValue(); - int valueIndex = ctlv.getValueIndex(); - int length = ctlv.getLength(); - - if (length != 0) { - // Each attribute is consisted of four bytes - int itemCount = length / 4; - - try { - for (int i = 0; i < itemCount; i++, valueIndex += 4) { - int start = rawValue[valueIndex] & 0xff; - int textLength = rawValue[valueIndex + 1] & 0xff; - int format = rawValue[valueIndex + 2] & 0xff; - int colorValue = rawValue[valueIndex + 3] & 0xff; - - int alignValue = format & 0x03; - TextAlignment align = TextAlignment.fromInt(alignValue); - - int sizeValue = (format >> 2) & 0x03; - FontSize size = FontSize.fromInt(sizeValue); - if (size == null) { - // Font size value is not defined. Use default. - size = FontSize.NORMAL; - } - - boolean bold = (format & 0x10) != 0; - boolean italic = (format & 0x20) != 0; - boolean underlined = (format & 0x40) != 0; - boolean strikeThrough = (format & 0x80) != 0; - - TextColor color = TextColor.fromInt(colorValue); - - TextAttribute attr = new TextAttribute(start, textLength, - align, size, bold, italic, underlined, - strikeThrough, color); - lst.add(attr); - } - - return lst; - - } catch (IndexOutOfBoundsException e) { - throw new ResultException(ResultCode.CMD_DATA_NOT_UNDERSTOOD); - } - } - return null; - } - - /** - * Retrieves alpha identifier from an Alpha Identifier COMPREHENSION-TLV - * object. - * - * @param ctlv An Alpha Identifier COMPREHENSION-TLV object - * @return String corresponding to the alpha identifier - * @throws ResultException - */ - private String retrieveAlphaId(ComprehensionTlv ctlv) - throws ResultException { - - byte[] rawValue = ctlv.getRawValue(); - int valueIndex = ctlv.getValueIndex(); - int length = ctlv.getLength(); - if (length != 0) { - try { - return SimUtils.adnStringFieldToString(rawValue, valueIndex, - length); - } catch (IndexOutOfBoundsException e) { - throw new ResultException(ResultCode.CMD_DATA_NOT_UNDERSTOOD); - } - } - return null; - } - - /** - * Handles RIL_UNSOL_STK_EVENT_NOTIFY unsolicited command from RIL. - * - * @param data String containing SAT/USAT commands or responses sent by ME - * to SIM or commands handled by ME, in hexadecimal format starting - * with first byte of response data or command tag - */ - private void handleEventNotify(String data) { - if (Config.LOGD) { - Log.d(TAG, "handleEventNotify begins"); - } - byte[] rawData = null; - BerTlv berTlv = null; - CtlvCommandDetails cmdDet = null; - CtlvDeviceIdentities devIds = null; - CommandType cmdType = null; - - // Nothing to do for empty strings. - if (data.length() == 0) { - return; - } - rawData = SimUtils.hexStringToBytes(data); - try { - berTlv = BerTlv.decode(rawData); - } catch (ResultException e) { - // Can't parse command buffer. - return; - } - - // Extract command details & Device identities tlv objects list. - List ctlvs = berTlv.getComprehensionTlvs(); - try { - cmdDet = retrieveCommandDetails(ctlvs); - devIds = retrieveDeviceIdentities(ctlvs); - } catch (ResultException e) { - if (Config.LOGD) { - Log.d(TAG, "invlaid command details/device identities"); - } - return; - } - - // Check to see if we support this command. - cmdType = CommandType.fromInt(cmdDet.typeOfCommand); - if (cmdType == null) { - return; - } - - // There are two scenarios for EVENT_NOTIFY messages: - // 1. A proactive command which is partially handled by the baseband and - // requires UI processing from the application. This messages will be - // tagged with PROACTIVE COMMAND tag. - // 2. A notification for an action completed by the baseband. This - // messages will be tagged with UNKNOWN tag and the command type inside - // the Command details object should indicate which action was completed. - if (berTlv.getTag() == BerTlv.BER_PROACTIVE_COMMAND_TAG) { - switch (cmdType) { - case SEND_SS: - case SEND_USSD: - case SEND_SMS: - case SEND_DTMF: - processEventNotify(cmdDet, devIds, ctlvs); - break; - case SET_UP_EVENT_LIST: - processSetUpEventList(cmdDet, devIds, ctlvs); - break; - case SET_UP_CALL: - processSetupCall(cmdDet, devIds, ctlvs); - break; - default: - // nada - break; - } - } + sendTerminalResponse(cmdDet, resMsg.resCode, false, 0, resp); + mCurrntCmd = null; } } diff --git a/telephony/java/com/android/internal/telephony/gsm/stk/StkAppInstaller.java b/telephony/java/com/android/internal/telephony/gsm/stk/StkAppInstaller.java deleted file mode 100644 index 07e3e56a31fc185150ce314b67934879d5754b55..0000000000000000000000000000000000000000 --- a/telephony/java/com/android/internal/telephony/gsm/stk/StkAppInstaller.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (C) 2007 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.android.internal.telephony.gsm.stk; - -import android.content.ComponentName; -import android.content.Context; -import android.content.pm.PackageManager; -import android.content.pm.PackageManager.NameNotFoundException; -import android.util.Log; - -/** - * Application installer for SIM Toolkit. - * - */ -public class StkAppInstaller { - // Application state actions: install, uninstall used by StkAppStateReceiver. - static final String STK_APP_INSTALL_ACTION = "com.android.stk.action.INSTALL"; - static final String STK_APP_UNINSTALL_ACTION = "com.android.stk.action.UNINSTALL"; - - public static void installApp(Context context) { - setAppState(context, PackageManager.COMPONENT_ENABLED_STATE_ENABLED); - } - - public static void unInstallApp(Context context) { - setAppState(context, PackageManager.COMPONENT_ENABLED_STATE_DISABLED); - } - - private static void setAppState(Context context, int state) { - if (context == null) { - return; - } - PackageManager pm = context.getPackageManager(); - if (pm == null) { - return; - } - // check that STK app package is known to the PackageManager - ComponentName cName = new ComponentName("com.android.stk", - "com.android.stk.StkActivity"); - - try { - pm.setComponentEnabledSetting(cName, state, - PackageManager.DONT_KILL_APP); - } catch (Exception e) { - Log.w("StkAppInstaller", "Could not change STK app state"); - } - } -} diff --git a/telephony/java/com/android/internal/telephony/gsm/stk/StkAppStateReceiver.java b/telephony/java/com/android/internal/telephony/gsm/stk/StkAppStateReceiver.java deleted file mode 100644 index 778ca2ed3dea75fe837015bbfeeff97b0e7f1f25..0000000000000000000000000000000000000000 --- a/telephony/java/com/android/internal/telephony/gsm/stk/StkAppStateReceiver.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (C) 2007 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.android.internal.telephony.gsm.stk; - -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import com.android.internal.telephony.gsm.stk.Service; -import android.util.Log; - -/** - * This class implements a Broadcast receiver. It waits for an intent sent by - * the STK service and install/uninstall the STK application. If no intent is - * received when the device finished booting, the application is then unistalled. - */ -public class StkAppStateReceiver extends BroadcastReceiver { - - private static final String TAG = "StkAppStateReceiver"; - - @Override - public void onReceive(Context context, Intent intent) { - Log.d(TAG, "onReceive"); - - String action = intent.getAction(); - Service stkService = Service.getInstance(); - if (stkService == null) { - return; - } - if (action.equals(StkAppInstaller.STK_APP_INSTALL_ACTION)) { - stkService.setAppIndication(Service.APP_INDICATOR_INSTALLED_NORMAL); - StkAppInstaller.installApp(context); - } else if (action.equals(StkAppInstaller.STK_APP_UNINSTALL_ACTION)) { - stkService.setAppIndication(Service.APP_INDICATOR_UNINSTALLED); - StkAppInstaller.unInstallApp(context); - } - } -} diff --git a/telephony/java/com/android/internal/telephony/gsm/stk/StkCmdMessage.java b/telephony/java/com/android/internal/telephony/gsm/stk/StkCmdMessage.java new file mode 100644 index 0000000000000000000000000000000000000000..62a778ed2b1666190fb1723a76225dee02c8a14d --- /dev/null +++ b/telephony/java/com/android/internal/telephony/gsm/stk/StkCmdMessage.java @@ -0,0 +1,175 @@ +/* + * Copyright (C) 2007 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.android.internal.telephony.gsm.stk; + +import android.os.Parcel; +import android.os.Parcelable; + +/** + * Class used to pass STK messages from telephony to application. Application + * should call getXXX() to get commands's specific values. + * + */ +public class StkCmdMessage implements Parcelable { + // members + CommandDetails mCmdDet; + private TextMessage mTextMsg; + private Menu mMenu; + private Input mInput; + private BrowserSettings mBrowserSettings = null; + private ToneSettings mToneSettings = null; + private CallSettings mCallSettings = null; + + /* + * Container for Launch Browser command settings. + */ + public class BrowserSettings { + public String url; + public LaunchBrowserMode mode; + } + + /* + * Container for Call Setup command settings. + */ + public class CallSettings { + public TextMessage confirmMsg; + public TextMessage callMsg; + } + + StkCmdMessage(CommandParams cmdParams) { + mCmdDet = cmdParams.cmdDet; + switch(getCmdType()) { + case SET_UP_MENU: + case SELECT_ITEM: + mMenu = ((SelectItemParams) cmdParams).menu; + break; + case DISPLAY_TEXT: + case SET_UP_IDLE_MODE_TEXT: + case SEND_DTMF: + case SEND_SMS: + case SEND_SS: + case SEND_USSD: + mTextMsg = ((DisplayTextParams) cmdParams).textMsg; + break; + case GET_INPUT: + case GET_INKEY: + mInput = ((GetInputParams) cmdParams).input; + break; + case LAUNCH_BROWSER: + mTextMsg = ((LaunchBrowserParams) cmdParams).confirmMsg; + mBrowserSettings = new BrowserSettings(); + mBrowserSettings.url = ((LaunchBrowserParams) cmdParams).url; + mBrowserSettings.mode = ((LaunchBrowserParams) cmdParams).mode; + break; + case PLAY_TONE: + PlayToneParams params = (PlayToneParams) cmdParams; + mToneSettings = params.settings; + mTextMsg = params.textMsg; + break; + case SET_UP_CALL: + mCallSettings = new CallSettings(); + mCallSettings.confirmMsg = ((CallSetupParams) cmdParams).confirmMsg; + mCallSettings.callMsg = ((CallSetupParams) cmdParams).callMsg; + break; + } + } + + public StkCmdMessage(Parcel in) { + mCmdDet = in.readParcelable(null); + mTextMsg = in.readParcelable(null); + mMenu = in.readParcelable(null); + mInput = in.readParcelable(null); + switch (getCmdType()) { + case LAUNCH_BROWSER: + mBrowserSettings = new BrowserSettings(); + mBrowserSettings.url = in.readString(); + mBrowserSettings.mode = LaunchBrowserMode.values()[in.readInt()]; + break; + case PLAY_TONE: + mToneSettings = in.readParcelable(null); + break; + case SET_UP_CALL: + mCallSettings = new CallSettings(); + mCallSettings.confirmMsg = in.readParcelable(null); + mCallSettings.callMsg = in.readParcelable(null); + break; + } + } + + public void writeToParcel(Parcel dest, int flags) { + dest.writeParcelable(mCmdDet, 0); + dest.writeParcelable(mTextMsg, 0); + dest.writeParcelable(mMenu, 0); + dest.writeParcelable(mInput, 0); + switch(getCmdType()) { + case LAUNCH_BROWSER: + dest.writeString(mBrowserSettings.url); + dest.writeInt(mBrowserSettings.mode.ordinal()); + break; + case PLAY_TONE: + dest.writeParcelable(mToneSettings, 0); + break; + case SET_UP_CALL: + dest.writeParcelable(mCallSettings.confirmMsg, 0); + dest.writeParcelable(mCallSettings.callMsg, 0); + break; + } + } + + public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { + public StkCmdMessage createFromParcel(Parcel in) { + return new StkCmdMessage(in); + } + + public StkCmdMessage[] newArray(int size) { + return new StkCmdMessage[size]; + } + }; + + public int describeContents() { + return 0; + } + + /* external API to be used by application */ + public AppInterface.CommandType getCmdType() { + return AppInterface.CommandType.fromInt(mCmdDet.typeOfCommand); + } + + public Menu getMenu() { + return mMenu; + } + + public Input geInput() { + return mInput; + } + + public TextMessage geTextMessage() { + return mTextMsg; + } + + public BrowserSettings getBrowserSettings() { + return mBrowserSettings; + } + + public ToneSettings getToneSettings() { + return mToneSettings; + } + + public CallSettings getCallSettings() { + return mCallSettings; + } +} diff --git a/telephony/java/com/android/internal/telephony/gsm/stk/StkLog.java b/telephony/java/com/android/internal/telephony/gsm/stk/StkLog.java new file mode 100644 index 0000000000000000000000000000000000000000..f6e568549ef0f36d05b6637351b45e38b46139d6 --- /dev/null +++ b/telephony/java/com/android/internal/telephony/gsm/stk/StkLog.java @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2007 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.android.internal.telephony.gsm.stk; + +import android.util.Log; + +public abstract class StkLog { + static final boolean DEBUG = true; + + public static void d(Object caller, String msg) { + if (!DEBUG) { + return; + } + + String className = caller.getClass().getName(); + Log.d("STK", className.substring(className.lastIndexOf('.') + 1) + ": " + + msg); + } + + public static void d(String caller, String msg) { + if (!DEBUG) { + return; + } + + Log.d("STK", caller + ": " + msg); + } +} diff --git a/telephony/java/com/android/internal/telephony/gsm/stk/StkResponseMessage.java b/telephony/java/com/android/internal/telephony/gsm/stk/StkResponseMessage.java new file mode 100644 index 0000000000000000000000000000000000000000..04a52e606d86193cf1b60bd518874f363c0b0afe --- /dev/null +++ b/telephony/java/com/android/internal/telephony/gsm/stk/StkResponseMessage.java @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2007 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.android.internal.telephony.gsm.stk; + +public class StkResponseMessage { + CommandDetails cmdDet = null; + ResultCode resCode = ResultCode.OK; + int usersMenuSelection = 0; + String usersInput = null; + boolean usersYesNoSelection = false; + boolean usersConfirm = false; + + public StkResponseMessage(StkCmdMessage cmdMsg) { + this.cmdDet = cmdMsg.mCmdDet; + } + + public void setResultCode(ResultCode resCode) { + this.resCode = resCode; + } + + public void setMenuSelection(int selection) { + this.usersMenuSelection = selection; + } + + public void setInput(String input) { + this.usersInput = input; + } + + public void setYesNo(boolean yesNo) { + usersYesNoSelection = yesNo; + } + + public void setConfirmation(boolean confirm) { + usersConfirm = confirm; + } + + CommandDetails getCmdDetails() { + return cmdDet; + } + } \ No newline at end of file diff --git a/telephony/java/com/android/internal/telephony/gsm/stk/TextMessage.java b/telephony/java/com/android/internal/telephony/gsm/stk/TextMessage.java new file mode 100644 index 0000000000000000000000000000000000000000..3b6a09a5d940965a216a42c369f9b35436ce8bfa --- /dev/null +++ b/telephony/java/com/android/internal/telephony/gsm/stk/TextMessage.java @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2007 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.android.internal.telephony.gsm.stk; + +import android.graphics.Bitmap; +import android.os.Parcel; +import android.os.Parcelable; + +public class TextMessage implements Parcelable { + public String title = ""; + public String text = null; + public Bitmap icon = null; + public boolean iconSelfExplanatory = false; + public boolean isHighPriority = false; + public boolean responseNeeded = true; + public boolean userClear = false; + public Duration duration = null; + + TextMessage() { + } + + private TextMessage(Parcel in) { + title = in.readString(); + text = in.readString(); + icon = in.readParcelable(null); + iconSelfExplanatory = in.readInt() == 1 ? true : false; + isHighPriority = in.readInt() == 1 ? true : false; + responseNeeded = in.readInt() == 1 ? true : false; + userClear = in.readInt() == 1 ? true : false; + duration = in.readParcelable(null); + } + + public int describeContents() { + return 0; + } + + public void writeToParcel(Parcel dest, int flags) { + dest.writeString(title); + dest.writeString(text); + dest.writeParcelable(icon, 0); + dest.writeInt(iconSelfExplanatory ? 1 : 0); + dest.writeInt(isHighPriority ? 1 : 0); + dest.writeInt(responseNeeded ? 1 : 0); + dest.writeInt(userClear ? 1 : 0); + dest.writeParcelable(duration, 0); + } + + public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { + public TextMessage createFromParcel(Parcel in) { + return new TextMessage(in); + } + + public TextMessage[] newArray(int size) { + return new TextMessage[size]; + } + }; +} \ No newline at end of file diff --git a/telephony/java/com/android/internal/telephony/gsm/stk/Tone.java b/telephony/java/com/android/internal/telephony/gsm/stk/Tone.java index c96f1641beb4e14b52f1c28864bd1f5bcc15bfd5..b64e777da6202ce94bced34cafdcbdaeebef68b4 100644 --- a/telephony/java/com/android/internal/telephony/gsm/stk/Tone.java +++ b/telephony/java/com/android/internal/telephony/gsm/stk/Tone.java @@ -16,6 +16,8 @@ package com.android.internal.telephony.gsm.stk; +import android.os.Parcel; +import android.os.Parcelable; /** * Enumeration for representing the tone values for use with PLAY TONE @@ -23,7 +25,7 @@ package com.android.internal.telephony.gsm.stk; * * {@hide} */ -public enum Tone { +public enum Tone implements Parcelable { // Standard supervisory tones /** @@ -163,4 +165,26 @@ public enum Tone { } return null; } + + Tone(Parcel in) { + mValue = in.readInt(); + } + + public void writeToParcel(Parcel dest, int flags) { + dest.writeInt(ordinal()); + } + + public int describeContents() { + return 0; + } + + public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { + public Tone createFromParcel(Parcel in) { + return Tone.values()[in.readInt()]; + } + + public Tone[] newArray(int size) { + return new Tone[size]; + } + }; } diff --git a/telephony/java/com/android/internal/telephony/gsm/stk/ToneSettings.java b/telephony/java/com/android/internal/telephony/gsm/stk/ToneSettings.java new file mode 100644 index 0000000000000000000000000000000000000000..bbc925eca190f2f6a2e4336f3a949582e37dafc7 --- /dev/null +++ b/telephony/java/com/android/internal/telephony/gsm/stk/ToneSettings.java @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2007 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.android.internal.telephony.gsm.stk; + +import android.os.Parcel; +import android.os.Parcelable; + +/** + * Container class for PlayTone commands parameters. + * + */ +public class ToneSettings implements Parcelable { + public Duration duration; + public Tone tone; + public boolean vibrate; + + public ToneSettings(Duration duration, Tone tone, boolean vibrate) { + this.duration = duration; + this.tone = tone; + this.vibrate = vibrate; + } + + private ToneSettings(Parcel in) { + duration = in.readParcelable(null); + tone = in.readParcelable(null); + vibrate = in.readInt() == 1; + } + + public int describeContents() { + return 0; + } + + public void writeToParcel(Parcel dest, int flags) { + dest.writeParcelable(duration, 0); + dest.writeParcelable(tone, 0); + dest.writeInt(vibrate ? 1 : 0); + } + + public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { + public ToneSettings createFromParcel(Parcel in) { + return new ToneSettings(in); + } + + public ToneSettings[] newArray(int size) { + return new ToneSettings[size]; + } + }; +} \ No newline at end of file diff --git a/telephony/java/com/android/internal/telephony/gsm/stk/ValueParser.java b/telephony/java/com/android/internal/telephony/gsm/stk/ValueParser.java new file mode 100644 index 0000000000000000000000000000000000000000..cd02a8bd70a2bf1eaf542ab1a71d4d03650ae8a1 --- /dev/null +++ b/telephony/java/com/android/internal/telephony/gsm/stk/ValueParser.java @@ -0,0 +1,340 @@ +/* + * Copyright (C) 2006-2007 Google Inc. + * + * 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.android.internal.telephony.gsm.stk; + +import android.util.Log; + +import com.android.internal.telephony.gsm.GsmAlphabet; +import com.android.internal.telephony.gsm.SimUtils; +import com.android.internal.telephony.gsm.stk.Duration.TimeUnit; + +import java.io.UnsupportedEncodingException; +import java.util.ArrayList; +import java.util.List; + +abstract class ValueParser { + + private static final String TAG = "ValueParser"; + + /** + * Search for a Command Details object from a list. + * + * @param ctlvs List of ComprehensionTlv objects used for search + * @return An CtlvCommandDetails object found from the objects. If no + * Command Details object is found, ResultException is thrown. + * @throws ResultException + */ + static CommandDetails retrieveCommandDetails(ComprehensionTlv ctlv) + throws ResultException { + + CommandDetails cmdDet = new CommandDetails(); + byte[] rawValue = ctlv.getRawValue(); + int valueIndex = ctlv.getValueIndex(); + try { + cmdDet.compRequired = ctlv.isComprehensionRequired(); + cmdDet.commandNumber = rawValue[valueIndex] & 0xff; + cmdDet.typeOfCommand = rawValue[valueIndex + 1] & 0xff; + cmdDet.commandQualifier = rawValue[valueIndex + 2] & 0xff; + return cmdDet; + } catch (IndexOutOfBoundsException e) { + throw new ResultException(ResultCode.CMD_DATA_NOT_UNDERSTOOD); + } + } + + /** + * Search for a Device Identities object from a list. + * + * @param ctlvs List of ComprehensionTlv objects used for search + * @return An CtlvDeviceIdentities object found from the objects. If no + * Command Details object is found, ResultException is thrown. + * @throws ResultException + */ + static DeviceIdentities retrieveDeviceIdentities(ComprehensionTlv ctlv) + throws ResultException { + + DeviceIdentities devIds = new DeviceIdentities(); + byte[] rawValue = ctlv.getRawValue(); + int valueIndex = ctlv.getValueIndex(); + try { + devIds.sourceId = rawValue[valueIndex] & 0xff; + devIds.destinationId = rawValue[valueIndex + 1] & 0xff; + return devIds; + } catch (IndexOutOfBoundsException e) { + throw new ResultException(ResultCode.REQUIRED_VALUES_MISSING); + } + } + + /** + * Retrieves Duration information from the Duration COMPREHENSION-TLV + * object. + * + * @param ctlv A Text Attribute COMPREHENSION-TLV object + * @return A Duration object + * @throws ResultException + */ + static Duration retrieveDuration(ComprehensionTlv ctlv) throws ResultException { + int timeInterval = 0; + TimeUnit timeUnit = TimeUnit.SECOND; + + byte[] rawValue = ctlv.getRawValue(); + int valueIndex = ctlv.getValueIndex(); + + try { + timeUnit = TimeUnit.values()[(rawValue[valueIndex] & 0xff)]; + timeInterval = rawValue[valueIndex + 1] & 0xff; + } catch (IndexOutOfBoundsException e) { + throw new ResultException(ResultCode.CMD_DATA_NOT_UNDERSTOOD); + } + return new Duration(timeInterval, timeUnit); + } + + /** + * Retrieves Item information from the COMPREHENSION-TLV object. + * + * @param ctlv A Text Attribute COMPREHENSION-TLV object + * @return An Item + * @throws ResultException + */ + static Item retrieveItem(ComprehensionTlv ctlv) throws ResultException { + Item item = null; + + byte[] rawValue = ctlv.getRawValue(); + int valueIndex = ctlv.getValueIndex(); + int length = ctlv.getLength(); + + if (length != 0) { + int textLen = length - 1; + + try { + int id = rawValue[valueIndex] & 0xff; + String text = SimUtils.adnStringFieldToString(rawValue, + valueIndex + 1, textLen); + item = new Item(id, text); + } catch (IndexOutOfBoundsException e) { + throw new ResultException(ResultCode.CMD_DATA_NOT_UNDERSTOOD); + } + } + + return item; + } + + /** + * Retrieves Item id information from the COMPREHENSION-TLV object. + * + * @param ctlv A Text Attribute COMPREHENSION-TLV object + * @return An Item id + * @throws ResultException + */ + static int retrieveItemId(ComprehensionTlv ctlv) throws ResultException { + int id = 0; + + byte[] rawValue = ctlv.getRawValue(); + int valueIndex = ctlv.getValueIndex(); + + try { + id = rawValue[valueIndex] & 0xff; + } catch (IndexOutOfBoundsException e) { + throw new ResultException(ResultCode.CMD_DATA_NOT_UNDERSTOOD); + } + + return id; + } + + /** + * Retrieves icon id from an Icon Identifier COMPREHENSION-TLV object + * + * @param ctlv An Icon Identifier COMPREHENSION-TLV object + * @return IconId instance + * @throws ResultException + */ + static IconId retrieveIconId(ComprehensionTlv ctlv) throws ResultException { + IconId id = new IconId(); + + byte[] rawValue = ctlv.getRawValue(); + int valueIndex = ctlv.getValueIndex(); + try { + id.selfExplanatory = (rawValue[valueIndex++] & 0xff) == 0x00; + id.recordNumber = rawValue[valueIndex] & 0xff; + } catch (IndexOutOfBoundsException e) { + throw new ResultException(ResultCode.CMD_DATA_NOT_UNDERSTOOD); + } + + return id; + } + + /** + * Retrieves item icons id from an Icon Identifier List COMPREHENSION-TLV + * object + * + * @param ctlv An Item Icon List Identifier COMPREHENSION-TLV object + * @return ItemsIconId instance + * @throws ResultException + */ + static ItemsIconId retrieveItemsIconId(ComprehensionTlv ctlv) + throws ResultException { + Log.d(TAG, "retrieveIconIdList:"); + ItemsIconId id = new ItemsIconId(); + + byte[] rawValue = ctlv.getRawValue(); + int valueIndex = ctlv.getValueIndex(); + int numOfItems = ctlv.getLength() - 1; + id.recordNumbers = new int[numOfItems]; + + try { + // get icon self-explanatory + id.selfExplanatory = (rawValue[valueIndex++] & 0xff) == 0x00; + + for (int index = 0; index < numOfItems;) { + id.recordNumbers[index++] = rawValue[valueIndex++]; + } + } catch (IndexOutOfBoundsException e) { + throw new ResultException(ResultCode.CMD_DATA_NOT_UNDERSTOOD); + } + return id; + } + + /** + * Retrieves text attribute information from the Text Attribute + * COMPREHENSION-TLV object. + * + * @param ctlv A Text Attribute COMPREHENSION-TLV object + * @return A list of TextAttribute objects + * @throws ResultException + */ + static List retrieveTextAttribute(ComprehensionTlv ctlv) + throws ResultException { + ArrayList lst = new ArrayList(); + + byte[] rawValue = ctlv.getRawValue(); + int valueIndex = ctlv.getValueIndex(); + int length = ctlv.getLength(); + + if (length != 0) { + // Each attribute is consisted of four bytes + int itemCount = length / 4; + + try { + for (int i = 0; i < itemCount; i++, valueIndex += 4) { + int start = rawValue[valueIndex] & 0xff; + int textLength = rawValue[valueIndex + 1] & 0xff; + int format = rawValue[valueIndex + 2] & 0xff; + int colorValue = rawValue[valueIndex + 3] & 0xff; + + int alignValue = format & 0x03; + TextAlignment align = TextAlignment.fromInt(alignValue); + + int sizeValue = (format >> 2) & 0x03; + FontSize size = FontSize.fromInt(sizeValue); + if (size == null) { + // Font size value is not defined. Use default. + size = FontSize.NORMAL; + } + + boolean bold = (format & 0x10) != 0; + boolean italic = (format & 0x20) != 0; + boolean underlined = (format & 0x40) != 0; + boolean strikeThrough = (format & 0x80) != 0; + + TextColor color = TextColor.fromInt(colorValue); + + TextAttribute attr = new TextAttribute(start, textLength, + align, size, bold, italic, underlined, + strikeThrough, color); + lst.add(attr); + } + + return lst; + + } catch (IndexOutOfBoundsException e) { + throw new ResultException(ResultCode.CMD_DATA_NOT_UNDERSTOOD); + } + } + return null; + } + + + /** + * Retrieves alpha identifier from an Alpha Identifier COMPREHENSION-TLV + * object. + * + * @param ctlv An Alpha Identifier COMPREHENSION-TLV object + * @return String corresponding to the alpha identifier + * @throws ResultException + */ + static String retrieveAlphaId(ComprehensionTlv ctlv) throws ResultException { + + byte[] rawValue = ctlv.getRawValue(); + int valueIndex = ctlv.getValueIndex(); + int length = ctlv.getLength(); + if (length != 0) { + try { + return SimUtils.adnStringFieldToString(rawValue, valueIndex, + length); + } catch (IndexOutOfBoundsException e) { + throw new ResultException(ResultCode.CMD_DATA_NOT_UNDERSTOOD); + } + } + return null; + } + + /** + * Retrieves text from the Text COMPREHENSION-TLV object, and decodes it + * into a Java String. + * + * @param ctlv A Text COMPREHENSION-TLV object + * @return A Java String object decoded from the Text object + * @throws ResultException + */ + static String retrieveTextString(ComprehensionTlv ctlv) throws ResultException { + byte[] rawValue = ctlv.getRawValue(); + int valueIndex = ctlv.getValueIndex(); + byte codingScheme = 0x00; + String text = null; + int textLen = ctlv.getLength(); + + // In case the text length is 0, return a null string. + if (textLen == 0) { + return text; + } else { + // one byte is coding scheme + textLen -= 1; + } + + try { + codingScheme = (byte) (rawValue[valueIndex] & 0x0c); + + if (codingScheme == 0x00) { // GSM 7-bit packed + text = GsmAlphabet.gsm7BitPackedToString(rawValue, + valueIndex + 1, (textLen * 8) / 7); + } else if (codingScheme == 0x04) { // GSM 8-bit unpacked + text = GsmAlphabet.gsm8BitUnpackedToString(rawValue, + valueIndex + 1, textLen); + } else if (codingScheme == 0x08) { // UCS2 + text = new String(rawValue, valueIndex + 1, textLen, "UTF-16"); + } else { + throw new ResultException(ResultCode.CMD_DATA_NOT_UNDERSTOOD); + } + + return text; + } catch (IndexOutOfBoundsException e) { + throw new ResultException(ResultCode.CMD_DATA_NOT_UNDERSTOOD); + } catch (UnsupportedEncodingException e) { + // This should never happen. + throw new ResultException(ResultCode.CMD_DATA_NOT_UNDERSTOOD); + } + } +} diff --git a/telephony/java/com/android/internal/telephony/test/ModelInterpreter.java b/telephony/java/com/android/internal/telephony/test/ModelInterpreter.java index 6af5d87c0d7ddcc1c774b5e63eda95eaa6007a83..25d2026dd3d0449416f3e979d20568259368c3dc 100644 --- a/telephony/java/com/android/internal/telephony/test/ModelInterpreter.java +++ b/telephony/java/com/android/internal/telephony/test/ModelInterpreter.java @@ -16,17 +16,18 @@ package com.android.internal.telephony.test; -import com.android.internal.os.HandlerThread; +import android.os.HandlerThread; +import android.os.Looper; +import android.os.Message; +import android.util.Log; + +import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; -import java.io.IOException; import java.io.UnsupportedEncodingException; - -import android.os.*; -import android.util.Log; +import java.net.InetSocketAddress; import java.net.ServerSocket; import java.net.Socket; -import java.net.InetSocketAddress; import java.util.List; // Also in ATChannel.java @@ -131,7 +132,7 @@ class InterpreterEx extends Exception } public class ModelInterpreter - implements Runnable, HandlerInterface, SimulatedRadioControl + implements Runnable, SimulatedRadioControl { static final int MAX_CALLS = 6; @@ -151,7 +152,7 @@ public class ModelInterpreter SimulatedGsmCallState simulatedCallState; - HandlerThread handlerThread; + HandlerThread mHandlerThread; int pausedResponseCount; Object pausedResponseMonitor = new Object(); @@ -186,15 +187,10 @@ public class ModelInterpreter init() { new Thread(this, "ModelInterpreter").start(); - - handlerThread - = new HandlerThread(this, - new Runnable() { - public void run() { - simulatedCallState = new SimulatedGsmCallState(); - } - }, - "ModelInterpreter"); + mHandlerThread = new HandlerThread("ModelInterpreter"); + mHandlerThread.start(); + Looper looper = mHandlerThread.getLooper(); + simulatedCallState = new SimulatedGsmCallState(looper); } //***** Runnable Implementation @@ -273,14 +269,6 @@ public class ModelInterpreter } } - //***** HandlerInterface Implementation - - public void - handleMessage(Message msg) - { - - } - //***** Instance Methods @@ -695,7 +683,10 @@ public class ModelInterpreter public void shutdown() { - handlerThread.getHandler().getLooper().quit(); + Looper looper = mHandlerThread.getLooper(); + if (looper != null) { + looper.quit(); + } try { in.close(); diff --git a/telephony/java/com/android/internal/telephony/test/SimulatedCommands.java b/telephony/java/com/android/internal/telephony/test/SimulatedCommands.java index 47fac4686aa4674f6fe2b9c50257c720871807aa..33c167953e05b27fdba0381c8cf5ddaf1c451212 100644 --- a/telephony/java/com/android/internal/telephony/test/SimulatedCommands.java +++ b/telephony/java/com/android/internal/telephony/test/SimulatedCommands.java @@ -16,27 +16,25 @@ package com.android.internal.telephony.test; -import com.android.internal.os.HandlerThread; + import android.os.AsyncResult; -import android.os.HandlerInterface; +import android.os.HandlerThread; +import android.os.Looper; import android.os.Message; -import com.android.internal.telephony.ATParseEx; +import android.util.Log; + import com.android.internal.telephony.Phone; import com.android.internal.telephony.gsm.BaseCommands; -import com.android.internal.telephony.gsm.BaseCommands; import com.android.internal.telephony.gsm.CallFailCause; import com.android.internal.telephony.gsm.CommandException; import com.android.internal.telephony.gsm.CommandsInterface; -import com.android.internal.telephony.gsm.DriverCall; import com.android.internal.telephony.gsm.PDPContextState; -import com.android.internal.telephony.gsm.stk.CtlvCommandDetails; -import com.android.internal.telephony.gsm.stk.ResultCode; import com.android.internal.telephony.gsm.SuppServiceNotification; -import android.util.Log; + import java.util.ArrayList; public final class SimulatedCommands extends BaseCommands - implements CommandsInterface, HandlerInterface, SimulatedRadioControl + implements CommandsInterface, SimulatedRadioControl { private final static String LOG_TAG = "SIM"; @@ -64,7 +62,7 @@ public final class SimulatedCommands extends BaseCommands //***** Instance Variables SimulatedGsmCallState simulatedCallState; - HandlerThread handlerThread; + HandlerThread mHandlerThread; SimLockState mSimLockedState; boolean mSimLockEnabled; int mPinUnlockAttempts; @@ -88,15 +86,12 @@ public final class SimulatedCommands extends BaseCommands public SimulatedCommands() { super(null); // Don't log statistics - handlerThread - = new HandlerThread(this, - new Runnable() { - public void run() { - simulatedCallState = new SimulatedGsmCallState(); - } - }, - "SimulatedCommands"); - + mHandlerThread = new HandlerThread("SimulatedCommands"); + mHandlerThread.start(); + Looper looper = mHandlerThread.getLooper(); + + simulatedCallState = new SimulatedGsmCallState(looper); + setRadioState(RadioState.RADIO_OFF); mSimLockedState = INITIAL_LOCK_STATE; mSimLockEnabled = (mSimLockedState != SimLockState.NONE); @@ -1274,7 +1269,10 @@ public final class SimulatedCommands extends BaseCommands shutdown() { setRadioState(RadioState.RADIO_UNAVAILABLE); - handlerThread.getHandler().getLooper().quit(); + Looper looper = mHandlerThread.getLooper(); + if (looper != null) { + looper.quit(); + } } /** hangup all */ @@ -1313,14 +1311,6 @@ public final class SimulatedCommands extends BaseCommands } } - //***** HandlerInterface implementation - - public void - handleMessage(Message msg) - { - - } - //***** Private Methods private void unimplemented(Message result) diff --git a/telephony/java/com/android/internal/telephony/test/SimulatedGsmCallState.java b/telephony/java/com/android/internal/telephony/test/SimulatedGsmCallState.java index bbc2bba4822ca54b6e5f4f77d9c37e21e92e5a8f..340d788ac861dda2acfa0085535416dc54cb134e 100644 --- a/telephony/java/com/android/internal/telephony/test/SimulatedGsmCallState.java +++ b/telephony/java/com/android/internal/telephony/test/SimulatedGsmCallState.java @@ -16,6 +16,7 @@ package com.android.internal.telephony.test; +import android.os.Looper; import android.os.Message; import android.os.Handler; import android.telephony.PhoneNumberUtils; @@ -162,6 +163,10 @@ class SimulatedGsmCallState extends Handler //***** Overridden from Handler + public SimulatedGsmCallState(Looper looper) { + super(looper); + } + public void handleMessage(Message msg) { @@ -176,7 +181,8 @@ class SimulatedGsmCallState extends Handler } //***** Public Methods - + + /** * Start the simulated phone ringing * true if succeeded, false if failed diff --git a/test-runner/android/test/ActivityInstrumentationTestCase.java b/test-runner/android/test/ActivityInstrumentationTestCase.java index b198a7a72c86cebafd04e71c48efaf3d1198fc1e..e5a9991ae557140a31114f641605bfe524108330 100644 --- a/test-runner/android/test/ActivityInstrumentationTestCase.java +++ b/test-runner/android/test/ActivityInstrumentationTestCase.java @@ -27,7 +27,12 @@ import java.lang.reflect.Field; * automatically here by {@link #setUp} and {@link #tearDown}. * *

              If you prefer an isolated unit test, see {@link android.test.ActivityUnitTestCase}. + * + * @deprecated new tests should be written using + * {@link android.test.ActivityInstrumentationTestCase2}, which provides more options for + * configuring the Activity under test */ +@Deprecated public abstract class ActivityInstrumentationTestCase extends ActivityTestCase { String mPackage; diff --git a/test-runner/android/test/ActivityInstrumentationTestCase2.java b/test-runner/android/test/ActivityInstrumentationTestCase2.java new file mode 100644 index 0000000000000000000000000000000000000000..7a84ecae7b38834d1ad551d282f2ab43a9327cd0 --- /dev/null +++ b/test-runner/android/test/ActivityInstrumentationTestCase2.java @@ -0,0 +1,174 @@ +/* + * 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 android.test; + +import android.app.Activity; +import android.content.Intent; + +import java.lang.reflect.Method; + +/** + * This class provides functional testing of a single activity. The activity under test will + * be created using the system infrastructure (by calling InstrumentationTestCase.launchActivity()) + * and you will then be able to manipulate your Activity directly. + * + *

              Other options supported by this test case include: + *

                + *
              • You can run any test method on the UI thread (see {@link android.test.UiThreadTest}).
              • + *
              • You can inject custom Intents into your Activity (see + * {@link #setActivityIntent(Intent)}).
              • + *
              + * + *

              This class replaces {@link android.test.ActivityInstrumentationTestCase}, which is deprecated. + * New tests should be written using this base class. + * + *

              If you prefer an isolated unit test, see {@link android.test.ActivityUnitTestCase}. + */ +public abstract class ActivityInstrumentationTestCase2 + extends ActivityTestCase { + String mPackage; + Class mActivityClass; + boolean mInitialTouchMode = false; + Intent mActivityIntent = null; + + /** + * @param pkg The package of the instrumentation. + * @param activityClass The activity to test. + */ + public ActivityInstrumentationTestCase2(String pkg, Class activityClass) { + mPackage = pkg; + mActivityClass = activityClass; + } + + /** + * Get the Activity under test, starting it if necessary. + * + * For each test method invocation, the Activity will not actually be created until the first + * time this method is called. + * + *

              If you wish to provide custom setup values to your Activity, you may call + * {@link #setActivityIntent(Intent)} and/or {@link #setActivityInitialTouchMode(boolean)} + * before your first call to getActivity(). Calling them after your Activity has + * started will have no effect. + * + *

              NOTE: Activities under test may not be started from within the UI thread. + * If your test method is annotated with {@link android.test.UiThreadTest}, then your Activity + * will be started automatically just before your test method is run. You still call this + * method in order to get the Activity under test. + * + * @return the Activity under test + */ + @Override + public T getActivity() { + Activity a = super.getActivity(); + if (a == null) { + // set initial touch mode + getInstrumentation().setInTouchMode(mInitialTouchMode); + // inject custom intent, if provided + if (mActivityIntent == null) { + a = launchActivity(mPackage, mActivityClass, null); + } else { + a = launchActivityWithIntent(mPackage, mActivityClass, mActivityIntent); + } + setActivity(a); + } + return (T) a; + } + + /** + * Call this method before the first call to {@link #getActivity} to inject a customized Intent + * into the Activity under test. + * + *

              If you do not call this, the default intent will be provided. If you call this after + * your Activity has been started, it will have no effect. + * + *

              NOTE: Activities under test may not be started from within the UI thread. + * If your test method is annotated with {@link android.test.UiThreadTest}, then you must call + * {@link #setActivityIntent(Intent)} from {@link #setUp()}. + * + *

              The default Intent (if this method is not called) is: + * action = {@link Intent#ACTION_MAIN} + * flags = {@link Intent#FLAG_ACTIVITY_NEW_TASK} + * All other fields are null or empty. + * + * @param i The Intent to start the Activity with, or null to reset to the default Intent. + */ + public void setActivityIntent(Intent i) { + mActivityIntent = i; + } + + /** + * Call this method before the first call to {@link #getActivity} to set the initial touch + * mode for the Activity under test. + * + *

              If you do not call this, the touch mode will be false. If you call this after + * your Activity has been started, it will have no effect. + * + *

              NOTE: Activities under test may not be started from within the UI thread. + * If your test method is annotated with {@link android.test.UiThreadTest}, then you must call + * {@link #setActivityInitialTouchMode(boolean)} from {@link #setUp()}. + * + * @param initialTouchMode true if the Activity should be placed into "touch mode" when started + */ + public void setActivityInitialTouchMode(boolean initialTouchMode) { + mInitialTouchMode = initialTouchMode; + } + + @Override + protected void setUp() throws Exception { + super.setUp(); + + boolean mInitialTouchMode = false; + Intent mActivityIntent = null; + } + + @Override + protected void tearDown() throws Exception { + // Finish the Activity off (unless was never launched anyway) + Activity a = super.getActivity(); + if (a != null) { + a.finish(); + setActivity(null); + } + + // Scrub out members - protects against memory leaks in the case where someone + // creates a non-static inner class (thus referencing the test case) and gives it to + // someone else to hold onto + scrubClass(ActivityInstrumentationTestCase2.class); + + super.tearDown(); + } + + /** + * Runs the current unit test. If the unit test is annotated with + * {@link android.test.UiThreadTest}, force the Activity to be created before switching to + * the UI thread. + */ + @Override + protected void runTest() throws Throwable { + try { + Method method = getClass().getMethod(getName(), (Class[]) null); + if (method.isAnnotationPresent(UiThreadTest.class)) { + getActivity(); + } + } catch (Exception e) { + // eat the exception here; super.runTest() will catch it again and handle it properly + } + super.runTest(); + } + +} diff --git a/test-runner/android/test/AndroidTestRunner.java b/test-runner/android/test/AndroidTestRunner.java index 353255e9df7336a88d7bc8d5b9457b9bab78f409..79cedb009e8a8e1b760ec930a25807970e346465 100644 --- a/test-runner/android/test/AndroidTestRunner.java +++ b/test-runner/android/test/AndroidTestRunner.java @@ -35,6 +35,7 @@ public class AndroidTestRunner extends BaseTestRunner { private String mTestClassName; private List mTestCases; private Context mContext; + private boolean mSkipExecution = false; private List mTestListeners = Lists.newArrayList(); private Instrumentation mInstrumentation; @@ -124,8 +125,15 @@ public class AndroidTestRunner extends BaseTestRunner { } protected TestResult createTestResult() { + if (mSkipExecution) { + return new NoExecTestResult(); + } return new TestResult(); } + + void setSkipExecution(boolean skip) { + mSkipExecution = skip; + } public List getTestCases() { return mTestCases; diff --git a/test-runner/android/test/DatabaseTestUtils.java b/test-runner/android/test/DatabaseTestUtils.java new file mode 100644 index 0000000000000000000000000000000000000000..23e0aba677a49943b019e4643417536cf60a31da --- /dev/null +++ b/test-runner/android/test/DatabaseTestUtils.java @@ -0,0 +1,57 @@ +/* + * 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 android.test; + +import com.google.android.collect.Sets; + +import android.database.sqlite.SQLiteDatabase; +import android.database.Cursor; + +import java.util.Set; + +/** + * A collection of utilities for writing unit tests for database code. + * @hide pending API council approval + */ +public class DatabaseTestUtils { + + /** + * Compares the schema of two databases and asserts that they are equal. + * @param expectedDb the db that is known to have the correct schema + * @param db the db whose schema should be checked + */ + public static void assertSchemaEquals(SQLiteDatabase expectedDb, SQLiteDatabase db) { + Set expectedSchema = getSchemaSet(expectedDb); + Set schema = getSchemaSet(db); + MoreAsserts.assertEquals(expectedSchema, schema); + } + + private static Set getSchemaSet(SQLiteDatabase db) { + Set schemaSet = Sets.newHashSet(); + + Cursor entityCursor = db.rawQuery("SELECT sql FROM sqlite_master", null); + try { + while (entityCursor.moveToNext()) { + String sql = entityCursor.getString(0); + schemaSet.add(sql); + } + } finally { + entityCursor.close(); + } + return schemaSet; + } +} diff --git a/test-runner/android/test/InstrumentationCoreTestRunner.java b/test-runner/android/test/InstrumentationCoreTestRunner.java new file mode 100644 index 0000000000000000000000000000000000000000..6b1a4e44d71b03e0b2c78f83e6807c61cedce6fe --- /dev/null +++ b/test-runner/android/test/InstrumentationCoreTestRunner.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 android.test; + +import java.io.File; + +import android.os.Bundle; + +/** + * This test runner extends the default InstrumentationTestRunner. It overrides + * the {@code onCreate(Bundle)} method and sets the system properties necessary + * for many core tests to run. This is needed because there are some core tests + * that need writing access to the filesystem. + * + * @hide + */ +public class InstrumentationCoreTestRunner extends InstrumentationTestRunner { + + @Override + public void onCreate(Bundle arguments) { + super.onCreate(arguments); + + File cacheDir = getTargetContext().getCacheDir(); + + System.setProperty("user.language", "en"); + System.setProperty("user.region", "US"); + System.setProperty("java.io.tmpdir", cacheDir.getAbsolutePath()); + } +} diff --git a/test-runner/android/test/InstrumentationTestRunner.java b/test-runner/android/test/InstrumentationTestRunner.java index 930da122b67d0a2b692cae43862b52bed9ffe299..8b8d47217ecb7d8724187f1cb2ecbd042730aa17 100644 --- a/test-runner/android/test/InstrumentationTestRunner.java +++ b/test-runner/android/test/InstrumentationTestRunner.java @@ -16,6 +16,19 @@ package android.test; +import static android.test.suitebuilder.TestPredicates.REJECT_PERFORMANCE; +import android.app.Activity; +import android.app.Instrumentation; +import android.os.Bundle; +import android.os.Debug; +import android.os.Looper; +import android.test.suitebuilder.TestMethod; +import android.test.suitebuilder.TestPredicates; +import android.test.suitebuilder.TestSuiteBuilder; +import android.util.Log; + +import com.android.internal.util.Predicate; + import junit.framework.AssertionFailedError; import junit.framework.Test; import junit.framework.TestCase; @@ -25,18 +38,12 @@ import junit.framework.TestSuite; import junit.runner.BaseTestRunner; import junit.textui.ResultPrinter; -import android.app.Activity; -import android.app.Instrumentation; -import android.content.Context; -import android.os.Bundle; -import android.os.Debug; -import android.os.Looper; -import android.test.suitebuilder.InstrumentationTestSuiteBuilder; -import android.test.suitebuilder.TestSuiteBuilder; -import android.test.suitebuilder.UnitTestSuiteBuilder; - import java.io.ByteArrayOutputStream; +import java.io.File; import java.io.PrintStream; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + /** * An {@link Instrumentation} that runs various types of {@link junit.framework.TestCase}s against @@ -69,10 +76,16 @@ import java.io.PrintStream; * Running all tests: adb shell am instrument -w * com.android.foo/android.test.InstrumentationTestRunner *

              - * Running unit tests: adb shell am instrument -w -e unit true + * Running all small tests: adb shell am instrument -w + * -e size small * com.android.foo/android.test.InstrumentationTestRunner *

              - * Running instrumentation tests: adb shell am instrument -w -e func true + * Running all medium tests: adb shell am instrument -w + * -e size medium + * com.android.foo/android.test.InstrumentationTestRunner + *

              + * Running all large tests: adb shell am instrument -w + * -e size large * com.android.foo/android.test.InstrumentationTestRunner *

              * Running a single testcase: adb shell am instrument -w @@ -83,8 +96,30 @@ import java.io.PrintStream; * -e class com.android.foo.FooTest#testFoo * com.android.foo/android.test.InstrumentationTestRunner *

              + * Running multiple tests: adb shell am instrument -w + * -e class com.android.foo.FooTest,com.android.foo.TooTest + * com.android.foo/android.test.InstrumentationTestRunner + *

              + * Including performance tests: adb shell am instrument -w + * -e perf true + * com.android.foo/android.test.InstrumentationTestRunner + *

              * To debug your tests, set a break point in your code and pass: * -e debug true + *

              + * To run in 'log only' mode + * -e log true + * This option will load and iterate through all test classes and methods, but will bypass actual + * test execution. Useful for quickly obtaining info on the tests to be executed by an + * instrumentation command. + *

              + * To generate EMMA code coverage: + * -e coverage true + * Note: this requires an emma instrumented build. By default, the code coverage results file + * will be saved as /sdcard/coverage.ec, unless overridden by coverageFile flag (see below) + *

              + * To specify EMMA code coverage results file path: + * -e coverageFile /sdcard/myFile.ec *
              * in addition to the other arguments. */ @@ -108,17 +143,36 @@ public class InstrumentationTestRunner extends Instrumentation implements TestSu /** @hide */ public static final String ARGUMENT_TEST_CLASS = "class"; /** @hide */ - public static final String ARGUMENT_UNIT_CLASS = "unit"; + public static final String ARGUMENT_TEST_PACKAGE = "package"; /** @hide */ - public static final String ARGUMENT_FUNC_CLASS = "func"; + public static final String ARGUMENT_TEST_SIZE_PREDICATE = "size"; /** @hide */ - public static final String ARGUMENT_TEST_PACKAGE = "package"; + public static final String ARGUMENT_INCLUDE_PERF = "perf"; + + private static final String SMALL_SUITE = "small"; + private static final String MEDIUM_SUITE = "medium"; + private static final String LARGE_SUITE = "large"; + + private static final String ARGUMENT_LOG_ONLY = "log"; + + + /** + * This constant defines the maximum allowed runtime (in ms) for a test included in the "small" suite. + * It is used to make an educated guess at what suite an unlabeled test belongs. + */ + private static final float SMALL_SUITE_MAX_RUNTIME = 100; + + /** + * This constant defines the maximum allowed runtime (in ms) for a test included in the "medium" suite. + * It is used to make an educated guess at what suite an unlabeled test belongs. + */ + private static final float MEDIUM_SUITE_MAX_RUNTIME = 1000; /** * The following keys are used in the status bundle to provide structured reports to * an IInstrumentationWatcher. */ - + /** * This value, if stored with key {@link android.app.Instrumentation#REPORT_KEY_IDENTIFIER}, * identifies InstrumentationTestRunner as the source of the report. This is sent with all @@ -149,6 +203,16 @@ public class InstrumentationTestRunner extends Instrumentation implements TestSu * describing a specific test being started or completed. */ public static final String REPORT_KEY_NAME_TEST = "test"; + /** + * If included in the status or final bundle sent to an IInstrumentationWatcher, this key + * reports the run time in seconds of the current test. + */ + private static final String REPORT_KEY_RUN_TIME = "runtime"; + /** + * If included in the status or final bundle sent to an IInstrumentationWatcher, this key + * reports the guessed suite assignment for the current test. + */ + private static final String REPORT_KEY_SUITE_ASSIGNMENT = "suiteassignment"; /** * The test is starting. */ @@ -172,14 +236,19 @@ public class InstrumentationTestRunner extends Instrumentation implements TestSu */ public static final String REPORT_KEY_STACK = "stack"; + private static final String DEFAULT_COVERAGE_FILE_PATH = "/sdcard/coverage.ec"; + + private static final String LOG_TAG = "InstrumentationTestRunner"; + private final Bundle mResults = new Bundle(); private AndroidTestRunner mTestRunner; private boolean mDebug; private boolean mJustCount; + private boolean mSuiteAssignmentMode; private int mTestCount; - private boolean mBundleOutput; - private boolean mDatabaseOutput; private String mPackageOfTests; + private boolean mCoverage; + private String mCoverageFilePath; @Override public void onCreate(Bundle arguments) { @@ -190,90 +259,95 @@ public class InstrumentationTestRunner extends Instrumentation implements TestSu {getTargetContext().getPackageCodePath(), getContext().getPackageCodePath()}; ClassPathPackageInfoSource.setApkPaths(apkPaths); - boolean useUnitTestSuite = false; - boolean useFunctionalTestSuite = false; - - String testClassName = null; - Test test = null; + Predicate testSizePredicate = null; + boolean includePerformance = false; + String testClassesArg = null; + boolean logOnly = false; if (arguments != null) { // Test class name passed as an argument should override any meta-data declaration. - testClassName = arguments.getString(ARGUMENT_TEST_CLASS); + testClassesArg = arguments.getString(ARGUMENT_TEST_CLASS); mDebug = getBooleanArgument(arguments, "debug"); mJustCount = getBooleanArgument(arguments, "count"); - mBundleOutput = getBooleanArgument(arguments, "bundle"); - mDatabaseOutput = getBooleanArgument(arguments, "database"); - useUnitTestSuite = getBooleanArgument(arguments, ARGUMENT_UNIT_CLASS); - useFunctionalTestSuite = getBooleanArgument(arguments, ARGUMENT_FUNC_CLASS); + mSuiteAssignmentMode = getBooleanArgument(arguments, "suiteAssignment"); mPackageOfTests = arguments.getString(ARGUMENT_TEST_PACKAGE); + testSizePredicate = getSizePredicateFromArg( + arguments.getString(ARGUMENT_TEST_SIZE_PREDICATE)); + includePerformance = getBooleanArgument(arguments, ARGUMENT_INCLUDE_PERF); + logOnly = getBooleanArgument(arguments, ARGUMENT_LOG_ONLY); + mCoverage = getBooleanArgument(arguments, "coverage"); + mCoverageFilePath = arguments.getString("coverageFile"); + } + + TestSuiteBuilder testSuiteBuilder = new TestSuiteBuilder(getClass().getName(), + getTargetContext().getClassLoader()); + + if (testSizePredicate != null) { + testSuiteBuilder.addRequirements(testSizePredicate); + } + if (!includePerformance) { + testSuiteBuilder.addRequirements(REJECT_PERFORMANCE); } - if (testClassName == null) { + if (testClassesArg == null) { + TestSuite testSuite = null; if (mPackageOfTests != null) { - test = createPackageTestSuite( - getTargetContext(), useUnitTestSuite, - useFunctionalTestSuite, mPackageOfTests); + testSuiteBuilder.includePackages(mPackageOfTests); } else { - test = getTestSuite(); + testSuite = getTestSuite(); + testSuiteBuilder.addTestSuite(testSuite); } - if (test == null) { - test = createDefaultTestSuite(getTargetContext(), useUnitTestSuite, - useFunctionalTestSuite); + if (testSuite == null) { + testSuiteBuilder.includePackages(getTargetContext().getPackageName()); } - mTestCount = test.countTestCases(); + } else { + parseTestClasses(testClassesArg, testSuiteBuilder); } mTestRunner = getAndroidTestRunner(); mTestRunner.setContext(getTargetContext()); mTestRunner.setInstrumentaiton(this); - mTestRunner.addTestListener(new TestPrinter("TestRunner", false)); - if (mDatabaseOutput) { - mTestRunner.addTestListener(new TestRecorder()); - } - - if (testClassName != null) { - int methodSeparatorIndex = testClassName.indexOf('#'); - String testMethodName = null; - - if (methodSeparatorIndex > 0) { - testMethodName = testClassName.substring(methodSeparatorIndex + 1); - testClassName = testClassName.substring(0, methodSeparatorIndex); - } - mTestRunner.setTestClassName(testClassName, testMethodName); - mTestCount = mTestRunner.getTestCases().size(); + mTestRunner.setSkipExecution(logOnly); + mTestRunner.setTest(testSuiteBuilder.build()); + mTestCount = mTestRunner.getTestCases().size(); + if (mSuiteAssignmentMode) { + mTestRunner.addTestListener(new SuiteAssignmentPrinter()); } else { - mTestRunner.setTest(test); - } - // add this now that we know the count - if (!mBundleOutput) { + mTestRunner.addTestListener(new TestPrinter("TestRunner", false)); mTestRunner.addTestListener(new WatcherResultPrinter(mTestCount)); } - start(); } - private TestSuite createDefaultTestSuite(Context context, boolean useUnitTestSuite, - boolean useFunctionalTestSuite) { - return createPackageTestSuite(context, useUnitTestSuite, useFunctionalTestSuite, context.getPackageName()); + /** + * Parses and loads the specified set of test classes + * @param testClassArg - comma-separated list of test classes and methods + * @param testSuiteBuilder - builder to add tests to + */ + private void parseTestClasses(String testClassArg, TestSuiteBuilder testSuiteBuilder) { + String[] testClasses = testClassArg.split(","); + for (String testClass : testClasses) { + parseTestClass(testClass, testSuiteBuilder); + } } - private TestSuite createPackageTestSuite(Context context, boolean useUnitTestSuite, - boolean useFunctionalTestSuite, String packageName) { - TestSuiteBuilder testSuiteBuilder = null; + /** + * Parse and load the given test class and, optionally, method + * @param testClassName - full package name of test class and optionally method to add. Expected + * format: com.android.TestClass#testMethod + * @param testSuiteBuilder - builder to add tests to + */ + private void parseTestClass(String testClassName, TestSuiteBuilder testSuiteBuilder) { + int methodSeparatorIndex = testClassName.indexOf('#'); + String testMethodName = null; - if (useUnitTestSuite) { - testSuiteBuilder = new UnitTestSuiteBuilder(getClass().getName(), - context.getClassLoader()); - } else if (useFunctionalTestSuite) { - testSuiteBuilder = new InstrumentationTestSuiteBuilder(getClass().getName(), - context.getClassLoader()); - } else { - testSuiteBuilder = new TestSuiteBuilder(getClass().getName(), - context.getClassLoader()); + if (methodSeparatorIndex > 0) { + testMethodName = testClassName.substring(methodSeparatorIndex + 1); + testClassName = testClassName.substring(0, methodSeparatorIndex); } - - return testSuiteBuilder.includePackages(packageName).build(); + testSuiteBuilder.addTestClassByName(testClassName, testMethodName, + getTargetContext()); } protected AndroidTestRunner getAndroidTestRunner() { @@ -284,7 +358,23 @@ public class InstrumentationTestRunner extends Instrumentation implements TestSu String tagString = arguments.getString(tag); return tagString != null && Boolean.parseBoolean(tagString); } - + + /* + * Returns the size predicate object, corresponding to the "size" argument value. + */ + private Predicate getSizePredicateFromArg(String sizeArg) { + + if (SMALL_SUITE.equals(sizeArg)) { + return TestPredicates.SELECT_SMALL; + } else if (MEDIUM_SUITE.equals(sizeArg)) { + return TestPredicates.SELECT_MEDIUM; + } else if (LARGE_SUITE.equals(sizeArg)) { + return TestPredicates.SELECT_LARGE; + } else { + return null; + } + } + @Override public void onStart() { Looper.prepare(); @@ -303,25 +393,24 @@ public class InstrumentationTestRunner extends Instrumentation implements TestSu try { StringResultPrinter resultPrinter = new StringResultPrinter(writer); - if (mBundleOutput) { - mTestRunner.addTestListener(new BundleTestListener(mResults)); - } else { - mTestRunner.addTestListener(resultPrinter); - } - + mTestRunner.addTestListener(resultPrinter); + long startTime = System.currentTimeMillis(); mTestRunner.runTest(); long runTime = System.currentTimeMillis() - startTime; resultPrinter.print(mTestRunner.getTestResult(), runTime); } finally { - if (!mBundleOutput) { - mResults.putString(Instrumentation.REPORT_KEY_STREAMRESULT, - String.format("\nTest results for %s=%s", - mTestRunner.getTestClassName(), - byteArrayOutputStream.toString())); + mResults.putString(Instrumentation.REPORT_KEY_STREAMRESULT, + String.format("\nTest results for %s=%s", + mTestRunner.getTestClassName(), + byteArrayOutputStream.toString())); + + if (mCoverage) { + generateCoverageReport(); } writer.close(); + finish(Activity.RESULT_OK, mResults); } } @@ -344,6 +433,51 @@ public class InstrumentationTestRunner extends Instrumentation implements TestSu public ClassLoader getLoader() { return null; } + + private void generateCoverageReport() { + // use reflection to call emma dump coverage method, to avoid + // always statically compiling against emma jar + java.io.File coverageFile = new java.io.File(getCoverageFilePath()); + try { + Class emmaRTClass = Class.forName("com.vladium.emma.rt.RT"); + Method dumpCoverageMethod = emmaRTClass.getMethod("dumpCoverageData", + coverageFile.getClass(), boolean.class, boolean.class); + + dumpCoverageMethod.invoke(null, coverageFile, false, false); + + } catch (ClassNotFoundException e) { + reportEmmaError("Is emma jar on classpath?", e); + } catch (SecurityException e) { + reportEmmaError(e); + } catch (NoSuchMethodException e) { + reportEmmaError(e); + } catch (IllegalArgumentException e) { + reportEmmaError(e); + } catch (IllegalAccessException e) { + reportEmmaError(e); + } catch (InvocationTargetException e) { + reportEmmaError(e); + } + } + + private String getCoverageFilePath() { + if (mCoverageFilePath == null) { + return DEFAULT_COVERAGE_FILE_PATH; + } + else { + return mCoverageFilePath; + } + } + + private void reportEmmaError(Exception e) { + reportEmmaError("", e); + } + + private void reportEmmaError(String hint, Exception e) { + String msg = "Failed to generate emma coverage. " + hint; + Log.e(LOG_TAG, msg, e); + mResults.putString(Instrumentation.REPORT_KEY_STREAMRESULT, "\nError: " + msg); + } // TODO kill this, use status() and prettyprint model for better output private class StringResultPrinter extends ResultPrinter { @@ -354,14 +488,84 @@ public class InstrumentationTestRunner extends Instrumentation implements TestSu synchronized void print(TestResult result, long runTime) { printHeader(runTime); - if (mBundleOutput) { - printErrors(result); - printFailures(result); - } printFooter(result); } } + /** + * This class sends status reports back to the IInstrumentationWatcher about + * which suite each test belongs. + */ + private class SuiteAssignmentPrinter implements TestListener + { + + private Bundle mTestResult; + private long mStartTime; + private long mEndTime; + private boolean mTimingValid; + + public SuiteAssignmentPrinter() { + } + + /** + * send a status for the start of a each test, so long tests can be seen as "running" + */ + public void startTest(Test test) { + mTimingValid = true; + mStartTime = System.currentTimeMillis(); + } + + /** + * @see junit.framework.TestListener#addError(Test, Throwable) + */ + public void addError(Test test, Throwable t) { + mTimingValid = false; + } + + /** + * @see junit.framework.TestListener#addFailure(Test, AssertionFailedError) + */ + public void addFailure(Test test, AssertionFailedError t) { + mTimingValid = false; + } + + /** + * @see junit.framework.TestListener#endTest(Test) + */ + public void endTest(Test test) { + float runTime; + String assignmentSuite; + mEndTime = System.currentTimeMillis(); + mTestResult = new Bundle(); + + if (!mTimingValid || mStartTime < 0) { + assignmentSuite = "NA"; + runTime = -1; + } else { + runTime = mEndTime - mStartTime; + if (runTime < SMALL_SUITE_MAX_RUNTIME + && !InstrumentationTestCase.class.isAssignableFrom(test.getClass())) { + assignmentSuite = SMALL_SUITE; + } else if (runTime < MEDIUM_SUITE_MAX_RUNTIME) { + assignmentSuite = MEDIUM_SUITE; + } else { + assignmentSuite = LARGE_SUITE; + } + } + // Clear mStartTime so that we can verify that it gets set next time. + mStartTime = -1; + + mTestResult.putString(Instrumentation.REPORT_KEY_STREAMRESULT, + test.getClass().getName() + "#" + ((TestCase) test).getName() + + "\nin " + assignmentSuite + " suite\nrunTime: " + + String.valueOf(runTime) + "\n"); + mTestResult.putFloat(REPORT_KEY_RUN_TIME, runTime); + mTestResult.putString(REPORT_KEY_SUITE_ASSIGNMENT, assignmentSuite); + + sendStatus(0, mTestResult); + } + } + /** * This class sends status reports back to the IInstrumentationWatcher */ @@ -437,6 +641,5 @@ public class InstrumentationTestRunner extends Instrumentation implements TestSu // TODO report the end of the cycle // TODO report runtime for each test } - - } + diff --git a/test-runner/android/test/NoExecTestResult.java b/test-runner/android/test/NoExecTestResult.java new file mode 100755 index 0000000000000000000000000000000000000000..1ee62c1690907fab8b92c9f4fb47291c71fc8d17 --- /dev/null +++ b/test-runner/android/test/NoExecTestResult.java @@ -0,0 +1,39 @@ +/* + * 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 android.test; + +import junit.framework.TestCase; +import junit.framework.TestResult; + +/** + * A benign test result that does no actually test execution, just runs + * through the motions + * + * {@hide} Not needed for SDK. + */ +class NoExecTestResult extends TestResult { + + /** + * Override parent to just inform listeners of test, + * and skip test execution. + */ + @Override + protected void run(final TestCase test) { + startTest(test); + endTest(test); + } + +} diff --git a/test-runner/android/test/ProviderTestCase.java b/test-runner/android/test/ProviderTestCase.java index 588238780d04cf2bfb820b68e999c81461a0cfa0..445b4ebd875c8c528321b0017d1cd1f1927c96aa 100644 --- a/test-runner/android/test/ProviderTestCase.java +++ b/test-runner/android/test/ProviderTestCase.java @@ -11,9 +11,12 @@ import android.database.DatabaseUtils; * If you would like to test a single content provider with an * {@link InstrumentationTestCase}, this provides some of the boiler plate in {@link #setUp} and * {@link #tearDown}. + * + * @deprecated this class extends InstrumentationTestCase but should extend AndroidTestCase. Use + * ProviderTestCase2, which corrects this problem, instead. */ public abstract class ProviderTestCase - extends InstrumentationTestCase { + extends InstrumentationTestCase { Class mProviderClass; String mProviderAuthority; @@ -66,18 +69,17 @@ public abstract class ProviderTestCase String databaseName, int databaseVersion, String sql) throws IllegalAccessException, InstantiationException { final String filenamePrefix = "test."; - MockContentResolver mockContentResolver = new MockContentResolver(); + MockContentResolver resolver = new MockContentResolver(); RenamingDelegatingContext targetContextWrapper = new RenamingDelegatingContext( new MockContext(), // The context that most methods are delegated to targetContext, // The context that file methods are delegated to filenamePrefix); Context context = new IsolatedContext( - mockContentResolver, targetContextWrapper); + resolver, targetContextWrapper); DatabaseUtils.createDbFromSqlStatements(context, databaseName, databaseVersion, sql); T provider = providerClass.newInstance(); provider.attachInfo(context, null); - MockContentResolver resolver = new MockContentResolver(); resolver.addProvider(authority, provider); return resolver; diff --git a/test-runner/android/test/ProviderTestCase2.java b/test-runner/android/test/ProviderTestCase2.java new file mode 100644 index 0000000000000000000000000000000000000000..714b77b56bb67142f49a01c52aae5b368d8b1795 --- /dev/null +++ b/test-runner/android/test/ProviderTestCase2.java @@ -0,0 +1,82 @@ +package android.test; + +import android.content.ContentProvider; +import android.content.ContentResolver; +import android.content.Context; +import android.test.mock.MockContext; +import android.test.mock.MockContentResolver; +import android.database.DatabaseUtils; + +/** + * If you would like to test a single content provider with an + * {@link android.test.InstrumentationTestCase}, this provides some of the boiler plate in + * {@link #setUp} and {@link #tearDown}. + * @hide pending API council approval + */ +public abstract class ProviderTestCase2 extends AndroidTestCase { + + Class mProviderClass; + String mProviderAuthority; + + private IsolatedContext mProviderContext; + private MockContentResolver mResolver; + + public ProviderTestCase2(Class providerClass, String providerAuthority) { + mProviderClass = providerClass; + mProviderAuthority = providerAuthority; + } + + /** + * The content provider that will be set up for use in each test method. + */ + private T mProvider; + + public T getProvider() { + return mProvider; + } + + @Override + protected void setUp() throws Exception { + super.setUp(); + + mResolver = new MockContentResolver(); + final String filenamePrefix = "test."; + RenamingDelegatingContext targetContextWrapper = new RenamingDelegatingContext( + new MockContext(), // The context that most methods are delegated to + getContext(), // The context that file methods are delegated to + filenamePrefix); + mProviderContext = new IsolatedContext(mResolver, targetContextWrapper); + + mProvider = mProviderClass.newInstance(); + mProvider.attachInfo(mProviderContext, null); + assertNotNull(mProvider); + mResolver.addProvider(mProviderAuthority, getProvider()); + } + + public MockContentResolver getMockContentResolver() { + return mResolver; + } + + public IsolatedContext getMockContext() { + return mProviderContext; + } + + public static ContentResolver newResolverWithContentProviderFromSql( + Context targetContext, String filenamePrefix, Class providerClass, String authority, + String databaseName, int databaseVersion, String sql) + throws IllegalAccessException, InstantiationException { + MockContentResolver resolver = new MockContentResolver(); + RenamingDelegatingContext targetContextWrapper = new RenamingDelegatingContext( + new MockContext(), // The context that most methods are delegated to + targetContext, // The context that file methods are delegated to + filenamePrefix); + Context context = new IsolatedContext(resolver, targetContextWrapper); + DatabaseUtils.createDbFromSqlStatements(context, databaseName, databaseVersion, sql); + + T provider = providerClass.newInstance(); + provider.attachInfo(context, null); + resolver.addProvider(authority, provider); + + return resolver; + } +} \ No newline at end of file diff --git a/test-runner/android/test/mock/MockContentResolver.java b/test-runner/android/test/mock/MockContentResolver.java index 66840a12d38297e0f6e2dc7993974c235bc3af38..3a1dc36cd31283420dd386d3ed6b5c28cc1d9da1 100644 --- a/test-runner/android/test/mock/MockContentResolver.java +++ b/test-runner/android/test/mock/MockContentResolver.java @@ -50,7 +50,12 @@ public class MockContentResolver extends ContentResolver { /** @hide */ @Override protected IContentProvider acquireProvider(Context context, String name) { - return mProviders.get(name).getIContentProvider(); + final ContentProvider provider = mProviders.get(name); + if (provider != null) { + return provider.getIContentProvider(); + } else { + return null; + } } /** @hide */ diff --git a/test-runner/android/test/mock/MockPackageManager.java b/test-runner/android/test/mock/MockPackageManager.java index 4f7745b9b2bcc4d3cb634978ed5b197ff3503805..34ebd78544a3c87ff422475ffc4ee2b6fd23c1e4 100644 --- a/test-runner/android/test/mock/MockPackageManager.java +++ b/test-runner/android/test/mock/MockPackageManager.java @@ -140,6 +140,14 @@ public class MockPackageManager extends PackageManager { public String getNameForUid(int uid) { throw new UnsupportedOperationException(); } + + /** + * @hide - to match hiding in superclass + */ + @Override + public int getUidForSharedUser(String sharedUserName) { + throw new UnsupportedOperationException(); + } @Override public List getInstalledApplications(int flags) { diff --git a/test-runner/android/test/suitebuilder/TestMethod.java b/test-runner/android/test/suitebuilder/TestMethod.java index 3a936c23d0f7b6864c117703aa0b8d81275fac55..08568d5d1a9be269b6908dd3923107863de9a230 100644 --- a/test-runner/android/test/suitebuilder/TestMethod.java +++ b/test-runner/android/test/suitebuilder/TestMethod.java @@ -26,8 +26,6 @@ import java.lang.reflect.Method; /** * Represents a test to be run. Can be constructed without instantiating the TestCase or even * loading the class. - * - * {@hide} Not needed for 1.0 SDK. */ public class TestMethod { @@ -36,9 +34,17 @@ public class TestMethod { private final Class enclosingClass; public TestMethod(Method method, Class enclosingClass) { + this(method.getName(), enclosingClass); + } + + public TestMethod(String methodName, Class enclosingClass) { this.enclosingClass = enclosingClass; this.enclosingClassname = enclosingClass.getName(); - this.testMethodName = method.getName(); + this.testMethodName = methodName; + } + + public TestMethod(TestCase testCase) { + this(testCase.getName(), testCase.getClass()); } public String getName() { @@ -53,7 +59,7 @@ public class TestMethod { try { return getEnclosingClass().getMethod(getName()).getAnnotation(annotationClass); } catch (NoSuchMethodException e) { - throw new RuntimeException(e); + return null; } } diff --git a/test-runner/android/test/suitebuilder/TestPredicates.java b/test-runner/android/test/suitebuilder/TestPredicates.java index ff75217236daecf12ebb8501191279c17c470f94..d814e0b8dd40409d3645b1e05b71f760dfa37954 100644 --- a/test-runner/android/test/suitebuilder/TestPredicates.java +++ b/test-runner/android/test/suitebuilder/TestPredicates.java @@ -20,6 +20,9 @@ import android.test.InstrumentationTestCase; import android.test.PerformanceTestBase; import android.test.suitebuilder.annotation.HasAnnotation; import android.test.suitebuilder.annotation.Suppress; +import android.test.suitebuilder.annotation.LargeTest; +import android.test.suitebuilder.annotation.MediumTest; +import android.test.suitebuilder.annotation.SmallTest; import android.test.suitebuilder.annotation.Smoke; import com.android.internal.util.Predicate; import com.android.internal.util.Predicates; @@ -35,6 +38,9 @@ public class TestPredicates { Predicates.not(SELECT_INSTRUMENTATION); public static final Predicate SELECT_SMOKE = new HasAnnotation(Smoke.class); + public static final Predicate SELECT_SMALL = new HasAnnotation(SmallTest.class); + public static final Predicate SELECT_MEDIUM = new HasAnnotation(MediumTest.class); + public static final Predicate SELECT_LARGE = new HasAnnotation(LargeTest.class); public static final Predicate REJECT_SUPPRESSED = Predicates.not(new HasAnnotation(Suppress.class)); public static final Predicate REJECT_PERFORMANCE = diff --git a/test-runner/android/test/suitebuilder/TestSuiteBuilder.java b/test-runner/android/test/suitebuilder/TestSuiteBuilder.java index 99d0eb9f19b1e315e0754bbbda8a38de296bfc00..428905eba085bf6aecc5d8dcc7b7c94eb81298d1 100644 --- a/test-runner/android/test/suitebuilder/TestSuiteBuilder.java +++ b/test-runner/android/test/suitebuilder/TestSuiteBuilder.java @@ -16,15 +16,22 @@ package android.test.suitebuilder; +import android.content.Context; +import android.test.AndroidTestRunner; +import android.test.TestCaseUtil; import android.util.Log; import com.android.internal.util.Predicate; +import com.google.android.collect.Lists; import static android.test.suitebuilder.TestGrouping.SORT_BY_FULLY_QUALIFIED_NAME; import static android.test.suitebuilder.TestPredicates.REJECT_SUPPRESSED; import static android.test.suitebuilder.TestPredicates.REJECT_PERFORMANCE; +import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; +import java.lang.reflect.InvocationTargetException; +import java.util.Enumeration; import java.util.List; import java.util.Set; import java.util.HashSet; @@ -37,8 +44,10 @@ import java.util.Collections; */ public class TestSuiteBuilder { + private Context context; private final TestGrouping testGrouping = new TestGrouping(SORT_BY_FULLY_QUALIFIED_NAME); private final Set> predicates = new HashSet>(); + private List testCases; private TestSuite rootSuite; private TestSuite suiteForCurrentClass; private String currentClassname; @@ -59,8 +68,28 @@ public class TestSuiteBuilder { public TestSuiteBuilder(String name, ClassLoader classLoader) { this.suiteName = name; this.testGrouping.setClassLoader(classLoader); + this.testCases = Lists.newArrayList(); addRequirements(REJECT_SUPPRESSED); - addRequirements(REJECT_PERFORMANCE); + } + + /** @hide pending API Council approval */ + public TestSuiteBuilder addTestClassByName(String testClassName, String testMethodName, + Context context) { + + AndroidTestRunner atr = new AndroidTestRunner(); + atr.setContext(context); + atr.setTestClassName(testClassName, testMethodName); + + this.testCases.addAll(atr.getTestCases()); + return this; + } + + /** @hide pending API Council approval */ + public TestSuiteBuilder addTestSuite(TestSuite testSuite) { + for (TestCase testCase : (List) TestCaseUtil.getTests(testSuite, true)) { + this.testCases.add(testCase); + } + return this; } /** @@ -156,6 +185,13 @@ public class TestSuiteBuilder { addTest(test); } } + if (testCases.size() > 0) { + for (TestCase testCase : testCases) { + if (satisfiesAllPredicates(new TestMethod(testCase))) { + addTest(testCase); + } + } + } } catch (Exception exception) { Log.i("TestSuiteBuilder", "Failed to create test.", exception); TestSuite suite = new TestSuite(getSuiteName()); @@ -223,12 +259,16 @@ public class TestSuiteBuilder { } private void addTest(TestMethod testMethod) throws Exception { - addSuiteIfNecessary(testMethod); + addSuiteIfNecessary(testMethod.getEnclosingClassname()); suiteForCurrentClass.addTest(testMethod.createTest()); } + + private void addTest(Test test) { + addSuiteIfNecessary(test.getClass().getName()); + suiteForCurrentClass.addTest(test); + } - private void addSuiteIfNecessary(TestMethod test) { - String parentClassname = test.getEnclosingClassname(); + private void addSuiteIfNecessary(String parentClassname) { if (!parentClassname.equals(currentClassname)) { currentClassname = parentClassname; suiteForCurrentClass = new TestSuite(parentClassname); diff --git a/tests/AndroidTests/Android.mk b/tests/AndroidTests/Android.mk new file mode 100644 index 0000000000000000000000000000000000000000..cf8ac94ca5f369341c297ef7f9728996e9ea8f62 --- /dev/null +++ b/tests/AndroidTests/Android.mk @@ -0,0 +1,22 @@ +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_MODULE_TAGS := eng tests + +LOCAL_JAVA_LIBRARIES := framework-tests android.test.runner + +LOCAL_STATIC_JAVA_LIBRARIES := googlelogin-client + +# Resource unit tests use a private locale +LOCAL_AAPT_FLAGS = -c xx_YY -c cs + +LOCAL_SRC_FILES := \ + $(call all-subdir-java-files) \ + src/com/android/unit_tests/os/IAidlTest.aidl + +LOCAL_PACKAGE_NAME := AndroidTests +LOCAL_CERTIFICATE := platform + +include $(BUILD_PACKAGE) + +include $(call all-makefiles-under,$(LOCAL_PATH)) diff --git a/tests/AndroidTests/AndroidManifest.xml b/tests/AndroidTests/AndroidManifest.xml new file mode 100644 index 0000000000000000000000000000000000000000..f126b8cbe60ffab1659400056a2a52e1ed3b973a --- /dev/null +++ b/tests/AndroidTests/AndroidManifest.xml @@ -0,0 +1,226 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/AndroidTests/DisabledTestApp/Android.mk b/tests/AndroidTests/DisabledTestApp/Android.mk new file mode 100644 index 0000000000000000000000000000000000000000..814607d58c53e7a84ef27733191a91ceb5214c65 --- /dev/null +++ b/tests/AndroidTests/DisabledTestApp/Android.mk @@ -0,0 +1,12 @@ +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_MODULE_TAGS := eng tests + +LOCAL_SRC_FILES := $(call all-subdir-java-files) + +LOCAL_PACKAGE_NAME := DisabledTestApp +LOCAL_CERTIFICATE := platform + +include $(BUILD_PACKAGE) + diff --git a/tests/AndroidTests/DisabledTestApp/AndroidManifest.xml b/tests/AndroidTests/DisabledTestApp/AndroidManifest.xml new file mode 100644 index 0000000000000000000000000000000000000000..4d6843e592017cc97b980b33e3469a049d95523c --- /dev/null +++ b/tests/AndroidTests/DisabledTestApp/AndroidManifest.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + diff --git a/tests/AndroidTests/DisabledTestApp/src/com/android/unit_tests/disabled_app/EnabledActivity.java b/tests/AndroidTests/DisabledTestApp/src/com/android/unit_tests/disabled_app/EnabledActivity.java new file mode 100644 index 0000000000000000000000000000000000000000..4e4dc85df7f3010ba309068c2e529e48d2170d9e --- /dev/null +++ b/tests/AndroidTests/DisabledTestApp/src/com/android/unit_tests/disabled_app/EnabledActivity.java @@ -0,0 +1,27 @@ +/* + * 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.android.unit_tests.disabled_app; + +import android.app.Activity; + +/** + * Empty Activity for testing + */ + +public class EnabledActivity extends Activity { + +} diff --git a/tests/AndroidTests/EnabledTestApp/Android.mk b/tests/AndroidTests/EnabledTestApp/Android.mk new file mode 100644 index 0000000000000000000000000000000000000000..2de5c3b5e2442184da15005c119bd45900a44d2a --- /dev/null +++ b/tests/AndroidTests/EnabledTestApp/Android.mk @@ -0,0 +1,12 @@ +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_MODULE_TAGS := eng tests + +LOCAL_SRC_FILES := $(call all-subdir-java-files) + +LOCAL_PACKAGE_NAME := EnabledTestApp +LOCAL_CERTIFICATE := platform + +include $(BUILD_PACKAGE) + diff --git a/tests/AndroidTests/EnabledTestApp/AndroidManifest.xml b/tests/AndroidTests/EnabledTestApp/AndroidManifest.xml new file mode 100644 index 0000000000000000000000000000000000000000..ad610f129a2a590c572b2d3dc22b8ce87ecac2b1 --- /dev/null +++ b/tests/AndroidTests/EnabledTestApp/AndroidManifest.xml @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/AndroidTests/EnabledTestApp/src/com/android/unit_tests/enabled_app/DisabledActivity.java b/tests/AndroidTests/EnabledTestApp/src/com/android/unit_tests/enabled_app/DisabledActivity.java new file mode 100644 index 0000000000000000000000000000000000000000..0ab04162fdadaeaf8cc39e9dfbda4f3339e712de --- /dev/null +++ b/tests/AndroidTests/EnabledTestApp/src/com/android/unit_tests/enabled_app/DisabledActivity.java @@ -0,0 +1,27 @@ +/* + * 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.android.unit_tests.enabled_app; + +import android.app.Activity; + +/** + * Empty Activity for testing + */ + +public class DisabledActivity extends Activity { + +} diff --git a/tests/AndroidTests/EnabledTestApp/src/com/android/unit_tests/enabled_app/DisabledProvider.java b/tests/AndroidTests/EnabledTestApp/src/com/android/unit_tests/enabled_app/DisabledProvider.java new file mode 100644 index 0000000000000000000000000000000000000000..06527f9fa5dc3991be2901167db14dd076a9023c --- /dev/null +++ b/tests/AndroidTests/EnabledTestApp/src/com/android/unit_tests/enabled_app/DisabledProvider.java @@ -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. + */ + +package com.android.unit_tests.enabled_app; + +import android.content.ContentProvider; +import android.content.ContentValues; +import android.database.Cursor; +import android.net.Uri; + +/** + * Empty ContentProvider for testing + */ + +public class DisabledProvider extends ContentProvider { + + public boolean onCreate() { + return false; + } + + public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, + String sortOrder) { + return null; + } + + public String getType(Uri uri) { + return null; + } + + public Uri insert(Uri uri, ContentValues values) { + return null; + } + + public int delete(Uri uri, String selection, String[] selectionArgs) { + return 0; + } + + public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { + return 0; + } +} diff --git a/tests/AndroidTests/EnabledTestApp/src/com/android/unit_tests/enabled_app/DisabledReceiver.java b/tests/AndroidTests/EnabledTestApp/src/com/android/unit_tests/enabled_app/DisabledReceiver.java new file mode 100644 index 0000000000000000000000000000000000000000..c27b87e63044e9d3bd24a52159f5442507fd7e1d --- /dev/null +++ b/tests/AndroidTests/EnabledTestApp/src/com/android/unit_tests/enabled_app/DisabledReceiver.java @@ -0,0 +1,32 @@ +/* + * 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.android.unit_tests.enabled_app; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; + +/** + * Empty IntentReceiver for testing + */ + +public class DisabledReceiver extends BroadcastReceiver { + + public void onReceive(Context context, Intent intent) { + + } +} diff --git a/tests/AndroidTests/EnabledTestApp/src/com/android/unit_tests/enabled_app/DisabledService.java b/tests/AndroidTests/EnabledTestApp/src/com/android/unit_tests/enabled_app/DisabledService.java new file mode 100644 index 0000000000000000000000000000000000000000..ed8d0b93b6db275d86f62f7635b28bd33c55ae5d --- /dev/null +++ b/tests/AndroidTests/EnabledTestApp/src/com/android/unit_tests/enabled_app/DisabledService.java @@ -0,0 +1,32 @@ +/* + * 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.android.unit_tests.enabled_app; + +import android.app.Service; +import android.os.IBinder; +import android.content.Intent; + +/** + * Empty Service for testing + */ + +public class DisabledService extends Service { + + public IBinder onBind(Intent intent) { + return null; + } +} diff --git a/tests/AndroidTests/EnabledTestApp/src/com/android/unit_tests/enabled_app/EnabledActivity.java b/tests/AndroidTests/EnabledTestApp/src/com/android/unit_tests/enabled_app/EnabledActivity.java new file mode 100644 index 0000000000000000000000000000000000000000..cfac3ec86bab72d162f2f4fb2f9ce5c91cded0c1 --- /dev/null +++ b/tests/AndroidTests/EnabledTestApp/src/com/android/unit_tests/enabled_app/EnabledActivity.java @@ -0,0 +1,27 @@ +/* + * 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.android.unit_tests.enabled_app; + +import android.app.Activity; + +/** + * Empty Activity for testing + */ + +public class EnabledActivity extends Activity { + +} diff --git a/tests/AndroidTests/EnabledTestApp/src/com/android/unit_tests/enabled_app/EnabledProvider.java b/tests/AndroidTests/EnabledTestApp/src/com/android/unit_tests/enabled_app/EnabledProvider.java new file mode 100644 index 0000000000000000000000000000000000000000..764937f84fcdbfe46700a105f20e39590a5301c6 --- /dev/null +++ b/tests/AndroidTests/EnabledTestApp/src/com/android/unit_tests/enabled_app/EnabledProvider.java @@ -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. + */ + +package com.android.unit_tests.enabled_app; + +import android.content.ContentProvider; +import android.content.ContentValues; +import android.database.Cursor; +import android.net.Uri; + +/** + * Empty ContentProvider for testing + */ + +public class EnabledProvider extends ContentProvider { + + public boolean onCreate() { + return false; + } + + public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, + String sortOrder) { + return null; + } + + public String getType(Uri uri) { + return null; + } + + public Uri insert(Uri uri, ContentValues values) { + return null; + } + + public int delete(Uri uri, String selection, String[] selectionArgs) { + return 0; + } + + public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { + return 0; + } +} diff --git a/tests/AndroidTests/EnabledTestApp/src/com/android/unit_tests/enabled_app/EnabledReceiver.java b/tests/AndroidTests/EnabledTestApp/src/com/android/unit_tests/enabled_app/EnabledReceiver.java new file mode 100644 index 0000000000000000000000000000000000000000..707448f3823ce6d1c8faea4c77ed07f25d854749 --- /dev/null +++ b/tests/AndroidTests/EnabledTestApp/src/com/android/unit_tests/enabled_app/EnabledReceiver.java @@ -0,0 +1,32 @@ +/* + * 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.android.unit_tests.enabled_app; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; + +/** + * Empty IntentReceiver for testing + */ + +public class EnabledReceiver extends BroadcastReceiver { + + public void onReceive(Context context, Intent intent) { + + } +} diff --git a/tests/AndroidTests/EnabledTestApp/src/com/android/unit_tests/enabled_app/EnabledService.java b/tests/AndroidTests/EnabledTestApp/src/com/android/unit_tests/enabled_app/EnabledService.java new file mode 100644 index 0000000000000000000000000000000000000000..81a80b307782aaebf20d48e0b092ef26a6130f77 --- /dev/null +++ b/tests/AndroidTests/EnabledTestApp/src/com/android/unit_tests/enabled_app/EnabledService.java @@ -0,0 +1,32 @@ +/* + * 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.android.unit_tests.enabled_app; + +import android.app.Service; +import android.os.IBinder; +import android.content.Intent; + +/** + * Empty Service for testing + */ + +public class EnabledService extends Service { + + public IBinder onBind(Intent intent) { + return null; + } +} diff --git a/tests/AndroidTests/MODULE_LICENSE_APACHE2 b/tests/AndroidTests/MODULE_LICENSE_APACHE2 new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/tests/AndroidTests/NOTICE b/tests/AndroidTests/NOTICE new file mode 100644 index 0000000000000000000000000000000000000000..c5b1efa7aac764ae6d8da63476a2d5cec02a6a5d --- /dev/null +++ b/tests/AndroidTests/NOTICE @@ -0,0 +1,190 @@ + + Copyright (c) 2005-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. + + 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. + + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + diff --git a/tests/AndroidTests/assets/text.txt b/tests/AndroidTests/assets/text.txt new file mode 100644 index 0000000000000000000000000000000000000000..3d8c5195bffcf0a36aec4727d59d344b722fa2e9 --- /dev/null +++ b/tests/AndroidTests/assets/text.txt @@ -0,0 +1 @@ +OneTwoThreeFourFiveSixSevenEightNineTen \ No newline at end of file diff --git a/tests/AndroidTests/res/drawable/test128x96.png b/tests/AndroidTests/res/drawable/test128x96.png new file mode 100644 index 0000000000000000000000000000000000000000..28dc925d266e1aca88847b8e2741f40e97dd8671 Binary files /dev/null and b/tests/AndroidTests/res/drawable/test128x96.png differ diff --git a/tests/AndroidTests/res/drawable/test16x12.png b/tests/AndroidTests/res/drawable/test16x12.png new file mode 100644 index 0000000000000000000000000000000000000000..1a3c7e5f9e97daedc8596f1c11212c2114ad73e2 Binary files /dev/null and b/tests/AndroidTests/res/drawable/test16x12.png differ diff --git a/tests/AndroidTests/res/drawable/test256x192.png b/tests/AndroidTests/res/drawable/test256x192.png new file mode 100644 index 0000000000000000000000000000000000000000..ce8ee04b68be433f2c6da1b4c820406789ffcb99 Binary files /dev/null and b/tests/AndroidTests/res/drawable/test256x192.png differ diff --git a/tests/AndroidTests/res/drawable/test320x240.png b/tests/AndroidTests/res/drawable/test320x240.png new file mode 100644 index 0000000000000000000000000000000000000000..9b5800da243df5027743d5a2076bdd8c3b8a244f Binary files /dev/null and b/tests/AndroidTests/res/drawable/test320x240.png differ diff --git a/tests/AndroidTests/res/drawable/test32x24.png b/tests/AndroidTests/res/drawable/test32x24.png new file mode 100644 index 0000000000000000000000000000000000000000..76bab755c943ebca659ff659ab82667a3a7f9e80 Binary files /dev/null and b/tests/AndroidTests/res/drawable/test32x24.png differ diff --git a/tests/AndroidTests/res/drawable/test64x48.png b/tests/AndroidTests/res/drawable/test64x48.png new file mode 100644 index 0000000000000000000000000000000000000000..91196130154cea6171f3e4e19726e112915a270a Binary files /dev/null and b/tests/AndroidTests/res/drawable/test64x48.png differ diff --git a/tests/AndroidTests/res/layout/layout_five.xml b/tests/AndroidTests/res/layout/layout_five.xml new file mode 100644 index 0000000000000000000000000000000000000000..fd1e0efde33fc5221c098100375ea5751bf1844e --- /dev/null +++ b/tests/AndroidTests/res/layout/layout_five.xml @@ -0,0 +1,22 @@ + + + + + diff --git a/tests/AndroidTests/res/layout/layout_four.xml b/tests/AndroidTests/res/layout/layout_four.xml new file mode 100644 index 0000000000000000000000000000000000000000..e5a78bcfdcf214e7ba9373d8d2257333388eb286 --- /dev/null +++ b/tests/AndroidTests/res/layout/layout_four.xml @@ -0,0 +1,20 @@ + + + diff --git a/tests/AndroidTests/res/layout/layout_one.xml b/tests/AndroidTests/res/layout/layout_one.xml new file mode 100644 index 0000000000000000000000000000000000000000..f5c78bd46a9cc528653b28dd4f7ba5052c92de44 --- /dev/null +++ b/tests/AndroidTests/res/layout/layout_one.xml @@ -0,0 +1,20 @@ + + + diff --git a/tests/AndroidTests/res/layout/layout_six.xml b/tests/AndroidTests/res/layout/layout_six.xml new file mode 100644 index 0000000000000000000000000000000000000000..6efcdf362016774c521debfb35d621f395a309bc --- /dev/null +++ b/tests/AndroidTests/res/layout/layout_six.xml @@ -0,0 +1,27 @@ + + + + + + + + + + diff --git a/tests/AndroidTests/res/layout/layout_tag.xml b/tests/AndroidTests/res/layout/layout_tag.xml new file mode 100644 index 0000000000000000000000000000000000000000..1f1770111ba0aae40d4597f70ee19347aaf34eb6 --- /dev/null +++ b/tests/AndroidTests/res/layout/layout_tag.xml @@ -0,0 +1,23 @@ + + + diff --git a/tests/AndroidTests/res/layout/layout_three.xml b/tests/AndroidTests/res/layout/layout_three.xml new file mode 100644 index 0000000000000000000000000000000000000000..77b2aa9f890f3289095a683f5c3e842133fe2a75 --- /dev/null +++ b/tests/AndroidTests/res/layout/layout_three.xml @@ -0,0 +1,27 @@ + + + + + + + + + + diff --git a/tests/AndroidTests/res/layout/layout_two.xml b/tests/AndroidTests/res/layout/layout_two.xml new file mode 100644 index 0000000000000000000000000000000000000000..9c997104f26e9b858d4beefbf5ce1cfbb0fd108c --- /dev/null +++ b/tests/AndroidTests/res/layout/layout_two.xml @@ -0,0 +1,23 @@ + + + + + + diff --git a/tests/AndroidTests/res/raw/calendarjs.txt b/tests/AndroidTests/res/raw/calendarjs.txt new file mode 100644 index 0000000000000000000000000000000000000000..15f7bab3a29226a73ce4b264db0a2a5303cebcf4 --- /dev/null +++ b/tests/AndroidTests/res/raw/calendarjs.txt @@ -0,0 +1 @@ +{"version":"1.0","encoding":"UTF-8","feed":{"xmlns":"http://www.w3.org/2005/Atom","xmlns$openSearch":"http://a9.com/-/spec/opensearchrss/1.0/","xmlns$gd":"http://schemas.google.com/g/2005","xmlns$gCal":"http://schemas.google.com/gCal/2005","id":{"$t":"http://www.google.com/calendar/feeds/wg%40voiceme.net/public/basic"},"updated":{"$t":"2007-02-06T02:55:15.000Z"},"category":[{"scheme":"http://schemas.google.com/g/2005#kind","term":"http://schemas.google.com/g/2005#event"}],"title":{"type":"text","$t":"w g"},"subtitle":{"type":"text","$t":"w g"},"link":[{"rel":"http://schemas.google.com/g/2005#feed","type":"application/atom+xml","href":"http://www.google.com/calendar/feeds/wg%40voiceme.net/public/basic"},{"rel":"self","type":"application/atom+xml","href":"http://www.google.com/calendar/feeds/wg%40voiceme.net/public/basic?alt\u003Djson\u0026max-results\u003D25"}],"author":[{"name":{"$t":"w g"},"email":{"$t":"wg@voiceme.net"}}],"generator":{"version":"1.0","uri":"http://www.google.com/calendar","$t":"Google Calendar"},"openSearch$totalResults":{"$t":"13"},"openSearch$startIndex":{"$t":"1"},"openSearch$itemsPerPage":{"$t":"25"},"gCal$timezone":{"value":"America/Los_Angeles"},"entry":[{"id":{"$t":"http://www.google.com/calendar/feeds/wg%40voiceme.net/public/basic/7iqc1ro0ihc69vhsiq3uabooig"},"published":{"$t":"2007-02-05T22:04:50.000Z"},"updated":{"$t":"2007-02-05T22:04:50.000Z"},"category":[{"scheme":"http://schemas.google.com/g/2005#kind","term":"http://schemas.google.com/g/2005#event"}],"title":{"type":"text","$t":"skate"},"summary":{"type":"html","$t":"When: Wed Feb 7, 2007 13:30 to Wed Feb 7, 2007 16:00\u0026nbsp; PST\u003Cbr\u003E \u003Cbr\u003EEvent Status: confirmed"},"content":{"type":"text","$t":"When: Wed Feb 7, 2007 13:30 to Wed Feb 7, 2007 16:00\u0026nbsp; PST\u003Cbr\u003E \u003Cbr\u003EEvent Status: confirmed"},"link":[{"rel":"alternate","type":"text/html","href":"http://www.google.com/calendar/event?eid\u003DN2lxYzFybzBpaGM2OXZoc2lxM3VhYm9vaWcgd2dAdm9pY2VtZS5uZXQ","title":"alternate"},{"rel":"self","type":"application/atom+xml","href":"http://www.google.com/calendar/feeds/wg%40voiceme.net/public/basic/7iqc1ro0ihc69vhsiq3uabooig"}],"author":[{"name":{"$t":"w g"},"email":{"$t":"wg@voiceme.net"}}],"gCal$sendEventNotifications":{"value":"false"}},{"id":{"$t":"http://www.google.com/calendar/feeds/wg%40voiceme.net/public/basic/kp4gil76n2vcrkt9kaotj3s12c"},"published":{"$t":"2007-02-05T22:04:42.000Z"},"updated":{"$t":"2007-02-05T22:04:42.000Z"},"category":[{"scheme":"http://schemas.google.com/g/2005#kind","term":"http://schemas.google.com/g/2005#event"}],"title":{"type":"text","$t":"skate"},"summary":{"type":"html","$t":"When: Fri Feb 9, 2007 15:30 to Fri Feb 9, 2007 18:00\u0026nbsp; PST\u003Cbr\u003E \u003Cbr\u003EEvent Status: confirmed"},"content":{"type":"text","$t":"When: Fri Feb 9, 2007 15:30 to Fri Feb 9, 2007 18:00\u0026nbsp; PST\u003Cbr\u003E \u003Cbr\u003EEvent Status: confirmed"},"link":[{"rel":"alternate","type":"text/html","href":"http://www.google.com/calendar/event?eid\u003Da3A0Z2lsNzZuMnZjcmt0OWthb3RqM3MxMmMgd2dAdm9pY2VtZS5uZXQ","title":"alternate"},{"rel":"self","type":"application/atom+xml","href":"http://www.google.com/calendar/feeds/wg%40voiceme.net/public/basic/kp4gil76n2vcrkt9kaotj3s12c"}],"author":[{"name":{"$t":"w g"},"email":{"$t":"wg@voiceme.net"}}],"gCal$sendEventNotifications":{"value":"false"}},{"id":{"$t":"http://www.google.com/calendar/feeds/wg%40voiceme.net/public/basic/gkhb48fj68lcp15fd1k03tjbj0"},"published":{"$t":"2007-02-05T22:04:35.000Z"},"updated":{"$t":"2007-02-05T22:04:35.000Z"},"category":[{"scheme":"http://schemas.google.com/g/2005#kind","term":"http://schemas.google.com/g/2005#event"}],"title":{"type":"text","$t":"test event 6"},"summary":{"type":"html","$t":"When: Sat Feb 10, 2007 14:00 to Sat Feb 10, 2007 17:00\u0026nbsp; PST\u003Cbr\u003E \u003Cbr\u003EEvent Status: confirmed"},"content":{"type":"text","$t":"When: Sat Feb 10, 2007 14:00 to Sat Feb 10, 2007 17:00\u0026nbsp; PST\u003Cbr\u003E \u003Cbr\u003EEvent Status: confirmed"},"link":[{"rel":"alternate","type":"text/html","href":"http://www.google.com/calendar/event?eid\u003DZ2toYjQ4Zmo2OGxjcDE1ZmQxazAzdGpiajAgd2dAdm9pY2VtZS5uZXQ","title":"alternate"},{"rel":"self","type":"application/atom+xml","href":"http://www.google.com/calendar/feeds/wg%40voiceme.net/public/basic/gkhb48fj68lcp15fd1k03tjbj0"}],"author":[{"name":{"$t":"w g"},"email":{"$t":"wg@voiceme.net"}}],"gCal$sendEventNotifications":{"value":"false"}},{"id":{"$t":"http://www.google.com/calendar/feeds/wg%40voiceme.net/public/basic/32p5g68cpean3p2ol7kanj38sg"},"published":{"$t":"2007-02-05T22:04:29.000Z"},"updated":{"$t":"2007-02-05T22:04:29.000Z"},"category":[{"scheme":"http://schemas.google.com/g/2005#kind","term":"http://schemas.google.com/g/2005#event"}],"title":{"type":"text","$t":"test event 5"},"summary":{"type":"html","$t":"When: Fri Feb 9, 2007 09:00 to 10:30\u0026nbsp; PST\u003Cbr\u003E \u003Cbr\u003EEvent Status: confirmed"},"content":{"type":"text","$t":"When: Fri Feb 9, 2007 09:00 to 10:30\u0026nbsp; PST\u003Cbr\u003E \u003Cbr\u003EEvent Status: confirmed"},"link":[{"rel":"alternate","type":"text/html","href":"http://www.google.com/calendar/event?eid\u003DMzJwNWc2OGNwZWFuM3Ayb2w3a2FuajM4c2cgd2dAdm9pY2VtZS5uZXQ","title":"alternate"},{"rel":"self","type":"application/atom+xml","href":"http://www.google.com/calendar/feeds/wg%40voiceme.net/public/basic/32p5g68cpean3p2ol7kanj38sg"}],"author":[{"name":{"$t":"w g"},"email":{"$t":"wg@voiceme.net"}}],"gCal$sendEventNotifications":{"value":"false"}},{"id":{"$t":"http://www.google.com/calendar/feeds/wg%40voiceme.net/public/basic/tfqpth26conshdmav0apje1tf4"},"published":{"$t":"2007-02-05T22:04:19.000Z"},"updated":{"$t":"2007-02-05T22:04:19.000Z"},"category":[{"scheme":"http://schemas.google.com/g/2005#kind","term":"http://schemas.google.com/g/2005#event"}],"title":{"type":"text","$t":"skate"},"summary":{"type":"html","$t":"When: Thu Feb 8, 2007 15:00 to Thu Feb 8, 2007 17:00\u0026nbsp; PST\u003Cbr\u003E \u003Cbr\u003EEvent Status: confirmed"},"content":{"type":"text","$t":"When: Thu Feb 8, 2007 15:00 to Thu Feb 8, 2007 17:00\u0026nbsp; PST\u003Cbr\u003E \u003Cbr\u003EEvent Status: confirmed"},"link":[{"rel":"alternate","type":"text/html","href":"http://www.google.com/calendar/event?eid\u003DdGZxcHRoMjZjb25zaGRtYXYwYXBqZTF0ZjQgd2dAdm9pY2VtZS5uZXQ","title":"alternate"},{"rel":"self","type":"application/atom+xml","href":"http://www.google.com/calendar/feeds/wg%40voiceme.net/public/basic/tfqpth26conshdmav0apje1tf4"}],"author":[{"name":{"$t":"w g"},"email":{"$t":"wg@voiceme.net"}}],"gCal$sendEventNotifications":{"value":"false"}},{"id":{"$t":"http://www.google.com/calendar/feeds/wg%40voiceme.net/public/basic/onbo9mhbr5m6mo356nog7uel4s"},"published":{"$t":"2007-02-05T22:04:07.000Z"},"updated":{"$t":"2007-02-05T22:04:07.000Z"},"category":[{"scheme":"http://schemas.google.com/g/2005#kind","term":"http://schemas.google.com/g/2005#event"}],"title":{"type":"text","$t":"Sharks at Anaheim"},"summary":{"type":"html","$t":"When: Wed Feb 7, 2007 19:00 to 22:00\u0026nbsp; PST\u003Cbr\u003E \u003Cbr\u003EEvent Status: confirmed"},"content":{"type":"text","$t":"When: Wed Feb 7, 2007 19:00 to 22:00\u0026nbsp; PST\u003Cbr\u003E \u003Cbr\u003EEvent Status: confirmed"},"link":[{"rel":"alternate","type":"text/html","href":"http://www.google.com/calendar/event?eid\u003Db25ibzltaGJyNW02bW8zNTZub2c3dWVsNHMgd2dAdm9pY2VtZS5uZXQ","title":"alternate"},{"rel":"self","type":"application/atom+xml","href":"http://www.google.com/calendar/feeds/wg%40voiceme.net/public/basic/onbo9mhbr5m6mo356nog7uel4s"}],"author":[{"name":{"$t":"w g"},"email":{"$t":"wg@voiceme.net"}}],"gCal$sendEventNotifications":{"value":"true"}},{"id":{"$t":"http://www.google.com/calendar/feeds/wg%40voiceme.net/public/basic/tjqrd9fve576hieh3sa67nql5k"},"published":{"$t":"2007-02-05T22:04:02.000Z"},"updated":{"$t":"2007-02-05T22:04:02.000Z"},"category":[{"scheme":"http://schemas.google.com/g/2005#kind","term":"http://schemas.google.com/g/2005#event"}],"title":{"type":"text","$t":"Sharks vs. ANAHEIM"},"summary":{"type":"html","$t":"When: Tue Feb 6, 2007 19:30 to 22:30\u0026nbsp; PST\u003Cbr\u003E \u003Cbr\u003EEvent Status: confirmed"},"content":{"type":"text","$t":"When: Tue Feb 6, 2007 19:30 to 22:30\u0026nbsp; PST\u003Cbr\u003E \u003Cbr\u003EEvent Status: confirmed"},"link":[{"rel":"alternate","type":"text/html","href":"http://www.google.com/calendar/event?eid\u003DdGpxcmQ5ZnZlNTc2aGllaDNzYTY3bnFsNWsgd2dAdm9pY2VtZS5uZXQ","title":"alternate"},{"rel":"self","type":"application/atom+xml","href":"http://www.google.com/calendar/feeds/wg%40voiceme.net/public/basic/tjqrd9fve576hieh3sa67nql5k"}],"author":[{"name":{"$t":"w g"},"email":{"$t":"wg@voiceme.net"}}],"gCal$sendEventNotifications":{"value":"true"}},{"id":{"$t":"http://www.google.com/calendar/feeds/wg%40voiceme.net/public/basic/or6dtpn065f9mntond4jh2docc"},"published":{"$t":"2007-02-05T22:03:52.000Z"},"updated":{"$t":"2007-02-05T22:03:52.000Z"},"category":[{"scheme":"http://schemas.google.com/g/2005#kind","term":"http://schemas.google.com/g/2005#event"}],"title":{"type":"text","$t":"skate"},"summary":{"type":"html","$t":"When: Tue Feb 6, 2007 14:00 to 15:00\u0026nbsp; PST\u003Cbr\u003E \u003Cbr\u003EEvent Status: confirmed"},"content":{"type":"text","$t":"When: Tue Feb 6, 2007 14:00 to 15:00\u0026nbsp; PST\u003Cbr\u003E \u003Cbr\u003EEvent Status: confirmed"},"link":[{"rel":"alternate","type":"text/html","href":"http://www.google.com/calendar/event?eid\u003Db3I2ZHRwbjA2NWY5bW50b25kNGpoMmRvY2Mgd2dAdm9pY2VtZS5uZXQ","title":"alternate"},{"rel":"self","type":"application/atom+xml","href":"http://www.google.com/calendar/feeds/wg%40voiceme.net/public/basic/or6dtpn065f9mntond4jh2docc"}],"author":[{"name":{"$t":"w g"},"email":{"$t":"wg@voiceme.net"}}],"gCal$sendEventNotifications":{"value":"false"}},{"id":{"$t":"http://www.google.com/calendar/feeds/wg%40voiceme.net/public/basic/k70v8o4jt1afi17hg2spavq1c0"},"published":{"$t":"2007-02-05T22:03:36.000Z"},"updated":{"$t":"2007-02-05T22:03:36.000Z"},"category":[{"scheme":"http://schemas.google.com/g/2005#kind","term":"http://schemas.google.com/g/2005#event"}],"title":{"type":"text","$t":"lunch"},"summary":{"type":"html","$t":"Recurring Event\u003Cbr\u003E First start: 2007-02-06 12:00:00 PST \u003Cbr\u003E Duration: 3600 \u003Cbr\u003EEvent Status: confirmed"},"content":{"type":"text","$t":"Recurring Event\u003Cbr\u003E First start: 2007-02-06 12:00:00 PST \u003Cbr\u003E Duration: 3600 \u003Cbr\u003EEvent Status: confirmed"},"link":[{"rel":"alternate","type":"text/html","href":"http://www.google.com/calendar/event?eid\u003DazcwdjhvNGp0MWFmaTE3aGcyc3BhdnExYzBfMjAwNzAyMDZUMjAwMDAwWiB3Z0B2b2ljZW1lLm5ldA","title":"alternate"},{"rel":"self","type":"application/atom+xml","href":"http://www.google.com/calendar/feeds/wg%40voiceme.net/public/basic/k70v8o4jt1afi17hg2spavq1c0"}],"author":[{"name":{"$t":"w g"},"email":{"$t":"wg@voiceme.net"}}],"gCal$sendEventNotifications":{"value":"true"}},{"id":{"$t":"http://www.google.com/calendar/feeds/wg%40voiceme.net/public/basic/6ee7b8nohdt03tv0gknm4v7124"},"published":{"$t":"2007-02-05T22:03:19.000Z"},"updated":{"$t":"2007-02-05T22:03:19.000Z"},"category":[{"scheme":"http://schemas.google.com/g/2005#kind","term":"http://schemas.google.com/g/2005#event"}],"title":{"type":"text","$t":"test event 4"},"summary":{"type":"html","$t":"When: Tue Feb 6, 2007 09:00 to 11:00\u0026nbsp; PST\u003Cbr\u003E \u003Cbr\u003EEvent Status: confirmed"},"content":{"type":"text","$t":"When: Tue Feb 6, 2007 09:00 to 11:00\u0026nbsp; PST\u003Cbr\u003E \u003Cbr\u003EEvent Status: confirmed"},"link":[{"rel":"alternate","type":"text/html","href":"http://www.google.com/calendar/event?eid\u003DNmVlN2I4bm9oZHQwM3R2MGdrbm00djcxMjQgd2dAdm9pY2VtZS5uZXQ","title":"alternate"},{"rel":"self","type":"application/atom+xml","href":"http://www.google.com/calendar/feeds/wg%40voiceme.net/public/basic/6ee7b8nohdt03tv0gknm4v7124"}],"author":[{"name":{"$t":"w g"},"email":{"$t":"wg@voiceme.net"}}],"gCal$sendEventNotifications":{"value":"false"}},{"id":{"$t":"http://www.google.com/calendar/feeds/wg%40voiceme.net/public/basic/of1vh1r2q5aqdplo65i8bqbn3o"},"published":{"$t":"2007-02-05T22:03:11.000Z"},"updated":{"$t":"2007-02-05T22:03:11.000Z"},"category":[{"scheme":"http://schemas.google.com/g/2005#kind","term":"http://schemas.google.com/g/2005#event"}],"title":{"type":"text","$t":"test event 3"},"summary":{"type":"html","$t":"When: Mon Feb 5, 2007 18:00 to 19:00\u0026nbsp; PST\u003Cbr\u003E \u003Cbr\u003EEvent Status: confirmed"},"content":{"type":"text","$t":"When: Mon Feb 5, 2007 18:00 to 19:00\u0026nbsp; PST\u003Cbr\u003E \u003Cbr\u003EEvent Status: confirmed"},"link":[{"rel":"alternate","type":"text/html","href":"http://www.google.com/calendar/event?eid\u003Db2YxdmgxcjJxNWFxZHBsbzY1aThicWJuM28gd2dAdm9pY2VtZS5uZXQ","title":"alternate"},{"rel":"self","type":"application/atom+xml","href":"http://www.google.com/calendar/feeds/wg%40voiceme.net/public/basic/of1vh1r2q5aqdplo65i8bqbn3o"}],"author":[{"name":{"$t":"w g"},"email":{"$t":"wg@voiceme.net"}}],"gCal$sendEventNotifications":{"value":"false"}},{"id":{"$t":"http://www.google.com/calendar/feeds/wg%40voiceme.net/public/basic/s7ahgfomlgii9qbkgpfbinr9u8"},"published":{"$t":"2007-02-05T22:02:40.000Z"},"updated":{"$t":"2007-02-05T22:03:04.000Z"},"category":[{"scheme":"http://schemas.google.com/g/2005#kind","term":"http://schemas.google.com/g/2005#event"}],"title":{"type":"text","$t":"test event 2"},"summary":{"type":"html","$t":"When: Mon Feb 5, 2007 16:30 to 17:30\u0026nbsp; PST\u003Cbr\u003E \u003Cbr\u003EEvent Status: confirmed"},"content":{"type":"text","$t":"When: Mon Feb 5, 2007 16:30 to 17:30\u0026nbsp; PST\u003Cbr\u003E \u003Cbr\u003EEvent Status: confirmed"},"link":[{"rel":"alternate","type":"text/html","href":"http://www.google.com/calendar/event?eid\u003DczdhaGdmb21sZ2lpOXFia2dwZmJpbnI5dTggd2dAdm9pY2VtZS5uZXQ","title":"alternate"},{"rel":"self","type":"application/atom+xml","href":"http://www.google.com/calendar/feeds/wg%40voiceme.net/public/basic/s7ahgfomlgii9qbkgpfbinr9u8"}],"author":[{"name":{"$t":"w g"},"email":{"$t":"wg@voiceme.net"}}],"gCal$sendEventNotifications":{"value":"false"}},{"id":{"$t":"http://www.google.com/calendar/feeds/wg%40voiceme.net/public/basic/rl8focglfe6jndql4u8lg73q5k"},"published":{"$t":"2007-02-05T22:02:28.000Z"},"updated":{"$t":"2007-02-05T22:02:53.000Z"},"category":[{"scheme":"http://schemas.google.com/g/2005#kind","term":"http://schemas.google.com/g/2005#event"}],"title":{"type":"text","$t":"test event 1"},"summary":{"type":"html","$t":"When: Mon Feb 5, 2007 15:00 to Mon Feb 5, 2007 16:00\u0026nbsp; PST\u003Cbr\u003E \u003Cbr\u003EEvent Status: confirmed"},"content":{"type":"text","$t":"When: Mon Feb 5, 2007 15:00 to Mon Feb 5, 2007 16:00\u0026nbsp; PST\u003Cbr\u003E \u003Cbr\u003EEvent Status: confirmed"},"link":[{"rel":"alternate","type":"text/html","href":"http://www.google.com/calendar/event?eid\u003Dcmw4Zm9jZ2xmZTZqbmRxbDR1OGxnNzNxNWsgd2dAdm9pY2VtZS5uZXQ","title":"alternate"},{"rel":"self","type":"application/atom+xml","href":"http://www.google.com/calendar/feeds/wg%40voiceme.net/public/basic/rl8focglfe6jndql4u8lg73q5k"}],"author":[{"name":{"$t":"w g"},"email":{"$t":"wg@voiceme.net"}}],"gCal$sendEventNotifications":{"value":"false"}}]}} \ No newline at end of file diff --git a/tests/AndroidTests/res/raw/calendarjsgz.jsgz b/tests/AndroidTests/res/raw/calendarjsgz.jsgz new file mode 100644 index 0000000000000000000000000000000000000000..6f1bf543ada85ad43f2562c9f834bf3d5abff00f Binary files /dev/null and b/tests/AndroidTests/res/raw/calendarjsgz.jsgz differ diff --git a/tests/AndroidTests/res/raw/calendarxml.xml b/tests/AndroidTests/res/raw/calendarxml.xml new file mode 100644 index 0000000000000000000000000000000000000000..1adcd7486ef7d813d404d305c96362d18381d1b7 --- /dev/null +++ b/tests/AndroidTests/res/raw/calendarxml.xml @@ -0,0 +1,38 @@ + + + +http://www.google.com/calendar/feeds/default/private/full2007-02-05T22:04:50.000Zw gw gw gwg@voiceme.netGoogle Calendar13125http://www.google.com/calendar/feeds/default/private/full/7iqc1ro0ihc69vhsiq3uabooig2007-02-05T22:04:50.000Z2007-02-05T22:04:50.000Zskatew gwg@voiceme.nethttp://www.google.com/calendar/feeds/default/private/full/kp4gil76n2vcrkt9kaotj3s12c2007-02-05T22:04:42.000Z2007-02-05T22:04:42.000Zskatew gwg@voiceme.nethttp://www.google.com/calendar/feeds/default/private/full/gkhb48fj68lcp15fd1k03tjbj02007-02-05T22:04:35.000Z2007-02-05T22:04:35.000Ztest event 6w gwg@voiceme.nethttp://www.google.com/calendar/feeds/default/private/full/32p5g68cpean3p2ol7kanj38sg2007-02-05T22:04:29.000Z2007-02-05T22:04:29.000Ztest event 5w gwg@voiceme.nethttp://www.google.com/calendar/feeds/default/private/full/tfqpth26conshdmav0apje1tf42007-02-05T22:04:19.000Z2007-02-05T22:04:19.000Zskatew gwg@voiceme.nethttp://www.google.com/calendar/feeds/default/private/full/onbo9mhbr5m6mo356nog7uel4s2007-02-05T22:04:07.000Z2007-02-05T22:04:07.000ZSharks at Anaheimw gwg@voiceme.nethttp://www.google.com/calendar/feeds/default/private/full/tjqrd9fve576hieh3sa67nql5k2007-02-05T22:04:02.000Z2007-02-05T22:04:02.000ZSharks vs. ANAHEIMw gwg@voiceme.nethttp://www.google.com/calendar/feeds/default/private/full/or6dtpn065f9mntond4jh2docc2007-02-05T22:03:52.000Z2007-02-05T22:03:52.000Zskatew gwg@voiceme.nethttp://www.google.com/calendar/feeds/default/private/full/k70v8o4jt1afi17hg2spavq1c02007-02-05T22:03:36.000Z2007-02-05T22:03:36.000Zlunchw gwg@voiceme.netDTSTART;TZID=America/Los_Angeles:20070206T120000 +DURATION:PT3600S +RRULE:FREQ=DAILY;WKST=SU +BEGIN:VTIMEZONE +TZID:America/Los_Angeles +X-LIC-LOCATION:America/Los_Angeles +BEGIN:STANDARD +TZOFFSETFROM:-0700 +TZOFFSETTO:-0800 +TZNAME:PST +DTSTART:19701025T020000 +RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU +END:STANDARD +BEGIN:DAYLIGHT +TZOFFSETFROM:-0800 +TZOFFSETTO:-0700 +TZNAME:PDT +DTSTART:19700405T020000 +RRULE:FREQ=YEARLY;BYMONTH=4;BYDAY=1SU +END:DAYLIGHT +END:VTIMEZONE +http://www.google.com/calendar/feeds/default/private/full/6ee7b8nohdt03tv0gknm4v71242007-02-05T22:03:19.000Z2007-02-05T22:03:19.000Ztest event 4w gwg@voiceme.nethttp://www.google.com/calendar/feeds/default/private/full/of1vh1r2q5aqdplo65i8bqbn3o2007-02-05T22:03:11.000Z2007-02-05T22:03:11.000Ztest event 3w gwg@voiceme.nethttp://www.google.com/calendar/feeds/default/private/full/s7ahgfomlgii9qbkgpfbinr9u82007-02-05T22:02:40.000Z2007-02-05T22:03:04.000Ztest event 2w gwg@voiceme.nethttp://www.google.com/calendar/feeds/default/private/full/rl8focglfe6jndql4u8lg73q5k2007-02-05T22:02:28.000Z2007-02-05T22:02:53.000Ztest event 1w gwg@voiceme.net diff --git a/tests/AndroidTests/res/raw/calendarxmlgz.xmlgz b/tests/AndroidTests/res/raw/calendarxmlgz.xmlgz new file mode 100644 index 0000000000000000000000000000000000000000..6c864627fa6ff2d06b4f1de775738367298b762f Binary files /dev/null and b/tests/AndroidTests/res/raw/calendarxmlgz.xmlgz differ diff --git a/tests/AndroidTests/res/raw/medium.xml b/tests/AndroidTests/res/raw/medium.xml new file mode 100644 index 0000000000000000000000000000000000000000..51c952c32879d6fc069e4658e55125525b3fbbc6 --- /dev/null +++ b/tests/AndroidTests/res/raw/medium.xml @@ -0,0 +1,27 @@ + + + + + + + + + + diff --git a/tests/AndroidTests/res/raw/small.xml b/tests/AndroidTests/res/raw/small.xml new file mode 100644 index 0000000000000000000000000000000000000000..2697fb8b4651a84ed92f4c0bd4d01ccdbfb9e42d --- /dev/null +++ b/tests/AndroidTests/res/raw/small.xml @@ -0,0 +1,20 @@ + + + diff --git a/tests/AndroidTests/res/raw/text.txt b/tests/AndroidTests/res/raw/text.txt new file mode 100644 index 0000000000000000000000000000000000000000..3d8c5195bffcf0a36aec4727d59d344b722fa2e9 --- /dev/null +++ b/tests/AndroidTests/res/raw/text.txt @@ -0,0 +1 @@ +OneTwoThreeFourFiveSixSevenEightNineTen \ No newline at end of file diff --git a/tests/AndroidTests/res/raw/youtube.xml b/tests/AndroidTests/res/raw/youtube.xml new file mode 100644 index 0000000000000000000000000000000000000000..fedaeacc16694978f4bef8f31740c86dfd1ac9a8 --- /dev/null +++ b/tests/AndroidTests/res/raw/youtube.xml @@ -0,0 +1,1852 @@ + + + + + http://dm5.google.com/feeds/standardfeeds/top_rated + 2007-05-01T18:13:20.333Z + Top Rated - Beta + http://www.youtube.com/img/pic_youtubelogo_123x63.gif + + + + + + YouTube + http://www.youtube.com/ + + YouTube data API + + 99 + 1 + 25 + + http://dm5.google.com/feeds/videos/nojWJ6-XmeQ + 2006-09-01T15:13:19.000Z + 2006-09-01T15:13:19.000Z + + + + + + + + + Banned Commercial - Condoms + + + + + + bannedcommercials + http://dm5.google.com/feeds/users/bannedcommercials + + + Banned Commercial - Condoms + Banned Commercial - Condoms + + Banned, Commercial, Condoms, funny, hilarious, + comedy, humor + + + + Comedy + + + + + + + + + + + + http://dm5.google.com/feeds/videos/JahdnOQ9XCA + 2006-09-01T17:25:14.000Z + 2006-09-01T17:25:14.000Z + + + + + + + + + + + + + Banned Commercial - Bill Clinton Voodoo doll very + funny + + + + + + + bannedcommercials + http://dm5.google.com/feeds/users/bannedcommercials + + + Banned Commercial - Bill Clinton Voodoo + doll very funny + + Banned Commercial - Bill Clinton + Voodoo doll very funny + + Banned, Commercial, Bill, Clinton, Voodoo, doll, + very, funny, humor, hilarious, comedy + + + + Entertainment + + + + + + + + + + + + http://dm5.google.com/feeds/videos/VcQIwbvGRKU + 2006-09-03T05:32:33.000Z + 2006-09-03T05:32:33.000Z + + + + + + + + + + Amazing funny TV Commercial - Talk Talk + + + + + + bannedcommercials + http://dm5.google.com/feeds/users/bannedcommercials + + + Amazing funny TV Commercial - Talk Talk + + Amazing funny TV Commercial - Talk + Talk + + Amazing, funny, TV, Commercial, Talk, humor, + hilarious, awesome + + + + Entertainment + + + + + + + + + + + + http://dm5.google.com/feeds/videos/JsD6uEZsIsU + 2006-11-28T16:42:47.000Z + 2006-11-28T16:42:47.000Z + + + + + + Andy Mckee - Rylynn - Acoustic Guitar - + www.candyrat.com + + + + + + + rpoland + http://dm5.google.com/feeds/users/rpoland + + + Andy Mckee - Rylynn - Acoustic Guitar - + www.candyrat.com + + Filmed Nov, 2006. + + CD - Art of Motion + + http://www.candyrat.com + + Transcriptions Available at: + + http://www.candyrat.com + + Andy, Mckee, Acoustic, Guitar + + + Music + + + + + + + + + + + + http://dm5.google.com/feeds/videos/dt1fB62cGbo + 2006-11-19T16:02:11.000Z + 2006-11-19T16:02:11.000Z + + + + + + + + + Andy Mckee - Africa - Toto - www.candyrat.com + + + + + + rpoland + http://dm5.google.com/feeds/users/rpoland + + + Andy Mckee - Africa - Toto - + www.candyrat.com + + Andy Mckee + + filmed, Nov, 2006. + + CD - Dreamcatcher + http://www.candyrat.com + + Transcriptions Available at: + http://www.candyrat.com + + Andy, Mckee, Acoustic, Guitar, Fingerstyle, Africa, + Toto + + + + Music + + + + + + + + + + + + http://dm5.google.com/feeds/videos/Ddn4MGaS3N4 + 2006-11-25T21:38:20.000Z + 2006-11-25T21:38:20.000Z + + + + + + Andy Mckee - Guitar - Drifting - www.candyrat.com + + + + + + + rpoland + http://dm5.google.com/feeds/users/rpoland + + + Andy Mckee - Guitar - Drifting - + www.candyrat.com + + Acoustic Guitar + + Drifting - Andy Mckee's Original Song + + filmed, Nov, 2006. + + CD - Art of Motion + + http://www.candyrat.com + + Transcriptions Available at: + + http://www.candyrat.com + + Acoustic, Guitar, Andy, Mckee + + + Music + + + + + + + + + + + + http://dm5.google.com/feeds/videos/SmVAWKfJ4Go + 2005-12-13T02:25:05.000Z + 2005-12-13T02:25:05.000Z + + + + Cash Hurt + + + + + + beachbuggy + http://dm5.google.com/feeds/users/beachbuggy + + + Cash Hurt + cash hurt + Cash, hurt + + + Music + + + + + + + + + + + + http://dm5.google.com/feeds/videos/AbndgwfG22k + 2006-06-18T18:07:46.000Z + 2006-06-18T18:07:46.000Z + + + + + + + + + + + + + + + + "AirTap!" + + + + + + erikmongrain + http://dm5.google.com/feeds/users/erikmongrain + + + "AirTap!" + MY FIRST CD IS NOW AVAILABLE ON MY + WEBSITE IN MP3 FORMAT !!! IN STORE MAY 2007 ! + www.erikmongrain.com + + Myself playing a composition I made 6 years ago in the streets + of Spain when I was travelling around.That was on "Belle et Bum" + (popular music show in Quebec ). + + Acoustic, Guitar, Michael, Hedges, Preston, Reed, + Don, Ross, Erik, Mongrain, Tommy, Emmanuel, Leo, Kottke + + + + Music + + + + + + + + + + + + http://dm5.google.com/feeds/videos/2Neop9OVaB8 + 2006-11-21T23:03:29.000Z + 2006-11-21T23:03:29.000Z + + + + + + + + + + + + + + + + + + + + + Remember The Name - Highlight Reel Video + + + + + + fortminor + http://dm5.google.com/feeds/users/fortminor + + + Remember The Name - Highlight Reel Video + + Fort Minor Remember The Name + "Highlight Reel" video - made from the winning video clips + submitted for the Fort Minor / Fuse Remember The Name contest - + congratulations to all the winners! + + Fort, Minor, Fuse, Highlight, Reel, Action, Sports, + Remember, The, Name, Rising, Ties, Mike, Shinoda, Skate, + Scooter, Tricks, Flips, Dunks + + + + Entertainment + + + + + + + + + + + + http://dm5.google.com/feeds/videos/QKXWAE8YYxY + 2006-02-03T00:07:12.000Z + 2006-02-03T00:07:12.000Z + + + + + + + + + + + + Resident Evil 4 -- Stupid MF + + + + + + raypinot + http://dm5.google.com/feeds/users/raypinot + + + Resident Evil 4 -- Stupid MF + Video I made for Resident Evil 4 + using "Separate Ways" and footage and that didn't make it into + my first video, "Vicinity of Obscenity" This video is done to + the song "Stupid MF" by Mindless Self Indulgence. + + http://www.help-lara-and-ray.com/ + + Resident, Evil, Four, RE4, Mindless, Self, + Indulgence, MSI, Stupid, MF + + + + Games + + + + + + + + + + + + http://dm5.google.com/feeds/videos/zQoAUI84amI + 2006-02-02T23:36:31.000Z + 2006-02-02T23:36:31.000Z + + + + + + + + + + + + Resident Evil 4 -- Vicinity of Obscenity + + + + + + raypinot + http://dm5.google.com/feeds/users/raypinot + + + Resident Evil 4 -- Vicinity of Obscenity + + Music video I made For Resident Evil + 4 (PS2), using the System of a Down song, "Vicinity of + Obscenity" + + + http://www.help-lara-and-ray.com/ + + Resident, Evil, Four, RE4, System, Down, SOAD, + Vicinity, of, Obscenity + + + + Games + + + + + + + + + + + + http://dm5.google.com/feeds/videos/JzqumbhfxRo + 2006-11-07T16:59:10.000Z + 2006-11-07T16:59:10.000Z + + + + + + + + + + + + + + + + + Amateur - Lasse Gjertsen + + + + + + lassegg + http://dm5.google.com/feeds/users/lassegg + + + Amateur - Lasse Gjertsen + I've taken my hyperactive editing + style a step further! Hope you'll enjoy it! + + If you want to download the audio from this video, go to + http://www11.nrk.no/urort/user/?id=36781 + It's a norwegian page where I uploaded some of my music. (Lytt = + Listen to, Last ned = Download) + + Oh shit, I forgot to put this in the video, and now it's too + late to change it: + Thanks to my friend Mattis for letting me borrow the drum kit. + Also thanks to the person letting me use her piano, but she + didn't want her name here :P + + And now; to you people saying I'm ripping off Michel Gondry: + I've seen his video with the drumkit called "Drumb and Drumber". + It's here on youtube somewhere. His video and my video are + different because of one very important detail: Gondy filmed + himself doing drumming sequences and LOOPED them, while I hit + each drum and piano chord seperately and edited them together. + This is a very big difference if you have any idea about video + editing. Actually, there is a short sequence of 5 sec where he + does cut the beat, but I didn't notice this until recently, + which makes me an idiot. But I still don't think it's a rip off, + only similar. SO one question to you guys: If I write a song + which includes the words "love" and "tight", am I ripping off + The Beatles?? :P I met Michel Gondry in Milan, Italy and asked + him. He didn't really give me a clear answer, but it seemed like + he thought so. Either that or he didn't like my clothes. Lol. + + amateur, lasse, gjertsen, drumkit, drums, piano, + music, norsk, norwegian, lassegg, hyperactive, editing, ass, + and, titties + + + + Film + + + + + + + + + + + + + http://dm5.google.com/feeds/videos/YxQrPXPSVhQ + 2006-06-17T16:04:49.000Z + 2006-06-17T16:04:49.000Z + + + Evanescence + + + + + + luke4leanne + http://dm5.google.com/feeds/users/luke4leanne + + + Evanescence + Evanescence-My Immortal + + Evanescence + + + Music + + + + + + + + + + + + http://dm5.google.com/feeds/videos/O9mEKMz2Pvo + 2006-02-15T12:14:08.000Z + 2006-02-15T12:14:08.000Z + + + + + + + + + + Jake Shimabukuro plays "While My Guitar Gently Weeps" + + + + + + + strewth + http://dm5.google.com/feeds/users/strewth + + + Jake Shimabukuro plays "While My Guitar + Gently Weeps" + + Jake Shimabukuro plays "While My + Guitar Gently Weeps" on the ukelele. Amazing. + + Jake, Shimabukuro, While, My, Guitar, Gently, Weeps, + ukelele + + + + Music + + + + + + + + + + + + http://dm5.google.com/feeds/videos/rP3qL4UG1TI + 2006-10-27T20:29:34.000Z + 2006-10-27T20:29:34.000Z + + + + + + + + + + + + + + + + + The Woody show "Aries Spears" rap Live105.com + + + + + + Livemorningshow + http://dm5.google.com/feeds/users/Livemorningshow + + + The Woody show "Aries Spears" rap + Live105.com + + Live 105 Morning show "Aries Spears" + rap with Woody,Tony and Ravey. Edited By: + myspace.com/whitemenace + + Woody, Tony, Ravey, Live, 105, radio, morning, show, + Aries, Spears, JayZ, whitemenace, snoop, dog, Q101 + + + + Entertainment + + + + + + + + + + + + http://dm5.google.com/feeds/videos/4NFiu-V7StQ + 2006-05-19T17:11:52.000Z + 2006-05-19T17:11:52.000Z + + + + + + + + + + + Helena - My Chemical Romance - Sims 2 version + + + + + + jaydee227 + http://dm5.google.com/feeds/users/jaydee227 + + + Helena - My Chemical Romance - Sims 2 + version + + This is the 3rd sims movie I made. + you need to watch it carefully or you won't understand the + story. But hope you enjoy :) + + USEFUL LINKS: + + Explanations to the storyline: + http://www.jd-movies.com/helenaexplained.html + + List of the custom content: + http://www.jd-movies.com/helenacc.html + + Movie FAQ: + http://www.jd-movies.com/helenafaq.html + + Download link (MUCH better quality): + http://www.archive.org/download/helenasims2/Helena.wmv + + Helena, My, Chemical, Romance, MCR, Sims, Movie, + machinima, Jaydee + + + + Film + + + + + + + + + + + + http://dm5.google.com/feeds/videos/bGFXKYvH39I + 2006-06-21T17:23:54.000Z + 2006-06-21T17:23:54.000Z + + + + + three days grace-Animal I Have Become + + + + + + jollech69 + http://dm5.google.com/feeds/users/jollech69 + + + three days grace-Animal I Have Become + + By 3 days grace + Three, days, grace + + + Music + + + + + + + + + + + + http://dm5.google.com/feeds/videos/V1_OkegYtZI + 2007-03-17T10:45:49.000Z + 2007-03-17T10:45:49.000Z + + + + + + + Yu-Gi-Oh: The Abridged Series - Episode 19 + + + + + + LittleKuriboh + http://dm5.google.com/feeds/users/LittleKuriboh + + + Yu-Gi-Oh: The Abridged Series - Episode 19 + + Imagine Yu-Gi-Oh condensed into + about nine minutes. That's basically what this is. + + Yu-Gi-Oh is the property of Konami and Kazuki Takahasi. + + yugioh, abridged, series, dub, spoof + + + + Comedy + + + + + + + + + + + + http://dm5.google.com/feeds/videos/1A42U-pKP0U + 2006-06-02T16:38:18.000Z + 2006-06-02T16:38:18.000Z + + + + + + ™[LINKIN PARK-From The Inside]™ + + + + + + linkin2789 + http://dm5.google.com/feeds/users/linkin2789 + + + ™[LINKIN PARK-From The Inside]™ + + Video de la canción From The Inside + de Linkin Park. + + LP, FroM, The, Inside + + + Music + + + + + + + + + + + + http://dm5.google.com/feeds/videos/s-7UX1xSEfU + 2006-07-18T17:06:52.000Z + 2006-07-18T17:06:52.000Z + + + + + + + + Yu-Gi-Oh: The Abridged Series (Episode 3) + + + + + + LittleKuriboh + http://dm5.google.com/feeds/users/LittleKuriboh + + + Yu-Gi-Oh: The Abridged Series (Episode 3) + + Imagine "Yu-Gi-Oh" condensed into + four minutes. That's basically what this is. + + yugioh, yu-gi-oh, dub, spoof, anime, abridged + + + + Comedy + + + + + + + + + + + + http://dm5.google.com/feeds/videos/V6k3YlcYtS0 + 2006-08-05T22:15:41.000Z + 2006-08-05T22:15:41.000Z + + + + + + + + Yu-Gi-Oh: The Abridged Series (Episode 6) + + + + + + LittleKuriboh + http://dm5.google.com/feeds/users/LittleKuriboh + + + Yu-Gi-Oh: The Abridged Series (Episode 6) + + Imagine "Yu-Gi-Oh" condensed into + four... uh, six minutes. That's basically what this is. + + Yu-Gi-Oh belongs to Kazuki Takahashi + + yu-gi-oh, yugioh, abridged, dub, spoof, anime + + + + Comedy + + + + + + + + + + + + http://dm5.google.com/feeds/videos/HTKs5ZT16PM + 2006-10-23T18:15:56.000Z + 2006-10-23T18:15:56.000Z + + + + + + + + Yu-Gi-Oh: The Abridged Series (Episode 13) + + + + + + LittleKuriboh + http://dm5.google.com/feeds/users/LittleKuriboh + + + Yu-Gi-Oh: The Abridged Series (Episode 13) + + Please ignore the imposter videos. + + Imagine "Yu-Gi-Oh" condensed into five/six minutes. That's + basically what this is. + + Yu-Gi-Oh belongs to Kazuki Takahashi + + yugioh, abridged, series, anime, spoof, dub + + + + Comedy + + + + + + + + + + + + http://dm5.google.com/feeds/videos/MePzWtHqrso + 2006-06-28T00:21:59.000Z + 2006-06-28T00:21:59.000Z + + + + + + Breaking Benjamin - "The Diary of Jane" + + + + + + BrienTA + http://dm5.google.com/feeds/users/BrienTA + + + Breaking Benjamin - "The Diary of Jane" + + Breaking Benjamin - "The Diary of + Jane" + + Breaking, Benjamin, Diary, Jane + + + Music + + + + + + + + + + + + http://dm5.google.com/feeds/videos/ElrldD02if0 + 2006-11-20T19:41:52.000Z + 2006-11-20T19:41:52.000Z + + + + + + + + + + + + + + + + + + + Re: How to draw a car in MS. Paint + + + + + + picster + http://dm5.google.com/feeds/users/picster + + + Re: How to draw a car in MS. Paint + + WATCH MY NEW VIDEO!!!! + http://www.youtube.com/watch?v=vUWqRhReaZk + + ---- + Wow! So many nice comments and views :) + I'm very happy you all like it. + + And thank you very much for all the nice emails! + + car, art, paint, draw, automobile, comaro, custom, + concept, how, ms.paint, great, good, awsome, design, artistic, + chip, foose + + + + Film + + + + + + + + + + + + http://dm5.google.com/feeds/videos/Ox0c_1l9al4 + 2006-07-04T01:56:27.000Z + 2006-07-04T01:56:27.000Z + + + + + AMV Comedians 2 (Dane Cook) + + + + + + Rubix89 + http://dm5.google.com/feeds/users/Rubix89 + + + AMV Comedians 2 (Dane Cook) + Anime: Naruto + Comedian: Dane Cook + I know I already did Dane Cook, but I couldnt pass up this joke. + http://www.animemusicvideos.org/members/members_videoinfo.php?v=130820 + + Naruto, Dane, Cook + + + Comedy + + + + + + + + + + + diff --git a/tests/AndroidTests/res/values-12key/configVarying.xml b/tests/AndroidTests/res/values-12key/configVarying.xml new file mode 100644 index 0000000000000000000000000000000000000000..14ce1a75a9f127940780041cb016fe165680981e --- /dev/null +++ b/tests/AndroidTests/res/values-12key/configVarying.xml @@ -0,0 +1,26 @@ + + + + + simple 12key + + bag 12key + + only simple 12key + + only bag 12key + + diff --git a/tests/AndroidTests/res/values-320x200/configVarying.xml b/tests/AndroidTests/res/values-320x200/configVarying.xml new file mode 100644 index 0000000000000000000000000000000000000000..035e55e162767d18ab96ae813103e0fedce3d76b --- /dev/null +++ b/tests/AndroidTests/res/values-320x200/configVarying.xml @@ -0,0 +1,26 @@ + + + + + simple 320x200 + + bag 320x200 + + only simple 320x200 + + only bag 320x200 + + diff --git a/tests/AndroidTests/res/values-480x320/configVarying.xml b/tests/AndroidTests/res/values-480x320/configVarying.xml new file mode 100644 index 0000000000000000000000000000000000000000..8b28d89085053aeef3a4515deb13f99b7f0a6b09 --- /dev/null +++ b/tests/AndroidTests/res/values-480x320/configVarying.xml @@ -0,0 +1,26 @@ + + + + + simple 480x320 + + bag 480x320 + + only simple 480x320 + + only bag 480x320 + + diff --git a/tests/AndroidTests/res/values-cs/strings.xml b/tests/AndroidTests/res/values-cs/strings.xml new file mode 100644 index 0000000000000000000000000000000000000000..bd402c7c315e5d3f02a5a2a658a1705976ed4dbe --- /dev/null +++ b/tests/AndroidTests/res/values-cs/strings.xml @@ -0,0 +1,25 @@ + + + + + + + A Czech dog + Few Czech dogs + Some Czech dogs + + + diff --git a/tests/AndroidTests/res/values-dpad/configVarying.xml b/tests/AndroidTests/res/values-dpad/configVarying.xml new file mode 100644 index 0000000000000000000000000000000000000000..c8d5767c834b7d494bf160c88eb73fda6f8fe9fe --- /dev/null +++ b/tests/AndroidTests/res/values-dpad/configVarying.xml @@ -0,0 +1,22 @@ + + + + + simple dpad + + bag dpad + + diff --git a/tests/AndroidTests/res/values-finger/configVarying.xml b/tests/AndroidTests/res/values-finger/configVarying.xml new file mode 100644 index 0000000000000000000000000000000000000000..efe47582f2b644b6e69dea5bd7ebf4f6d5adbc7c --- /dev/null +++ b/tests/AndroidTests/res/values-finger/configVarying.xml @@ -0,0 +1,26 @@ + + + + + simple finger + + bag finger + + only simple finger + + only bag finger + + diff --git a/tests/AndroidTests/res/values-keysexposed/configVarying.xml b/tests/AndroidTests/res/values-keysexposed/configVarying.xml new file mode 100644 index 0000000000000000000000000000000000000000..2380e7e6e6822b6eed3279a8fea376f779b3522d --- /dev/null +++ b/tests/AndroidTests/res/values-keysexposed/configVarying.xml @@ -0,0 +1,22 @@ + + + + + simple keysexposed + + bag keysexposed + + diff --git a/tests/AndroidTests/res/values-keyshidden/configVarying.xml b/tests/AndroidTests/res/values-keyshidden/configVarying.xml new file mode 100644 index 0000000000000000000000000000000000000000..fdffc4d76622b2221f1f7418128ef25c9afd8a97 --- /dev/null +++ b/tests/AndroidTests/res/values-keyshidden/configVarying.xml @@ -0,0 +1,22 @@ + + + + + simple keyshidden + + bag keyshidden + + diff --git a/tests/AndroidTests/res/values-mcc111/configVarying.xml b/tests/AndroidTests/res/values-mcc111/configVarying.xml new file mode 100644 index 0000000000000000000000000000000000000000..16b13a56f010b0ffdf6e00bb86f67fc1fad51f48 --- /dev/null +++ b/tests/AndroidTests/res/values-mcc111/configVarying.xml @@ -0,0 +1,26 @@ + + + + + simple mcc111 + + bag mcc111 + + only simple mcc111 + + only bag mcc111 + + diff --git a/tests/AndroidTests/res/values-mnc222/configVarying.xml b/tests/AndroidTests/res/values-mnc222/configVarying.xml new file mode 100644 index 0000000000000000000000000000000000000000..7f6872998618909d4fe6ebca5428224d6e5517db --- /dev/null +++ b/tests/AndroidTests/res/values-mnc222/configVarying.xml @@ -0,0 +1,26 @@ + + + + + simple mnc222 + + bag mnc222 + + only simple mnc222 + + only bag mnc222 + + diff --git a/tests/AndroidTests/res/values-nokeys/configVarying.xml b/tests/AndroidTests/res/values-nokeys/configVarying.xml new file mode 100644 index 0000000000000000000000000000000000000000..71f7e0b3e0322d44a5b9d7586ab28095aeedebdd --- /dev/null +++ b/tests/AndroidTests/res/values-nokeys/configVarying.xml @@ -0,0 +1,22 @@ + + + + + simple nokeys + + bag nokeys + + diff --git a/tests/AndroidTests/res/values-nonav/configVarying.xml b/tests/AndroidTests/res/values-nonav/configVarying.xml new file mode 100644 index 0000000000000000000000000000000000000000..12549207b1d4c0c8431ba8a563a7b7d9d438df02 --- /dev/null +++ b/tests/AndroidTests/res/values-nonav/configVarying.xml @@ -0,0 +1,22 @@ + + + + + simple nonav + + bag nonav + + diff --git a/tests/AndroidTests/res/values-notouch/configVarying.xml b/tests/AndroidTests/res/values-notouch/configVarying.xml new file mode 100644 index 0000000000000000000000000000000000000000..8a71de45bc5e98c43f0a828d38b1ab6e090c3f68 --- /dev/null +++ b/tests/AndroidTests/res/values-notouch/configVarying.xml @@ -0,0 +1,26 @@ + + + + + simple notouch + + bag notouch + + only simple notouch + + only bag notouch + + diff --git a/tests/AndroidTests/res/values-qwerty/configVarying.xml b/tests/AndroidTests/res/values-qwerty/configVarying.xml new file mode 100644 index 0000000000000000000000000000000000000000..939f682e8809d634de24d692010e426d79ff0548 --- /dev/null +++ b/tests/AndroidTests/res/values-qwerty/configVarying.xml @@ -0,0 +1,22 @@ + + + + + simple qwerty + + bag qwerty + + diff --git a/tests/AndroidTests/res/values-stylus/configVarying.xml b/tests/AndroidTests/res/values-stylus/configVarying.xml new file mode 100644 index 0000000000000000000000000000000000000000..87df119dc17ceccbb47c75812520cce155fcaa48 --- /dev/null +++ b/tests/AndroidTests/res/values-stylus/configVarying.xml @@ -0,0 +1,26 @@ + + + + + simple stylus + + bag stylus + + only simple stylus + + only bag stylus + + diff --git a/tests/AndroidTests/res/values-trackball/configVarying.xml b/tests/AndroidTests/res/values-trackball/configVarying.xml new file mode 100644 index 0000000000000000000000000000000000000000..0dec30012ea44b762f937d478482505abbd77a74 --- /dev/null +++ b/tests/AndroidTests/res/values-trackball/configVarying.xml @@ -0,0 +1,22 @@ + + + + + simple trackball + + bag trackball + + diff --git a/tests/AndroidTests/res/values-wheel/configVarying.xml b/tests/AndroidTests/res/values-wheel/configVarying.xml new file mode 100644 index 0000000000000000000000000000000000000000..6164855aee86f6dd0e60b07ffb20ff465ef8ae80 --- /dev/null +++ b/tests/AndroidTests/res/values-wheel/configVarying.xml @@ -0,0 +1,22 @@ + + + + + simple wheel + + bag wheel + + diff --git a/tests/AndroidTests/res/values-xx-rYY/configVarying.xml b/tests/AndroidTests/res/values-xx-rYY/configVarying.xml new file mode 100644 index 0000000000000000000000000000000000000000..4e52db97822438bc915dc79e42e948e328e694db --- /dev/null +++ b/tests/AndroidTests/res/values-xx-rYY/configVarying.xml @@ -0,0 +1,26 @@ + + + + + simple xx-rYY + + bag xx-rYY + + only simple xx_rYY + + only bag xx_rYY + + diff --git a/tests/AndroidTests/res/values-xx/configVarying.xml b/tests/AndroidTests/res/values-xx/configVarying.xml new file mode 100644 index 0000000000000000000000000000000000000000..e50649d29d9c4b45f5a241da46f5f469d7f6bd7f --- /dev/null +++ b/tests/AndroidTests/res/values-xx/configVarying.xml @@ -0,0 +1,26 @@ + + + + + simple xx + + bag xx + + only simple xx + + only bag xx + + diff --git a/tests/AndroidTests/res/values/arrays.xml b/tests/AndroidTests/res/values/arrays.xml new file mode 100644 index 0000000000000000000000000000000000000000..20ab4077bc054dbf710f94d7f2d123138caea88a --- /dev/null +++ b/tests/AndroidTests/res/values/arrays.xml @@ -0,0 +1,42 @@ + + + + + 101 + + + + zero + 1 + @string/reference + + + 0 + 1 + @integer/reference + + diff --git a/tests/AndroidTests/res/values/attrs.xml b/tests/AndroidTests/res/values/attrs.xml new file mode 100644 index 0000000000000000000000000000000000000000..d3a31caf2c31d28169b4401d01a5ea96eca617f4 --- /dev/null +++ b/tests/AndroidTests/res/values/attrs.xml @@ -0,0 +1,44 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/AndroidTests/res/values/bools.xml b/tests/AndroidTests/res/values/bools.xml new file mode 100644 index 0000000000000000000000000000000000000000..ffa89555639c1f3143808564fec925cc800dcf58 --- /dev/null +++ b/tests/AndroidTests/res/values/bools.xml @@ -0,0 +1,20 @@ + + + + + true + false + diff --git a/tests/AndroidTests/res/values/configVarying.xml b/tests/AndroidTests/res/values/configVarying.xml new file mode 100644 index 0000000000000000000000000000000000000000..c4a20ad93513012915a31e8bea10a9c8a3524d18 --- /dev/null +++ b/tests/AndroidTests/res/values/configVarying.xml @@ -0,0 +1,27 @@ + + + + + simple default + + bag default + + + only simple default + + only bag default + + diff --git a/tests/AndroidTests/res/values/dimens.xml b/tests/AndroidTests/res/values/dimens.xml new file mode 100644 index 0000000000000000000000000000000000000000..72d10107f858c1b66db662bb9d6f4ba1554eb0b9 --- /dev/null +++ b/tests/AndroidTests/res/values/dimens.xml @@ -0,0 +1,42 @@ + + + + + 100% + 1% + .1% + .01% + 0% + 1.1% + 100.1% + 25510% + 25610% + 6553510% + 6553610% + + 100%p + 1%p + .1%p + .01%p + 0%p + 1.1%p + 100.1%p + 25510%p + 25610%p + 6553510%p + 6553610%p + + diff --git a/tests/AndroidTests/res/values/strings.xml b/tests/AndroidTests/res/values/strings.xml new file mode 100644 index 0000000000000000000000000000000000000000..21c72cf8b93f0272ab6a771b24586883c870dd79 --- /dev/null +++ b/tests/AndroidTests/res/values/strings.xml @@ -0,0 +1,54 @@ + + + + + Test Granted + Used for running unit tests, for + testing operations where we have the permission. + Test Denied + Used for running unit tests, for + testing operations where we do not have the permission. + + S + + S + + S + + 100 + true + #fff + 100.0 + 100px + 100% + + Format[] + Format[%d] + Format[%3$d,%2$s] + + here + + text + + test + + + A dog + Some dogs + + + + diff --git a/tests/AndroidTests/res/values/styles.xml b/tests/AndroidTests/res/values/styles.xml new file mode 100644 index 0000000000000000000000000000000000000000..6c60e21481a507a0c8b4be973925ce9919d1b221 --- /dev/null +++ b/tests/AndroidTests/res/values/styles.xml @@ -0,0 +1,46 @@ + + + + + + + + + + + + + + + + diff --git a/tests/AndroidTests/res/xml/calendar.xml b/tests/AndroidTests/res/xml/calendar.xml new file mode 100644 index 0000000000000000000000000000000000000000..1adcd7486ef7d813d404d305c96362d18381d1b7 --- /dev/null +++ b/tests/AndroidTests/res/xml/calendar.xml @@ -0,0 +1,38 @@ + + + +http://www.google.com/calendar/feeds/default/private/full2007-02-05T22:04:50.000Zw gw gw gwg@voiceme.netGoogle Calendar13125http://www.google.com/calendar/feeds/default/private/full/7iqc1ro0ihc69vhsiq3uabooig2007-02-05T22:04:50.000Z2007-02-05T22:04:50.000Zskatew gwg@voiceme.nethttp://www.google.com/calendar/feeds/default/private/full/kp4gil76n2vcrkt9kaotj3s12c2007-02-05T22:04:42.000Z2007-02-05T22:04:42.000Zskatew gwg@voiceme.nethttp://www.google.com/calendar/feeds/default/private/full/gkhb48fj68lcp15fd1k03tjbj02007-02-05T22:04:35.000Z2007-02-05T22:04:35.000Ztest event 6w gwg@voiceme.nethttp://www.google.com/calendar/feeds/default/private/full/32p5g68cpean3p2ol7kanj38sg2007-02-05T22:04:29.000Z2007-02-05T22:04:29.000Ztest event 5w gwg@voiceme.nethttp://www.google.com/calendar/feeds/default/private/full/tfqpth26conshdmav0apje1tf42007-02-05T22:04:19.000Z2007-02-05T22:04:19.000Zskatew gwg@voiceme.nethttp://www.google.com/calendar/feeds/default/private/full/onbo9mhbr5m6mo356nog7uel4s2007-02-05T22:04:07.000Z2007-02-05T22:04:07.000ZSharks at Anaheimw gwg@voiceme.nethttp://www.google.com/calendar/feeds/default/private/full/tjqrd9fve576hieh3sa67nql5k2007-02-05T22:04:02.000Z2007-02-05T22:04:02.000ZSharks vs. ANAHEIMw gwg@voiceme.nethttp://www.google.com/calendar/feeds/default/private/full/or6dtpn065f9mntond4jh2docc2007-02-05T22:03:52.000Z2007-02-05T22:03:52.000Zskatew gwg@voiceme.nethttp://www.google.com/calendar/feeds/default/private/full/k70v8o4jt1afi17hg2spavq1c02007-02-05T22:03:36.000Z2007-02-05T22:03:36.000Zlunchw gwg@voiceme.netDTSTART;TZID=America/Los_Angeles:20070206T120000 +DURATION:PT3600S +RRULE:FREQ=DAILY;WKST=SU +BEGIN:VTIMEZONE +TZID:America/Los_Angeles +X-LIC-LOCATION:America/Los_Angeles +BEGIN:STANDARD +TZOFFSETFROM:-0700 +TZOFFSETTO:-0800 +TZNAME:PST +DTSTART:19701025T020000 +RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU +END:STANDARD +BEGIN:DAYLIGHT +TZOFFSETFROM:-0800 +TZOFFSETTO:-0700 +TZNAME:PDT +DTSTART:19700405T020000 +RRULE:FREQ=YEARLY;BYMONTH=4;BYDAY=1SU +END:DAYLIGHT +END:VTIMEZONE +http://www.google.com/calendar/feeds/default/private/full/6ee7b8nohdt03tv0gknm4v71242007-02-05T22:03:19.000Z2007-02-05T22:03:19.000Ztest event 4w gwg@voiceme.nethttp://www.google.com/calendar/feeds/default/private/full/of1vh1r2q5aqdplo65i8bqbn3o2007-02-05T22:03:11.000Z2007-02-05T22:03:11.000Ztest event 3w gwg@voiceme.nethttp://www.google.com/calendar/feeds/default/private/full/s7ahgfomlgii9qbkgpfbinr9u82007-02-05T22:02:40.000Z2007-02-05T22:03:04.000Ztest event 2w gwg@voiceme.nethttp://www.google.com/calendar/feeds/default/private/full/rl8focglfe6jndql4u8lg73q5k2007-02-05T22:02:28.000Z2007-02-05T22:02:53.000Ztest event 1w gwg@voiceme.net diff --git a/tests/AndroidTests/res/xml/metadata.xml b/tests/AndroidTests/res/xml/metadata.xml new file mode 100644 index 0000000000000000000000000000000000000000..e352f27f814817f23051490aa7105ba39e566339 --- /dev/null +++ b/tests/AndroidTests/res/xml/metadata.xml @@ -0,0 +1,23 @@ + + + + diff --git a/tests/AndroidTests/res/xml/metadata_app.xml b/tests/AndroidTests/res/xml/metadata_app.xml new file mode 100644 index 0000000000000000000000000000000000000000..c37e6badcb7e5bf9e429d64ec3356e0914eee98a --- /dev/null +++ b/tests/AndroidTests/res/xml/metadata_app.xml @@ -0,0 +1,24 @@ + + + + diff --git a/tests/AndroidTests/res/xml/searchable.xml b/tests/AndroidTests/res/xml/searchable.xml new file mode 100644 index 0000000000000000000000000000000000000000..a40d53de051166fa3ea678cc43888860614f5de7 --- /dev/null +++ b/tests/AndroidTests/res/xml/searchable.xml @@ -0,0 +1,21 @@ + + + + + diff --git a/tests/AndroidTests/run_test.sh b/tests/AndroidTests/run_test.sh new file mode 100755 index 0000000000000000000000000000000000000000..0cdf63f538acc70bb2d9b450127ecf80588ca8ce --- /dev/null +++ b/tests/AndroidTests/run_test.sh @@ -0,0 +1,4 @@ +framework=/system/framework +bpath=$framework/core.jar:$framework/ext.jar:$framework/framework.jar:$framework/android.test.runner.jar +adb shell exec dalvikvm -Xbootclasspath:$bpath -cp system/app/AndroidTests.apk \ + com.android.internal.util.WithFramework junit.textui.TestRunner $* diff --git a/tests/AndroidTests/src/com/android/unit_tests/AndroidPerformanceTests.java b/tests/AndroidTests/src/com/android/unit_tests/AndroidPerformanceTests.java new file mode 100644 index 0000000000000000000000000000000000000000..b6a859457e21ffe470ae09ae4887a5f00439e857 --- /dev/null +++ b/tests/AndroidTests/src/com/android/unit_tests/AndroidPerformanceTests.java @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2007 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.android.unit_tests; + +import android.test.TestListActivity; + +public class AndroidPerformanceTests extends TestListActivity { + @Override + public String getTestSuite() { + return "com.android.unit_tests.AndroidPerformanceTests$Suite"; + } + + public static class Suite { + public static String[] children() { + return new String[] { + DatabasePerformanceTests.class.getName(), + GraphicsPerformanceTests.class.getName(), + JavaPerformanceTests.class.getName(), + LogTest.PerformanceTest.class.getName(), + PerformanceTests.class.getName(), + TextViewPerformanceTest.class.getName(), + }; + } + } +} diff --git a/tests/AndroidTests/src/com/android/unit_tests/AndroidTests.java b/tests/AndroidTests/src/com/android/unit_tests/AndroidTests.java new file mode 100644 index 0000000000000000000000000000000000000000..4b86add1c7d0ec1412d336a9f69c24af3035d2d1 --- /dev/null +++ b/tests/AndroidTests/src/com/android/unit_tests/AndroidTests.java @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2005 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.android.unit_tests; + +import android.test.FrameworkTests; +import android.test.suitebuilder.TestSuiteBuilder; + +import junit.framework.TestSuite; + +public class AndroidTests extends TestSuite { + + public static TestSuite suite() { + TestSuiteBuilder suiteBuilder = new TestSuiteBuilder(AndroidTests.class); + TestSuite suite = suiteBuilder.includeAllPackagesUnderHere().build(); + + return suite; + } +} diff --git a/tests/AndroidTests/src/com/android/unit_tests/ApacheHttpTests.java b/tests/AndroidTests/src/com/android/unit_tests/ApacheHttpTests.java new file mode 100644 index 0000000000000000000000000000000000000000..cf759e02b9617aeb46b0d44d54f31ec88d168070 --- /dev/null +++ b/tests/AndroidTests/src/com/android/unit_tests/ApacheHttpTests.java @@ -0,0 +1,13 @@ +package com.android.unit_tests; + +import junit.framework.TestSuite; + +public class ApacheHttpTests { + public static TestSuite suite() { + TestSuite suite = new TestSuite(ApacheHttpTests.class.getName()); + + suite.addTestSuite(TestHttpService.class); + + return suite; + } +} diff --git a/tests/AndroidTests/src/com/android/unit_tests/AppCacheTest.java b/tests/AndroidTests/src/com/android/unit_tests/AppCacheTest.java new file mode 100755 index 0000000000000000000000000000000000000000..914d98bcfd53a12be657ae31c52729abbb5e06aa --- /dev/null +++ b/tests/AndroidTests/src/com/android/unit_tests/AppCacheTest.java @@ -0,0 +1,654 @@ +/* + * Copyright (C) 2006 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.android.unit_tests; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import android.content.Context; +import android.content.pm.ApplicationInfo; +import android.content.pm.IPackageDataObserver; +import android.content.pm.IPackageStatsObserver; +import android.content.pm.PackageStats; +import android.content.pm.IPackageManager; +import android.test.AndroidTestCase; +import android.test.suitebuilder.annotation.LargeTest; +import android.test.suitebuilder.annotation.MediumTest; +import android.test.suitebuilder.annotation.SmallTest; +import android.test.suitebuilder.annotation.Suppress; +import android.util.Log; +import android.os.RemoteException; +import android.os.ServiceManager; +import android.os.StatFs; + +public class AppCacheTest extends AndroidTestCase { + private static final boolean localLOGV = false; + public static final String TAG="AppCacheTest"; + public final long MAX_WAIT_TIME=60*1000; + public final long WAIT_TIME_INCR=10*1000; + private static final int THRESHOLD=5; + private static final int ACTUAL_THRESHOLD=10; + + @Override + protected void setUp() throws Exception { + super.setUp(); + if(localLOGV) Log.i(TAG, "Cleaning up cache directory first"); + cleanUpCacheDirectory(); + } + + void cleanUpDirectory(File pDir, String dirName) { + File testDir = new File(pDir, dirName); + if(!testDir.exists()) { + return; + } + String fList[] = testDir.list(); + for(int i = 0; i < fList.length; i++) { + File file = new File(testDir, fList[i]); + if(file.isDirectory()) { + cleanUpDirectory(testDir, fList[i]); + } else { + file.delete(); + } + } + testDir.delete(); + } + + void cleanUpCacheDirectory() { + File testDir = mContext.getCacheDir(); + if(!testDir.exists()) { + return; + } + + String fList[] = testDir.list(); + if(fList == null) { + testDir.delete(); + return; + } + for(int i = 0; i < fList.length; i++) { + File file = new File(testDir, fList[i]); + if(file.isDirectory()) { + cleanUpDirectory(testDir, fList[i]); + } else { + file.delete(); + } + } + } + + @SmallTest + public void testDeleteAllCacheFiles() { + String testName="testDeleteAllCacheFiles"; + cleanUpCacheDirectory(); + } + + void failStr(String errMsg) { + Log.w(TAG, "errMsg="+errMsg); + fail(errMsg); + } + void failStr(Exception e) { + Log.w(TAG, "e.getMessage="+e.getMessage()); + Log.w(TAG, "e="+e); + } + long getFreeStorageBlks(StatFs st) { + st.restat("/data"); + return st.getFreeBlocks(); + } + + long getFreeStorageSize(StatFs st) { + st.restat("/data"); + return (st.getFreeBlocks()*st.getBlockSize()); + } + @LargeTest + public void testFreeApplicationCacheAllFiles() throws Exception { + StatFs st = new StatFs("/data"); + long blks1 = getFreeStorageBlks(st); + long availableMem = getFreeStorageSize(st); + File cacheDir = mContext.getCacheDir(); + assertNotNull(cacheDir); + createTestFiles1(cacheDir, "testtmpdir", 5); + long blks2 = getFreeStorageBlks(st); + if(localLOGV) Log.i(TAG, "blk1="+blks1+", blks2="+blks2); + //this should free up the test files that were created earlier + invokePMFreeApplicationCache(availableMem); + long blks3 = getFreeStorageBlks(st); + if(localLOGV) Log.i(TAG, "blks3="+blks3); + verifyTestFiles1(cacheDir, "testtmpdir", 5); + } + + @LargeTest + public void testFreeApplicationCacheSomeFiles() throws Exception { + StatFs st = new StatFs("/data"); + long blks1 = getFreeStorageBlks(st); + File cacheDir = mContext.getCacheDir(); + assertNotNull(cacheDir); + createTestFiles1(cacheDir, "testtmpdir", 5); + long blks2 = getFreeStorageBlks(st); + Log.i(TAG, "blk1="+blks1+", blks2="+blks2); + long diff = (blks1-blks2-2); + assertTrue(invokePMFreeApplicationCache(diff*st.getBlockSize())); + long blks3 = getFreeStorageBlks(st); + //blks3 should be greater than blks2 and less than blks1 + if(!((blks3 <= blks1) && (blks3 >= blks2))) { + failStr("Expected "+(blks1-blks2)+" number of blocks to be freed but freed only " + +(blks1-blks3)); + } + } + + /** + * This method opens an output file writes to it, opens the same file as an input + * stream, reads the contents and verifies the data that was written earlier can be read + */ + public void openOutFileInAppFilesDir(File pFile, String pFileOut) { + FileOutputStream fos = null; + try { + fos = new FileOutputStream(pFile); + } catch (FileNotFoundException e1) { + failStr("Error when opening file "+e1); + return; + } + try { + fos.write(pFileOut.getBytes()); + fos.close(); + } catch (FileNotFoundException e) { + failStr(e.getMessage()); + } catch (IOException e) { + failStr(e.getMessage()); + } + int count = pFileOut.getBytes().length; + byte[] buffer = new byte[count]; + try { + FileInputStream fis = new FileInputStream(pFile); + fis.read(buffer, 0, count); + fis.close(); + } catch (FileNotFoundException e) { + failStr("Failed when verifing output opening file "+e.getMessage()); + } catch (IOException e) { + failStr("Failed when verifying output, reading from written file "+e); + } + String str = new String(buffer); + assertEquals(str, pFileOut); + } + + /* + * This test case verifies that output written to a file + * using Context.openFileOutput has executed successfully. + * The operation is verified by invoking Context.openFileInput + */ + @MediumTest + public void testAppFilesCreateFile() { + String fileName = "testFile1.txt"; + String fileOut = "abcdefghijklmnopqrstuvwxyz"; + Context con = super.getContext(); + try { + FileOutputStream fos = con.openFileOutput(fileName, Context.MODE_PRIVATE); + fos.close(); + } catch (FileNotFoundException e) { + failStr(e); + } catch (IOException e) { + failStr(e); + } + } + + @SmallTest + public void testAppCacheCreateFile() { + String fileName = "testFile1.txt"; + String fileOut = "abcdefghijklmnopqrstuvwxyz"; + Context con = super.getContext(); + File file = new File(con.getCacheDir(), fileName); + openOutFileInAppFilesDir(file, fileOut); + cleanUpCacheDirectory(); + } + + @MediumTest + public void testAppCreateCacheFiles() { + File cacheDir = mContext.getCacheDir(); + String testDirName = "testtmp"; + File testTmpDir = new File(cacheDir, testDirName); + testTmpDir.mkdir(); + int numDirs = 3; + File fileArr[] = new File[numDirs]; + for(int i = 0; i < numDirs; i++) { + fileArr[i] = new File(testTmpDir, "dir"+(i+1)); + fileArr[i].mkdir(); + } + byte buffer[] = getBuffer(); + Log.i(TAG, "Size of bufer="+buffer.length); + for(int i = 0; i < numDirs; i++) { + for(int j = 1; j <= (i); j++) { + File file1 = new File(fileArr[i], "testFile"+j+".txt"); + FileOutputStream fos = null; + try { + fos = new FileOutputStream(file1); + for(int k = 1; k < 10; k++) { + fos.write(buffer); + } + Log.i(TAG, "wrote 10K bytes to "+file1); + fos.close(); + } catch (FileNotFoundException e) { + Log.i(TAG, "Excetion ="+e); + fail("Error when creating outputstream "+e); + } catch(IOException e) { + Log.i(TAG, "Excetion ="+e); + fail("Error when writing output "+e); + } + } + } + } + + byte[] getBuffer() { + String sbuffer = "a"; + for(int i = 0; i < 10; i++) { + sbuffer += sbuffer; + } + return sbuffer.getBytes(); + } + + long getFileNumBlocks(long fileSize, int blkSize) { + long ret = fileSize/blkSize; + if(ret*blkSize < fileSize) { + ret++; + } + return ret; + } + + //@LargeTest + public void testAppCacheClear() { + String dataDir="/data/data"; + StatFs st = new StatFs(dataDir); + int blkSize = st.getBlockSize(); + int totBlks = st.getBlockCount(); + long availableBlks = st.getFreeBlocks(); + long thresholdBlks = (totBlks*THRESHOLD)/100; + String testDirName = "testdir"; + //create directory in cache + File testDir = new File(mContext.getCacheDir(), testDirName); + testDir.mkdirs(); + byte[] buffer = getBuffer(); + int i = 1; + if(localLOGV) Log.i(TAG, "availableBlks="+availableBlks+", thresholdBlks="+thresholdBlks); + long createdFileBlks = 0; + int imax = 300; + while((availableBlks > thresholdBlks) &&(i < imax)) { + File testFile = new File(testDir, "testFile"+i+".txt"); + if(localLOGV) Log.i(TAG, "Creating "+i+"th test file "+testFile); + int jmax = i; + i++; + FileOutputStream fos; + try { + fos = new FileOutputStream(testFile); + } catch (FileNotFoundException e) { + Log.i(TAG, "Failed creating test file:"+testFile); + continue; + } + boolean err = false; + for(int j = 1; j <= jmax;j++) { + try { + fos.write(buffer); + } catch (IOException e) { + Log.i(TAG, "Failed to write to file:"+testFile); + err = true; + } + } + try { + fos.close(); + } catch (IOException e) { + Log.i(TAG, "Failed closing file:"+testFile); + } + if(err) { + continue; + } + createdFileBlks += getFileNumBlocks(testFile.length(), blkSize); + st.restat(dataDir); + availableBlks = st.getFreeBlocks(); + } + st.restat(dataDir); + long availableBytes = st.getFreeBlocks()*blkSize; + long shouldFree = (ACTUAL_THRESHOLD-THRESHOLD)*totBlks; + //would have run out of memory + //wait for some time and confirm cache is deleted + try { + Log.i(TAG, "Sleeping for 2 minutes..."); + Thread.sleep(2*60*1000); + } catch (InterruptedException e) { + fail("Exception when sleeping "+e); + } + boolean removedFlag = false; + long existingFileBlks = 0; + for(int k = 1; k MAX_WAIT_TIME)) { + observer.wait(WAIT_TIME_INCR); + waitTime += WAIT_TIME_INCR; + } + if(!observer.isDone()) { + throw new Exception("timed out waiting for PackageDataObserver.onRemoveCompleted"); + } + } + return observer.retValue; + } catch (RemoteException e) { + Log.w(TAG, "Failed to get handle for PackageManger Exception: "+e); + return false; + } catch (InterruptedException e) { + Log.w(TAG, "InterruptedException :"+e); + return false; + } + } + + boolean invokePMFreeApplicationCache(long idealStorageSize) throws Exception { + try { + + String packageName = mContext.getPackageName(); + PackageDataObserver observer = new PackageDataObserver(); + //wait on observer + synchronized(observer) { + getPm().freeApplicationCache(idealStorageSize, observer); + long waitTime = 0; + while(!observer.isDone() || (waitTime > MAX_WAIT_TIME)) { + observer.wait(WAIT_TIME_INCR); + waitTime += WAIT_TIME_INCR; + } + if(!observer.isDone()) { + throw new Exception("timed out waiting for PackageDataObserver.onRemoveCompleted"); + } + } + return observer.retValue; + } catch (RemoteException e) { + Log.w(TAG, "Failed to get handle for PackageManger Exception: "+e); + return false; + } catch (InterruptedException e) { + Log.w(TAG, "InterruptedException :"+e); + return false; + } + } + + @LargeTest + public void testDeleteAppCacheFiles() throws Exception { + String testName="testDeleteAppCacheFiles"; + File cacheDir = mContext.getCacheDir(); + createTestFiles1(cacheDir, "testtmpdir", 5); + assertTrue(invokePMDeleteAppCacheFiles()); + //confirm files dont exist + verifyTestFiles1(cacheDir, "testtmpdir", 5); + } + + class PackageStatsObserver extends IPackageStatsObserver.Stub { + public boolean retValue = false; + public PackageStats stats; + private boolean doneFlag = false; + + public void onGetStatsCompleted(PackageStats pStats, boolean succeeded) + throws RemoteException { + synchronized(this) { + retValue = succeeded; + stats = pStats; + doneFlag = true; + notifyAll(); + } + } + public boolean isDone() { + return doneFlag; + } + } + + public PackageStats invokePMGetPackageSizeInfo() throws Exception { + try { + String packageName = mContext.getPackageName(); + PackageStatsObserver observer = new PackageStatsObserver(); + //wait on observer + synchronized(observer) { + getPm().getPackageSizeInfo(packageName, observer); + long waitTime = 0; + while((!observer.isDone()) || (waitTime > MAX_WAIT_TIME) ) { + observer.wait(WAIT_TIME_INCR); + waitTime += WAIT_TIME_INCR; + } + if(!observer.isDone()) { + throw new Exception("Timed out waiting for PackageStatsObserver.onGetStatsCompleted"); + } + } + if(localLOGV) Log.i(TAG, "OBSERVER RET VALUES code="+observer.stats.codeSize+ + ", data="+observer.stats.dataSize+", cache="+observer.stats.cacheSize); + return observer.stats; + } catch (RemoteException e) { + Log.w(TAG, "Failed to get handle for PackageManger Exception: "+e); + return null; + } catch (InterruptedException e) { + Log.w(TAG, "InterruptedException :"+e); + return null; + } + } + + @SmallTest + public void testGetPackageSizeInfo() throws Exception { + String testName="testGetPackageSizeInfo"; + PackageStats stats = invokePMGetPackageSizeInfo(); + assertTrue(stats!=null); + //confirm result + if(localLOGV) Log.i(TAG, "code="+stats.codeSize+", data="+stats.dataSize+ + ", cache="+stats.cacheSize); + } + + /* utility method used to create observer and check async call back from PackageManager. + * ClearApplicationUserData + */ + boolean invokePMClearApplicationUserData() throws Exception { + try { + String packageName = mContext.getPackageName(); + PackageDataObserver observer = new PackageDataObserver(); + //wait on observer + synchronized(observer) { + getPm().clearApplicationUserData(packageName, observer); + long waitTime = 0; + while(!observer.isDone() || (waitTime > MAX_WAIT_TIME)) { + observer.wait(WAIT_TIME_INCR); + waitTime += WAIT_TIME_INCR; + } + if(!observer.isDone()) { + throw new Exception("timed out waiting for PackageDataObserver.onRemoveCompleted"); + } + } + return observer.retValue; + } catch (RemoteException e) { + Log.w(TAG, "Failed to get handle for PackageManger Exception: "+e); + return false; + } catch (InterruptedException e) { + Log.w(TAG, "InterruptedException :"+e); + return false; + } + } + + void verifyUserDataCleared(File pDir) { + if(localLOGV) Log.i(TAG, "Verifying "+pDir); + if(pDir == null) { + return; + } + String fileList[] = pDir.list(); + if(fileList == null) { + return; + } + int imax = fileList.length; + //look recursively in user data dir + for(int i = 0; i < imax; i++) { + if(localLOGV) Log.i(TAG, "Found entry "+fileList[i]+ "in "+pDir); + if("lib".equalsIgnoreCase(fileList[i])) { + if(localLOGV) Log.i(TAG, "Ignoring lib directory"); + continue; + } + fail(pDir+" should be empty or contain only lib subdirectory. Found "+fileList[i]); + } + } + + File getDataDir() { + try { + ApplicationInfo appInfo = getPm().getApplicationInfo(mContext.getPackageName(), 0); + return new File(appInfo.dataDir); + } catch (RemoteException e) { + throw new RuntimeException("Pacakge manager dead", e); + } + } + + @LargeTest + public void testClearApplicationUserDataWithTestData() throws Exception { + File cacheDir = mContext.getCacheDir(); + createTestFiles1(cacheDir, "testtmpdir", 5); + if(localLOGV) { + Log.i(TAG, "Created test data Waiting for 60seconds before continuing"); + Thread.sleep(60*1000); + } + assertTrue(invokePMClearApplicationUserData()); + //confirm files dont exist + verifyUserDataCleared(getDataDir()); + } + + @SmallTest + public void testClearApplicationUserDataWithNoTestData() throws Exception { + assertTrue(invokePMClearApplicationUserData()); + //confirm files dont exist + verifyUserDataCleared(getDataDir()); + } + + @LargeTest + public void testClearApplicationUserDataNoObserver() throws Exception { + getPm().clearApplicationUserData(mContext.getPackageName(), null); + //sleep for 1 minute + Thread.sleep(60*1000); + //confirm files dont exist + verifyUserDataCleared(getDataDir()); + } + +} diff --git a/tests/AndroidTests/src/com/android/unit_tests/ArrayListTest.java b/tests/AndroidTests/src/com/android/unit_tests/ArrayListTest.java new file mode 100644 index 0000000000000000000000000000000000000000..81e6efd91542129e2f78982abcbafb2d5c73d8f4 --- /dev/null +++ b/tests/AndroidTests/src/com/android/unit_tests/ArrayListTest.java @@ -0,0 +1,327 @@ +/* + * Copyright (C) 2007 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.android.unit_tests; + +import java.util.ArrayList; +import android.test.PerformanceTestBase; + +public class ArrayListTest extends PerformanceTestBase { + + private ArrayList mList; + + @Override + @SuppressWarnings("unchecked") + protected void setUp() throws Exception { + super.setUp(); + + mList = new ArrayList(); + mList.add(0); + mList.add(1); + mList.add(2); + mList.add(3); + mList.add(4); + mList.add(5); + mList.add(6); + mList.add(7); + mList.add(8); + mList.add(9); + } + + public void testArrayListAdd() { + int i = 0; + for (; i < 10; i++) { + mList.add(i); + mList.add(i); + mList.add(i); + mList.add(i); + mList.add(i); + mList.add(i); + mList.add(i); + mList.add(i); + mList.add(i); + mList.add(i); + } + } + + public void testArrayListAdd1() { + int i = 0; + for (; i < 10; i++) { + mList.add(7, i); + mList.add(7, i); + mList.add(7, i); + mList.add(7, i); + mList.add(7, i); + mList.add(7, i); + mList.add(7, i); + mList.add(7, i); + mList.add(7, i); + mList.add(7, i); + } + } + + public void testArrayListToArray() { + Object rArray; + int i = 0; + for (; i < 100; i++) { + rArray = mList.toArray(); + rArray = mList.toArray(); + rArray = mList.toArray(); + rArray = mList.toArray(); + rArray = mList.toArray(); + rArray = mList.toArray(); + rArray = mList.toArray(); + rArray = mList.toArray(); + rArray = mList.toArray(); + rArray = mList.toArray(); + } + } + + public void testArrayListSize() { + int i = 0, len; + for (; i < 100; i++) { + len = mList.size(); + len = mList.size(); + len = mList.size(); + len = mList.size(); + len = mList.size(); + len = mList.size(); + len = mList.size(); + len = mList.size(); + len = mList.size(); + len = mList.size(); + } + } + + public void testArrayListGet() { + int i = 0, value; + int len = mList.size(); + for (; i < len; i++) { + value = mList.get(i); + value = mList.get(i); + value = mList.get(i); + value = mList.get(i); + value = mList.get(i); + value = mList.get(i); + value = mList.get(i); + value = mList.get(i); + value = mList.get(i); + value = mList.get(i); + } + } + + public void testArrayListContains() { + boolean flag; + int i = 0; + + for (; i < 100; i++) { + flag = mList.contains(i); + flag = mList.contains(i); + flag = mList.contains(i); + flag = mList.contains(i); + flag = mList.contains(i); + flag = mList.contains(i); + flag = mList.contains(i); + flag = mList.contains(i); + flag = mList.contains(i); + flag = mList.contains(i); + + } + } + + public void testArrayListToArray1() { + Integer[] rArray = new Integer[10]; + + Integer[] mArray; + int i = 0; + for (; i < 100; i++) { + mArray = mList.toArray(rArray); + mArray = mList.toArray(rArray); + mArray = mList.toArray(rArray); + mArray = mList.toArray(rArray); + mArray = mList.toArray(rArray); + mArray = mList.toArray(rArray); + mArray = mList.toArray(rArray); + mArray = mList.toArray(rArray); + mArray = mList.toArray(rArray); + mArray = mList.toArray(rArray); + } + } + + public void testArrayListSet() { + int i = 0; + for (; i < 10; i++) { + mList.set(5, 0); + mList.set(5, 0); + mList.set(5, 0); + mList.set(5, 0); + mList.set(5, 0); + mList.set(5, 0); + mList.set(5, 0); + mList.set(5, 0); + mList.set(5, 0); + mList.set(5, 0); + } + } + + public void testArrayListIndexOf() { + int i = 0, index; + + for (; i < 100; i++) { + index = mList.indexOf(0); + index = mList.indexOf(0); + index = mList.indexOf(0); + index = mList.indexOf(0); + index = mList.indexOf(0); + index = mList.indexOf(0); + index = mList.indexOf(0); + index = mList.indexOf(0); + index = mList.indexOf(0); + index = mList.indexOf(0); + } + } + + public void testArrayListLastIndexOf() { + int i = 0, index; + + for (; i < 100; i++) { + index = mList.lastIndexOf(0); + index = mList.lastIndexOf(0); + index = mList.lastIndexOf(0); + index = mList.lastIndexOf(0); + index = mList.lastIndexOf(0); + index = mList.lastIndexOf(0); + index = mList.lastIndexOf(0); + index = mList.lastIndexOf(0); + index = mList.lastIndexOf(0); + index = mList.lastIndexOf(0); + } + } + + @SuppressWarnings("unchecked") + public void testArrayListRemove() { + ArrayList aList; + aList = new ArrayList(); + for (int j = 0; j < 10000; j++) { + aList.add(0); + } + + int i = 0, index; + + for (; i < 10; i++) { + index = aList.remove(0); + index = aList.remove(0); + index = aList.remove(0); + index = aList.remove(0); + index = aList.remove(0); + index = aList.remove(0); + index = aList.remove(0); + index = aList.remove(0); + index = aList.remove(0); + index = aList.remove(0); + + + } + } + + @SuppressWarnings("unchecked") + public void testArrayListAddAll() { + ArrayList aList = new ArrayList(); + + int i = 0; + boolean b; + for (; i < 10; i++) { + b = aList.addAll(mList); + b = aList.addAll(mList); + b = aList.addAll(mList); + b = aList.addAll(mList); + b = aList.addAll(mList); + b = aList.addAll(mList); + b = aList.addAll(mList); + b = aList.addAll(mList); + b = aList.addAll(mList); + b = aList.addAll(mList); + + } + } + + @SuppressWarnings("unchecked") + public void testArrayListRemove1() { + ArrayList aList; + String s; + + aList = new ArrayList(); + for (int j = 0; j < 100; j++) { + aList.add("a"); + aList.add("b"); + } + s = new String("a"); + + int i = 0; + boolean b; + for (; i < 10; i++) { + b = aList.remove(s); + b = aList.remove(s); + b = aList.remove(s); + b = aList.remove(s); + b = aList.remove(s); + b = aList.remove(s); + b = aList.remove(s); + b = aList.remove(s); + b = aList.remove(s); + b = aList.remove(s); + } + } + + @SuppressWarnings("unchecked") + public void testArrayListAddAll1() { + ArrayList aList = new ArrayList(); + + int i = 0; + boolean b; + + for (; i < 10; i++) { + b = aList.addAll(0, mList); + b = aList.addAll(0, mList); + b = aList.addAll(0, mList); + b = aList.addAll(0, mList); + b = aList.addAll(0, mList); + b = aList.addAll(0, mList); + b = aList.addAll(0, mList); + b = aList.addAll(0, mList); + b = aList.addAll(0, mList); + b = aList.addAll(0, mList); + } + } + + public void testArrayListClone() { + Object rObj; + int i = 0; + + for (; i < 100; i++) { + rObj = mList.clone(); + rObj = mList.clone(); + rObj = mList.clone(); + rObj = mList.clone(); + rObj = mList.clone(); + rObj = mList.clone(); + rObj = mList.clone(); + rObj = mList.clone(); + rObj = mList.clone(); + rObj = mList.clone(); + } + } +} diff --git a/tests/AndroidTests/src/com/android/unit_tests/BluetoothTest.java b/tests/AndroidTests/src/com/android/unit_tests/BluetoothTest.java new file mode 100644 index 0000000000000000000000000000000000000000..48a02c4a728bcfc213a2792ee893abd0b2a7c616 --- /dev/null +++ b/tests/AndroidTests/src/com/android/unit_tests/BluetoothTest.java @@ -0,0 +1,510 @@ +/* + * Copyright (C) 2007 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.android.unit_tests; + +import android.bluetooth.BluetoothA2dp; +import android.bluetooth.BluetoothDevice; +import android.bluetooth.BluetoothIntent; +import android.bluetooth.BluetoothClass; +import android.bluetooth.IBluetoothDeviceCallback; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.os.SystemProperties; +import android.test.AndroidTestCase; +import android.test.suitebuilder.annotation.LargeTest; +import android.test.suitebuilder.annotation.MediumTest; +import android.test.suitebuilder.annotation.SmallTest; +import android.util.Log; + +import junit.framework.Assert; + +import java.util.List; +import java.util.HashSet; + +public class BluetoothTest extends AndroidTestCase { + private static final String TAG = "BluetoothTest"; + + @MediumTest + public void testBluetoothSmokeTest() throws Exception { + + BluetoothDevice btDevice = + (BluetoothDevice)getContext().getSystemService(Context.BLUETOOTH_SERVICE); + + // TODO: Use a more reliable check to see if this product should + // support Bluetooth - see bug 988521 + boolean shouldSupportBluetooth = SystemProperties.get("ro.kernel.qemu").equals("0"); + + assertFalse(shouldSupportBluetooth && btDevice == null); + if (!shouldSupportBluetooth) { + Log.i(TAG, "Skipping test - this device does not have bluetooth."); + return; + } + + boolean bluetoothWasEnabled = btDevice.isEnabled(); + + if (bluetoothWasEnabled) { + Log.i(TAG, "Bluetooth already enabled"); + } else { + Log.i(TAG, "Enabling Bluetooth..."); + btDevice.enable(); + Log.i(TAG, "Bluetooth enabled"); + } + Assert.assertTrue(btDevice.isEnabled()); + + String myAddress = btDevice.getAddress(); + Assert.assertTrue(myAddress != null); + Log.i(TAG, "My Bluetooth Address is " + myAddress); + Assert.assertFalse(myAddress.equals("00:00:00:00:00:00")); + + if (!bluetoothWasEnabled) { + Log.i(TAG, "Disabling Bluetooth..."); + btDevice.disable(); + Log.i(TAG, "Bluetooth disabled"); + } + } + + private boolean listenA2dp = false; + private void listenA2dp() { + if (!listenA2dp) { + listenA2dp = true; + getContext().registerReceiver(new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + int state = intent.getIntExtra(BluetoothA2dp.SINK_STATE, -1); + int oldState = intent.getIntExtra(BluetoothA2dp.SINK_PREVIOUS_STATE, -1); + Log.e(TAG, "A2DP INTENT: state = " + state + " oldState = " + oldState); + } + }, new IntentFilter(BluetoothIntent.REMOTE_DEVICE_FOUND_ACTION)); + } + } + + @MediumTest + public void testA2dpSmokeTest() throws Exception { + listenA2dp(); + + BluetoothA2dp a2dp = new BluetoothA2dp(getContext()); + + List sinks = a2dp.listConnectedSinks(); + Log.e(TAG, "listConnectedSinks()..."); + for (String sink : sinks) { + Log.e(TAG, sink + " state = " + a2dp.getSinkState(sink)); + } + } + + @MediumTest + public void testA2dpConnect() throws Exception { + listenA2dp(); + String address = SystemProperties.get("debug.a2dp.address", ""); + BluetoothA2dp a2dp = new BluetoothA2dp(getContext()); + int result = a2dp.connectSink(address); + Log.e(TAG, "connectSink(" + address + ") = " + result); + } + + @MediumTest + public void testA2dpDisconnect() throws Exception { + listenA2dp(); + String address = SystemProperties.get("debug.a2dp.address", ""); + BluetoothA2dp a2dp = new BluetoothA2dp(getContext()); + int result = a2dp.disconnectSink(address); + Log.e(TAG, "disconnectSink(" + address + ") = " + result); + } + + @MediumTest + public void testBluetoothEnabled() throws Exception { + BluetoothDevice device = + (BluetoothDevice)getContext().getSystemService(Context.BLUETOOTH_SERVICE); + if (device == null) { + Log.i(TAG, "Device not Bluetooth capable, skipping test"); + return; + } + + if (device.isEnabled()) { + Log.i(TAG, "isEnabled() = yes"); + } else { + Log.i(TAG, "isEnabled() = no"); + } + } + + @MediumTest + public void testEnableBluetooth() throws Exception { + BluetoothDevice device = + (BluetoothDevice)getContext().getSystemService(Context.BLUETOOTH_SERVICE); + if (device == null) { + Log.i(TAG, "Device not Bluetooth capable, skipping test"); + return; + } + device.enable(); + } + + @MediumTest + public void testEnableBluetoothWithCallback() throws Exception { + BluetoothDevice device = + (BluetoothDevice)getContext().getSystemService(Context.BLUETOOTH_SERVICE); + if (device == null) { + Log.i(TAG, "Device not Bluetooth capable, skipping test"); + return; + } + if (!device.enable(mCallback)) { + Log.e(TAG, "enable() failed"); + } + } + + @MediumTest + public void testDisableBluetooth() throws Exception { + BluetoothDevice device = + (BluetoothDevice)getContext().getSystemService(Context.BLUETOOTH_SERVICE); + if (device == null) { + Log.i(TAG, "Device not Bluetooth capable, skipping test"); + return; + } + device.disable(); + } + + @LargeTest + public void testDiscovery() throws Exception { + BluetoothDevice device = + (BluetoothDevice)getContext().getSystemService(Context.BLUETOOTH_SERVICE); + if (device == null) { + Log.i(TAG, "Device not Bluetooth capable, skipping test"); + return; + } + if (device.isEnabled()) { + getContext().registerReceiver((BroadcastReceiver)new TestDiscoveryReceiver(), + new IntentFilter(BluetoothIntent.REMOTE_DEVICE_FOUND_ACTION)); + Log.i(TAG, "Starting discovery..."); + String result = device.startDiscovery() ? "true" : "false"; + Log.i(TAG, "startDiscovery() = " + result); + } + } + + @LargeTest + public void testMultipleDiscovery() throws Exception { + BluetoothDevice device = + (BluetoothDevice)getContext().getSystemService(Context.BLUETOOTH_SERVICE); + if (device == null) { + Log.i(TAG, "Device not Bluetooth capable, skipping test"); + return; + } + if (device.isEnabled()) { + getContext().registerReceiver((BroadcastReceiver)new TestDiscoveryReceiver(), + new IntentFilter(BluetoothIntent.REMOTE_DEVICE_FOUND_ACTION)); + String result; + Log.i(TAG, "Starting multiple discovery..."); + for (int i = 0; i < 5; i++) { + result = device.startDiscovery() ? "true" : "false"; + Log.i(TAG, "startDiscovery() = " + result); + } + } + } + private class TestDiscoveryReceiver extends BroadcastReceiver { + @Override public void onReceive(Context context, Intent intent) { + String address = intent.getStringExtra(BluetoothIntent.ADDRESS); + int deviceClass = intent.getIntExtra(BluetoothIntent.CLASS, -1); + short rssi = intent.getShortExtra(BluetoothIntent.RSSI, (short)-1); + Log.i(TAG, "Discovered Device: " + address + " " + deviceClass + " " + rssi); + } + } + + private IBluetoothDeviceCallback mCallback = new IBluetoothDeviceCallback.Stub() { + public void onEnableResult(int res) { + String result = "unknown"; + switch (res) { + case BluetoothDevice.RESULT_SUCCESS: + result = "success"; + break; + case BluetoothDevice.RESULT_FAILURE: + result = "FAILURE"; + break; + } + Log.i(TAG, "onEnableResult(" + result + ")"); + } + public void onCreateBondingResult(String device, int res) { + String result = "unknown"; + switch (res) { + case BluetoothDevice.RESULT_SUCCESS: + result = "success"; + break; + case BluetoothDevice.RESULT_FAILURE: + result = "FAILURE"; + break; + } + Log.i(TAG, "onEnableResult(" + device + ", " + result + ")"); + } + public void onGetRemoteServiceChannelResult(String device, int channel) {} + }; + + @SmallTest + public void testCreateBondingWithCallback() throws Exception { + BluetoothDevice device = + (BluetoothDevice)getContext().getSystemService(Context.BLUETOOTH_SERVICE); + if (device == null) { + Log.i(TAG, "Device not Bluetooth capable, skipping test"); + return; + } + if (!device.createBonding("01:23:45:67:89:AB", mCallback)) { + Log.e(TAG, "createBonding() failed"); + } + } + + @SmallTest + public void testIsPeriodicDiscovery() throws Exception { + BluetoothDevice device = + (BluetoothDevice)getContext().getSystemService(Context.BLUETOOTH_SERVICE); + if (device == null) { + Log.i(TAG, "Device not Bluetooth capable, skipping test"); + return; + } + boolean ret = device.isPeriodicDiscovery(); + if (ret) { + Log.i(TAG, "isPeriodicDiscovery() = TRUE"); + } else { + Log.i(TAG, "isPeriodicDiscovery() = FALSE"); + } + } + + @LargeTest + public void testListBondings() throws Exception { + BluetoothDevice device = + (BluetoothDevice)getContext().getSystemService(Context.BLUETOOTH_SERVICE); + if (device == null) { + Log.i(TAG, "Device not Bluetooth capable, skipping test"); + return; + } + String[] addresses = device.listBondings(); + if (addresses == null) { + Log.i(TAG, "Bluetooth disabled"); + return; + } + for (String address : addresses) { + String name = device.getRemoteName(address); + Log.i(TAG, "BONDING: " + address + " (" + name + ")"); + } + } + + @LargeTest + public void testListAclConnections() throws Exception { + BluetoothDevice device = + (BluetoothDevice)getContext().getSystemService(Context.BLUETOOTH_SERVICE); + if (device == null) { + Log.i(TAG, "Device not Bluetooth capable, skipping test"); + return; + } + String[] addresses = device.listAclConnections(); + if (addresses == null) { + Log.i(TAG, "Bluetooth disabled"); + return; + } + for (String address : addresses) { + String name = device.getRemoteName(address); + Log.i(TAG, "CONNECTION: " + address + " (" + name + ")"); + } + } + + @LargeTest + public void testListRemoteDevices() throws Exception { + BluetoothDevice device = + (BluetoothDevice)getContext().getSystemService(Context.BLUETOOTH_SERVICE); + if (device == null) { + Log.i(TAG, "Device not Bluetooth capable, skipping test"); + return; + } + String[] addresses = device.listRemoteDevices(); + if (addresses == null) { + Log.i(TAG, "Bluetooth disabled"); + return; + } + for (String address : addresses) { + String name = device.getRemoteName(address); + Log.i(TAG, "KNOWN DEVICE: " + address + " (" + name + ")"); + } + } + + @MediumTest + public void testSetupBTIntentRecv() throws Exception { + BluetoothDevice device = + (BluetoothDevice)getContext().getSystemService(Context.BLUETOOTH_SERVICE); + if (device == null) { + Log.i(TAG, "Device not Bluetooth capable, skipping test"); + return; + } + if (device.isEnabled()) { + IntentFilter filter = new IntentFilter(BluetoothIntent.ENABLED_ACTION); + filter.addAction(BluetoothIntent.ENABLED_ACTION); + filter.addAction(BluetoothIntent.DISABLED_ACTION); + filter.addAction(BluetoothIntent.NAME_CHANGED_ACTION); + filter.addAction(BluetoothIntent.MODE_CHANGED_ACTION); + filter.addAction(BluetoothIntent.DISCOVERY_STARTED_ACTION); + filter.addAction(BluetoothIntent.DISCOVERY_COMPLETED_ACTION); + filter.addAction(BluetoothIntent.PAIRING_REQUEST_ACTION); + filter.addAction(BluetoothIntent.PAIRING_CANCEL_ACTION); + filter.addAction(BluetoothIntent.REMOTE_DEVICE_FOUND_ACTION); + filter.addAction(BluetoothIntent.REMOTE_DEVICE_DISAPPEARED_ACTION); + filter.addAction(BluetoothIntent.REMOTE_DEVICE_CLASS_UPDATED_ACTION); + filter.addAction(BluetoothIntent.REMOTE_DEVICE_CONNECTED_ACTION); + filter.addAction(BluetoothIntent.REMOTE_DEVICE_DISCONNECT_REQUESTED_ACTION); + filter.addAction(BluetoothIntent.REMOTE_DEVICE_DISCONNECTED_ACTION); + filter.addAction(BluetoothIntent.REMOTE_NAME_UPDATED_ACTION); + filter.addAction(BluetoothIntent.REMOTE_NAME_FAILED_ACTION); + filter.addAction(BluetoothIntent.REMOTE_ALIAS_CHANGED_ACTION); + filter.addAction(BluetoothIntent.REMOTE_ALIAS_CLEARED_ACTION); + filter.addAction(BluetoothIntent.BONDING_CREATED_ACTION); + filter.addAction(BluetoothIntent.BONDING_REMOVED_ACTION); + filter.addAction(BluetoothIntent.HEADSET_STATE_CHANGED_ACTION); + getContext().registerReceiver( + (BroadcastReceiver)new BluetoothIntentReceiver(), filter); + Log.i(TAG, "Listening for BLUETOOTH INTENTS...."); + } else { + Log.e(TAG, "BT not enabled"); + } + } + + + private class BluetoothIntentReceiver extends BroadcastReceiver { + @Override public void onReceive(Context context, Intent intent) { + String msg = ""; + + String address = intent.getStringExtra(BluetoothIntent.ADDRESS); + if (address != null) { + msg += " address=" + address; + } + + int deviceClass = intent.getIntExtra(BluetoothIntent.CLASS, BluetoothClass.ERROR); + if (deviceClass != BluetoothClass.ERROR) { + msg += " class=" + deviceClass; + } + + int rssi = intent.getIntExtra(BluetoothIntent.RSSI, -1); + if (rssi != -1) { + msg += " rssi=" + rssi; + } + + String name = intent.getStringExtra(BluetoothIntent.NAME); + if (name != null) { + msg += " name=" + name; + } + + String alias = intent.getStringExtra(BluetoothIntent.ALIAS); + if (alias != null) { + msg += " alias=" + alias; + } + + int mode = intent.getIntExtra(BluetoothIntent.MODE, -10); + if (mode != -10) { + msg += " mode=" + mode; + } + + int state = intent.getIntExtra(BluetoothIntent.HEADSET_STATE, -10); + if (state != -10) { + msg += " headset state=" + state; + } + Log.i(TAG, "BLUETOOTH INTENT: " + intent.getAction() + msg); + } + } + + + private static final int[] ALL_SERVICE_CLASSES = new int[] { + BluetoothClass.Service.LIMITED_DISCOVERABILITY, + BluetoothClass.Service.POSITIONING, + BluetoothClass.Service.NETWORKING, + BluetoothClass.Service.RENDER, + BluetoothClass.Service.CAPTURE, + BluetoothClass.Service.OBJECT_TRANSFER, + BluetoothClass.Service.AUDIO, + BluetoothClass.Service.TELEPHONY, + BluetoothClass.Service.INFORMATION + }; + private void assertOnlyTheseServiceClassesAreSupported(int deviceClass, HashSet serviceClasses) { + for (int serviceClassType : ALL_SERVICE_CLASSES) { + Assert.assertEquals(serviceClasses.contains(new Integer(serviceClassType)), + BluetoothClass.Service.hasService(deviceClass, serviceClassType)); + } + } + + @SmallTest + public void testDeviceClass() throws Exception { + // This test does not require bluetooth hardware + int deviceClass; + HashSet serviceClasses; + + deviceClass = BluetoothClass.ERROR; // bogus class + serviceClasses = new HashSet(); + assertOnlyTheseServiceClassesAreSupported(deviceClass, serviceClasses); + Assert.assertEquals(BluetoothClass.ERROR, BluetoothClass.Device.Major.getDeviceMajor(deviceClass)); + Assert.assertEquals(BluetoothClass.ERROR, BluetoothClass.Device.getDevice(deviceClass)); + + deviceClass = 0x10210C; // mac book pro + serviceClasses = new HashSet(); + serviceClasses.add(BluetoothClass.Service.OBJECT_TRANSFER); + serviceClasses.add(BluetoothClass.Service.LIMITED_DISCOVERABILITY); + assertOnlyTheseServiceClassesAreSupported(deviceClass, serviceClasses); + Assert.assertEquals(BluetoothClass.Device.Major.COMPUTER, + BluetoothClass.Device.Major.getDeviceMajor(deviceClass)); + Assert.assertEquals(0x10C, BluetoothClass.Device.getDevice(deviceClass)); + + // mac book pro with some unused bits set. Expecting the same results + deviceClass = 0xFF10210F; + serviceClasses = new HashSet(); + serviceClasses.add(BluetoothClass.Service.OBJECT_TRANSFER); + serviceClasses.add(BluetoothClass.Service.LIMITED_DISCOVERABILITY); + assertOnlyTheseServiceClassesAreSupported(deviceClass, serviceClasses); + Assert.assertEquals(BluetoothClass.Device.Major.COMPUTER, + BluetoothClass.Device.Major.getDeviceMajor(deviceClass)); + Assert.assertEquals(0x10C, BluetoothClass.Device.getDevice(deviceClass)); + + deviceClass = 0x3E0100; // droid.corp.google.com + serviceClasses = new HashSet(); + serviceClasses.add(BluetoothClass.Service.AUDIO); + serviceClasses.add(BluetoothClass.Service.OBJECT_TRANSFER); + serviceClasses.add(BluetoothClass.Service.CAPTURE); + serviceClasses.add(BluetoothClass.Service.RENDER); + serviceClasses.add(BluetoothClass.Service.NETWORKING); + assertOnlyTheseServiceClassesAreSupported(deviceClass, serviceClasses); + Assert.assertEquals(BluetoothClass.Device.Major.COMPUTER, + BluetoothClass.Device.Major.getDeviceMajor(deviceClass)); + Assert.assertEquals(0x100, BluetoothClass.Device.getDevice(deviceClass)); + + deviceClass = 0x40020C; // Android + serviceClasses = new HashSet(); + serviceClasses.add(BluetoothClass.Service.TELEPHONY); + assertOnlyTheseServiceClassesAreSupported(deviceClass, serviceClasses); + Assert.assertEquals(BluetoothClass.Device.Major.PHONE, BluetoothClass.Device.Major.getDeviceMajor(deviceClass)); + Assert.assertEquals(0x20C, BluetoothClass.Device.getDevice(deviceClass)); + + // Motorola T305 & Jabra BT125 & Jabra BT250V + // This seems to be a very common headset & handsfree device code + deviceClass = 0x200404; + serviceClasses = new HashSet(); + serviceClasses.add(BluetoothClass.Service.AUDIO); + assertOnlyTheseServiceClassesAreSupported(deviceClass, serviceClasses); + Assert.assertEquals(BluetoothClass.Device.Major.AUDIO_VIDEO, + BluetoothClass.Device.Major.getDeviceMajor(deviceClass)); + Assert.assertEquals(BluetoothClass.Device.AUDIO_VIDEO_WEARABLE_HEADSET, + BluetoothClass.Device.getDevice(deviceClass)); + + // Audi UHV 0128 + deviceClass = 0x200408; + serviceClasses = new HashSet(); + serviceClasses.add(BluetoothClass.Service.AUDIO); + assertOnlyTheseServiceClassesAreSupported(deviceClass, serviceClasses); + Assert.assertEquals(BluetoothClass.Device.Major.AUDIO_VIDEO, + BluetoothClass.Device.Major.getDeviceMajor(deviceClass)); + Assert.assertEquals(BluetoothClass.Device.AUDIO_VIDEO_HANDSFREE, + BluetoothClass.Device.getDevice(deviceClass)); + } +} diff --git a/tests/AndroidTests/src/com/android/unit_tests/BrickDeniedTest.java b/tests/AndroidTests/src/com/android/unit_tests/BrickDeniedTest.java new file mode 100644 index 0000000000000000000000000000000000000000..0f2b23ba6eaf8be9a79b57c21ea224035eaf7426 --- /dev/null +++ b/tests/AndroidTests/src/com/android/unit_tests/BrickDeniedTest.java @@ -0,0 +1,33 @@ +/* + * 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.android.unit_tests; + +import android.content.Intent; +import android.test.AndroidTestCase; +import android.test.suitebuilder.annotation.MediumTest; + +/** Test to make sure brick intents don't work without permission. */ +public class BrickDeniedTest extends AndroidTestCase { + @MediumTest + public void testBrick() { + // Try both the old and new brick intent names. Neither should work, + // since this test application doesn't have the required permission. + // If it does work, well, the test certainly won't pass. + getContext().sendBroadcast(new Intent("SHES_A_BRICK_HOUSE")); + getContext().sendBroadcast(new Intent("android.intent.action.BRICK")); + } +} diff --git a/tests/AndroidTests/src/com/android/unit_tests/BuildTest.java b/tests/AndroidTests/src/com/android/unit_tests/BuildTest.java new file mode 100644 index 0000000000000000000000000000000000000000..a8c51f4bef0a8003ea749bcae09c89155fcf19b4 --- /dev/null +++ b/tests/AndroidTests/src/com/android/unit_tests/BuildTest.java @@ -0,0 +1,130 @@ +/* + * 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.android.unit_tests; + +import android.os.Build; +import android.server.data.BuildData; +import android.test.suitebuilder.annotation.SmallTest; +import android.util.Log; +import junit.framework.Assert; +import junit.framework.TestCase; + +/** + * Provides test cases for android.os.Build and android.server.data.BuildData, + * and, in turn, many of the system properties set by the build system. + */ +public class BuildTest extends TestCase { + + private static final String TAG = "BuildTest"; + + /** + * Asserts that a String is non-null and non-empty. If it is not, + * an AssertionFailedError is thrown with the given message. + */ + private static void assertNotEmpty(String message, String string) { + //Log.i(TAG, "" + message + ": " + string); + assertNotNull(message, string); + assertFalse(message, string.equals("")); + } + + /** + * Asserts that a String is non-null and non-empty. If it is not, + * an AssertionFailedError is thrown. + */ + private static void assertNotEmpty(String string) { + assertNotEmpty(null, string); + } + + /** + * Asserts that all android.os.Build fields are non-empty and/or in a valid range. + */ + @SmallTest + public void testBuildFields() throws Exception { + assertNotEmpty("ID", Build.ID); + assertNotEmpty("PRODUCT", Build.PRODUCT); + assertNotEmpty("DEVICE", Build.DEVICE); + assertNotEmpty("BOARD", Build.BOARD); + assertNotEmpty("BRAND", Build.BRAND); + assertNotEmpty("MODEL", Build.MODEL); + assertNotEmpty("VERSION.INCREMENTAL", Build.VERSION.INCREMENTAL); + assertNotEmpty("VERSION.RELEASE", Build.VERSION.RELEASE); + assertNotEmpty("TYPE", Build.TYPE); + Assert.assertNotNull("TAGS", Build.TAGS); // TAGS is allowed to be empty. + assertNotEmpty("FINGERPRINT", Build.FINGERPRINT); + Assert.assertTrue("TIME", Build.TIME > 0); + assertNotEmpty("USER", Build.USER); + assertNotEmpty("HOST", Build.HOST); + + // TODO: if any of the android.os.Build fields have additional constraints + // (e.g., must be a C identifier, must be a valid filename, must not contain any spaces) + // add tests for them. + } + + /** + * Asserts that android.server.data.BuildData behaves as expected. + */ + @SmallTest + public void testBuildData() throws Exception { + BuildData bd; + + /* + * Default constructor + */ + bd = new BuildData(); + assertNotEmpty(bd.getFingerprint()); + assertNotEmpty(bd.getIncrementalVersion()); + Assert.assertTrue(bd.getTime() > 0); + + /* + * Explicit constructor + */ + final String FINGERPRINT = "fingerprint"; + final String INCREMENTAL_VERSION = "74321"; // a valid long, for the serialization test + final long TIME = 12345; + bd = new BuildData(FINGERPRINT, INCREMENTAL_VERSION, TIME); + Assert.assertEquals(FINGERPRINT, bd.getFingerprint()); + Assert.assertEquals(INCREMENTAL_VERSION, bd.getIncrementalVersion()); + Assert.assertTrue(bd.getTime() == TIME); + +// The serialization methods are package-private. +// +// import java.io.ByteArrayInputStream; +// import java.io.ByteArrayOutputStream; +// import java.io.DataInputStream; +// import java.io.DataOutputStream; +// +// /* +// * Serialization +// */ +// ByteArrayOutputStream out = new ByteArrayOutputStream(); +// bd.write(new DataOutputStream(out)); +// Assert.assertTrue(out.size() > 0); +// +// /* +// * Deserialization +// * +// * The current version of BuildData converts the incremental version to +// * and from a long when serializing/deserializing. Future versions should +// * treat it as a string. +// */ +// BuildData bd2 = +// new BuildData(new DataInputStream(new ByteArrayInputStream(out.toByteArray()))); +// Assert.assertEquals(bd.getFingerprint(), bd2.getFingerprint()); +// Assert.assertEquals(bd.getIncrementalVersion(), bd2.getIncrementalVersion()); +// Assert.assertTrue(bd.getTime() == bd2.getTime()); + } +} diff --git a/tests/AndroidTests/src/com/android/unit_tests/CharSequencesTest.java b/tests/AndroidTests/src/com/android/unit_tests/CharSequencesTest.java new file mode 100644 index 0000000000000000000000000000000000000000..092f309189ad42fdf42299bfc635480697082bd9 --- /dev/null +++ b/tests/AndroidTests/src/com/android/unit_tests/CharSequencesTest.java @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2007 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.android.unit_tests; + +import com.android.internal.util.CharSequences; +import static com.android.internal.util.CharSequences.forAsciiBytes; +import junit.framework.TestCase; +import android.test.suitebuilder.annotation.SmallTest; + +public class CharSequencesTest extends TestCase { + + @SmallTest + public void testCharSequences() { + String s = "Crazy Bob"; + byte[] bytes = s.getBytes(); + + String copy = toString(forAsciiBytes(bytes)); + assertTrue(s.equals(copy)); + + copy = toString(forAsciiBytes(bytes, 0, s.length())); + assertTrue(s.equals(copy)); + + String crazy = toString(forAsciiBytes(bytes, 0, 5)); + assertTrue("Crazy".equals(crazy)); + + String a = toString(forAsciiBytes(bytes, 0, 3).subSequence(2, 3)); + assertTrue("a".equals(a)); + + String empty = toString(forAsciiBytes(bytes, 0, 3).subSequence(3, 3)); + assertTrue("".equals(empty)); + + assertTrue(CharSequences.equals("bob", "bob")); + assertFalse(CharSequences.equals("b", "bob")); + assertFalse(CharSequences.equals("", "bob")); + } + + /** + * Converts a CharSequence to a string the slow way. Useful for testing + * a CharSequence implementation. + */ + static String toString(CharSequence charSequence) { + return new StringBuilder().append(charSequence).toString(); + } +} diff --git a/tests/AndroidTests/src/com/android/unit_tests/CheckinProviderTest.java b/tests/AndroidTests/src/com/android/unit_tests/CheckinProviderTest.java new file mode 100644 index 0000000000000000000000000000000000000000..f9a2ec0f08a6d0c6ff9f27820c0059313987e368 --- /dev/null +++ b/tests/AndroidTests/src/com/android/unit_tests/CheckinProviderTest.java @@ -0,0 +1,187 @@ +/* + * Copyright (C) 2006 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.android.unit_tests; + +import org.apache.commons.codec.binary.Base64; + +import android.content.ContentResolver; +import android.content.ContentValues; +import android.content.ContentUris; +import android.database.Cursor; +import android.net.Uri; +import android.provider.Checkin; +import android.server.checkin.CheckinProvider; +import android.server.data.BuildData; +import android.server.data.CrashData; +import android.server.data.ThrowableData; +import android.test.AndroidTestCase; +import android.test.suitebuilder.annotation.MediumTest; +import android.test.suitebuilder.annotation.SmallTest; + +import java.io.DataInputStream; +import java.io.ByteArrayInputStream; + +/** Unit test for {@link CheckinProvider}. */ +public class CheckinProviderTest extends AndroidTestCase { + @MediumTest + public void testEventReport() { + long start = System.currentTimeMillis(); + ContentResolver r = getContext().getContentResolver(); + Checkin.logEvent(r, Checkin.Events.Tag.TEST, "Test Value"); + + Cursor c = r.query(Checkin.Events.CONTENT_URI, + null, + Checkin.Events.TAG + "=?", + new String[] { Checkin.Events.Tag.TEST.toString() }, + null); + + long id = -1; + while (c.moveToNext()) { + String tag = c.getString(c.getColumnIndex(Checkin.Events.TAG)); + String value = c.getString(c.getColumnIndex(Checkin.Events.VALUE)); + long date = c.getLong(c.getColumnIndex(Checkin.Events.DATE)); + assertEquals(Checkin.Events.Tag.TEST.toString(), tag); + if ("Test Value".equals(value) && date >= start) { + assertTrue(id < 0); + id = c.getInt(c.getColumnIndex(Checkin.Events._ID)); + } + } + assertTrue(id > 0); + + int rows = r.delete(ContentUris.withAppendedId(Checkin.Events.CONTENT_URI, id), null, null); + assertEquals(1, rows); + c.requery(); + while (c.moveToNext()) { + long date = c.getLong(c.getColumnIndex(Checkin.Events.DATE)); + assertTrue(date < start); // Have deleted the only newer TEST. + } + + c.close(); + } + + @MediumTest + public void testStatsUpdate() { + ContentResolver r = getContext().getContentResolver(); + + // First, delete any existing data associated with the TEST tag. + Uri uri = Checkin.updateStats(r, Checkin.Stats.Tag.TEST, 0, 0); + assertNotNull(uri); + assertEquals(1, r.delete(uri, null, null)); + assertFalse(r.query(uri, null, null, null, null).moveToNext()); + + // Now, add a known quantity to the TEST tag. + Uri u2 = Checkin.updateStats(r, Checkin.Stats.Tag.TEST, 1, 0.5); + assertFalse(uri.equals(u2)); + + Cursor c = r.query(u2, null, null, null, null); + assertTrue(c.moveToNext()); + assertEquals(1, c.getInt(c.getColumnIndex(Checkin.Stats.COUNT))); + assertEquals(0.5, c.getDouble(c.getColumnIndex(Checkin.Stats.SUM))); + assertFalse(c.moveToNext()); // Only one. + + // Add another known quantity to TEST (should sum with the first). + Uri u3 = Checkin.updateStats(r, Checkin.Stats.Tag.TEST, 2, 1.0); + assertEquals(u2, u3); + c.requery(); + assertTrue(c.moveToNext()); + assertEquals(3, c.getInt(c.getColumnIndex(Checkin.Stats.COUNT))); + assertEquals(1.5, c.getDouble(c.getColumnIndex(Checkin.Stats.SUM))); + assertFalse(c.moveToNext()); // Only one. + + // Now subtract the values; the whole row should disappear. + Uri u4 = Checkin.updateStats(r, Checkin.Stats.Tag.TEST, -3, -1.5); + assertNull(u4); + c.requery(); + assertFalse(c.moveToNext()); // Row has been deleted. + c.close(); + } + + @MediumTest + public void testCrashReport() throws Exception { + long start = System.currentTimeMillis(); + ContentResolver r = getContext().getContentResolver(); + + // Log a test (fake) crash report. + Checkin.reportCrash(r, new CrashData( + "Test", + "Test Activity", + new BuildData("Test Build", "123", start), + new ThrowableData(new RuntimeException("Test Exception")))); + + + // Crashes aren't indexed; go through them all to find the one we added. + Cursor c = r.query(Checkin.Crashes.CONTENT_URI, null, null, null, null); + + Uri uri = null; + while (c.moveToNext()) { + String coded = c.getString(c.getColumnIndex(Checkin.Crashes.DATA)); + byte[] bytes = Base64.decodeBase64(coded.getBytes()); + CrashData crash = new CrashData( + new DataInputStream(new ByteArrayInputStream(bytes))); + + // Should be exactly one recently added "Test" crash. + if (crash.getId().equals("Test") && crash.getTime() > start) { + assertEquals("Test Activity", crash.getActivity()); + assertEquals("Test Build", crash.getBuildData().getFingerprint()); + assertEquals("Test Exception", + crash.getThrowableData().getMessage()); + + assertNull(uri); + uri = ContentUris.withAppendedId(Checkin.Crashes.CONTENT_URI, c.getInt(c.getColumnIndex(Checkin.Crashes._ID))); + } + } + assertNotNull(uri); + c.close(); + + // Update the "logs" column. + ContentValues values = new ContentValues(); + values.put(Checkin.Crashes.LOGS, "Test Logs"); + assertEquals(1, r.update(uri, values, null, null)); + + c = r.query(uri, null, null, null, null); + assertTrue(c.moveToNext()); + String logs = c.getString(c.getColumnIndex(Checkin.Crashes.LOGS)); + assertEquals("Test Logs", logs); + c.deleteRow(); + c.close(); + + c.requery(); + assertFalse(c.moveToNext()); + c.close(); + } + + @MediumTest + public void testPropertiesRestricted() throws Exception { + ContentResolver r = getContext().getContentResolver(); + + // The test app doesn't have the permission to access properties, + // so any attempt to do so should fail. + try { + r.insert(Checkin.Properties.CONTENT_URI, new ContentValues()); + fail("SecurityException expected"); + } catch (SecurityException e) { + // expected + } + + try { + r.query(Checkin.Properties.CONTENT_URI, null, null, null, null); + fail("SecurityException expected"); + } catch (SecurityException e) { + // expected + } + } +} diff --git a/tests/AndroidTests/src/com/android/unit_tests/ComponentTest.java b/tests/AndroidTests/src/com/android/unit_tests/ComponentTest.java new file mode 100644 index 0000000000000000000000000000000000000000..08fe7427f25e8980f434103691cbc1580a858758 --- /dev/null +++ b/tests/AndroidTests/src/com/android/unit_tests/ComponentTest.java @@ -0,0 +1,738 @@ +/* + * 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.android.unit_tests; + +import com.android.unit_tests.enabled_app.DisabledActivity; +import com.android.unit_tests.enabled_app.DisabledProvider; +import com.android.unit_tests.enabled_app.DisabledReceiver; +import com.android.unit_tests.enabled_app.DisabledService; +import com.android.unit_tests.enabled_app.EnabledActivity; +import com.android.unit_tests.enabled_app.EnabledProvider; +import com.android.unit_tests.enabled_app.EnabledReceiver; +import com.android.unit_tests.enabled_app.EnabledService; + +import android.content.ComponentName; +import android.content.Intent; +import android.content.pm.ActivityInfo; +import android.content.pm.ComponentInfo; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; +import android.test.suitebuilder.annotation.LargeTest; +import android.test.suitebuilder.annotation.MediumTest; +import android.test.suitebuilder.annotation.SmallTest; +import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DEFAULT; +import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED; +import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_ENABLED; +import static android.content.pm.PackageManager.GET_DISABLED_COMPONENTS; +import android.content.pm.ProviderInfo; +import android.content.pm.ResolveInfo; +import android.content.pm.ServiceInfo; +import android.test.AndroidTestCase; + +import java.util.List; + +/** + * Tests for disabling and enabling application components. + * + * Note: These tests are on the slow side. This is probably because most of the tests trigger the + * package settings file to get written out by the PackageManagerService. Better, more unit-y test + * would fix this. + */ + +public class ComponentTest extends AndroidTestCase { + + private PackageManager mPackageManager; + private Intent mDisabledActivityIntent; + private Intent mEnabledActivityIntent; + private Intent mDisabledServiceIntent; + private Intent mEnabledServiceIntent; + private Intent mDisabledReceiverIntent; + private Intent mEnabledReceiverIntent; + private Intent mDisabledAppEnabledActivityIntent; + + private static final String ENABLED_PACKAGENAME = + "com.android.unit_tests.enabled_app"; + private static final String DISABLED_PACKAGENAME = + "com.android.unit_tests.disabled_app"; + private static final String DISABLED_ACTIVITY_CLASSNAME = + DisabledActivity.class.getName(); + private static final ComponentName DISABLED_ACTIVITY_COMPONENTNAME = + new ComponentName(ENABLED_PACKAGENAME, DISABLED_ACTIVITY_CLASSNAME); + private static final String ENABLED_ACTIVITY_CLASSNAME = + EnabledActivity.class.getName(); + private static final ComponentName ENABLED_ACTIVITY_COMPONENTNAME = + new ComponentName(ENABLED_PACKAGENAME, ENABLED_ACTIVITY_CLASSNAME); + private static final String DISABLED_SERVICE_CLASSNAME = + DisabledService.class.getName(); + private static final ComponentName DISABLED_SERVICE_COMPONENTNAME = + new ComponentName(ENABLED_PACKAGENAME, DISABLED_SERVICE_CLASSNAME); + private static final String DISABLED_PROVIDER_CLASSNAME = + DisabledProvider.class.getName(); + private static final ComponentName DISABLED_PROVIDER_COMPONENTNAME = + new ComponentName(ENABLED_PACKAGENAME, DISABLED_PROVIDER_CLASSNAME); + private static final String DISABLED_PROVIDER_NAME = DisabledProvider.class.getName(); + private static final String ENABLED_SERVICE_CLASSNAME = + EnabledService.class.getName(); + private static final ComponentName ENABLED_SERVICE_COMPONENTNAME = + new ComponentName(ENABLED_PACKAGENAME, ENABLED_SERVICE_CLASSNAME); + private static final String DISABLED_RECEIVER_CLASSNAME = + DisabledReceiver.class.getName(); + private static final ComponentName DISABLED_RECEIVER_COMPONENTNAME = + new ComponentName(ENABLED_PACKAGENAME, DISABLED_RECEIVER_CLASSNAME); + private static final String ENABLED_RECEIVER_CLASSNAME = + EnabledReceiver.class.getName(); + private static final ComponentName ENABLED_RECEIVER_COMPONENTNAME = + new ComponentName(ENABLED_PACKAGENAME, ENABLED_RECEIVER_CLASSNAME); + private static final String ENABLED_PROVIDER_CLASSNAME = + EnabledProvider.class.getName(); + private static final ComponentName ENABLED_PROVIDER_COMPONENTNAME = + new ComponentName(ENABLED_PACKAGENAME, ENABLED_PROVIDER_CLASSNAME); + private static final String ENABLED_PROVIDER_NAME = EnabledProvider.class.getName(); + private static final String DISABLED_APP_ENABLED_ACTIVITY_CLASSNAME = + com.android.unit_tests.disabled_app.EnabledActivity.class.getName(); + private static final ComponentName DISABLED_APP_ENABLED_ACTIVITY_COMPONENTNAME = + new ComponentName(DISABLED_PACKAGENAME, DISABLED_APP_ENABLED_ACTIVITY_CLASSNAME); + private static final String TEST_CATEGORY = + "com.android.unit_tests.enabled_app.TEST_CATEGORY"; + + @Override + protected void setUp() throws Exception { + super.setUp(); + mPackageManager = mContext.getPackageManager(); + mDisabledActivityIntent = new Intent(); + mDisabledActivityIntent.setComponent(DISABLED_ACTIVITY_COMPONENTNAME); + mEnabledActivityIntent = new Intent(); + mEnabledActivityIntent.setComponent(ENABLED_ACTIVITY_COMPONENTNAME); + mDisabledServiceIntent = new Intent(); + mDisabledServiceIntent.setComponent(DISABLED_SERVICE_COMPONENTNAME); + mEnabledServiceIntent = new Intent(); + mEnabledServiceIntent.setComponent(ENABLED_SERVICE_COMPONENTNAME); + mDisabledReceiverIntent = new Intent("android.intent.action.ENABLED_APP_DISABLED_RECEIVER"); + mDisabledReceiverIntent.setComponent(DISABLED_RECEIVER_COMPONENTNAME); + mEnabledReceiverIntent = new Intent("android.intent.action.ENABLED_APP_ENABLED_RECEIVER"); + mEnabledReceiverIntent.setComponent(ENABLED_RECEIVER_COMPONENTNAME); + mDisabledAppEnabledActivityIntent = new Intent(); + mDisabledAppEnabledActivityIntent.setComponent(DISABLED_APP_ENABLED_ACTIVITY_COMPONENTNAME); + } + + @SmallTest + public void testContextNotNull() throws Exception { + assertNotNull(mContext); + } + + @MediumTest + public void testResolveDisabledActivity() throws Exception { + mPackageManager.setComponentEnabledSetting(DISABLED_ACTIVITY_COMPONENTNAME, + COMPONENT_ENABLED_STATE_DEFAULT, + PackageManager.DONT_KILL_APP); + + final ResolveInfo info = mPackageManager.resolveActivity(mDisabledActivityIntent, 0); + assertNull(info); + + final ResolveInfo info2 = mPackageManager.resolveActivity( + mDisabledActivityIntent, GET_DISABLED_COMPONENTS); + assertNotNull(info2); + assertNotNull(info2.activityInfo); + assertFalse(info2.activityInfo.enabled); + } + + @MediumTest + public void testResolveEnabledActivity() throws Exception { + mPackageManager.setComponentEnabledSetting(ENABLED_ACTIVITY_COMPONENTNAME, + COMPONENT_ENABLED_STATE_DEFAULT, + PackageManager.DONT_KILL_APP); + + final ResolveInfo info = mPackageManager.resolveActivity(mEnabledActivityIntent, 0); + assertNotNull(info); + assertNotNull(info); + assertNotNull(info.activityInfo); + assertTrue(info.activityInfo.enabled); + } + + @MediumTest + public void testQueryDisabledActivity() throws Exception { + mPackageManager.setComponentEnabledSetting(DISABLED_ACTIVITY_COMPONENTNAME, + COMPONENT_ENABLED_STATE_DEFAULT, + PackageManager.DONT_KILL_APP); + + final List infoList = + mPackageManager.queryIntentActivities(mDisabledActivityIntent, 0); + assertEquals(0, infoList.size()); + + final List infoList2 = + mPackageManager.queryIntentActivities(mDisabledActivityIntent, + GET_DISABLED_COMPONENTS); + assertEquals(1, infoList2.size()); + final ResolveInfo info = infoList2.get(0); + assertNotNull(info); + assertNotNull(info.activityInfo); + assertFalse(info.activityInfo.enabled); + } + + @MediumTest + public void testQueryEnabledActivity() throws Exception { + mPackageManager.setComponentEnabledSetting(ENABLED_ACTIVITY_COMPONENTNAME, + COMPONENT_ENABLED_STATE_DEFAULT, + PackageManager.DONT_KILL_APP); + + final List infoList = + mPackageManager.queryIntentActivities(mEnabledActivityIntent, 0); + assertEquals(1, infoList.size()); + final ResolveInfo info = infoList.get(0); + assertNotNull(info); + assertNotNull(info.activityInfo); + assertTrue(info.activityInfo.enabled); + } + + @MediumTest + public void testGetDisabledActivityInfo() throws Exception { + mPackageManager.setComponentEnabledSetting(DISABLED_ACTIVITY_COMPONENTNAME, + COMPONENT_ENABLED_STATE_DEFAULT, + PackageManager.DONT_KILL_APP); + + try { + mPackageManager.getActivityInfo(DISABLED_ACTIVITY_COMPONENTNAME, 0); + fail("Attempt to get info on disabled component should fail."); + } catch (PackageManager.NameNotFoundException e) { + // expected + } + + final ActivityInfo activityInfo = + mPackageManager.getActivityInfo(DISABLED_ACTIVITY_COMPONENTNAME, + GET_DISABLED_COMPONENTS); + assertNotNull(activityInfo); + assertFalse(activityInfo.enabled); + } + + @MediumTest + public void testGetEnabledActivityInfo() throws Exception { + mPackageManager.setComponentEnabledSetting(ENABLED_ACTIVITY_COMPONENTNAME, + COMPONENT_ENABLED_STATE_DEFAULT, + PackageManager.DONT_KILL_APP); + + ActivityInfo activityInfo = + mPackageManager.getActivityInfo(ENABLED_ACTIVITY_COMPONENTNAME, 0); + assertNotNull(activityInfo); + assertTrue(activityInfo.enabled); + } + + @MediumTest + public void testEnableActivity() throws Exception { + mPackageManager.setComponentEnabledSetting(DISABLED_ACTIVITY_COMPONENTNAME, + COMPONENT_ENABLED_STATE_DEFAULT, + PackageManager.DONT_KILL_APP); + + final ResolveInfo info = mPackageManager.resolveActivity(mDisabledActivityIntent, 0); + assertNull(info); + mPackageManager.setComponentEnabledSetting(DISABLED_ACTIVITY_COMPONENTNAME, + COMPONENT_ENABLED_STATE_ENABLED, + PackageManager.DONT_KILL_APP); + final ResolveInfo info2 = + mPackageManager.resolveActivity(mDisabledActivityIntent, + 0); + assertNotNull(info2); + assertNotNull(info2.activityInfo); + assertFalse(info2.activityInfo.enabled); + + final List infoList = + mPackageManager.queryIntentActivities(mDisabledActivityIntent, 0); + assertEquals(1, infoList.size()); + } + + @LargeTest + public void testDisableActivity() throws Exception { + mPackageManager.setComponentEnabledSetting(ENABLED_ACTIVITY_COMPONENTNAME, + COMPONENT_ENABLED_STATE_DEFAULT, + PackageManager.DONT_KILL_APP); + + final ResolveInfo info = mPackageManager.resolveActivity(mEnabledActivityIntent, 0); + assertNotNull(info); + assertNotNull(info.activityInfo); + mPackageManager.setComponentEnabledSetting(ENABLED_ACTIVITY_COMPONENTNAME, + COMPONENT_ENABLED_STATE_DISABLED, + PackageManager.DONT_KILL_APP); + final ResolveInfo info2 = + mPackageManager.resolveActivity(mEnabledActivityIntent, + 0); + assertNull(info2); + + final ResolveInfo info3 = mPackageManager.resolveActivity(mEnabledActivityIntent, + GET_DISABLED_COMPONENTS); + assertNotNull(info3); + assertNotNull(info3.activityInfo); + assertTrue(info3.activityInfo.enabled); + + final List infoList = + mPackageManager.queryIntentActivities(mEnabledActivityIntent, 0); + assertEquals(0, infoList.size()); + } + + @MediumTest + public void testResolveDisabledService() throws Exception { + mPackageManager.setComponentEnabledSetting(DISABLED_SERVICE_COMPONENTNAME, + COMPONENT_ENABLED_STATE_DEFAULT, + PackageManager.DONT_KILL_APP); + + final ResolveInfo info = mPackageManager.resolveService(mDisabledServiceIntent, 0); + assertNull(info); + + final ResolveInfo info2 = mPackageManager.resolveService( + mDisabledServiceIntent, GET_DISABLED_COMPONENTS); + assertNotNull(info2); + assertNotNull(info2.serviceInfo); + assertFalse(info2.serviceInfo.enabled); + } + + @MediumTest + public void testResolveEnabledService() throws Exception { + mPackageManager.setComponentEnabledSetting(ENABLED_SERVICE_COMPONENTNAME, + COMPONENT_ENABLED_STATE_DEFAULT, + PackageManager.DONT_KILL_APP); + + final ResolveInfo info = mPackageManager.resolveService(mEnabledServiceIntent, 0); + assertNotNull(info); + assertNotNull(info); + assertNotNull(info.serviceInfo); + assertTrue(info.serviceInfo.enabled); + } + + @MediumTest + public void testQueryDisabledService() throws Exception { + mPackageManager.setComponentEnabledSetting(DISABLED_SERVICE_COMPONENTNAME, + COMPONENT_ENABLED_STATE_DEFAULT, + PackageManager.DONT_KILL_APP); + + final List infoList = + mPackageManager.queryIntentServices(mDisabledServiceIntent, 0); + assertEquals(0, infoList.size()); + + final List infoList2 = + mPackageManager.queryIntentServices(mDisabledServiceIntent, + GET_DISABLED_COMPONENTS); + assertEquals(1, infoList2.size()); + final ResolveInfo info = infoList2.get(0); + assertNotNull(info); + assertNotNull(info.serviceInfo); + assertFalse(info.serviceInfo.enabled); + } + + @MediumTest + public void testQueryEnabledService() throws Exception { + mPackageManager.setComponentEnabledSetting(ENABLED_SERVICE_COMPONENTNAME, + COMPONENT_ENABLED_STATE_DEFAULT, + PackageManager.DONT_KILL_APP); + + final List infoList = + mPackageManager.queryIntentServices(mEnabledServiceIntent, 0); + assertEquals(1, infoList.size()); + final ResolveInfo info = infoList.get(0); + assertNotNull(info); + assertNotNull(info.serviceInfo); + assertTrue(info.serviceInfo.enabled); + } + + @MediumTest + public void testGetDisabledServiceInfo() throws Exception { + mPackageManager.setComponentEnabledSetting(DISABLED_SERVICE_COMPONENTNAME, + COMPONENT_ENABLED_STATE_DEFAULT, + PackageManager.DONT_KILL_APP); + + try { + mPackageManager.getServiceInfo(DISABLED_SERVICE_COMPONENTNAME, 0); + fail("Attempt to get info on disabled component should fail."); + } catch (PackageManager.NameNotFoundException e) { + // expected + } + + final ServiceInfo serviceInfo = + mPackageManager.getServiceInfo(DISABLED_SERVICE_COMPONENTNAME, + GET_DISABLED_COMPONENTS); + assertNotNull(serviceInfo); + assertFalse(serviceInfo.enabled); + } + + @MediumTest + public void testGetEnabledServiceInfo() throws Exception { + mPackageManager.setComponentEnabledSetting(ENABLED_SERVICE_COMPONENTNAME, + COMPONENT_ENABLED_STATE_DEFAULT, + PackageManager.DONT_KILL_APP); + + ServiceInfo serviceInfo = + mPackageManager.getServiceInfo(ENABLED_SERVICE_COMPONENTNAME, 0); + assertNotNull(serviceInfo); + assertTrue(serviceInfo.enabled); + } + + @MediumTest + public void testEnableService() throws Exception { + mPackageManager.setComponentEnabledSetting(DISABLED_SERVICE_COMPONENTNAME, + COMPONENT_ENABLED_STATE_DEFAULT, + PackageManager.DONT_KILL_APP); + + final ResolveInfo info = mPackageManager.resolveService(mDisabledServiceIntent, 0); + assertNull(info); + mPackageManager.setComponentEnabledSetting(DISABLED_SERVICE_COMPONENTNAME, + COMPONENT_ENABLED_STATE_ENABLED, + PackageManager.DONT_KILL_APP); + final ResolveInfo info2 = + mPackageManager.resolveService(mDisabledServiceIntent, + 0); + assertNotNull(info2); + assertNotNull(info2.serviceInfo); + assertFalse(info2.serviceInfo.enabled); + } + + @LargeTest + public void testDisableService() throws Exception { + mPackageManager.setComponentEnabledSetting(ENABLED_SERVICE_COMPONENTNAME, + COMPONENT_ENABLED_STATE_DEFAULT, + PackageManager.DONT_KILL_APP); + + final ResolveInfo info = mPackageManager.resolveService(mEnabledServiceIntent, 0); + assertNotNull(info); + assertNotNull(info.serviceInfo); + mPackageManager.setComponentEnabledSetting(ENABLED_SERVICE_COMPONENTNAME, + COMPONENT_ENABLED_STATE_DISABLED, + PackageManager.DONT_KILL_APP); + final ResolveInfo info2 = + mPackageManager.resolveService(mEnabledServiceIntent, + 0); + assertNull(info2); + + final ResolveInfo info3 = mPackageManager.resolveService(mEnabledServiceIntent, + GET_DISABLED_COMPONENTS); + assertNotNull(info3); + assertNotNull(info3.serviceInfo); + assertTrue(info3.serviceInfo.enabled); + } + + @MediumTest + public void testQueryDisabledReceiver() throws Exception { + mPackageManager.setComponentEnabledSetting(DISABLED_RECEIVER_COMPONENTNAME, + COMPONENT_ENABLED_STATE_DEFAULT, + PackageManager.DONT_KILL_APP); + + final List infoList = + mPackageManager.queryBroadcastReceivers(mDisabledReceiverIntent, 0); + assertEquals(0, infoList.size()); + + final List infoList2 = + mPackageManager.queryBroadcastReceivers(mDisabledReceiverIntent, + GET_DISABLED_COMPONENTS); + assertEquals(1, infoList2.size()); + final ResolveInfo info = infoList2.get(0); + assertNotNull(info); + assertNotNull(info.activityInfo); + assertFalse(info.activityInfo.enabled); + } + + @MediumTest + public void testQueryEnabledReceiver() throws Exception { + mPackageManager.setComponentEnabledSetting(ENABLED_RECEIVER_COMPONENTNAME, + COMPONENT_ENABLED_STATE_DEFAULT, + PackageManager.DONT_KILL_APP); + + final List infoList = + mPackageManager.queryBroadcastReceivers(mEnabledReceiverIntent, 0); + assertEquals(1, infoList.size()); + final ResolveInfo info = infoList.get(0); + assertNotNull(info); + assertNotNull(info.activityInfo); + assertTrue(info.activityInfo.enabled); + } + + @MediumTest + public void testGetDisabledReceiverInfo() throws Exception { + mPackageManager.setComponentEnabledSetting(DISABLED_RECEIVER_COMPONENTNAME, + COMPONENT_ENABLED_STATE_DEFAULT, + PackageManager.DONT_KILL_APP); + + try { + mPackageManager.getReceiverInfo(DISABLED_RECEIVER_COMPONENTNAME, 0); + fail("Attempt to get info on disabled component should fail."); + } catch (PackageManager.NameNotFoundException e) { + // expected + } + + final ActivityInfo activityInfo = + mPackageManager.getReceiverInfo(DISABLED_RECEIVER_COMPONENTNAME, + GET_DISABLED_COMPONENTS); + assertNotNull(activityInfo); + assertFalse(activityInfo.enabled); + } + + @MediumTest + public void testGetEnabledReceiverInfo() throws Exception { + mPackageManager.setComponentEnabledSetting(ENABLED_RECEIVER_COMPONENTNAME, + COMPONENT_ENABLED_STATE_DEFAULT, + PackageManager.DONT_KILL_APP); + + ActivityInfo activityInfo = + mPackageManager.getReceiverInfo(ENABLED_RECEIVER_COMPONENTNAME, 0); + assertNotNull(activityInfo); + assertTrue(activityInfo.enabled); + } + + @MediumTest + public void testEnableReceiver() throws Exception { + mPackageManager.setComponentEnabledSetting(DISABLED_RECEIVER_COMPONENTNAME, + COMPONENT_ENABLED_STATE_DEFAULT, + PackageManager.DONT_KILL_APP); + + try { + mPackageManager.getReceiverInfo(DISABLED_RECEIVER_COMPONENTNAME, 0); + fail("Attempt to get info on disabled component should fail."); + } catch (PackageManager.NameNotFoundException e) { + // expected + } + + mPackageManager.setComponentEnabledSetting(DISABLED_RECEIVER_COMPONENTNAME, + COMPONENT_ENABLED_STATE_ENABLED, + PackageManager.DONT_KILL_APP); + ActivityInfo activityInfo = + mPackageManager.getReceiverInfo(DISABLED_RECEIVER_COMPONENTNAME, 0); + assertNotNull(activityInfo); + assertFalse(activityInfo.enabled); + } + + @MediumTest + public void testDisableReceiver() throws Exception { + mPackageManager.setComponentEnabledSetting(ENABLED_RECEIVER_COMPONENTNAME, + COMPONENT_ENABLED_STATE_DEFAULT, + PackageManager.DONT_KILL_APP); + + ActivityInfo activityInfo = + mPackageManager.getReceiverInfo(ENABLED_RECEIVER_COMPONENTNAME, 0); + assertNotNull(activityInfo); + assertTrue(activityInfo.enabled); + mPackageManager.setComponentEnabledSetting(DISABLED_RECEIVER_COMPONENTNAME, + COMPONENT_ENABLED_STATE_DISABLED, + PackageManager.DONT_KILL_APP); + try { + mPackageManager.getReceiverInfo(DISABLED_RECEIVER_COMPONENTNAME, 0); + fail("Attempt to get info on disabled component should fail."); + } catch (PackageManager.NameNotFoundException e) { + // expected + } + } + + @MediumTest + public void testResolveEnabledProvider() throws Exception { + mPackageManager.setComponentEnabledSetting(ENABLED_PROVIDER_COMPONENTNAME, + COMPONENT_ENABLED_STATE_DEFAULT, + PackageManager.DONT_KILL_APP); + + ProviderInfo providerInfo = + mPackageManager.resolveContentProvider(ENABLED_PROVIDER_NAME, 0); + assertNotNull(providerInfo); + assertTrue(providerInfo.enabled); + } + + @MediumTest + public void testResolveDisabledProvider() throws Exception { + mPackageManager.setComponentEnabledSetting(DISABLED_PROVIDER_COMPONENTNAME, + COMPONENT_ENABLED_STATE_DEFAULT, + PackageManager.DONT_KILL_APP); + + ProviderInfo providerInfo = + mPackageManager.resolveContentProvider(DISABLED_PROVIDER_NAME, 0); + assertNull(providerInfo); + ProviderInfo providerInfo2 = + mPackageManager.resolveContentProvider(DISABLED_PROVIDER_NAME, + GET_DISABLED_COMPONENTS); + assertNotNull(providerInfo2); + assertFalse(providerInfo2.enabled); + } + + @MediumTest + public void testEnableProvider() throws Exception { + mPackageManager.setComponentEnabledSetting(DISABLED_PROVIDER_COMPONENTNAME, + COMPONENT_ENABLED_STATE_DEFAULT, + PackageManager.DONT_KILL_APP); + ProviderInfo providerInfo = + mPackageManager.resolveContentProvider(DISABLED_PROVIDER_NAME, 0); + assertNull(providerInfo); + + mPackageManager.setComponentEnabledSetting(DISABLED_PROVIDER_COMPONENTNAME, + COMPONENT_ENABLED_STATE_ENABLED, + PackageManager.DONT_KILL_APP); + ProviderInfo providerInfo2 = + mPackageManager.resolveContentProvider(DISABLED_PROVIDER_NAME, 0); + assertNotNull(providerInfo2); + assertFalse(providerInfo2.enabled); + } + + @MediumTest + public void testDisableProvider() throws Exception { + mPackageManager.setComponentEnabledSetting(ENABLED_PROVIDER_COMPONENTNAME, + COMPONENT_ENABLED_STATE_DEFAULT, + PackageManager.DONT_KILL_APP); + ProviderInfo providerInfo = + mPackageManager.resolveContentProvider(ENABLED_PROVIDER_NAME, 0); + assertNotNull(providerInfo); + assertTrue(providerInfo.enabled); + + mPackageManager.setComponentEnabledSetting(ENABLED_PROVIDER_COMPONENTNAME, + COMPONENT_ENABLED_STATE_DISABLED, + PackageManager.DONT_KILL_APP); + ProviderInfo providerInfo2 = + mPackageManager.resolveContentProvider(ENABLED_PROVIDER_NAME, 0); + assertNull(providerInfo2); + } + + @MediumTest + public void testQueryEnabledProvider() throws Exception { + mPackageManager.setComponentEnabledSetting(ENABLED_PROVIDER_COMPONENTNAME, + COMPONENT_ENABLED_STATE_DEFAULT, + PackageManager.DONT_KILL_APP); + + String enabledProviderProcessName = getComponentProcessName(ENABLED_PROVIDER_NAME); + PackageInfo pi = mPackageManager.getPackageInfo(ENABLED_PACKAGENAME, 0); + List providerInfoList = + mPackageManager.queryContentProviders(enabledProviderProcessName, + pi.applicationInfo.uid, 0); + assertNotNull(providerInfoList); + assertEquals(1, providerInfoList.size()); + assertEquals(ENABLED_PROVIDER_CLASSNAME, + providerInfoList.get(0).name); + } + + @MediumTest + public void testQueryDisabledProvider() throws Exception { + mPackageManager.setComponentEnabledSetting(DISABLED_PROVIDER_COMPONENTNAME, + COMPONENT_ENABLED_STATE_DEFAULT, + PackageManager.DONT_KILL_APP); + + PackageInfo pi = mPackageManager.getPackageInfo(ENABLED_PACKAGENAME, 0); + + String disabledProviderProcessName = getComponentProcessName(DISABLED_PROVIDER_NAME); + List providerInfoList = + mPackageManager.queryContentProviders(disabledProviderProcessName, + pi.applicationInfo.uid, 0); + assertNull(providerInfoList); + + + List providerInfoList2 = + mPackageManager.queryContentProviders(disabledProviderProcessName, + pi.applicationInfo.uid, GET_DISABLED_COMPONENTS); + assertNotNull(providerInfoList2); + assertEquals(1, providerInfoList2.size()); + assertEquals(DISABLED_PROVIDER_CLASSNAME, + providerInfoList2.get(0).name); + } + + private String getComponentProcessName(String componentNameStr) { + ComponentInfo providerInfo = + mPackageManager.resolveContentProvider(componentNameStr, + GET_DISABLED_COMPONENTS); + return providerInfo.processName; + } + + public void DISABLED_testResolveEnabledActivityInDisabledApp() throws Exception { + mPackageManager.setApplicationEnabledSetting(DISABLED_PACKAGENAME, + COMPONENT_ENABLED_STATE_DEFAULT, + 0); + mPackageManager.setComponentEnabledSetting(DISABLED_APP_ENABLED_ACTIVITY_COMPONENTNAME, + COMPONENT_ENABLED_STATE_DEFAULT, + PackageManager.DONT_KILL_APP); + + final ResolveInfo info = + mPackageManager.resolveActivity(mDisabledAppEnabledActivityIntent, 0); + assertNull(info); + + final ResolveInfo info2 = mPackageManager.resolveActivity( + mDisabledAppEnabledActivityIntent, GET_DISABLED_COMPONENTS); + assertNotNull(info2); + assertNotNull(info2.activityInfo); + assertTrue(info2.activityInfo.enabled); + } + + public void DISABLED_testEnableApplication() throws Exception { + mPackageManager.setApplicationEnabledSetting(DISABLED_PACKAGENAME, + COMPONENT_ENABLED_STATE_DEFAULT, + 0); + mPackageManager.setComponentEnabledSetting(DISABLED_APP_ENABLED_ACTIVITY_COMPONENTNAME, + COMPONENT_ENABLED_STATE_DEFAULT, + PackageManager.DONT_KILL_APP); + + final ResolveInfo info = + mPackageManager.resolveActivity(mDisabledAppEnabledActivityIntent, 0); + assertNull(info); + + mPackageManager.setApplicationEnabledSetting(DISABLED_PACKAGENAME, + COMPONENT_ENABLED_STATE_ENABLED, + 0); + final ResolveInfo info2 = mPackageManager.resolveActivity( + mDisabledAppEnabledActivityIntent, 0); + assertNotNull(info2); + assertNotNull(info2.activityInfo); + assertTrue(info2.activityInfo.enabled); + + } + + public void DISABLED_testDisableApplication() throws Exception { + mPackageManager.setApplicationEnabledSetting(ENABLED_PACKAGENAME, + COMPONENT_ENABLED_STATE_DEFAULT, + 0); + mPackageManager.setComponentEnabledSetting(ENABLED_ACTIVITY_COMPONENTNAME, + COMPONENT_ENABLED_STATE_DEFAULT, + PackageManager.DONT_KILL_APP); + + final ResolveInfo info = mPackageManager.resolveActivity(mEnabledActivityIntent, 0); + assertNotNull(info); + assertNotNull(info.activityInfo); + assertTrue(info.activityInfo.enabled); + + mPackageManager.setApplicationEnabledSetting(ENABLED_PACKAGENAME, + COMPONENT_ENABLED_STATE_DISABLED, + 0); + final ResolveInfo info2 = mPackageManager.resolveActivity(mEnabledActivityIntent, 0); + assertNull(info2); + + // Clean up + mPackageManager.setApplicationEnabledSetting(ENABLED_PACKAGENAME, + COMPONENT_ENABLED_STATE_DEFAULT, + 0); + + } + + @MediumTest + public void testNonExplicitResolveAfterEnabling() throws Exception { + mPackageManager.setComponentEnabledSetting(DISABLED_ACTIVITY_COMPONENTNAME, + COMPONENT_ENABLED_STATE_DEFAULT, + PackageManager.DONT_KILL_APP); + + Intent intent = new Intent(Intent.ACTION_MAIN, null); + intent.addCategory(TEST_CATEGORY); + + final List launchables = + mPackageManager.queryIntentActivities(intent, 0); + + int numItems = launchables.size(); + assertEquals(0, numItems); + + mPackageManager.setComponentEnabledSetting(DISABLED_ACTIVITY_COMPONENTNAME, + COMPONENT_ENABLED_STATE_ENABLED, + PackageManager.DONT_KILL_APP); + + final List launchables2 = + mPackageManager.queryIntentActivities(intent, 0); + + int numItems2 = launchables2.size(); + assertEquals(1, numItems2); + } +} diff --git a/tests/AndroidTests/src/com/android/unit_tests/ContentQueryMapTest.java b/tests/AndroidTests/src/com/android/unit_tests/ContentQueryMapTest.java new file mode 100644 index 0000000000000000000000000000000000000000..241a1bf8f3d41efcc30863d22f32edb7b70c29bb --- /dev/null +++ b/tests/AndroidTests/src/com/android/unit_tests/ContentQueryMapTest.java @@ -0,0 +1,104 @@ +/* + * 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.android.unit_tests; + +import android.content.ContentQueryMap; +import android.content.ContentResolver; +import android.content.ContentValues; +import android.database.Cursor; +import android.os.Handler; +import android.os.Looper; +import android.provider.Settings; +import android.test.AndroidTestCase; +import android.test.suitebuilder.annotation.MediumTest; + +import java.util.Observable; +import java.util.Observer; + +/** Test of {@link ContentQueryMap} */ +public class ContentQueryMapTest extends AndroidTestCase { + /** Helper class to run test code in a new thread with a Looper. */ + private abstract class LooperThread extends Thread { + public Throwable mError = null; + public boolean mSuccess = false; + + abstract void go(); + + public void run() { + try { + Looper.prepare(); + go(); + Looper.loop(); + } catch (Throwable e) { + mError = e; + } + } + } + + @MediumTest + public void testContentQueryMap() throws Throwable { + LooperThread thread = new LooperThread() { + void go() { + ContentResolver r = getContext().getContentResolver(); + Settings.System.putString(r, "test", "Value"); + Cursor cursor = r.query( + Settings.System.CONTENT_URI, + new String[] { + Settings.System.NAME, + Settings.System.VALUE, + }, null, null, null); + + final ContentQueryMap cqm = new ContentQueryMap( + cursor, Settings.System.NAME, true, null); + // Get the current state of the CQM. This forces a requery and means that the + // call to getValues() below won't do a requery(). + cqm.getRows(); + + // The cache won't notice changes until the loop runs. + Settings.System.putString(r, "test", "New Value"); + ContentValues v = cqm.getValues("test"); + String value = v.getAsString(Settings.System.VALUE); + assertEquals("Value", value); + + // Use an Observer to find out when the cache does update. + cqm.addObserver(new Observer() { + public void update(Observable o, Object arg) { + // Should have the new values by now. + ContentValues v = cqm.getValues("test"); + String value = v.getAsString(Settings.System.VALUE); + assertEquals("New Value", value); + Looper.myLooper().quit(); + cqm.close(); + mSuccess = true; + } + }); + + // Give up after a few seconds, if it doesn't. + new Handler().postDelayed(new Runnable() { + public void run() { + fail("Timed out"); + } + }, 5000); + } + }; + + thread.start(); + thread.join(); + if (thread.mError != null) throw thread.mError; + assertTrue(thread.mSuccess); + } +} diff --git a/tests/AndroidTests/src/com/android/unit_tests/CreateViewTest.java b/tests/AndroidTests/src/com/android/unit_tests/CreateViewTest.java new file mode 100644 index 0000000000000000000000000000000000000000..342094dfba7cd7f242d23c2aa05449f72db9a0db --- /dev/null +++ b/tests/AndroidTests/src/com/android/unit_tests/CreateViewTest.java @@ -0,0 +1,123 @@ +/* + * Copyright (C) 2006 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.android.unit_tests; + +import android.content.Context; +import android.test.AndroidTestCase; +import android.test.PerformanceTestCase; +import android.test.suitebuilder.annotation.SmallTest; +import android.view.View; +import static android.view.ViewGroup.LayoutParams.FILL_PARENT; +import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT; +import android.widget.LinearLayout; +import android.widget.TextView; + +public class CreateViewTest extends AndroidTestCase implements PerformanceTestCase { + + public boolean isPerformanceOnly() { + return false; + } + + public int startPerformance(PerformanceTestCase.Intermediates intermediates) { + return 0; + } + + @SmallTest + public void testLayout1() throws Exception { + new CreateViewTest.ViewOne(mContext); + } + + @SmallTest + public void testLayout2() throws Exception { + LinearLayout vert = new LinearLayout(mContext); + vert.addView(new CreateViewTest.ViewOne(mContext), + new LinearLayout.LayoutParams(FILL_PARENT, FILL_PARENT, 0)); + } + + @SmallTest + public void testLayout3() throws Exception { + LinearLayout vert = new LinearLayout(mContext); + + ViewOne one = new ViewOne(mContext); + vert.addView(one, new LinearLayout.LayoutParams(FILL_PARENT, FILL_PARENT, 0)); + + ViewOne two = new ViewOne(mContext); + vert.addView(two, new LinearLayout.LayoutParams(FILL_PARENT, FILL_PARENT, 0)); + + ViewOne three = new ViewOne(mContext); + vert.addView(three, new LinearLayout.LayoutParams(FILL_PARENT, FILL_PARENT, 0)); + + ViewOne four = new ViewOne(mContext); + vert.addView(four, new LinearLayout.LayoutParams(FILL_PARENT, FILL_PARENT, 0)); + + ViewOne five = new ViewOne(mContext); + vert.addView(five, new LinearLayout.LayoutParams(FILL_PARENT, FILL_PARENT, 0)); + + ViewOne six = new ViewOne(mContext); + vert.addView(six, new LinearLayout.LayoutParams(FILL_PARENT, FILL_PARENT, 0)); + } + + @SmallTest + public void testLayout4() throws Exception { + TextView text = new TextView(mContext); + text.setText("S"); + } + + @SmallTest + public void testLayout5() throws Exception { + TextView text = new TextView(mContext); + text.setText("S"); + + LinearLayout vert = new LinearLayout(mContext); + vert.addView(text, new LinearLayout.LayoutParams(FILL_PARENT, WRAP_CONTENT, 0)); + } + + @SmallTest + public void testLayout6() throws Exception { + LinearLayout vert = new LinearLayout(mContext); + + TextView one = new TextView(mContext); + one.setText("S"); + vert.addView(one, new LinearLayout.LayoutParams(FILL_PARENT, WRAP_CONTENT, 0)); + + TextView two = new TextView(mContext); + two.setText("M"); + vert.addView(two, new LinearLayout.LayoutParams(FILL_PARENT, WRAP_CONTENT, 0)); + + TextView three = new TextView(mContext); + three.setText("T"); + vert.addView(three, new LinearLayout.LayoutParams(FILL_PARENT, WRAP_CONTENT, 0)); + + TextView four = new TextView(mContext); + four.setText("W"); + vert.addView(four, new LinearLayout.LayoutParams(FILL_PARENT, WRAP_CONTENT, 0)); + + TextView five = new TextView(mContext); + five.setText("H"); + vert.addView(five, new LinearLayout.LayoutParams(FILL_PARENT, WRAP_CONTENT, 0)); + + TextView six = new TextView(mContext); + six.setText("F"); + vert.addView(six, new LinearLayout.LayoutParams(FILL_PARENT, WRAP_CONTENT, 0)); + } + + public static class ViewOne extends View { + public ViewOne(Context context) { + super(context); + } + } +} diff --git a/tests/AndroidTests/src/com/android/unit_tests/CursorWindowTest.java b/tests/AndroidTests/src/com/android/unit_tests/CursorWindowTest.java new file mode 100644 index 0000000000000000000000000000000000000000..d9068c89d509c2a375b6ef39aa6b1b8d6c4a8806 --- /dev/null +++ b/tests/AndroidTests/src/com/android/unit_tests/CursorWindowTest.java @@ -0,0 +1,173 @@ +/* + * 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.android.unit_tests; + +import android.database.AbstractCursor; +import android.test.suitebuilder.annotation.SmallTest; +import com.android.internal.database.ArrayListCursor; +import android.database.CursorWindow; +import android.test.PerformanceTestCase; + +import com.google.android.collect.Lists; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Random; + +import junit.framework.TestCase; + +public class CursorWindowTest extends TestCase implements PerformanceTestCase { + public boolean isPerformanceOnly() { + return false; + } + + // These test can only be run once. + public int startPerformance(Intermediates intermediates) { + return 1; + } + + @SmallTest + public void testWriteCursorToWindow() throws Exception { + // create cursor + String[] colNames = new String[]{"name", "number", "profit"}; + int colsize = colNames.length; + ArrayList list = createTestList(10, colsize); + AbstractCursor cursor = new ArrayListCursor(colNames, (ArrayList) list); + + // fill window + CursorWindow window = new CursorWindow(false); + cursor.fillWindow(0, window); + + // read from cursor window + for (int i = 0; i < list.size(); i++) { + ArrayList col = list.get(i); + for (int j = 0; j < colsize; j++) { + String s = window.getString(i, j); + int r2 = col.get(j); + int r1 = Integer.parseInt(s); + assertEquals(r2, r1); + } + } + + // test cursor window handle startpos != 0 + window.clear(); + cursor.fillWindow(1, window); + // read from cursor from window + for (int i = 1; i < list.size(); i++) { + ArrayList col = list.get(i); + for (int j = 0; j < colsize; j++) { + String s = window.getString(i, j); + int r2 = col.get(j); + int r1 = Integer.parseInt(s); + assertEquals(r2, r1); + } + } + + // Clear the window and make sure it's empty + window.clear(); + assertEquals(0, window.getNumRows()); + } + + @SmallTest + public void testValuesLocalWindow() { + doTestValues(new CursorWindow(true)); + } + + @SmallTest + public void testValuesRemoteWindow() { + doTestValues(new CursorWindow(false)); + } + + private void doTestValues(CursorWindow window) { + assertTrue(window.setNumColumns(7)); + assertTrue(window.allocRow()); + double db1 = 1.26; + assertTrue(window.putDouble(db1, 0, 0)); + double db2 = window.getDouble(0, 0); + assertEquals(db1, db2); + + long int1 = Long.MAX_VALUE; + assertTrue(window.putLong(int1, 0, 1)); + long int2 = window.getLong(0, 1); + assertEquals(int1, int2); + + assertTrue(window.putString("1198032740000", 0, 3)); + assertEquals("1198032740000", window.getString(0, 3)); + assertEquals(1198032740000L, window.getLong(0, 3)); + + assertTrue(window.putString(Long.toString(1198032740000L), 0, 3)); + assertEquals(Long.toString(1198032740000L), window.getString(0, 3)); + assertEquals(1198032740000L, window.getLong(0, 3)); + + assertTrue(window.putString(Double.toString(42.0), 0, 4)); + assertEquals(Double.toString(42.0), window.getString(0, 4)); + assertEquals(42.0, window.getDouble(0, 4)); + + // put blob + byte[] blob = new byte[1000]; + byte value = 99; + Arrays.fill(blob, value); + assertTrue(window.putBlob(blob, 0, 6)); + assertTrue(Arrays.equals(blob, window.getBlob(0, 6))); + } + + @SmallTest + public void testNull() { + CursorWindow window = getOneByOneWindow(); + + // Put in a null value and read it back as various types + assertTrue(window.putNull(0, 0)); + assertNull(window.getString(0, 0)); + assertEquals(0, window.getLong(0, 0)); + assertEquals(0.0, window.getDouble(0, 0)); + assertNull(window.getBlob(0, 0)); + } + + @SmallTest + public void testEmptyString() { + CursorWindow window = getOneByOneWindow(); + + // put size 0 string and read it back as various types + assertTrue(window.putString("", 0, 0)); + assertEquals("", window.getString(0, 0)); + assertEquals(0, window.getLong(0, 0)); + assertEquals(0.0, window.getDouble(0, 0)); + } + + private CursorWindow getOneByOneWindow() { + CursorWindow window = new CursorWindow(false); + assertTrue(window.setNumColumns(1)); + assertTrue(window.allocRow()); + return window; + } + + private static ArrayList createTestList(int rows, int cols) { + ArrayList list = Lists.newArrayList(); + Random generator = new Random(); + + for (int i = 0; i < rows; i++) { + ArrayList col = Lists.newArrayList(); + list.add(col); + for (int j = 0; j < cols; j++) { + // generate random number + Integer r = generator.nextInt(); + col.add(r); + } + } + return list; + } +} diff --git a/tests/AndroidTests/src/com/android/unit_tests/DatabaseCursorTest.java b/tests/AndroidTests/src/com/android/unit_tests/DatabaseCursorTest.java new file mode 100644 index 0000000000000000000000000000000000000000..5df499d1604dd7086eb28df246a218750e93ecb0 --- /dev/null +++ b/tests/AndroidTests/src/com/android/unit_tests/DatabaseCursorTest.java @@ -0,0 +1,626 @@ +/* + * Copyright (C) 2007 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.android.unit_tests; + +import android.content.ContentValues; +import android.database.Cursor; +import android.database.CursorIndexOutOfBoundsException; +import android.database.DataSetObserver; +import android.database.DatabaseUtils; +import android.database.sqlite.SQLiteCursor; +import android.database.sqlite.SQLiteCursorDriver; +import android.database.sqlite.SQLiteDatabase; +import android.database.sqlite.SQLiteQuery; +import android.database.sqlite.SQLiteStatement; +import android.os.Looper; +import android.test.PerformanceTestCase; +import android.test.suitebuilder.annotation.LargeTest; +import android.test.suitebuilder.annotation.MediumTest; +import android.test.suitebuilder.annotation.SmallTest; +import android.test.suitebuilder.annotation.Suppress; +import android.util.Log; + +import java.io.File; +import java.util.Arrays; +import java.util.Random; + +import junit.framework.TestCase; + +public class DatabaseCursorTest extends TestCase implements PerformanceTestCase { + + private static final String sString1 = "this is a test"; + private static final String sString2 = "and yet another test"; + private static final String sString3 = "this string is a little longer, but still a test"; + + private static final int CURRENT_DATABASE_VERSION = 42; + private SQLiteDatabase mDatabase; + private File mDatabaseFile; + + @Override + protected void setUp() throws Exception { + super.setUp(); + mDatabaseFile = new File("/sqlite_stmt_journals", "database_test.db"); + if (mDatabaseFile.exists()) { + mDatabaseFile.delete(); + } + mDatabase = SQLiteDatabase.openOrCreateDatabase(mDatabaseFile.getPath(), null); + assertNotNull(mDatabase); + mDatabase.setVersion(CURRENT_DATABASE_VERSION); + } + + @Override + protected void tearDown() throws Exception { + mDatabase.close(); + mDatabaseFile.delete(); + super.tearDown(); + } + + public boolean isPerformanceOnly() { + return false; + } + + // These test can only be run once. + public int startPerformance(Intermediates intermediates) { + return 1; + } + + private void populateDefaultTable() { + mDatabase.execSQL("CREATE TABLE test (_id INTEGER PRIMARY KEY, data TEXT);"); + + mDatabase.execSQL("INSERT INTO test (data) VALUES ('" + sString1 + "');"); + mDatabase.execSQL("INSERT INTO test (data) VALUES ('" + sString2 + "');"); + mDatabase.execSQL("INSERT INTO test (data) VALUES ('" + sString3 + "');"); + } + + @MediumTest + public void testCursorUpdate() { + mDatabase.execSQL( + "CREATE TABLE test (_id INTEGER PRIMARY KEY, d INTEGER, s INTEGER);"); + for(int i = 0; i < 20; i++) { + mDatabase.execSQL("INSERT INTO test (d, s) VALUES (" + i + + "," + i%2 + ");"); + } + + Cursor c = mDatabase.query("test", null, "s = 0", null, null, null, null); + int dCol = c.getColumnIndexOrThrow("d"); + int sCol = c.getColumnIndexOrThrow("s"); + + int count = 0; + while (c.moveToNext()) { + assertTrue(c.updateInt(dCol, 3)); + count++; + } + assertEquals(10, count); + + assertTrue(c.commitUpdates()); + + assertTrue(c.requery()); + + count = 0; + while (c.moveToNext()) { + assertEquals(3, c.getInt(dCol)); + count++; + } + + assertEquals(10, count); + assertTrue(c.moveToFirst()); + assertTrue(c.deleteRow()); + assertEquals(9, c.getCount()); + c.close(); + } + + @MediumTest + public void testBlob() throws Exception { + // create table + mDatabase.execSQL( + "CREATE TABLE test (_id INTEGER PRIMARY KEY, s TEXT, d REAL, l INTEGER, b BLOB);"); + // insert blob + Object[] args = new Object[4]; + + byte[] blob = new byte[1000]; + byte value = 99; + Arrays.fill(blob, value); + args[3] = blob; + + String s = new String("text"); + args[0] = s; + Double d = 99.9; + args[1] = d; + Long l = (long)1000; + args[2] = l; + + String sql = "INSERT INTO test (s, d, l, b) VALUES (?,?,?,?)"; + mDatabase.execSQL(sql, args); + // use cursor to access blob + Cursor c = mDatabase.query("test", null, null, null, null, null, null); + c.moveToNext(); + ContentValues cv = new ContentValues(); + DatabaseUtils.cursorRowToContentValues(c, cv); + + int bCol = c.getColumnIndexOrThrow("b"); + int sCol = c.getColumnIndexOrThrow("s"); + int dCol = c.getColumnIndexOrThrow("d"); + int lCol = c.getColumnIndexOrThrow("l"); + byte[] cBlob = c.getBlob(bCol); + assertTrue(Arrays.equals(blob, cBlob)); + assertEquals(s, c.getString(sCol)); + assertEquals((double)d, c.getDouble(dCol)); + assertEquals((long)l, c.getLong(lCol)); + + // new byte[] + byte[] newblob = new byte[1000]; + value = 98; + Arrays.fill(blob, value); + + c.updateBlob(bCol, newblob); + cBlob = c.getBlob(bCol); + assertTrue(Arrays.equals(newblob, cBlob)); + + // commit + assertTrue(c.commitUpdates()); + assertTrue(c.requery()); + c.moveToNext(); + cBlob = c.getBlob(bCol); + assertTrue(Arrays.equals(newblob, cBlob)); + c.close(); + } + + @MediumTest + public void testRealColumns() throws Exception { + mDatabase.execSQL("CREATE TABLE test (_id INTEGER PRIMARY KEY, data REAL);"); + ContentValues values = new ContentValues(); + values.put("data", 42.11); + long id = mDatabase.insert("test", "data", values); + assertTrue(id > 0); + Cursor c = mDatabase.rawQuery("SELECT data FROM test", null); + assertNotNull(c); + assertTrue(c.moveToFirst()); + assertEquals(42.11, c.getDouble(0)); + c.close(); + } + + @MediumTest + public void testCursor1() throws Exception { + populateDefaultTable(); + + Cursor c = mDatabase.query("test", null, null, null, null, null, null); + + int dataColumn = c.getColumnIndexOrThrow("data"); + + // The cursor should ignore text before the last period when looking for a column. (This + // is a temporary hack in all implementations of getColumnIndex.) + int dataColumn2 = c.getColumnIndexOrThrow("junk.data"); + assertEquals(dataColumn, dataColumn2); + + assertSame(3, c.getCount()); + + assertTrue(c.isBeforeFirst()); + + try { + c.getInt(0); + fail("CursorIndexOutOfBoundsException expected"); + } catch (CursorIndexOutOfBoundsException ex) { + // expected + } + + c.moveToNext(); + assertEquals(1, c.getInt(0)); + + String s = c.getString(dataColumn); + assertEquals(sString1, s); + + c.moveToNext(); + s = c.getString(dataColumn); + assertEquals(sString2, s); + + c.moveToNext(); + s = c.getString(dataColumn); + assertEquals(sString3, s); + + c.moveToPosition(-1); + c.moveToNext(); + s = c.getString(dataColumn); + assertEquals(sString1, s); + + c.moveToPosition(2); + s = c.getString(dataColumn); + assertEquals(sString3, s); + + int i; + + for (c.moveToFirst(), i = 0; !c.isAfterLast(); c.moveToNext(), i++) { + c.getInt(0); + } + + assertEquals(3, i); + + try { + c.getInt(0); + fail("CursorIndexOutOfBoundsException expected"); + } catch (CursorIndexOutOfBoundsException ex) { + // expected + } + c.close(); + } + + @MediumTest + public void testCursor2() throws Exception { + populateDefaultTable(); + + Cursor c = mDatabase.query("test", null, "_id > 1000", null, null, null, null); + assertEquals(0, c.getCount()); + assertTrue(c.isBeforeFirst()); + + try { + c.getInt(0); + fail("CursorIndexOutOfBoundsException expected"); + } catch (CursorIndexOutOfBoundsException ex) { + // expected + } + + int i; + for (c.moveToFirst(), i = 0; !c.isAfterLast(); c.moveToNext(), i++) { + c.getInt(0); + } + assertEquals(0, i); + try { + c.getInt(0); + fail("CursorIndexOutOfBoundsException expected"); + } catch (CursorIndexOutOfBoundsException ex) { + // expected + } + c.close(); + } + + @MediumTest + public void testLargeField() throws Exception { + mDatabase.execSQL("CREATE TABLE test (_id INTEGER PRIMARY KEY, data TEXT);"); + + StringBuilder sql = new StringBuilder(2100); + sql.append("INSERT INTO test (data) VALUES ('"); + Random random = new Random(System.currentTimeMillis()); + StringBuilder randomString = new StringBuilder(1979); + for (int i = 0; i < 1979; i++) { + randomString.append((random.nextInt() & 0xf) % 10); + } + sql.append(randomString); + sql.append("');"); + mDatabase.execSQL(sql.toString()); + + Cursor c = mDatabase.query("test", null, null, null, null, null, null); + assertNotNull(c); + assertEquals(1, c.getCount()); + + assertTrue(c.moveToFirst()); + assertEquals(0, c.getPosition()); + String largeString = c.getString(c.getColumnIndexOrThrow("data")); + assertNotNull(largeString); + assertEquals(randomString.toString(), largeString); + c.close(); + } + + class TestObserver extends DataSetObserver { + int total; + SQLiteCursor c; + boolean quit = false; + public TestObserver(int total_, SQLiteCursor cursor) { + c = cursor; + total = total_; + } + + @Override + public void onChanged() { + int count = c.getCount(); + if (total == count) { + int i = 0; + while (c.moveToNext()) { + assertEquals(i, c.getInt(1)); + i++; + } + assertEquals(count, i); + quit = true; + Looper.myLooper().quit(); + } + } + + @Override + public void onInvalidated() { + } + } + + //@Large + @Suppress + public void testLoadingThreadDelayRegisterData() throws Exception { + mDatabase.execSQL("CREATE TABLE test (_id INTEGER PRIMARY KEY, data INT);"); + + final int count = 505; + String sql = "INSERT INTO test (data) VALUES (?);"; + SQLiteStatement s = mDatabase.compileStatement(sql); + for (int i = 0; i < count; i++) { + s.bindLong(1, i); + s.execute(); + } + + int maxRead = 500; + int initialRead = 5; + SQLiteCursor c = (SQLiteCursor)mDatabase.rawQuery("select * from test;", + null, initialRead, maxRead); + + TestObserver observer = new TestObserver(count, c); + c.getCount(); + c.registerDataSetObserver(observer); + if (!observer.quit) { + Looper.loop(); + } + c.close(); + } + + @LargeTest + public void testLoadingThread() throws Exception { + mDatabase.execSQL("CREATE TABLE test (_id INTEGER PRIMARY KEY, data INT);"); + + final int count = 50000; + String sql = "INSERT INTO test (data) VALUES (?);"; + SQLiteStatement s = mDatabase.compileStatement(sql); + for (int i = 0; i < count; i++) { + s.bindLong(1, i); + s.execute(); + } + + int maxRead = 1000; + int initialRead = 5; + SQLiteCursor c = (SQLiteCursor)mDatabase.rawQuery("select * from test;", + null, initialRead, maxRead); + + TestObserver observer = new TestObserver(count, c); + c.registerDataSetObserver(observer); + c.getCount(); + + Looper.loop(); + c.close(); + } + + @LargeTest + public void testLoadingThreadClose() throws Exception { + mDatabase.execSQL("CREATE TABLE test (_id INTEGER PRIMARY KEY, data INT);"); + + final int count = 1000; + String sql = "INSERT INTO test (data) VALUES (?);"; + SQLiteStatement s = mDatabase.compileStatement(sql); + for (int i = 0; i < count; i++) { + s.bindLong(1, i); + s.execute(); + } + + int maxRead = 11; + int initialRead = 5; + SQLiteCursor c = (SQLiteCursor)mDatabase.rawQuery("select * from test;", + null, initialRead, maxRead); + + TestObserver observer = new TestObserver(count, c); + c.registerDataSetObserver(observer); + c.getCount(); + c.close(); + } + + @LargeTest + public void testLoadingThreadDeactivate() throws Exception { + mDatabase.execSQL("CREATE TABLE test (_id INTEGER PRIMARY KEY, data INT);"); + + final int count = 1000; + String sql = "INSERT INTO test (data) VALUES (?);"; + SQLiteStatement s = mDatabase.compileStatement(sql); + for (int i = 0; i < count; i++) { + s.bindLong(1, i); + s.execute(); + } + + int maxRead = 11; + int initialRead = 5; + SQLiteCursor c = (SQLiteCursor)mDatabase.rawQuery("select * from test;", + null, initialRead, maxRead); + + TestObserver observer = new TestObserver(count, c); + c.registerDataSetObserver(observer); + c.getCount(); + c.deactivate(); + c.close(); + } + + @LargeTest + public void testManyRowsLong() throws Exception { + mDatabase.execSQL("CREATE TABLE test (_id INTEGER PRIMARY KEY, data INT);"); + + final int count = 36799; + for (int i = 0; i < count; i++) { + mDatabase.execSQL("INSERT INTO test (data) VALUES (" + i + ");"); + } + + Cursor c = mDatabase.query("test", new String[]{"data"}, null, null, null, null, null); + assertNotNull(c); + + int i = 0; + while (c.moveToNext()) { + assertEquals(i, c.getInt(0)); + i++; + } + assertEquals(count, i); + assertEquals(count, c.getCount()); + + Log.d("testManyRows", "count " + Integer.toString(i)); + c.close(); + } + + @LargeTest + public void testManyRowsTxt() throws Exception { + mDatabase.execSQL("CREATE TABLE test (_id INTEGER PRIMARY KEY, data TEXT);"); + StringBuilder sql = new StringBuilder(2100); + sql.append("INSERT INTO test (data) VALUES ('"); + Random random = new Random(System.currentTimeMillis()); + StringBuilder randomString = new StringBuilder(1979); + for (int i = 0; i < 1979; i++) { + randomString.append((random.nextInt() & 0xf) % 10); + } + sql.append(randomString); + sql.append("');"); + + // if cursor window size changed, adjust this value too + final int count = 600; // more than two fillWindow needed + for (int i = 0; i < count; i++) { + mDatabase.execSQL(sql.toString()); + } + + Cursor c = mDatabase.query("test", new String[]{"data"}, null, null, null, null, null); + assertNotNull(c); + + int i = 0; + while (c.moveToNext()) { + assertEquals(randomString.toString(), c.getString(0)); + i++; + } + assertEquals(count, i); + assertEquals(count, c.getCount()); + c.close(); + } + + @LargeTest + public void testManyRowsTxtLong() throws Exception { + mDatabase.execSQL("CREATE TABLE test (_id INTEGER PRIMARY KEY, txt TEXT, data INT);"); + + Random random = new Random(System.currentTimeMillis()); + StringBuilder randomString = new StringBuilder(1979); + for (int i = 0; i < 1979; i++) { + randomString.append((random.nextInt() & 0xf) % 10); + } + + // if cursor window size changed, adjust this value too + final int count = 600; + for (int i = 0; i < count; i++) { + StringBuilder sql = new StringBuilder(2100); + sql.append("INSERT INTO test (txt, data) VALUES ('"); + sql.append(randomString); + sql.append("','"); + sql.append(i); + sql.append("');"); + mDatabase.execSQL(sql.toString()); + } + + Cursor c = mDatabase.query("test", new String[]{"txt", "data"}, null, null, null, null, null); + assertNotNull(c); + + int i = 0; + while (c.moveToNext()) { + assertEquals(randomString.toString(), c.getString(0)); + assertEquals(i, c.getInt(1)); + i++; + } + assertEquals(count, i); + assertEquals(count, c.getCount()); + c.close(); + } + + @MediumTest + public void testRequery() throws Exception { + populateDefaultTable(); + + Cursor c = mDatabase.rawQuery("SELECT * FROM test", null); + assertNotNull(c); + assertEquals(3, c.getCount()); + c.deactivate(); + c.requery(); + assertEquals(3, c.getCount()); + c.close(); + } + + @MediumTest + public void testRequeryWithSelection() throws Exception { + populateDefaultTable(); + + Cursor c = mDatabase.rawQuery("SELECT data FROM test WHERE data = '" + sString1 + "'", + null); + assertNotNull(c); + assertEquals(1, c.getCount()); + assertTrue(c.moveToFirst()); + assertEquals(sString1, c.getString(0)); + c.deactivate(); + c.requery(); + assertEquals(1, c.getCount()); + assertTrue(c.moveToFirst()); + assertEquals(sString1, c.getString(0)); + c.close(); + } + + @MediumTest + public void testRequeryWithSelectionArgs() throws Exception { + populateDefaultTable(); + + Cursor c = mDatabase.rawQuery("SELECT data FROM test WHERE data = ?", + new String[]{sString1}); + assertNotNull(c); + assertEquals(1, c.getCount()); + assertTrue(c.moveToFirst()); + assertEquals(sString1, c.getString(0)); + c.deactivate(); + c.requery(); + assertEquals(1, c.getCount()); + assertTrue(c.moveToFirst()); + assertEquals(sString1, c.getString(0)); + c.close(); + } + + @MediumTest + public void testRequeryWithAlteredSelectionArgs() throws Exception { + /** + * Test the ability of a subclass of SQLiteCursor to change its query arguments. + */ + populateDefaultTable(); + + SQLiteDatabase.CursorFactory factory = new SQLiteDatabase.CursorFactory() { + public Cursor newCursor( + SQLiteDatabase db, SQLiteCursorDriver masterQuery, String editTable, + SQLiteQuery query) { + return new SQLiteCursor(db, masterQuery, editTable, query) { + @Override + public boolean requery() { + setSelectionArguments(new String[]{"2"}); + return super.requery(); + } + }; + } + }; + Cursor c = mDatabase.rawQueryWithFactory( + factory, "SELECT data FROM test WHERE _id <= ?", new String[]{"1"}, + null); + assertNotNull(c); + assertEquals(1, c.getCount()); + assertTrue(c.moveToFirst()); + assertEquals(sString1, c.getString(0)); + + // Our hacked requery() changes the query arguments in the cursor. + c.requery(); + + assertEquals(2, c.getCount()); + assertTrue(c.moveToFirst()); + assertEquals(sString1, c.getString(0)); + assertTrue(c.moveToNext()); + assertEquals(sString2, c.getString(0)); + + // Test that setting query args on a deactivated cursor also works. + c.deactivate(); + c.requery(); + } +} diff --git a/tests/AndroidTests/src/com/android/unit_tests/DatabaseGeneralTest.java b/tests/AndroidTests/src/com/android/unit_tests/DatabaseGeneralTest.java new file mode 100644 index 0000000000000000000000000000000000000000..b004c938f72e4bd2d3feb4036abdb2dff27b8361 --- /dev/null +++ b/tests/AndroidTests/src/com/android/unit_tests/DatabaseGeneralTest.java @@ -0,0 +1,871 @@ +/* + * Copyright (C) 2006 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.android.unit_tests; + +import android.content.ContentValues; +import android.database.ContentObserver; +import android.database.Cursor; +import android.database.DatabaseUtils; +import android.database.CharArrayBuffer; +import android.database.sqlite.SQLiteDatabase; +import android.database.sqlite.SQLiteStatement; +import android.os.Handler; +import android.os.Parcel; +import android.test.PerformanceTestCase; +import android.test.suitebuilder.annotation.MediumTest; +import android.test.suitebuilder.annotation.SmallTest; +import android.util.Log; + +import java.io.File; +import java.io.UnsupportedEncodingException; +import java.text.Collator; +import java.util.Arrays; + +import junit.framework.Assert; +import junit.framework.TestCase; + +import static android.database.DatabaseUtils.InsertHelper.TABLE_INFO_PRAGMA_COLUMNNAME_INDEX; +import static android.database.DatabaseUtils.InsertHelper.TABLE_INFO_PRAGMA_DEFAULT_INDEX; + +public class DatabaseGeneralTest extends TestCase implements PerformanceTestCase { + + private static final String sString1 = "this is a test"; + private static final String sString2 = "and yet another test"; + private static final String sString3 = "this string is a little longer, but still a test"; + private static final String PHONE_NUMBER = "16175551212"; + + private static final int CURRENT_DATABASE_VERSION = 42; + private SQLiteDatabase mDatabase; + private File mDatabaseFile; + + @Override + protected void setUp() throws Exception { + super.setUp(); + mDatabaseFile = new File("/sqlite_stmt_journals", "database_test.db"); + if (mDatabaseFile.exists()) { + mDatabaseFile.delete(); + } + mDatabase = SQLiteDatabase.openOrCreateDatabase(mDatabaseFile.getPath(), null); + assertNotNull(mDatabase); + mDatabase.setVersion(CURRENT_DATABASE_VERSION); + } + + @Override + protected void tearDown() throws Exception { + mDatabase.close(); + mDatabaseFile.delete(); + super.tearDown(); + } + + public boolean isPerformanceOnly() { + return false; + } + + // These test can only be run once. + public int startPerformance(Intermediates intermediates) { + return 1; + } + + private void populateDefaultTable() { + mDatabase.execSQL("CREATE TABLE test (_id INTEGER PRIMARY KEY, data TEXT);"); + + mDatabase.execSQL("INSERT INTO test (data) VALUES ('" + sString1 + "');"); + mDatabase.execSQL("INSERT INTO test (data) VALUES ('" + sString2 + "');"); + mDatabase.execSQL("INSERT INTO test (data) VALUES ('" + sString3 + "');"); + } + + @MediumTest + public void testVersion() throws Exception { + assertEquals(CURRENT_DATABASE_VERSION, mDatabase.getVersion()); + mDatabase.setVersion(11); + assertEquals(11, mDatabase.getVersion()); + } + + @MediumTest + public void testUpdate() throws Exception { + populateDefaultTable(); + + ContentValues values = new ContentValues(1); + values.put("data", "this is an updated test"); + assertEquals(1, mDatabase.update("test", values, "_id=1", null)); + Cursor c = mDatabase.query("test", null, "_id=1", null, null, null, null); + assertNotNull(c); + assertEquals(1, c.getCount()); + c.moveToFirst(); + String value = c.getString(c.getColumnIndexOrThrow("data")); + assertEquals("this is an updated test", value); + } + + @MediumTest + public void testPhoneNumbersEqual() throws Exception { + mDatabase.execSQL("CREATE TABLE phones (num TEXT);"); + mDatabase.execSQL("INSERT INTO phones (num) VALUES ('911');"); + mDatabase.execSQL("INSERT INTO phones (num) VALUES ('5555');"); + mDatabase.execSQL("INSERT INTO phones (num) VALUES ('+" + PHONE_NUMBER + "');"); + + String number; + Cursor c; + + c = mDatabase.query("phones", null, + "PHONE_NUMBERS_EQUAL(num, '504-555-7683')", null, null, null, null); + assertTrue(c == null || c.getCount() == 0); + c.close(); + + c = mDatabase.query("phones", null, + "PHONE_NUMBERS_EQUAL(num, '911')", null, null, null, null); + assertNotNull(c); + assertEquals(1, c.getCount()); + c.moveToFirst(); + number = c.getString(c.getColumnIndexOrThrow("num")); + assertEquals("911", number); + c.close(); + + c = mDatabase.query("phones", null, + "PHONE_NUMBERS_EQUAL(num, '5555')", null, null, null, null); + assertNotNull(c); + assertEquals(1, c.getCount()); + c.moveToFirst(); + number = c.getString(c.getColumnIndexOrThrow("num")); + assertEquals("5555", number); + c.close(); + + c = mDatabase.query("phones", null, + "PHONE_NUMBERS_EQUAL(num, '180055555555')", null, null, null, null); + assertTrue(c == null || c.getCount() == 0); + c.close(); + + c = mDatabase.query("phones", null, + "PHONE_NUMBERS_EQUAL(num, '+" + PHONE_NUMBER + "')", null, null, null, null); + assertNotNull(c); + assertEquals(1, c.getCount()); + c.moveToFirst(); + number = c.getString(c.getColumnIndexOrThrow("num")); + assertEquals("+" + PHONE_NUMBER, number); + c.close(); + + c = mDatabase.query("phones", null, + "PHONE_NUMBERS_EQUAL(num, '+1 (617).555-1212')", null, null, null, null); + assertNotNull(c); + assertEquals(1, c.getCount()); + c.moveToFirst(); + number = c.getString(c.getColumnIndexOrThrow("num")); + assertEquals("+" + PHONE_NUMBER, number); + c.close(); + + c = mDatabase.query("phones", null, + "PHONE_NUMBERS_EQUAL(num, '+1 (617).555-1212p1234')", null, null, null, null); + assertNotNull(c); + assertEquals(1, c.getCount()); + c.moveToFirst(); + number = c.getString(c.getColumnIndexOrThrow("num")); + assertEquals("+" + PHONE_NUMBER, number); + c.close(); + + c = mDatabase.query("phones", null, + "PHONE_NUMBERS_EQUAL(num, '" + PHONE_NUMBER + "')", null, null, null, null); + assertNotNull(c); + assertEquals(1, c.getCount()); + c.moveToFirst(); + number = c.getString(c.getColumnIndexOrThrow("num")); + assertEquals("+" + PHONE_NUMBER, number); + c.close(); + + c = mDatabase.query("phones", null, + "PHONE_NUMBERS_EQUAL(num, '5551212')", null, null, null, null); + assertNotNull(c); + assertEquals(1, c.getCount()); + c.moveToFirst(); + number = c.getString(c.getColumnIndexOrThrow("num")); + assertEquals("+" + PHONE_NUMBER, number); + c.close(); + + c = mDatabase.query("phones", null, + "PHONE_NUMBERS_EQUAL(num, '011" + PHONE_NUMBER + "')", null, null, null, null); + assertNotNull(c); + assertEquals(1, c.getCount()); + c.moveToFirst(); + number = c.getString(c.getColumnIndexOrThrow("num")); + assertEquals("+" + PHONE_NUMBER, number); + c.close(); + + c = mDatabase.query("phones", null, + "PHONE_NUMBERS_EQUAL(num, '00" + PHONE_NUMBER + "')", null, null, null, null); + assertNotNull(c); + assertEquals(1, c.getCount()); + c.moveToFirst(); + number = c.getString(c.getColumnIndexOrThrow("num")); + assertEquals("+" + PHONE_NUMBER, number); + c.close(); + } + + /** + * Tests international matching issues for the PHONE_NUMBERS_EQUAL function. + * + * @throws Exception + */ + public void testPhoneNumbersEqualInternationl() throws Exception { + Cursor c; + String[] phoneNumbers = new String[2]; + + // Russian trunk digit + phoneNumbers[0] = "+79161234567"; // globablly dialable number + phoneNumbers[1] = "89161234567"; // in-country dialable number + c = mDatabase.rawQuery( + "SELECT CASE WHEN PHONE_NUMBERS_EQUAL(?, ?) THEN 'equal' ELSE 'not equal' END", + phoneNumbers); + assertTrue(c.moveToFirst()); + assertEquals("equal", c.getString(0)); + c.close(); + + // French trunk digit + phoneNumbers[0] = "+33123456789"; // globablly dialable number + phoneNumbers[1] = "0123456789"; // in-country dialable number + c = mDatabase.rawQuery( + "SELECT CASE WHEN PHONE_NUMBERS_EQUAL(?, ?) THEN 'equal' ELSE 'not equal' END", + phoneNumbers); + assertTrue(c.moveToFirst()); + assertEquals("equal", c.getString(0)); + c.close(); + + + // Trunk digit for city codes in the Netherlands + phoneNumbers[0] = "+31771234567"; // globablly dialable number + phoneNumbers[1] = "0771234567"; // in-country dialable number + c = mDatabase.rawQuery( + "SELECT CASE WHEN PHONE_NUMBERS_EQUAL(?, ?) THEN 'equal' ELSE 'not equal' END", + phoneNumbers); + assertTrue(c.moveToFirst()); + assertEquals("equal", c.getString(0)); + c.close(); + + // Test broken caller ID seen on call from Thailand to the US + phoneNumbers[0] = "+66811234567"; // in address book + phoneNumbers[1] = "166811234567"; // came in from the network + c = mDatabase.rawQuery( + "SELECT CASE WHEN PHONE_NUMBERS_EQUAL(?, ?) THEN 'equal' ELSE 'not equal' END", + phoneNumbers); + assertTrue(c.moveToFirst()); + assertEquals("equal", c.getString(0)); + c.close(); + + // Test the same in-country number with different country codes + phoneNumbers[0] = "+33123456789"; + phoneNumbers[1] = "+1123456789"; + c = mDatabase.rawQuery( + "SELECT CASE WHEN PHONE_NUMBERS_EQUAL(?, ?) THEN 'equal' ELSE 'not equal' END", + phoneNumbers); + assertTrue(c.moveToFirst()); + assertEquals("not equal", c.getString(0)); + c.close(); + + // Test one number with country code and the other without + phoneNumbers[0] = "5125551212"; + phoneNumbers[1] = "+15125551212"; + c = mDatabase.rawQuery( + "SELECT CASE WHEN PHONE_NUMBERS_EQUAL(?, ?) THEN 'equal' ELSE 'not equal' END", + phoneNumbers); + assertTrue(c.moveToFirst()); + assertEquals("equal", c.getString(0)); + c.close(); + + // Test two NANP numbers that only differ in the area code + phoneNumbers[0] = "5125551212"; + phoneNumbers[1] = "6505551212"; + c = mDatabase.rawQuery( + "SELECT CASE WHEN PHONE_NUMBERS_EQUAL(?, ?) THEN 'equal' ELSE 'not equal' END", + phoneNumbers); + assertTrue(c.moveToFirst()); + assertEquals("not equal", c.getString(0)); + c.close(); + } + + @MediumTest + public void testCopyString() throws Exception { + mDatabase.execSQL("CREATE TABLE guess (numi INTEGER, numf FLOAT, str TEXT);"); + mDatabase.execSQL( + "INSERT INTO guess (numi,numf,str) VALUES (0,0.0,'ZoomZoomZoomZoom');"); + mDatabase.execSQL("INSERT INTO guess (numi,numf,str) VALUES (2000000000,3.1415926535,'');"); + String chinese = "\u4eac\u4ec5 \u5c3d\u5f84\u60ca"; + String[] arr = new String[1]; + arr[0] = chinese; + mDatabase.execSQL("INSERT INTO guess (numi,numf,str) VALUES (-32768,-1.0,?)", arr); + + Cursor c; + + c = mDatabase.rawQuery("SELECT * FROM guess", null); + + c.moveToFirst(); + + CharArrayBuffer buf = new CharArrayBuffer(14); + + String compareTo = c.getString(c.getColumnIndexOrThrow("numi")); + int numiIdx = c.getColumnIndexOrThrow("numi"); + int numfIdx = c.getColumnIndexOrThrow("numf"); + int strIdx = c.getColumnIndexOrThrow("str"); + + c.copyStringToBuffer(numiIdx, buf); + assertEquals(1, buf.sizeCopied); + assertEquals(compareTo, new String(buf.data, 0, buf.sizeCopied)); + + c.copyStringToBuffer(strIdx, buf); + assertEquals("ZoomZoomZoomZoom", new String(buf.data, 0, buf.sizeCopied)); + + c.moveToNext(); + compareTo = c.getString(numfIdx); + + c.copyStringToBuffer(numfIdx, buf); + assertEquals(compareTo, new String(buf.data, 0, buf.sizeCopied)); + c.copyStringToBuffer(strIdx, buf); + assertEquals(0, buf.sizeCopied); + + c.moveToNext(); + c.copyStringToBuffer(numfIdx, buf); + assertEquals(-1.0, Double.valueOf( + new String(buf.data, 0, buf.sizeCopied)).doubleValue()); + + c.copyStringToBuffer(strIdx, buf); + compareTo = c.getString(strIdx); + assertEquals(chinese, compareTo); + + assertEquals(chinese, new String(buf.data, 0, buf.sizeCopied)); + c.close(); + } + + @MediumTest + public void testSchemaChange1() throws Exception { + SQLiteDatabase db1 = mDatabase; + Cursor cursor; + + db1.execSQL("CREATE TABLE db1 (_id INTEGER PRIMARY KEY, data TEXT);"); + + cursor = db1.query("db1", null, null, null, null, null, null); + assertNotNull("Cursor is null", cursor); + + db1.execSQL("CREATE TABLE db2 (_id INTEGER PRIMARY KEY, data TEXT);"); + + assertEquals(0, cursor.getCount()); + cursor.deactivate(); + } + + @MediumTest + public void testSchemaChange2() throws Exception { + SQLiteDatabase db1 = mDatabase; + SQLiteDatabase db2 = SQLiteDatabase.openOrCreateDatabase(mDatabaseFile, null); + Cursor cursor; + + db1.execSQL("CREATE TABLE db1 (_id INTEGER PRIMARY KEY, data TEXT);"); + + cursor = db1.query("db1", null, null, null, null, null, null); + assertNotNull("Cursor is null", cursor); + assertEquals(0, cursor.getCount()); + cursor.deactivate(); + // this cause exception because we're still using sqlite_prepate16 and not + // sqlite_prepare16_v2. The v2 variant added the ability to check the + // schema version and handle the case when the schema has changed + // Marco Nelissen claim it was 2x slower to compile SQL statements so + // I reverted back to the v1 variant. + /* db2.execSQL("CREATE TABLE db2 (_id INTEGER PRIMARY KEY, data TEXT);"); + + cursor = db1.query("db1", null, null, null, null, null, null); + assertNotNull("Cursor is null", cursor); + assertEquals(0, cursor.count()); + cursor.deactivate(); + */ + } + + @MediumTest + public void testSchemaChange3() throws Exception { + SQLiteDatabase db1 = mDatabase; + SQLiteDatabase db2 = SQLiteDatabase.openOrCreateDatabase(mDatabaseFile, null); + Cursor cursor; + + + db1.execSQL("CREATE TABLE db1 (_id INTEGER PRIMARY KEY, data TEXT);"); + db1.execSQL("INSERT INTO db1 (data) VALUES ('test');"); + + cursor = db1.query("db1", null, null, null, null, null, null); + // this cause exception because we're still using sqlite_prepate16 and not + // sqlite_prepare16_v2. The v2 variant added the ability to check the + // schema version and handle the case when the schema has changed + // Marco Nelissen claim it was 2x slower to compile SQL statements so + // I reverted back to the v1 variant. + /* db2.execSQL("CREATE TABLE db2 (_id INTEGER PRIMARY KEY, data TEXT);"); + + assertNotNull("Cursor is null", cursor); + assertEquals(1, cursor.count()); + assertTrue(cursor.first()); + assertEquals("test", cursor.getString(cursor.getColumnIndexOrThrow("data"))); + cursor.deactivate(); + */ + } + + private class ChangeObserver extends ContentObserver { + private int mCursorNotificationCount = 0; + private int mNotificationCount = 0; + + public int getCursorNotificationCount() { + return mCursorNotificationCount; + } + + public int getNotificationCount() { + return mNotificationCount; + } + + public ChangeObserver(boolean cursor) { + super(new Handler()); + mCursor = cursor; + } + + @Override + public boolean deliverSelfNotifications() { + return true; + } + + @Override + public void onChange(boolean selfChange) { + if (mCursor) { + mCursorNotificationCount++; + } else { + mNotificationCount++; + } + } + + boolean mCursor; + } + + @MediumTest + public void testNotificationTest1() throws Exception { + /* + Cursor c = mContentResolver.query(Notes.CONTENT_URI, + new String[] {Notes._ID, Notes.NOTE}, + null, null); + c.registerContentObserver(new MyContentObserver(true)); + int count = c.count(); + + MyContentObserver observer = new MyContentObserver(false); + mContentResolver.registerContentObserver(Notes.CONTENT_URI, true, observer); + + Uri uri; + + HashMap values = new HashMap(); + values.put(Notes.NOTE, "test note1"); + uri = mContentResolver.insert(Notes.CONTENT_URI, values); + assertEquals(1, mCursorNotificationCount); + assertEquals(1, mNotificationCount); + + c.requery(); + assertEquals(count + 1, c.count()); + c.first(); + assertEquals("test note1", c.getString(c.getColumnIndex(Notes.NOTE))); + c.updateString(c.getColumnIndex(Notes.NOTE), "test note2"); + c.commitUpdates(); + + assertEquals(2, mCursorNotificationCount); + assertEquals(2, mNotificationCount); + + mContentResolver.delete(uri, null); + + assertEquals(3, mCursorNotificationCount); + assertEquals(3, mNotificationCount); + + mContentResolver.unregisterContentObserver(observer); + */ + } + + @MediumTest + public void testSelectionArgs() throws Exception { + mDatabase.execSQL("CREATE TABLE test (_id INTEGER PRIMARY KEY, data TEXT);"); + ContentValues values = new ContentValues(1); + values.put("data", "don't forget to handled 's"); + mDatabase.insert("test", "data", values); + values.clear(); + values.put("data", "no apostrophes here"); + mDatabase.insert("test", "data", values); + Cursor c = mDatabase.query( + "test", null, "data GLOB ?", new String[]{"*'*"}, null, null, null); + assertEquals(1, c.getCount()); + assertTrue(c.moveToFirst()); + assertEquals("don't forget to handled 's", c.getString(1)); + c.deactivate(); + + // make sure code should checking null string properly so that + // it won't crash + try { + mDatabase.query("test", new String[]{"_id"}, + "_id=?", new String[]{null}, null, null, null); + fail("expected exception not thrown"); + } catch (IllegalArgumentException e) { + // expected + } + } + + @MediumTest + public void testTokenize() throws Exception { + Cursor c; + mDatabase.execSQL("CREATE TABLE tokens (" + + "token TEXT COLLATE unicode," + + "source INTEGER " + + ");"); + String[] cols = new String[]{"token", "source"}; + + Assert.assertEquals(0, DatabaseUtils.longForQuery(mDatabase, + "SELECT _TOKENIZE(NULL, NULL, NULL, NULL)", null)); + Assert.assertEquals(0, DatabaseUtils.longForQuery(mDatabase, + "SELECT _TOKENIZE('tokens', NULL, NULL, NULL)", null)); + Assert.assertEquals(0, DatabaseUtils.longForQuery(mDatabase, + "SELECT _TOKENIZE('tokens', 10, NULL, NULL)", null)); + Assert.assertEquals(0, DatabaseUtils.longForQuery(mDatabase, + "SELECT _TOKENIZE('tokens', 10, 'some string', NULL)", null)); + + Assert.assertEquals(3, DatabaseUtils.longForQuery(mDatabase, + "SELECT _TOKENIZE('tokens', 1, 'some string ok', ' ')", null)); + + // test Chinese + String chinese = new String("\u4eac\u4ec5 \u5c3d\u5f84\u60ca"); + Assert.assertEquals(2, DatabaseUtils.longForQuery(mDatabase, + "SELECT _TOKENIZE('tokens', 1,'" + chinese + "', ' ')", null)); + + String icustr = new String("Fr\u00e9d\u00e9ric Hj\u00f8nnev\u00e5g"); + + Assert.assertEquals(2, DatabaseUtils.longForQuery(mDatabase, + "SELECT _TOKENIZE('tokens', 1, '" + icustr + "', ' ')", null)); + + Assert.assertEquals(7, DatabaseUtils.longForQuery(mDatabase, + "SELECT count(*) from tokens;", null)); + + String key = DatabaseUtils.getHexCollationKey("Frederic Hjonneva"); + Assert.assertEquals(1, DatabaseUtils.longForQuery(mDatabase, + "SELECT count(*) from tokens where token GLOB '" + key + "*'", null)); + key = DatabaseUtils.getHexCollationKey("Hjonneva"); + Assert.assertEquals(1, DatabaseUtils.longForQuery(mDatabase, + "SELECT count(*) from tokens where token GLOB '" + key + "*'", null)); + + key = DatabaseUtils.getHexCollationKey("some string ok"); + Assert.assertEquals(1, DatabaseUtils.longForQuery(mDatabase, + "SELECT count(*) from tokens where token GLOB '" + key + "*'", null)); + key = DatabaseUtils.getHexCollationKey("string"); + Assert.assertEquals(1, DatabaseUtils.longForQuery(mDatabase, + "SELECT count(*) from tokens where token GLOB '" + key + "*'", null)); + key = DatabaseUtils.getHexCollationKey("ok"); + Assert.assertEquals(1, DatabaseUtils.longForQuery(mDatabase, + "SELECT count(*) from tokens where token GLOB '" + key + "*'", null)); + + key = DatabaseUtils.getHexCollationKey(chinese); + String[] a = new String[1]; + a[0] = key; + Assert.assertEquals(1, DatabaseUtils.longForQuery(mDatabase, + "SELECT count(*) from tokens where token= ?", a)); + a[0] += "*"; + Assert.assertEquals(1, DatabaseUtils.longForQuery(mDatabase, + "SELECT count(*) from tokens where token GLOB ?", a)); + + Assert.assertEquals(1, DatabaseUtils.longForQuery(mDatabase, + "SELECT count(*) from tokens where token= '" + key + "'", null)); + + Assert.assertEquals(1, DatabaseUtils.longForQuery(mDatabase, + "SELECT count(*) from tokens where token GLOB '" + key + "*'", null)); + + key = DatabaseUtils.getHexCollationKey("\u4eac\u4ec5"); + Assert.assertEquals(1, DatabaseUtils.longForQuery(mDatabase, + "SELECT count(*) from tokens where token GLOB '" + key + "*'", null)); + + + Assert.assertEquals(0, DatabaseUtils.longForQuery(mDatabase, + "SELECT count(*) from tokens where token GLOB 'ab*'", null)); + } + + @MediumTest + public void testTransactions() throws Exception { + mDatabase.execSQL("CREATE TABLE test (num INTEGER);"); + mDatabase.execSQL("INSERT INTO test (num) VALUES (0)"); + + // Make sure that things work outside an explicit transaction. + setNum(1); + checkNum(1); + + // Test a single-level transaction. + setNum(0); + mDatabase.beginTransaction(); + setNum(1); + mDatabase.setTransactionSuccessful(); + mDatabase.endTransaction(); + checkNum(1); + Assert.assertFalse(mDatabase.isDbLockedByCurrentThread()); + + // Test a rolled-back transaction. + setNum(0); + mDatabase.beginTransaction(); + setNum(1); + mDatabase.endTransaction(); + checkNum(0); + Assert.assertFalse(mDatabase.isDbLockedByCurrentThread()); + + // We should get an error if we end a non-existent transaction. + assertThrowsIllegalState(new Runnable() { public void run() { + mDatabase.endTransaction(); + }}); + + // We should get an error if a set a non-existent transaction as clean. + assertThrowsIllegalState(new Runnable() { public void run() { + mDatabase.setTransactionSuccessful(); + }}); + + mDatabase.beginTransaction(); + mDatabase.setTransactionSuccessful(); + // We should get an error if we mark a transaction as clean twice. + assertThrowsIllegalState(new Runnable() { public void run() { + mDatabase.setTransactionSuccessful(); + }}); + // We should get an error if we begin a transaction after marking the parent as clean. + assertThrowsIllegalState(new Runnable() { public void run() { + mDatabase.beginTransaction(); + }}); + mDatabase.endTransaction(); + Assert.assertFalse(mDatabase.isDbLockedByCurrentThread()); + + // Test a two-level transaction. + setNum(0); + mDatabase.beginTransaction(); + mDatabase.beginTransaction(); + setNum(1); + mDatabase.setTransactionSuccessful(); + mDatabase.endTransaction(); + mDatabase.setTransactionSuccessful(); + mDatabase.endTransaction(); + checkNum(1); + Assert.assertFalse(mDatabase.isDbLockedByCurrentThread()); + + // Test rolling back an inner transaction. + setNum(0); + mDatabase.beginTransaction(); + mDatabase.beginTransaction(); + setNum(1); + mDatabase.endTransaction(); + mDatabase.setTransactionSuccessful(); + mDatabase.endTransaction(); + checkNum(0); + Assert.assertFalse(mDatabase.isDbLockedByCurrentThread()); + + // Test rolling back an outer transaction. + setNum(0); + mDatabase.beginTransaction(); + mDatabase.beginTransaction(); + setNum(1); + mDatabase.setTransactionSuccessful(); + mDatabase.endTransaction(); + mDatabase.endTransaction(); + checkNum(0); + Assert.assertFalse(mDatabase.isDbLockedByCurrentThread()); + } + + private void setNum(int num) { + mDatabase.execSQL("UPDATE test SET num = " + num); + } + + private void checkNum(int num) { + Assert.assertEquals( + num, DatabaseUtils.longForQuery(mDatabase, "SELECT num FROM test", null)); + } + + private void assertThrowsIllegalState(Runnable r) { + boolean ok = false; + try { + r.run(); + } catch (IllegalStateException e) { + ok = true; + } + Assert.assertTrue(ok); + } + + // Disable these until we can explicitly mark them as stress tests + public void xxtestMem1() throws Exception { + populateDefaultTable(); + + for (int i = 0; i < 50000; i++) { + Cursor cursor = mDatabase.query("test", null, null, null, null, null, null); + cursor.moveToFirst(); + cursor.close(); +// Log.i("~~~~", "Finished round " + i); + } + } + + // Disable these until we can explicitly mark them as stress tests + public void xxtestMem2() throws Exception { + populateDefaultTable(); + + for (int i = 0; i < 50000; i++) { + Cursor cursor = mDatabase.query("test", null, null, null, null, null, null); + cursor.close(); +// Log.i("~~~~", "Finished round " + i); + } + } + + // Disable these until we can explicitly mark them as stress tests + public void xxtestMem3() throws Exception { + populateDefaultTable(); + + for (int i = 0; i < 50000; i++) { + Cursor cursor = mDatabase.query("test", null, null, null, null, null, null); + cursor.deactivate(); +// Log.i("~~~~", "Finished round " + i); + } + } + + @MediumTest + public void testContentValues() throws Exception { + ContentValues values = new ContentValues(); + values.put("string", "value"); + assertEquals("value", values.getAsString("string")); + byte[] bytes = new byte[42]; + Arrays.fill(bytes, (byte) 0x28); + values.put("byteArray", bytes); + assertTrue(Arrays.equals(bytes, values.getAsByteArray("byteArray"))); + + // Write the ContentValues to a Parcel and then read them out + Parcel p = Parcel.obtain(); + values.writeToParcel(p, 0); + p.setDataPosition(0); + values = ContentValues.CREATOR.createFromParcel(p); + + // Read the values out again and make sure they're the same + assertTrue(Arrays.equals(bytes, values.getAsByteArray("byteArray"))); + assertEquals("value", values.get("string")); + } + + @MediumTest + public void testTableInfoPragma() throws Exception { + mDatabase.execSQL("CREATE TABLE pragma_test (" + + "i INTEGER DEFAULT 1234, " + + "j INTEGER, " + + "s TEXT DEFAULT 'hello', " + + "t TEXT, " + + "'select' TEXT DEFAULT \"hello\")"); + try { + Cursor cur = mDatabase.rawQuery("PRAGMA table_info(pragma_test)", null); + Assert.assertEquals(5, cur.getCount()); + + Assert.assertTrue(cur.moveToNext()); + Assert.assertEquals("i", + cur.getString(TABLE_INFO_PRAGMA_COLUMNNAME_INDEX)); + Assert.assertEquals("1234", + cur.getString(TABLE_INFO_PRAGMA_DEFAULT_INDEX)); + + Assert.assertTrue(cur.moveToNext()); + Assert.assertEquals("j", + cur.getString(TABLE_INFO_PRAGMA_COLUMNNAME_INDEX)); + Assert.assertNull(cur.getString(TABLE_INFO_PRAGMA_DEFAULT_INDEX)); + + Assert.assertTrue(cur.moveToNext()); + Assert.assertEquals("s", + cur.getString(TABLE_INFO_PRAGMA_COLUMNNAME_INDEX)); + Assert.assertEquals("'hello'", + cur.getString(TABLE_INFO_PRAGMA_DEFAULT_INDEX)); + + Assert.assertTrue(cur.moveToNext()); + Assert.assertEquals("t", + cur.getString(TABLE_INFO_PRAGMA_COLUMNNAME_INDEX)); + Assert.assertNull(cur.getString(TABLE_INFO_PRAGMA_DEFAULT_INDEX)); + + Assert.assertTrue(cur.moveToNext()); + Assert.assertEquals("select", + cur.getString(TABLE_INFO_PRAGMA_COLUMNNAME_INDEX)); + Assert.assertEquals("\"hello\"", + cur.getString(TABLE_INFO_PRAGMA_DEFAULT_INDEX)); + + cur.close(); + } catch (Throwable t) { + throw new RuntimeException( + "If you see this test fail, it's likely that something about " + + "sqlite's PRAGMA table_info(...) command has changed.", t); + } + } + + @MediumTest + public void testInsertHelper() throws Exception { + Cursor cur; + ContentValues cv; + long row; + + mDatabase.execSQL("CREATE TABLE insert_test (" + + "_id INTEGER PRIMARY KEY, " + + "s TEXT NOT NULL UNIQUE, " + + "t TEXT NOT NULL DEFAULT 'hello world', " + + "i INTEGER, " + + "j INTEGER NOT NULL DEFAULT 1234, " + + "'select' TEXT)"); + + DatabaseUtils.InsertHelper ih = + new DatabaseUtils.InsertHelper(mDatabase, "insert_test"); + + cv = new ContentValues(); + cv.put("s", "one"); + row = ih.insert(cv); + cur = mDatabase.rawQuery("SELECT * FROM insert_test WHERE _id == " + row, null); + Assert.assertTrue(cur.moveToFirst()); + Assert.assertEquals("one", cur.getString(1)); + Assert.assertEquals("hello world", cur.getString(2)); + Assert.assertNull(cur.getString(3)); + Assert.assertEquals(1234, cur.getLong(4)); + Assert.assertNull(cur.getString(5)); + + cv = new ContentValues(); + cv.put("s", "two"); + cv.put("t", "goodbye world"); + row = ih.insert(cv); + cur = mDatabase.rawQuery("SELECT * FROM insert_test WHERE _id == " + row, null); + Assert.assertTrue(cur.moveToFirst()); + Assert.assertEquals("two", cur.getString(1)); + Assert.assertEquals("goodbye world", cur.getString(2)); + Assert.assertNull(cur.getString(3)); + Assert.assertEquals(1234, cur.getLong(4)); + Assert.assertNull(cur.getString(5)); + + cv = new ContentValues(); + cv.put("t", "goodbye world"); + row = ih.insert(cv); + Assert.assertEquals(-1, row); + + cv = new ContentValues(); + cv.put("s", "three"); + cv.put("i", 2345); + cv.put("j", 3456); + cv.put("select", "tricky"); + row = ih.insert(cv); + cur = mDatabase.rawQuery("SELECT * FROM insert_test WHERE _id == " + row, null); + Assert.assertTrue(cur.moveToFirst()); + Assert.assertEquals("three", cur.getString(1)); + Assert.assertEquals("hello world", cur.getString(2)); + Assert.assertEquals(2345, cur.getLong(3)); + Assert.assertEquals(3456, cur.getLong(4)); + Assert.assertEquals("tricky", cur.getString(5)); + + cv = new ContentValues(); + cv.put("s", "three"); + cv.put("i", 6789); + row = ih.insert(cv); + Assert.assertEquals(-1, row); + row = ih.replace(cv); + cur = mDatabase.rawQuery("SELECT * FROM insert_test WHERE _id == " + row, null); + Assert.assertTrue(cur.moveToFirst()); + Assert.assertEquals("three", cur.getString(1)); + Assert.assertEquals("hello world", cur.getString(2)); + Assert.assertEquals(6789, cur.getLong(3)); + + ih.close(); + } + +} diff --git a/tests/AndroidTests/src/com/android/unit_tests/DatabaseLocaleTest.java b/tests/AndroidTests/src/com/android/unit_tests/DatabaseLocaleTest.java new file mode 100644 index 0000000000000000000000000000000000000000..0560c21ec5543f013d4f4b36fec664c64e2ba532 --- /dev/null +++ b/tests/AndroidTests/src/com/android/unit_tests/DatabaseLocaleTest.java @@ -0,0 +1,102 @@ +/* + * Copyright (C) 2007 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.android.unit_tests; + +import android.database.sqlite.SQLiteDatabase; +import android.database.Cursor; +import android.test.suitebuilder.annotation.MediumTest; +import android.test.suitebuilder.annotation.SmallTest; +import android.util.Log; +import android.test.MoreAsserts; + +import java.util.ArrayList; +import java.util.Locale; + +import junit.framework.TestCase; + +public class DatabaseLocaleTest extends TestCase { + + private SQLiteDatabase mDatabase; + + private static final String[] STRINGS = { + "c\u00f4t\u00e9", + "cote", + "c\u00f4te", + "cot\u00e9", + "boy", + "dog", + "COTE", + }; + + @Override + protected void setUp() throws Exception { + super.setUp(); + mDatabase = SQLiteDatabase.create(null); + mDatabase.execSQL("CREATE TABLE test (data TEXT COLLATE LOCALIZED);"); + for (String s : STRINGS) { + mDatabase.execSQL("INSERT INTO test VALUES('" + s + "');"); + } + } + + @Override + protected void tearDown() throws Exception { + mDatabase.close(); + super.tearDown(); + } + + private String[] query(String sql) { + Log.i("LocaleTest", "Querying: " + sql); + Cursor c = mDatabase.rawQuery(sql, null); + assertNotNull(c); + ArrayList items = new ArrayList(); + while (c.moveToNext()) { + items.add(c.getString(0)); + Log.i("LocaleTest", "...." + c.getString(0)); + } + String[] result = items.toArray(new String[items.size()]); + assertEquals(STRINGS.length, result.length); + c.close(); + return result; + } + + @MediumTest + public void testLocaleInsertOrder() throws Exception { + String[] results = query("SELECT data FROM test"); + MoreAsserts.assertEquals(STRINGS, results); + } + + @MediumTest + public void testLocaleenUS() throws Exception { + Log.i("LocaleTest", "about to call setLocale en_US"); + mDatabase.setLocale(new Locale("en", "US")); + String[] results; + results = query("SELECT data FROM test ORDER BY data COLLATE LOCALIZED ASC"); + + // The database code currently uses PRIMARY collation strength, + // meaning that all versions of a character compare equal (regardless + // of case or accents), leaving the "cote" flavors in database order. + MoreAsserts.assertEquals(results, new String[] { + STRINGS[4], // "boy" + STRINGS[0], // sundry forms of "cote" + STRINGS[1], + STRINGS[2], + STRINGS[3], + STRINGS[6], // "COTE" + STRINGS[5], // "dog" + }); + } +} diff --git a/tests/AndroidTests/src/com/android/unit_tests/DatabasePerformanceTests.java b/tests/AndroidTests/src/com/android/unit_tests/DatabasePerformanceTests.java new file mode 100644 index 0000000000000000000000000000000000000000..68ce5e1585e73c03f99db47af341c5df779342ec --- /dev/null +++ b/tests/AndroidTests/src/com/android/unit_tests/DatabasePerformanceTests.java @@ -0,0 +1,1353 @@ +/* + * Copyright (C) 2007 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.android.unit_tests; + +import junit.framework.Assert; + +import android.content.ContentValues; +import android.content.Context; +import android.database.Cursor; +import android.database.sqlite.SQLiteDatabase; +import android.provider.Contacts; +import android.provider.Contacts.People; +import android.test.PerformanceTestCase; +import android.test.TestCase; + +import java.io.File; +import java.util.Random; + +/** + * Database Performance Tests + * + */ + +public class DatabasePerformanceTests { + + public static String[] children() { + return new String[] { + ContactReadingTest1.class.getName(), + Perf1Test.class.getName(), + Perf2Test.class.getName(), + Perf3Test.class.getName(), + Perf4Test.class.getName(), + Perf5Test.class.getName(), + Perf6Test.class.getName(), + Perf7Test.class.getName(), + Perf8Test.class.getName(), + Perf9Test.class.getName(), + Perf10Test.class.getName(), + Perf11Test.class.getName(), + Perf12Test.class.getName(), + Perf13Test.class.getName(), + Perf14Test.class.getName(), + Perf15Test.class.getName(), + Perf16Test.class.getName(), + Perf17Test.class.getName(), + Perf18Test.class.getName(), + Perf19Test.class.getName(), + Perf20Test.class.getName(), + Perf21Test.class.getName(), + Perf22Test.class.getName(), + Perf23Test.class.getName(), + Perf24Test.class.getName(), + Perf25Test.class.getName(), + Perf26Test.class.getName(), + Perf27Test.class.getName(), + Perf28Test.class.getName(), + Perf29Test.class.getName(), + Perf30Test.class.getName(), + Perf31Test.class.getName(), + }; + } + + public static abstract class PerformanceBase implements TestCase, + PerformanceTestCase { + protected static final int CURRENT_DATABASE_VERSION = 42; + protected SQLiteDatabase mDatabase; + protected File mDatabaseFile; + protected Context mContext; + + public void setUp(Context c) { + mContext = c; + mDatabaseFile = new File("/tmp", "perf_database_test.db"); + if (mDatabaseFile.exists()) { + mDatabaseFile.delete(); + } + mDatabase = SQLiteDatabase.openOrCreateDatabase(mDatabaseFile.getPath(), null); + Assert.assertTrue(mDatabase != null); + mDatabase.setVersion(CURRENT_DATABASE_VERSION); + } + + public void tearDown() { + mDatabase.close(); + mDatabaseFile.delete(); + } + + public boolean isPerformanceOnly() { + return true; + } + + // These test can only be run once. + public int startPerformance(Intermediates intermediates) { + return 0; + } + + public void run() { + } + + public String numberName(int number) { + String result = ""; + + if (number >= 1000) { + result += numberName((number / 1000)) + " thousand"; + number = (number % 1000); + + if (number > 0) result += " "; + } + + if (number >= 100) { + result += ONES[(number / 100)] + " hundred"; + number = (number % 100); + + if (number > 0) result += " "; + } + + if (number >= 20) { + result += TENS[(number / 10)]; + number = (number % 10); + + if (number > 0) result += " "; + } + + if (number > 0) { + result += ONES[number]; + } + + return result; + } + } + + /** + * Test reading all contact data. + */ + public static class ContactReadingTest1 implements TestCase, PerformanceTestCase { + private static final String[] PEOPLE_PROJECTION = new String[] { + Contacts.People._ID, // 0 + Contacts.People.PRIMARY_PHONE_ID, // 1 + Contacts.People.TYPE, // 2 + Contacts.People.NUMBER, // 3 + Contacts.People.LABEL, // 4 + Contacts.People.NAME, // 5 + Contacts.People.PRESENCE_STATUS, // 6 + }; + + private Cursor mCursor; + + public void setUp(Context c) { + mCursor = c.getContentResolver().query(People.CONTENT_URI, PEOPLE_PROJECTION, null, + null, People.DEFAULT_SORT_ORDER); + } + + public void tearDown() { + mCursor.close(); + } + + public boolean isPerformanceOnly() { + return true; + } + + public int startPerformance(Intermediates intermediates) { + // This test can only be run once. + return 0; + } + + public void run() { + while (mCursor.moveToNext()) { + // Read out all of the data + mCursor.getLong(0); + mCursor.getLong(1); + mCursor.getLong(2); + mCursor.getString(3); + mCursor.getString(4); + mCursor.getString(5); + mCursor.getLong(6); + } + } + } + + /** + * Test 1000 inserts + */ + + public static class Perf1Test extends PerformanceBase { + private static final int SIZE = 1000; + + private String[] statements = new String[SIZE]; + + @Override + public void setUp(Context c) { + super.setUp(c); + Random random = new Random(42); + + for (int i = 0; i < SIZE; i++) { + int r = random.nextInt(100000); + statements[i] = + "INSERT INTO t1 VALUES(" + i + "," + r + ",'" + + numberName(r) + "')"; + } + + mDatabase + .execSQL("CREATE TABLE t1(a INTEGER, b INTEGER, c VARCHAR(100))"); + } + + @Override + public void run() { + for (int i = 0; i < SIZE; i++) { + mDatabase.execSQL(statements[i]); + } + } + } + + /** + * Test 1000 inserts into and indexed table + */ + + public static class Perf2Test extends PerformanceBase { + private static final int SIZE = 1000; + + private String[] statements = new String[SIZE]; + + @Override + public void setUp(Context c) { + super.setUp(c); + Random random = new Random(42); + + for (int i = 0; i < SIZE; i++) { + int r = random.nextInt(100000); + statements[i] = + "INSERT INTO t1 VALUES(" + i + "," + r + ",'" + + numberName(r) + "')"; + } + + mDatabase + .execSQL("CREATE TABLE t1(a INTEGER, b INTEGER, c VARCHAR(100))"); + mDatabase.execSQL("CREATE INDEX i1c ON t1(c)"); + } + + @Override + public void run() { + for (int i = 0; i < SIZE; i++) { + mDatabase.execSQL(statements[i]); + } + } + } + + /** + * 100 SELECTs without an index + */ + + public static class Perf3Test extends PerformanceBase { + private static final int SIZE = 100; + private static final String[] COLUMNS = {"count(*)", "avg(b)"}; + + private String[] where = new String[SIZE]; + + @Override + public void setUp(Context c) { + super.setUp(c); + Random random = new Random(42); + + mDatabase + .execSQL("CREATE TABLE t1(a INTEGER, b INTEGER, c VARCHAR(100))"); + + for (int i = 0; i < SIZE; i++) { + int r = random.nextInt(100000); + mDatabase.execSQL("INSERT INTO t1 VALUES(" + i + "," + r + ",'" + + numberName(r) + "')"); + } + + for (int i = 0; i < SIZE; i++) { + int lower = i * 100; + int upper = (i + 10) * 100; + where[i] = "b >= " + lower + " AND b < " + upper; + } + } + + @Override + public void run() { + for (int i = 0; i < SIZE; i++) { + mDatabase + .query("t1", COLUMNS, where[i], null, null, null, null); + } + } + } + + /** + * 100 SELECTs on a string comparison + */ + + public static class Perf4Test extends PerformanceBase { + private static final int SIZE = 100; + private static final String[] COLUMNS = {"count(*)", "avg(b)"}; + + private String[] where = new String[SIZE]; + + @Override + public void setUp(Context c) { + super.setUp(c); + Random random = new Random(42); + + mDatabase + .execSQL("CREATE TABLE t1(a INTEGER, b INTEGER, c VARCHAR(100))"); + + for (int i = 0; i < SIZE; i++) { + int r = random.nextInt(100000); + mDatabase.execSQL("INSERT INTO t1 VALUES(" + i + "," + r + ",'" + + numberName(r) + "')"); + } + + for (int i = 0; i < SIZE; i++) { + where[i] = "c LIKE '" + numberName(i) + "'"; + } + } + + @Override + public void run() { + for (int i = 0; i < SIZE; i++) { + mDatabase + .query("t1", COLUMNS, where[i], null, null, null, null); + } + } + } + + /** + * 100 SELECTs with an index + */ + + public static class Perf5Test extends PerformanceBase { + private static final int SIZE = 100; + private static final String[] COLUMNS = {"count(*)", "avg(b)"}; + + private String[] where = new String[SIZE]; + + @Override + public void setUp(Context c) { + super.setUp(c); + Random random = new Random(42); + + mDatabase + .execSQL("CREATE TABLE t1(a INTEGER, b INTEGER, c VARCHAR(100))"); + mDatabase.execSQL("CREATE INDEX i1b ON t1(b)"); + + for (int i = 0; i < SIZE; i++) { + int r = random.nextInt(100000); + mDatabase.execSQL("INSERT INTO t1 VALUES(" + i + "," + r + ",'" + + numberName(r) + "')"); + } + + for (int i = 0; i < SIZE; i++) { + int lower = i * 100; + int upper = (i + 10) * 100; + where[i] = "b >= " + lower + " AND b < " + upper; + } + } + + @Override + public void run() { + for (int i = 0; i < SIZE; i++) { + mDatabase + .query("t1", COLUMNS, where[i], null, null, null, null); + } + } + } + + /** + * INNER JOIN without an index + */ + + public static class Perf6Test extends PerformanceBase { + private static final int SIZE = 100; + private static final String[] COLUMNS = {"t1.a"}; + + @Override + public void setUp(Context c) { + super.setUp(c); + Random random = new Random(42); + + mDatabase + .execSQL("CREATE TABLE t1(a INTEGER, b INTEGER, c VARCHAR(100))"); + mDatabase + .execSQL("CREATE TABLE t2(a INTEGER, b INTEGER, c VARCHAR(100))"); + + for (int i = 0; i < SIZE; i++) { + int r = random.nextInt(100000); + mDatabase.execSQL("INSERT INTO t1 VALUES(" + i + "," + r + ",'" + + numberName(r) + "')"); + } + + for (int i = 0; i < SIZE; i++) { + int r = random.nextInt(100000); + mDatabase.execSQL("INSERT INTO t2 VALUES(" + i + "," + r + ",'" + + numberName(r) + "')"); + } + } + + @Override + public void run() { + mDatabase.query("t1 INNER JOIN t2 ON t1.b = t2.b", COLUMNS, null, + null, null, null, null); + } + } + + /** + * INNER JOIN without an index on one side + */ + + public static class Perf7Test extends PerformanceBase { + private static final int SIZE = 100; + private static final String[] COLUMNS = {"t1.a"}; + + @Override + public void setUp(Context c) { + super.setUp(c); + Random random = new Random(42); + + mDatabase + .execSQL("CREATE TABLE t1(a INTEGER, b INTEGER, c VARCHAR(100))"); + mDatabase + .execSQL("CREATE TABLE t2(a INTEGER, b INTEGER, c VARCHAR(100))"); + + mDatabase.execSQL("CREATE INDEX i1b ON t1(b)"); + + for (int i = 0; i < SIZE; i++) { + int r = random.nextInt(100000); + mDatabase.execSQL("INSERT INTO t1 VALUES(" + i + "," + r + ",'" + + numberName(r) + "')"); + } + + for (int i = 0; i < SIZE; i++) { + int r = random.nextInt(100000); + mDatabase.execSQL("INSERT INTO t2 VALUES(" + i + "," + r + ",'" + + numberName(r) + "')"); + } + } + + @Override + public void run() { + mDatabase.query("t1 INNER JOIN t2 ON t1.b = t2.b", COLUMNS, null, + null, null, null, null); + } + } + + /** + * INNER JOIN without an index on one side + */ + + public static class Perf8Test extends PerformanceBase { + private static final int SIZE = 100; + private static final String[] COLUMNS = {"t1.a"}; + + @Override + public void setUp(Context c) { + super.setUp(c); + Random random = new Random(42); + + mDatabase + .execSQL("CREATE TABLE t1(a INTEGER, b INTEGER, c VARCHAR(100))"); + mDatabase + .execSQL("CREATE TABLE t2(a INTEGER, b INTEGER, c VARCHAR(100))"); + + mDatabase.execSQL("CREATE INDEX i1b ON t1(b)"); + + for (int i = 0; i < SIZE; i++) { + int r = random.nextInt(100000); + mDatabase.execSQL("INSERT INTO t1 VALUES(" + i + "," + r + ",'" + + numberName(r) + "')"); + } + + for (int i = 0; i < SIZE; i++) { + int r = random.nextInt(100000); + mDatabase.execSQL("INSERT INTO t2 VALUES(" + i + "," + r + ",'" + + numberName(r) + "')"); + } + } + + @Override + public void run() { + mDatabase.query("t1 INNER JOIN t2 ON t1.c = t2.c", COLUMNS, null, + null, null, null, null); + } + } + + /** + * 100 SELECTs with subqueries. Subquery is using an index + */ + + public static class Perf9Test extends PerformanceBase { + private static final int SIZE = 100; + private static final String[] COLUMNS = {"t1.a"}; + + private String[] where = new String[SIZE]; + + @Override + public void setUp(Context c) { + super.setUp(c); + Random random = new Random(42); + + mDatabase + .execSQL("CREATE TABLE t1(a INTEGER, b INTEGER, c VARCHAR(100))"); + mDatabase + .execSQL("CREATE TABLE t2(a INTEGER, b INTEGER, c VARCHAR(100))"); + + mDatabase.execSQL("CREATE INDEX i2b ON t2(b)"); + + for (int i = 0; i < SIZE; i++) { + int r = random.nextInt(100000); + mDatabase.execSQL("INSERT INTO t1 VALUES(" + i + "," + r + ",'" + + numberName(r) + "')"); + } + + for (int i = 0; i < SIZE; i++) { + int r = random.nextInt(100000); + mDatabase.execSQL("INSERT INTO t2 VALUES(" + i + "," + r + ",'" + + numberName(r) + "')"); + } + + for (int i = 0; i < SIZE; i++) { + int lower = i * 100; + int upper = (i + 10) * 100; + where[i] = + "t1.b IN (SELECT t2.b FROM t2 WHERE t2.b >= " + lower + + " AND t2.b < " + upper + ")"; + } + } + + @Override + public void run() { + for (int i = 0; i < SIZE; i++) { + mDatabase + .query("t1", COLUMNS, where[i], null, null, null, null); + } + } + } + + /** + * 100 SELECTs on string comparison with Index + */ + + public static class Perf10Test extends PerformanceBase { + private static final int SIZE = 100; + private static final String[] COLUMNS = {"count(*)", "avg(b)"}; + + private String[] where = new String[SIZE]; + + @Override + public void setUp(Context c) { + super.setUp(c); + Random random = new Random(42); + + mDatabase + .execSQL("CREATE TABLE t1(a INTEGER, b INTEGER, c VARCHAR(100))"); + mDatabase.execSQL("CREATE INDEX i3c ON t1(c)"); + + for (int i = 0; i < SIZE; i++) { + int r = random.nextInt(100000); + mDatabase.execSQL("INSERT INTO t1 VALUES(" + i + "," + r + ",'" + + numberName(r) + "')"); + } + + for (int i = 0; i < SIZE; i++) { + where[i] = "c LIKE '" + numberName(i) + "'"; + } + } + + @Override + public void run() { + for (int i = 0; i < SIZE; i++) { + mDatabase + .query("t1", COLUMNS, where[i], null, null, null, null); + } + } + } + + /** + * 100 SELECTs on integer + */ + + public static class Perf11Test extends PerformanceBase { + private static final int SIZE = 100; + private static final String[] COLUMNS = {"b"}; + + private String[] where = new String[SIZE]; + + @Override + public void setUp(Context c) { + super.setUp(c); + Random random = new Random(42); + + mDatabase + .execSQL("CREATE TABLE t1(a INTEGER, b INTEGER, c VARCHAR(100))"); + + for (int i = 0; i < SIZE; i++) { + int r = random.nextInt(100000); + mDatabase.execSQL("INSERT INTO t1 VALUES(" + i + "," + r + ",'" + + numberName(r) + "')"); + } + + } + + @Override + public void run() { + for (int i = 0; i < SIZE; i++) { + mDatabase.query("t1", COLUMNS, null, null, null, null, null); + } + } + } + + /** + * 100 SELECTs on String + */ + + public static class Perf12Test extends PerformanceBase { + private static final int SIZE = 100; + private static final String[] COLUMNS = {"c"}; + + private String[] where = new String[SIZE]; + + @Override + public void setUp(Context c) { + super.setUp(c); + Random random = new Random(42); + + mDatabase + .execSQL("CREATE TABLE t1(a INTEGER, b INTEGER, c VARCHAR(100))"); + + for (int i = 0; i < SIZE; i++) { + int r = random.nextInt(100000); + mDatabase.execSQL("INSERT INTO t1 VALUES(" + i + "," + r + ",'" + + numberName(r) + "')"); + } + + } + + @Override + public void run() { + for (int i = 0; i < SIZE; i++) { + mDatabase.query("t1", COLUMNS, null, null, null, null, null); + } + } + } + + /** + * 100 SELECTs on integer with index + */ + + public static class Perf13Test extends PerformanceBase { + private static final int SIZE = 100; + private static final String[] COLUMNS = {"b"}; + + @Override + public void setUp(Context c) { + super.setUp(c); + Random random = new Random(42); + + mDatabase + .execSQL("CREATE TABLE t1(a INTEGER, b INTEGER, c VARCHAR(100))"); + mDatabase.execSQL("CREATE INDEX i1b on t1(b)"); + + for (int i = 0; i < SIZE; i++) { + int r = random.nextInt(100000); + mDatabase.execSQL("INSERT INTO t1 VALUES(" + i + "," + r + ",'" + + numberName(r) + "')"); + } + + } + + @Override + public void run() { + for (int i = 0; i < SIZE; i++) { + mDatabase.query("t1", COLUMNS, null, null, null, null, null); + } + } + } + + /** + * 100 SELECTs on String with index + */ + + public static class Perf14Test extends PerformanceBase { + private static final int SIZE = 100; + private static final String[] COLUMNS = {"c"}; + + @Override + public void setUp(Context c) { + super.setUp(c); + Random random = new Random(42); + + mDatabase + .execSQL("CREATE TABLE t1(a INTEGER, b INTEGER, c VARCHAR(100))"); + mDatabase.execSQL("CREATE INDEX i1c ON t1(c)"); + + for (int i = 0; i < SIZE; i++) { + int r = random.nextInt(100000); + mDatabase.execSQL("INSERT INTO t1 VALUES(" + i + "," + r + ",'" + + numberName(r) + "')"); + } + + } + + @Override + public void run() { + for (int i = 0; i < SIZE; i++) { + mDatabase.query("t1", COLUMNS, null, null, null, null, null); + } + } + } + + /** + * 100 SELECTs on String with starts with + */ + + public static class Perf15Test extends PerformanceBase { + private static final int SIZE = 100; + private static final String[] COLUMNS = {"c"}; + private String[] where = new String[SIZE]; + + @Override + public void setUp(Context c) { + super.setUp(c); + Random random = new Random(42); + + mDatabase + .execSQL("CREATE TABLE t1(a INTEGER, b INTEGER, c VARCHAR(100))"); + mDatabase.execSQL("CREATE INDEX i1c ON t1(c)"); + + for (int i = 0; i < SIZE; i++) { + int r = random.nextInt(100000); + mDatabase.execSQL("INSERT INTO t1 VALUES(" + i + "," + r + ",'" + + numberName(r) + "')"); + } + + for (int i = 0; i < SIZE; i++) { + int r = random.nextInt(100000); + where[i] = "c LIKE '" + numberName(r).substring(0, 1) + "*'"; + + } + + } + + @Override + public void run() { + for (int i = 0; i < SIZE; i++) { + mDatabase + .query("t1", COLUMNS, where[i], null, null, null, null); + } + } + } + + /** + * 1000 Deletes on an indexed table + */ + + public static class Perf16Test extends PerformanceBase { + private static final int SIZE = 1000; + private static final String[] COLUMNS = {"c"}; + + @Override + public void setUp(Context c) { + super.setUp(c); + Random random = new Random(42); + + mDatabase + .execSQL("CREATE TABLE t1(a INTEGER, b INTEGER, c VARCHAR(100))"); + mDatabase.execSQL("CREATE INDEX i3c ON t1(c)"); + + for (int i = 0; i < SIZE; i++) { + int r = random.nextInt(100000); + mDatabase.execSQL("INSERT INTO t1 VALUES(" + i + "," + r + ",'" + + numberName(r) + "')"); + } + + } + + @Override + public void run() { + for (int i = 0; i < SIZE; i++) { + mDatabase.delete("t1", null, null); + } + } + } + + /** + * 1000 Deletes + */ + + public static class Perf17Test extends PerformanceBase { + private static final int SIZE = 1000; + private static final String[] COLUMNS = {"c"}; + + @Override + public void setUp(Context c) { + super.setUp(c); + Random random = new Random(42); + + mDatabase + .execSQL("CREATE TABLE t1(a INTEGER, b INTEGER, c VARCHAR(100))"); + + for (int i = 0; i < SIZE; i++) { + int r = random.nextInt(100000); + mDatabase.execSQL("INSERT INTO t1 VALUES(" + i + "," + r + ",'" + + numberName(r) + "')"); + } + + } + + @Override + public void run() { + for (int i = 0; i < SIZE; i++) { + mDatabase.delete("t1", null, null); + } + } + } + + /** + * 1000 DELETE's without an index with where clause + */ + + public static class Perf18Test extends PerformanceBase { + private static final int SIZE = 1000; + private String[] where = new String[SIZE]; + + @Override + public void setUp(Context c) { + super.setUp(c); + Random random = new Random(42); + + mDatabase + .execSQL("CREATE TABLE t1(a INTEGER, b INTEGER, c VARCHAR(100))"); + + for (int i = 0; i < SIZE; i++) { + int r = random.nextInt(100000); + mDatabase.execSQL("INSERT INTO t1 VALUES(" + i + "," + r + ",'" + + numberName(r) + "')"); + } + + for (int i = 0; i < SIZE; i++) { + int lower = i * 100; + int upper = (i + 10) * 100; + where[i] = "b >= " + lower + " AND b < " + upper; + } + } + + @Override + public void run() { + for (int i = 0; i < SIZE; i++) { + mDatabase.delete("t1", where[i], null); + } + } + } + + /** + * 1000 DELETE's with an index with where clause + */ + + public static class Perf19Test extends PerformanceBase { + private static final int SIZE = 1000; + private String[] where = new String[SIZE]; + + @Override + public void setUp(Context c) { + super.setUp(c); + Random random = new Random(42); + + mDatabase + .execSQL("CREATE TABLE t1(a INTEGER, b INTEGER, c VARCHAR(100))"); + mDatabase.execSQL("CREATE INDEX i1b ON t1(b)"); + + for (int i = 0; i < SIZE; i++) { + int r = random.nextInt(100000); + mDatabase.execSQL("INSERT INTO t1 VALUES(" + i + "," + r + ",'" + + numberName(r) + "')"); + } + + for (int i = 0; i < SIZE; i++) { + int lower = i * 100; + int upper = (i + 10) * 100; + where[i] = "b >= " + lower + " AND b < " + upper; + } + } + + @Override + public void run() { + for (int i = 0; i < SIZE; i++) { + mDatabase.delete("t1", where[i], null); + } + } + } + + /** + * 1000 update's with an index with where clause + */ + + public static class Perf20Test extends PerformanceBase { + private static final int SIZE = 1000; + private String[] where = new String[SIZE]; + ContentValues[] mValues = new ContentValues[SIZE]; + + @Override + public void setUp(Context c) { + super.setUp(c); + Random random = new Random(42); + + mDatabase + .execSQL("CREATE TABLE t1(a INTEGER, b INTEGER, c VARCHAR(100))"); + mDatabase.execSQL("CREATE INDEX i1b ON t1(b)"); + + for (int i = 0; i < SIZE; i++) { + int r = random.nextInt(100000); + mDatabase.execSQL("INSERT INTO t1 VALUES(" + i + "," + r + ",'" + + numberName(r) + "')"); + } + + for (int i = 0; i < SIZE; i++) { + + int lower = i * 100; + int upper = (i + 10) * 100; + where[i] = "b >= " + lower + " AND b < " + upper; + ContentValues b = new ContentValues(1); + b.put("b", upper); + mValues[i] = b; + + } + } + + @Override + public void run() { + for (int i = 0; i < SIZE; i++) { + mDatabase.update("t1", mValues[i], where[i], null); + } + } + } + + /** + * 1000 update's without an index with where clause + */ + + public static class Perf21Test extends PerformanceBase { + private static final int SIZE = 1000; + private String[] where = new String[SIZE]; + ContentValues[] mValues = new ContentValues[SIZE]; + + @Override + public void setUp(Context c) { + super.setUp(c); + Random random = new Random(42); + + mDatabase + .execSQL("CREATE TABLE t1(a INTEGER, b INTEGER, c VARCHAR(100))"); + + for (int i = 0; i < SIZE; i++) { + int r = random.nextInt(100000); + mDatabase.execSQL("INSERT INTO t1 VALUES(" + i + "," + r + ",'" + + numberName(r) + "')"); + } + + for (int i = 0; i < SIZE; i++) { + + int lower = i * 100; + int upper = (i + 10) * 100; + where[i] = "b >= " + lower + " AND b < " + upper; + ContentValues b = new ContentValues(1); + b.put("b", upper); + mValues[i] = b; + } + } + + @Override + public void run() { + for (int i = 0; i < SIZE; i++) { + mDatabase.update("t1", mValues[i], where[i], null); + } + } + } + + /** + * 10000 inserts for an integer + */ + + public static class Perf22Test extends PerformanceBase { + private static final int SIZE = 10000; + ContentValues[] mValues = new ContentValues[SIZE]; + + @Override + public void setUp(Context c) { + super.setUp(c); + Random random = new Random(42); + + mDatabase + .execSQL("CREATE TABLE t1(a INTEGER)"); + + for (int i = 0; i < SIZE; i++) { + int r = random.nextInt(100000); + ContentValues b = new ContentValues(1); + b.put("a", r); + mValues[i] = b; + } + } + + @Override + public void run() { + for (int i = 0; i < SIZE; i++) { + mDatabase.insert("t1", null, mValues[i]); + } + } + } + + /** + * 10000 inserts for an integer -indexed table + */ + + public static class Perf23Test extends PerformanceBase { + private static final int SIZE = 10000; + ContentValues[] mValues = new ContentValues[SIZE]; + + @Override + public void setUp(Context c) { + super.setUp(c); + Random random = new Random(42); + + mDatabase + .execSQL("CREATE TABLE t1(a INTEGER)"); + mDatabase.execSQL("CREATE INDEX i1a ON t1(a)"); + + for (int i = 0; i < SIZE; i++) { + int r = random.nextInt(100000); + ContentValues b = new ContentValues(1); + b.put("a", r); + mValues[i] = b; + } + } + + @Override + public void run() { + for (int i = 0; i < SIZE; i++) { + mDatabase.insert("t1", null, mValues[i]); + } + } + } + + /** + * 10000 inserts for a String + */ + + public static class Perf24Test extends PerformanceBase { + private static final int SIZE = 10000; + ContentValues[] mValues = new ContentValues[SIZE]; + + @Override + public void setUp(Context c) { + super.setUp(c); + Random random = new Random(42); + + mDatabase + .execSQL("CREATE TABLE t1(a VARCHAR(100))"); + + for (int i = 0; i < SIZE; i++) { + int r = random.nextInt(100000); + ContentValues b = new ContentValues(1); + b.put("a", numberName(r)); + mValues[i] = b; + } + } + + @Override + public void run() { + for (int i = 0; i < SIZE; i++) { + mDatabase.insert("t1", null, mValues[i]); + } + } + } + + /** + * 10000 inserts for a String - indexed table + */ + + public static class Perf25Test extends PerformanceBase { + private static final int SIZE = 10000; + ContentValues[] mValues = new ContentValues[SIZE]; + + @Override + public void setUp(Context c) { + super.setUp(c); + Random random = new Random(42); + + mDatabase + .execSQL("CREATE TABLE t1(a VARCHAR(100))"); + mDatabase.execSQL("CREATE INDEX i1a ON t1(a)"); + + for (int i = 0; i < SIZE; i++) { + int r = random.nextInt(100000); + ContentValues b = new ContentValues(1); + b.put("a", numberName(r)); + mValues[i] = b; + } + } + + @Override + public void run() { + for (int i = 0; i < SIZE; i++) { + mDatabase.insert("t1", null, mValues[i]); + } + } + } + + + /** + * 10000 selects for a String -starts with + */ + + public static class Perf26Test extends PerformanceBase { + private static final int SIZE = 10000; + private static final String[] COLUMNS = {"t3.a"}; + private String[] where = new String[SIZE]; + + @Override + public void setUp(Context c) { + super.setUp(c); + Random random = new Random(42); + + mDatabase + .execSQL("CREATE TABLE t3(a VARCHAR(100))"); + + for (int i = 0; i < SIZE; i++) { + int r = random.nextInt(100000); + mDatabase.execSQL("INSERT INTO t3 VALUES('" + + numberName(r) + "')"); + } + + for (int i = 0; i < SIZE; i++) { + int r = random.nextInt(100000); + where[i] = "a LIKE '" + numberName(r).substring(0, 1) + "*'"; + + } + } + + @Override + public void run() { + for (int i = 0; i < SIZE; i++) { + mDatabase.query("t3", COLUMNS, where[i], null, null, null, null); + } + } + } + + /** + * 10000 selects for a String - indexed table -starts with + */ + + public static class Perf27Test extends PerformanceBase { + private static final int SIZE = 10000; + private static final String[] COLUMNS = {"t3.a"}; + private String[] where = new String[SIZE]; + + @Override + public void setUp(Context c) { + super.setUp(c); + Random random = new Random(42); + + mDatabase + .execSQL("CREATE TABLE t3(a VARCHAR(100))"); + mDatabase.execSQL("CREATE INDEX i3a ON t3(a)"); + + for (int i = 0; i < SIZE; i++) { + int r = random.nextInt(100000); + mDatabase.execSQL("INSERT INTO t3 VALUES('" + + numberName(r) + "')"); + } + + for (int i = 0; i < SIZE; i++) { + int r = random.nextInt(100000); + where[i] = "a LIKE '" + numberName(r).substring(0, 1) + "*'"; + + } + } + + @Override + public void run() { + for (int i = 0; i < SIZE; i++) { + mDatabase.query("t3", COLUMNS, where[i], null, null, null, null); + } + } + } + + /** + * 10000 selects for an integer - + */ + + public static class Perf28Test extends PerformanceBase { + private static final int SIZE = 10000; + private static final String[] COLUMNS = {"t4.a"}; + private String[] where = new String[SIZE]; + + @Override + public void setUp(Context c) { + super.setUp(c); + Random random = new Random(42); + + mDatabase + .execSQL("CREATE TABLE t4(a INTEGER)"); + + for (int i = 0; i < SIZE; i++) { + int r = random.nextInt(100000); + mDatabase.execSQL("INSERT INTO t4 VALUES(" + r + ")"); + int lower = i * 100; + int upper = (i + 10) * 100; + where[i] = "a >= " + lower + " AND a < " + upper; + } + } + + @Override + public void run() { + for (int i = 0; i < SIZE; i++) { + mDatabase.query("t4", COLUMNS, where[i], null, null, null, null); + } + } + } + + /** + * 10000 selects for an integer -indexed table + */ + + public static class Perf29Test extends PerformanceBase { + private static final int SIZE = 10000; + private static final String[] COLUMNS = {"t4.a"}; + private String[] where = new String[SIZE]; + + @Override + public void setUp(Context c) { + super.setUp(c); + Random random = new Random(42); + + mDatabase + .execSQL("CREATE TABLE t4(a INTEGER)"); + mDatabase.execSQL("CREATE INDEX i4a ON t4(a)"); + + for (int i = 0; i < SIZE; i++) { + int r = random.nextInt(100000); + mDatabase.execSQL("INSERT INTO t4 VALUES(" + r + ")"); + + int lower = i * 100; + int upper = (i + 10) * 100; + where[i] = "a >= " + lower + " AND a < " + upper; + } + + } + + @Override + public void run() { + for (int i = 0; i < SIZE; i++) { + mDatabase.query("t4", COLUMNS, where[i], null, null, null, null); + } + } + } + + + /** + * 10000 selects for a String - contains 'e' + */ + + public static class Perf30Test extends PerformanceBase { + private static final int SIZE = 10000; + private static final String[] COLUMNS = {"t3.a"}; + private String[] where = new String[SIZE]; + + @Override + public void setUp(Context c) { + super.setUp(c); + Random random = new Random(42); + + mDatabase + .execSQL("CREATE TABLE t3(a VARCHAR(100))"); + + for (int i = 0; i < SIZE; i++) { + int r = random.nextInt(100000); + mDatabase.execSQL("INSERT INTO t3 VALUES('" + + numberName(r) + "')"); + } + + for (int i = 0; i < SIZE; i++) { + where[i] = "a LIKE '*e*'"; + + } + } + + @Override + public void run() { + for (int i = 0; i < SIZE; i++) { + mDatabase.query("t3", COLUMNS, where[i], null, null, null, null); + } + } + } + + /** + * 10000 selects for a String - contains 'e'-indexed table + */ + + public static class Perf31Test extends PerformanceBase { + private static final int SIZE = 10000; + private static final String[] COLUMNS = {"t3.a"}; + private String[] where = new String[SIZE]; + + @Override + public void setUp(Context c) { + super.setUp(c); + Random random = new Random(42); + + mDatabase + .execSQL("CREATE TABLE t3(a VARCHAR(100))"); + mDatabase.execSQL("CREATE INDEX i3a ON t3(a)"); + + for (int i = 0; i < SIZE; i++) { + int r = random.nextInt(100000); + mDatabase.execSQL("INSERT INTO t3 VALUES('" + + numberName(r) + "')"); + } + + for (int i = 0; i < SIZE; i++) { + where[i] = "a LIKE '*e*'"; + + } + + } + + @Override + public void run() { + for (int i = 0; i < SIZE; i++) { + mDatabase.query("t3", COLUMNS, where[i], null, null, null, null); + } + } + } + + public static final String[] ONES = + {"zero", "one", "two", "three", "four", "five", "six", "seven", + "eight", "nine", "ten", "eleven", "twelve", "thirteen", + "fourteen", "fifteen", "sixteen", "seventeen", "eighteen", + "nineteen"}; + + public static final String[] TENS = + {"", "ten", "twenty", "thirty", "forty", "fifty", "sixty", + "seventy", "eighty", "ninety"}; +} diff --git a/tests/AndroidTests/src/com/android/unit_tests/DatabaseStatementTest.java b/tests/AndroidTests/src/com/android/unit_tests/DatabaseStatementTest.java new file mode 100644 index 0000000000000000000000000000000000000000..16ca59f51b83ff2b69df80a7ad11e1e7d0c824a2 --- /dev/null +++ b/tests/AndroidTests/src/com/android/unit_tests/DatabaseStatementTest.java @@ -0,0 +1,320 @@ +/* + * Copyright (C) 2007 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.android.unit_tests; + +import android.database.Cursor; +import android.database.sqlite.SQLiteConstraintException; +import android.database.sqlite.SQLiteDatabase; +import android.database.sqlite.SQLiteDoneException; +import android.database.sqlite.SQLiteStatement; +import android.test.PerformanceTestCase; +import android.test.suitebuilder.annotation.MediumTest; +import android.test.suitebuilder.annotation.SmallTest; +import junit.framework.TestCase; + +import java.io.File; + +public class DatabaseStatementTest extends TestCase implements PerformanceTestCase { + + private static final String sString1 = "this is a test"; + private static final String sString2 = "and yet another test"; + private static final String sString3 = "this string is a little longer, but still a test"; + + private static final int CURRENT_DATABASE_VERSION = 42; + private SQLiteDatabase mDatabase; + private File mDatabaseFile; + + @Override + protected void setUp() throws Exception { + super.setUp(); + mDatabaseFile = new File("/sqlite_stmt_journals", "database_test.db"); + if (mDatabaseFile.exists()) { + mDatabaseFile.delete(); + } + mDatabase = SQLiteDatabase.openOrCreateDatabase(mDatabaseFile.getPath(), null); + assertNotNull(mDatabase); + mDatabase.setVersion(CURRENT_DATABASE_VERSION); + } + + @Override + protected void tearDown() throws Exception { + mDatabase.close(); + mDatabaseFile.delete(); + super.tearDown(); + } + + public boolean isPerformanceOnly() { + return false; + } + + // These test can only be run once. + public int startPerformance(Intermediates intermediates) { + return 1; + } + + private void populateDefaultTable() { + mDatabase.execSQL("CREATE TABLE test (_id INTEGER PRIMARY KEY, data TEXT);"); + + mDatabase.execSQL("INSERT INTO test (data) VALUES ('" + sString1 + "');"); + mDatabase.execSQL("INSERT INTO test (data) VALUES ('" + sString2 + "');"); + mDatabase.execSQL("INSERT INTO test (data) VALUES ('" + sString3 + "');"); + } + + @MediumTest + public void testExecuteStatement() throws Exception { + populateDefaultTable(); + SQLiteStatement statement = mDatabase.compileStatement("DELETE FROM test"); + statement.execute(); + + Cursor c = mDatabase.query("test", null, null, null, null, null, null); + assertEquals(0, c.getCount()); + c.deactivate(); + statement.close(); + } + + @MediumTest + public void testSimpleQuery() throws Exception { + mDatabase.execSQL("CREATE TABLE test (num INTEGER NOT NULL, str TEXT NOT NULL);"); + mDatabase.execSQL("INSERT INTO test VALUES (1234, 'hello');"); + SQLiteStatement statement1 = + mDatabase.compileStatement("SELECT num FROM test WHERE str = ?"); + SQLiteStatement statement2 = + mDatabase.compileStatement("SELECT str FROM test WHERE num = ?"); + + try { + statement1.bindString(1, "hello"); + long value = statement1.simpleQueryForLong(); + assertEquals(1234, value); + + statement1.bindString(1, "world"); + statement1.simpleQueryForLong(); + fail("shouldn't get here"); + } catch (SQLiteDoneException e) { + // expected + } + + try { + statement2.bindLong(1, 1234); + String value = statement1.simpleQueryForString(); + assertEquals("hello", value); + + statement2.bindLong(1, 5678); + statement1.simpleQueryForString(); + fail("shouldn't get here"); + } catch (SQLiteDoneException e) { + // expected + } + + statement1.close(); + statement2.close(); + } + + @MediumTest + public void testStatementLongBinding() throws Exception { + mDatabase.execSQL("CREATE TABLE test (num INTEGER);"); + SQLiteStatement statement = mDatabase.compileStatement("INSERT INTO test (num) VALUES (?)"); + + for (int i = 0; i < 10; i++) { + statement.bindLong(1, i); + statement.execute(); + } + statement.close(); + + Cursor c = mDatabase.query("test", null, null, null, null, null, null); + int numCol = c.getColumnIndexOrThrow("num"); + c.moveToFirst(); + for (long i = 0; i < 10; i++) { + long num = c.getLong(numCol); + assertEquals(i, num); + c.moveToNext(); + } + c.close(); + } + + @MediumTest + public void testStatementStringBinding() throws Exception { + mDatabase.execSQL("CREATE TABLE test (num TEXT);"); + SQLiteStatement statement = mDatabase.compileStatement("INSERT INTO test (num) VALUES (?)"); + + for (long i = 0; i < 10; i++) { + statement.bindString(1, Long.toHexString(i)); + statement.execute(); + } + statement.close(); + + Cursor c = mDatabase.query("test", null, null, null, null, null, null); + int numCol = c.getColumnIndexOrThrow("num"); + c.moveToFirst(); + for (long i = 0; i < 10; i++) { + String num = c.getString(numCol); + assertEquals(Long.toHexString(i), num); + c.moveToNext(); + } + c.close(); + } + + @MediumTest + public void testStatementClearBindings() throws Exception { + mDatabase.execSQL("CREATE TABLE test (num INTEGER);"); + SQLiteStatement statement = mDatabase.compileStatement("INSERT INTO test (num) VALUES (?)"); + + for (long i = 0; i < 10; i++) { + statement.bindLong(1, i); + statement.clearBindings(); + statement.execute(); + } + statement.close(); + + Cursor c = mDatabase.query("test", null, null, null, null, null, "ROWID"); + int numCol = c.getColumnIndexOrThrow("num"); + assertTrue(c.moveToFirst()); + for (long i = 0; i < 10; i++) { + assertTrue(c.isNull(numCol)); + c.moveToNext(); + } + c.close(); + } + + @MediumTest + public void testSimpleStringBinding() throws Exception { + mDatabase.execSQL("CREATE TABLE test (num TEXT, value TEXT);"); + String statement = "INSERT INTO test (num, value) VALUES (?,?)"; + + String[] args = new String[2]; + for (int i = 0; i < 2; i++) { + args[i] = Integer.toHexString(i); + } + + mDatabase.execSQL(statement, args); + + Cursor c = mDatabase.query("test", null, null, null, null, null, null); + int numCol = c.getColumnIndexOrThrow("num"); + int valCol = c.getColumnIndexOrThrow("value"); + c.moveToFirst(); + String num = c.getString(numCol); + assertEquals(Integer.toHexString(0), num); + + String val = c.getString(valCol); + assertEquals(Integer.toHexString(1), val); + c.close(); + } + + @MediumTest + public void testStatementMultipleBindings() throws Exception { + mDatabase.execSQL("CREATE TABLE test (num INTEGER, str TEXT);"); + SQLiteStatement statement = + mDatabase.compileStatement("INSERT INTO test (num, str) VALUES (?, ?)"); + + for (long i = 0; i < 10; i++) { + statement.bindLong(1, i); + statement.bindString(2, Long.toHexString(i)); + statement.execute(); + } + statement.close(); + + Cursor c = mDatabase.query("test", null, null, null, null, null, "ROWID"); + int numCol = c.getColumnIndexOrThrow("num"); + int strCol = c.getColumnIndexOrThrow("str"); + assertTrue(c.moveToFirst()); + for (long i = 0; i < 10; i++) { + long num = c.getLong(numCol); + String str = c.getString(strCol); + assertEquals(i, num); + assertEquals(Long.toHexString(i), str); + c.moveToNext(); + } + c.close(); + } + + private static class StatementTestThread extends Thread { + private SQLiteDatabase mDatabase; + private SQLiteStatement mStatement; + + public StatementTestThread(SQLiteDatabase db, SQLiteStatement statement) { + super(); + mDatabase = db; + mStatement = statement; + } + + @Override + public void run() { + mDatabase.beginTransaction(); + for (long i = 0; i < 10; i++) { + mStatement.bindLong(1, i); + mStatement.bindString(2, Long.toHexString(i)); + mStatement.execute(); + } + mDatabase.setTransactionSuccessful(); + mDatabase.endTransaction(); + + Cursor c = mDatabase.query("test", null, null, null, null, null, "ROWID"); + int numCol = c.getColumnIndexOrThrow("num"); + int strCol = c.getColumnIndexOrThrow("str"); + assertTrue(c.moveToFirst()); + for (long i = 0; i < 10; i++) { + long num = c.getLong(numCol); + String str = c.getString(strCol); + assertEquals(i, num); + assertEquals(Long.toHexString(i), str); + c.moveToNext(); + } + c.close(); + } + } + + @MediumTest + public void testStatementMultiThreaded() throws Exception { + mDatabase.execSQL("CREATE TABLE test (num INTEGER, str TEXT);"); + SQLiteStatement statement = + mDatabase.compileStatement("INSERT INTO test (num, str) VALUES (?, ?)"); + + StatementTestThread thread = new StatementTestThread(mDatabase, statement); + thread.start(); + try { + thread.join(); + } finally { + statement.close(); + } + } + + @MediumTest + public void testStatementConstraint() throws Exception { + mDatabase.execSQL("CREATE TABLE test (num INTEGER NOT NULL);"); + SQLiteStatement statement = mDatabase.compileStatement("INSERT INTO test (num) VALUES (?)"); + + // Try to insert NULL, which violates the constraint + try { + statement.clearBindings(); + statement.execute(); + fail("expected exception not thrown"); + } catch (SQLiteConstraintException e) { + // expected + } + + // Make sure the statement can still be used + statement.bindLong(1, 1); + statement.execute(); + statement.close(); + + Cursor c = mDatabase.query("test", null, null, null, null, null, null); + int numCol = c.getColumnIndexOrThrow("num"); + c.moveToFirst(); + long num = c.getLong(numCol); + assertEquals(1, num); + c.close(); + } +} diff --git a/tests/AndroidTests/src/com/android/unit_tests/DatabaseStressTest.java b/tests/AndroidTests/src/com/android/unit_tests/DatabaseStressTest.java new file mode 100644 index 0000000000000000000000000000000000000000..b1101254556b0cc86b7bc99b7f769dc25b5427bc --- /dev/null +++ b/tests/AndroidTests/src/com/android/unit_tests/DatabaseStressTest.java @@ -0,0 +1,99 @@ +/* + * 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.android.unit_tests; + +import android.content.Context; +import android.database.sqlite.*; +import android.util.Log; + +import android.test.AndroidTestCase; +import android.test.suitebuilder.annotation.Suppress; + +import java.io.File; + +// This test suite is too desctructive and takes too long to be included in the +// automated suite. +@Suppress +public class DatabaseStressTest extends AndroidTestCase { + private static final String TAG = "DatabaseStressTest"; + private static final int CURRENT_DATABASE_VERSION = 1; + private SQLiteDatabase mDatabase; + private File mDatabaseFile; + + @Override + protected void setUp() throws Exception { + super.setUp(); + Context c = getContext(); + + mDatabaseFile = c.getDatabasePath("database_test.db"); + if (mDatabaseFile.exists()) { + mDatabaseFile.delete(); + } + + mDatabase = c.openOrCreateDatabase("database_test.db", 0, null); + + assertNotNull(mDatabase); + mDatabase.setVersion(CURRENT_DATABASE_VERSION); + + mDatabase.execSQL("CREATE TABLE IF NOT EXISTS test (_id INTEGER PRIMARY KEY, data TEXT);"); + + } + + @Override + protected void tearDown() throws Exception { + mDatabase.close(); + mDatabaseFile.delete(); + super.tearDown(); + } + + public void testSingleThreadInsertDelete() { + int i = 0; + char[] ch = new char[100000]; + String str = new String(ch); + String[] strArr = new String[1]; + strArr[0] = str; + for (; i < 10000; ++i) { + try { + mDatabase.execSQL("INSERT INTO test (data) VALUES (?)", strArr); + mDatabase.execSQL("delete from test;"); + } catch (Exception e) { + Log.e(TAG, "exception " + e.getMessage()); + } + } + } + + /** + * use fillup -p 90 before run the test + * and when disk run out + * start delete some fillup files + * and see if db recover + */ + public void testOutOfSpace() { + int i = 0; + char[] ch = new char[100000]; + String str = new String(ch); + String[] strArr = new String[1]; + strArr[0] = str; + for (; i < 10000; ++i) { + try { + mDatabase.execSQL("INSERT INTO test (data) VALUES (?)", strArr); + } catch (Exception e) { + Log.e(TAG, "exception " + e.getMessage()); + } + } + } +} diff --git a/tests/AndroidTests/src/com/android/unit_tests/DatabaseTests.java b/tests/AndroidTests/src/com/android/unit_tests/DatabaseTests.java new file mode 100644 index 0000000000000000000000000000000000000000..68b0b83aaa35dc0f66712e122ad7123fc9bcb410 --- /dev/null +++ b/tests/AndroidTests/src/com/android/unit_tests/DatabaseTests.java @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2007 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.android.unit_tests; + +import junit.framework.TestSuite; + +public class DatabaseTests { + public static TestSuite suite() { + TestSuite suite = new TestSuite(DatabaseTests.class.getName()); + + suite.addTestSuite(DatabaseGeneralTest.class); + suite.addTestSuite(DatabaseCursorTest.class); + suite.addTestSuite(DatabaseStatementTest.class); + suite.addTestSuite(DatabaseLocaleTest.class); + suite.addTestSuite(CursorWindowTest.class); + + return suite; + } +} diff --git a/tests/AndroidTests/src/com/android/unit_tests/ExpatPerformanceTest.java b/tests/AndroidTests/src/com/android/unit_tests/ExpatPerformanceTest.java new file mode 100644 index 0000000000000000000000000000000000000000..0d51047224e26a37841f611298fff28a3bee1ca0 --- /dev/null +++ b/tests/AndroidTests/src/com/android/unit_tests/ExpatPerformanceTest.java @@ -0,0 +1,123 @@ +/* + * Copyright (C) 2007 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.android.unit_tests; + +import android.test.AndroidTestCase; +import android.test.suitebuilder.annotation.LargeTest; +import android.util.Log; +import android.util.Xml; +import org.kxml2.io.KXmlParser; +import org.xml.sax.SAXException; +import org.xml.sax.helpers.DefaultHandler; +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; + +public class ExpatPerformanceTest extends AndroidTestCase { + + private static final String TAG = ExpatPerformanceTest.class.getSimpleName(); + + private byte[] mXmlBytes; + + @Override + public void setUp() throws Exception { + super.setUp(); + InputStream in = mContext.getResources().openRawResource(R.raw.youtube); + ByteArrayOutputStream out = new ByteArrayOutputStream(); + byte[] buffer = new byte[1024]; + int length; + while ((length = in.read(buffer)) != -1) { + out.write(buffer, 0, length); + } + mXmlBytes = out.toByteArray(); + + Log.i("***", "File size: " + (mXmlBytes.length / 1024) + "k"); + } + + @LargeTest + public void testPerformance() throws Exception { +// try { +// Debug.startMethodTracing("expat3"); +// for (int i = 0; i < 1; i++) { + runJavaPullParser(); + runSax(); + runExpatPullParser(); +// } +// } finally { +// Debug.stopMethodTracing(); +// } + } + + private InputStream newInputStream() { + return new ByteArrayInputStream(mXmlBytes); + } + + private void runSax() throws IOException, SAXException { + long start = System.currentTimeMillis(); + Xml.parse(newInputStream(), Xml.Encoding.UTF_8, new DefaultHandler()); + long elapsed = System.currentTimeMillis() - start; + Log.i(TAG, "expat SAX: " + elapsed + "ms"); + } + + private void runExpatPullParser() throws XmlPullParserException, IOException { + long start = System.currentTimeMillis(); + XmlPullParser pullParser = Xml.newPullParser(); + pullParser.setInput(newInputStream(), "UTF-8"); + withPullParser(pullParser); + long elapsed = System.currentTimeMillis() - start; + Log.i(TAG, "expat pull: " + elapsed + "ms"); + } + + private void runJavaPullParser() throws XmlPullParserException, IOException { + XmlPullParser pullParser; + long start = System.currentTimeMillis(); + pullParser = new KXmlParser(); + pullParser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true); + pullParser.setInput(newInputStream(), "UTF-8"); + withPullParser(pullParser); + long elapsed = System.currentTimeMillis() - start; + Log.i(TAG, "java pull parser: " + elapsed + "ms"); + } + + private static void withPullParser(XmlPullParser pullParser) + throws IOException, XmlPullParserException { + int eventType = pullParser.next(); + while (eventType != XmlPullParser.END_DOCUMENT) { + switch (eventType) { + case XmlPullParser.START_TAG: + pullParser.getName(); +// int nattrs = pullParser.getAttributeCount(); +// for (int i = 0; i < nattrs; ++i) { +// pullParser.getAttributeName(i); +// pullParser.getAttributeValue(i); +// } + break; + case XmlPullParser.END_TAG: + pullParser.getName(); + break; + case XmlPullParser.TEXT: + pullParser.getText(); + break; + } + eventType = pullParser.next(); + } + } +} diff --git a/tests/AndroidTests/src/com/android/unit_tests/GDataParseTest.java b/tests/AndroidTests/src/com/android/unit_tests/GDataParseTest.java new file mode 100644 index 0000000000000000000000000000000000000000..af854832aff0204b9de30b71b6c7cbbdc9c30fe3 --- /dev/null +++ b/tests/AndroidTests/src/com/android/unit_tests/GDataParseTest.java @@ -0,0 +1,162 @@ +/* + * Copyright (C) 2006 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.android.unit_tests; + +import android.content.res.XmlResourceParser; +import android.test.AndroidTestCase; +import android.test.PerformanceTestCase; +import android.test.suitebuilder.annotation.MediumTest; +import android.test.suitebuilder.annotation.SmallTest; +import android.util.Xml; +import com.google.wireless.gdata.data.Entry; +import com.google.wireless.gdata.data.Feed; +import com.google.wireless.gdata.parser.ParseException; +import com.google.wireless.gdata.parser.xml.XmlGDataParser; +import org.json.JSONObject; +import org.json.JSONTokener; +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.zip.GZIPInputStream; + +/** + * Tests timing on parsing various formats of GData. + */ +public class GDataParseTest extends AndroidTestCase implements PerformanceTestCase { + + private static void parseXml(InputStream is) throws ParseException, IOException { + XmlPullParser xmlParser = Xml.newPullParser(); + XmlGDataParser parser = new XmlGDataParser(is, xmlParser); + Feed feed = parser.init(); + Entry entry = null; + while (parser.hasMoreData()) { + entry = parser.readNextEntry(entry); + } + } + + private static void parseXml(XmlPullParser xmlP) throws ParseException, IOException { + XmlGDataParser parser = new XmlGDataParser(null /* in */, xmlP); + Feed feed = parser.init(); + Entry entry = null; + while (parser.hasMoreData()) { + entry = parser.readNextEntry(entry); + } + } + + private static void dumpXml(XmlPullParser parser) throws + XmlPullParserException, IOException { + int eventType = parser.nextTag(); + while (eventType != XmlPullParser.END_DOCUMENT) { + switch (eventType) { + case XmlPullParser.START_TAG: + parser.getName(); + // System.out.print("<" + parser.getName()); + int nattrs = parser.getAttributeCount(); + for (int i = 0; i < nattrs; ++i) { + parser.getAttributeName(i); + parser.getAttributeValue(i); + // System.out.print(" " + parser.getAttributeName(i) + "=\"" + // + parser.getAttributeValue(i) + "\""); + } + // System.out.print(">"); + break; + case XmlPullParser.END_TAG: + parser.getName(); + // System.out.print(""); + break; + case XmlPullParser.TEXT: + parser.getText(); + // System.out.print(parser.getText()); + break; + default: + // do nothing + } + eventType = parser.next(); + } + } + + private byte[] getBytesForResource(int resid) throws Exception { + // all resources are written into a zip file, so the InputStream we + // get for a resource is on top of zipped + // data. in order to compare performance of parsing unzipped vs. + // zipped content, we first read the data into an in-memory buffer. + InputStream zipIs = null; + try { + zipIs = mContext.getResources().openRawResource(resid); + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + byte buf[] = new byte[1024]; + int bytesRead = zipIs.read(buf); + while (bytesRead > 0) { + baos.write(buf, 0, bytesRead); + bytesRead = zipIs.read(buf); + } + return baos.toByteArray(); + } finally { + if (zipIs != null) { + zipIs.close(); + } + } + } + + public boolean isPerformanceOnly() { + return true; + } + + public int startPerformance(PerformanceTestCase.Intermediates intermediates) { + return 0; + } + + @MediumTest + public void testXml() throws Exception { + InputStream is = new ByteArrayInputStream(getBytesForResource(R.raw.calendarxml)); + try { + is.reset(); + parseXml(is); + } finally { + is.close(); + } + } + + @MediumTest + public void testXmlGzip() throws Exception { + InputStream gzIs = new GZIPInputStream( + new ByteArrayInputStream(getBytesForResource(R.raw.calendarxmlgz))); + try { + parseXml(gzIs); + } finally { + gzIs.close(); + } + } + + @MediumTest + public void testJson() throws Exception { + String jsonString = new String(getBytesForResource(R.raw.calendarjs), "UTF-8"); + JSONTokener tokens = new JSONTokener(jsonString); + assertNotNull(new JSONObject(tokens)); + } + + @SmallTest + public void testBinaryXml() throws Exception { + XmlResourceParser parser = mContext.getResources().getXml(R.xml.calendar); + parseXml(parser); + parser.close(); + } +} diff --git a/tests/AndroidTests/src/com/android/unit_tests/GeocoderTest.java b/tests/AndroidTests/src/com/android/unit_tests/GeocoderTest.java new file mode 100644 index 0000000000000000000000000000000000000000..e28a7dc489f5a26f254a8f209a6777dbdf587e0a --- /dev/null +++ b/tests/AndroidTests/src/com/android/unit_tests/GeocoderTest.java @@ -0,0 +1,64 @@ +package com.android.unit_tests; + +/* + * Copyright (C) 2007 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. + */ + +import android.location.Address; +import android.location.Geocoder; +import android.test.AndroidTestCase; +import android.test.suitebuilder.annotation.Suppress; +import android.util.Log; + +import java.io.IOException; +import java.util.HashSet; +import java.util.Locale; +import java.util.Set; +import java.util.List; + +@Suppress +public class GeocoderTest extends AndroidTestCase { + + public void testGeocoder() throws Exception { + Locale locale = new Locale("en", "us"); + Geocoder g = new Geocoder(mContext, locale); + + List

              addresses1 = g.getFromLocation(37.435067, -122.166767, 2); + assertNotNull(addresses1); + assertEquals(1, addresses1.size()); + + Address addr = addresses1.get(0); + assertEquals("94305", addr.getFeatureName()); + assertEquals("Palo Alto, CA 94305", addr.getAddressLine(0)); + assertEquals("USA", addr.getAddressLine(1)); + assertEquals("94305", addr.getPostalCode()); + assertFalse(Math.abs(addr.getLatitude() - 37.4240385) > 0.1); + + List
              addresses2 = g.getFromLocationName("San Francisco, CA", 1); + assertNotNull(addresses2); + assertEquals(1, addresses2.size()); + + addr = addresses2.get(0); + assertEquals("San Francisco", addr.getFeatureName()); + assertEquals("San Francisco, CA", addr.getAddressLine(0)); + assertEquals("United States", addr.getAddressLine(1)); + assertEquals("San Francisco", addr.getLocality()); + assertEquals("CA", addr.getAdminArea()); + assertEquals(null, addr.getPostalCode()); + + assertFalse(Math.abs(addr.getLatitude() - 37.77916) > 0.1); + + } +} diff --git a/tests/AndroidTests/src/com/android/unit_tests/GoogleHttpClientTest.java b/tests/AndroidTests/src/com/android/unit_tests/GoogleHttpClientTest.java new file mode 100644 index 0000000000000000000000000000000000000000..9eb3e9468ba082b8492a3498c226b6a68071f884 --- /dev/null +++ b/tests/AndroidTests/src/com/android/unit_tests/GoogleHttpClientTest.java @@ -0,0 +1,120 @@ +/* + * 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.android.unit_tests; + +import android.content.ContentResolver; +import android.net.http.AndroidHttpClient; +import android.provider.Checkin; +import android.provider.Settings; +import android.test.AndroidTestCase; +import android.test.suitebuilder.annotation.LargeTest; +import android.test.suitebuilder.annotation.MediumTest; + +import com.google.android.collect.Lists; +import com.google.android.net.GoogleHttpClient; + +import org.apache.http.HttpException; +import org.apache.http.HttpRequest; +import org.apache.http.HttpResponse; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.entity.StringEntity; +import org.apache.http.protocol.HttpContext; +import org.apache.http.protocol.HttpRequestHandler; +import org.apache.http.util.EntityUtils; + +import java.io.IOException; + +/** Unit test for {@link GoogleHttpClient}. */ +public class GoogleHttpClientTest extends AndroidTestCase { + private TestHttpServer mServer; + private String mServerUrl; + + protected void setUp() throws Exception { + // Run a test server that echoes the URI back to the caller. + mServer = new TestHttpServer(); + mServer.registerHandler("*", new HttpRequestHandler() { + public void handle( + HttpRequest request, + HttpResponse response, + HttpContext context) throws HttpException, IOException { + String uri = request.getRequestLine().getUri(); + response.setEntity(new StringEntity(uri)); + } + }); + + mServer.start(); + mServerUrl = "http://localhost:" + mServer.getPort() + "/"; + } + + protected void tearDown() throws Exception { + if (mServer != null) mServer.shutdown(); + } + + @LargeTest + public void testThreadCheck() throws Exception { + ContentResolver resolver = getContext().getContentResolver(); + GoogleHttpClient client = new GoogleHttpClient(resolver, "Test"); + + try { + // Note: we must test against a real server, because the connection + // gets established before the interceptor can crash the request. + HttpGet method = new HttpGet(mServerUrl); + + // This is actually an AndroidHttpClient feature... + // TODO: somehow test that Activity threads have the flag set? + AndroidHttpClient.setThreadBlocked(true); + + try { + client.execute(method); + fail("\"thread forbids HTTP requests\" exception expected"); + } catch (RuntimeException e) { + if (!e.toString().contains("forbids HTTP requests")) throw e; + } finally { + AndroidHttpClient.setThreadBlocked(false); + } + + HttpResponse response = client.execute(method); + assertEquals("/", EntityUtils.toString(response.getEntity())); + } finally { + client.close(); + } + } + + @MediumTest + public void testUrlRewriteRules() throws Exception { + // Don't do anything exotic; UrlRulesTest checks the actual rewriter. + // Just make sure that URLs are, in fact, rewritten. + + // TODO: Use a MockContentProvider/MockContentResolver instead. + ContentResolver resolver = getContext().getContentResolver(); + GoogleHttpClient client = new GoogleHttpClient(resolver, "Test"); + Settings.Gservices.putString(resolver, + "url:test", "http://foo.bar/ rewrite " + mServerUrl + "new/"); + + // Update the digest, so the UrlRules cache is reloaded. + Settings.Gservices.putString(resolver, "digest", mServerUrl); + + try { + HttpGet method = new HttpGet("http://foo.bar/path"); + HttpResponse response = client.execute(method); + String body = EntityUtils.toString(response.getEntity()); + assertEquals("/new/path", body); + } finally { + client.close(); + } + } +} diff --git a/tests/AndroidTests/src/com/android/unit_tests/GoogleLoginServiceTest.java b/tests/AndroidTests/src/com/android/unit_tests/GoogleLoginServiceTest.java new file mode 100644 index 0000000000000000000000000000000000000000..59f14bf23ed11bd15dd41258f0fe414cc1054011 --- /dev/null +++ b/tests/AndroidTests/src/com/android/unit_tests/GoogleLoginServiceTest.java @@ -0,0 +1,145 @@ +// Copyright 2008 The Android Open Source Project +// All rights reserved. + +package com.android.unit_tests; + +import java.util.Arrays; +import java.util.concurrent.locks.ReentrantLock; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.Condition; + +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.ServiceConnection; +import android.os.IBinder; +import android.test.AndroidTestCase; +import android.test.suitebuilder.annotation.Suppress; +import android.util.Log; + +import com.google.android.googleapps.GoogleLoginCredentialsResult; +import com.google.android.googleapps.IGoogleLoginService; +import com.google.android.googlelogin.GoogleLoginServiceConstants; + +import junit.framework.Assert; + +// Suppress until bug http://b/issue?id=1416570 is fixed +@Suppress +/** Unit test for the Google login service. */ +public class GoogleLoginServiceTest extends AndroidTestCase { + private static final String TAG = "GoogleLoginServiceTest"; + + private IGoogleLoginService mGls = null; + private Lock mGlsLock = new ReentrantLock(); + private Condition mGlsCv = mGlsLock.newCondition(); + + private ServiceConnection mConnection = new ServiceConnection() { + public void onServiceConnected(ComponentName className, IBinder service) { + mGlsLock.lock(); + try { + mGls = IGoogleLoginService.Stub.asInterface(service); + mGlsCv.signalAll(); + } finally { + mGlsLock.unlock(); + } + Log.v(TAG, "service is connected"); + } + public void onServiceDisconnected(ComponentName className) { + mGlsLock.lock(); + try { + mGls = null; + mGlsCv.signalAll(); + } finally { + mGlsLock.unlock(); + } + Log.v(TAG, "service is disconnected"); + } + }; + + @Override + protected void setUp() throws Exception { + super.setUp(); + getContext().bindService((new Intent()) + .setClassName("com.google.android.googleapps", + "com.google.android.googleapps.GoogleLoginService"), + mConnection, Context.BIND_AUTO_CREATE); + + // wait for the service to cnnnect + mGlsLock.lock(); + try { + while (mGls == null) { + try { + mGlsCv.await(); + } catch (InterruptedException ignore) { + } + } + } finally { + mGlsLock.unlock(); + } + } + + @Override + protected void tearDown() throws Exception { + getContext().unbindService(mConnection); + super.tearDown(); + } + + public void testSingleAccountScheme() throws Exception { + Assert.assertNotNull(mGls); + mGls.deleteAllAccounts(); + + Assert.assertNull(mGls.getAccount(false)); + Assert.assertNull(mGls.getAccount(true)); + + mGls.saveUsernameAndPassword("vespa@gmail.com", "meow", + GoogleLoginServiceConstants.FLAG_GOOGLE_ACCOUNT); + Assert.assertEquals("vespa@gmail.com", mGls.getAccount(false)); + Assert.assertEquals("vespa@gmail.com", mGls.getAccount(true)); + + mGls.saveUsernameAndPassword("mackerel@hosted.com", "purr", + GoogleLoginServiceConstants.FLAG_HOSTED_ACCOUNT); + Assert.assertEquals("mackerel@hosted.com", mGls.getAccount(false)); + Assert.assertEquals("vespa@gmail.com", mGls.getAccount(true)); + } + + public void listsEqual(String[] a, String[] b) { + Assert.assertEquals(a.length, b.length); + Arrays.sort(a); + Arrays.sort(b); + Assert.assertTrue(Arrays.equals(a, b)); + } + + public void testAuthTokens() throws Exception { + Assert.assertNotNull(mGls); + mGls.deleteAllAccounts(); + + Assert.assertNull(mGls.peekCredentials("vespa@example.com", "mail")); + + mGls.saveUsernameAndPassword("vespa@example.com", "meow", + GoogleLoginServiceConstants.FLAG_HOSTED_ACCOUNT); + Assert.assertNull(mGls.peekCredentials("vespa@example.com", "mail")); + Assert.assertNull(mGls.peekCredentials(null, "mail")); + + mGls.saveAuthToken("vespa@example.com", "mail", "1234"); + Assert.assertEquals("1234", mGls.peekCredentials("vespa@example.com", "mail")); + Assert.assertEquals("1234", mGls.peekCredentials(null, "mail")); + + mGls.saveUsernameAndPassword("mackerel@example.com", "purr", + GoogleLoginServiceConstants.FLAG_GOOGLE_ACCOUNT); + mGls.saveAuthToken("mackerel@example.com", "mail", "5678"); + Assert.assertEquals("1234", mGls.peekCredentials(null, "mail")); + + mGls.saveAuthToken("mackerel@example.com", "mail", "8765"); + Assert.assertEquals("8765", mGls.peekCredentials("mackerel@example.com", "mail")); + + GoogleLoginCredentialsResult r = mGls.blockingGetCredentials( + "vespa@example.com", "mail", false); + Assert.assertEquals("vespa@example.com", r.getAccount()); + Assert.assertEquals("1234", r.getCredentialsString()); + Assert.assertNull(r.getCredentialsIntent()); + + mGls.saveAuthToken("vespa@example.com", "cl", "abcd"); + Assert.assertEquals("1234", mGls.peekCredentials("vespa@example.com", "mail")); + Assert.assertEquals("abcd", mGls.peekCredentials("vespa@example.com", "cl")); + } +} diff --git a/tests/AndroidTests/src/com/android/unit_tests/GraphicsPerformanceTests.java b/tests/AndroidTests/src/com/android/unit_tests/GraphicsPerformanceTests.java new file mode 100644 index 0000000000000000000000000000000000000000..a6c58699b2dc4ad38ef099cf6d1392ced83297fd --- /dev/null +++ b/tests/AndroidTests/src/com/android/unit_tests/GraphicsPerformanceTests.java @@ -0,0 +1,448 @@ +/* + * Copyright (C) 2007 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.android.unit_tests; + +import junit.framework.Assert; +import android.content.Context; +import android.content.res.Resources; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.test.AndroidTestCase; +import android.test.PerformanceTestCase; +import android.test.suitebuilder.annotation.Suppress; +import android.util.Log; + +/** + * Graphics Performance Tests + * + */ +//We don't want to run these perf tests in the continuous build. +@Suppress +public class GraphicsPerformanceTests { + private static final String TAG = "GfxPerf"; + public static String[] children() { + return new String[] { + // test decoding bitmaps of various sizes + DecodeBitmapTest.class.getName(), + + // odd-sized bitmap drawing tests + DrawBitmap7x7.class.getName(), + DrawBitmap15x15.class.getName(), + DrawBitmap31x31.class.getName(), + DrawBitmap63x63.class.getName(), + DrawBitmap127x127.class.getName(), + DrawBitmap319x239.class.getName(), + DrawBitmap319x479.class.getName(), + + // even-sized bitmap drawing tests + DrawBitmap8x8.class.getName(), + DrawBitmap16x16.class.getName(), + DrawBitmap32x32.class.getName(), + DrawBitmap64x64.class.getName(), + DrawBitmap128x128.class.getName(), + DrawBitmap320x240.class.getName(), + DrawBitmap320x480.class.getName()}; + } + + /** + * Base class for all graphics tests + * + */ + public static abstract class GraphicsTestBase extends AndroidTestCase + implements PerformanceTestCase { + /** Target "screen" (bitmap) width and height */ + private static final int DEFAULT_ITERATIONS = 1; + private static final int SCREEN_WIDTH = 320; + private static final int SCREEN_HEIGHT = 480; + + /** Number of iterations to pass back to harness. Subclass should override */ + protected int mIterations = 1; + + /** Bitmap we allocate and draw to */ + protected Bitmap mDestBitmap; + + /** Canvas of drawing routines */ + protected Canvas mCanvas; + + /** Style and color information (uses defaults) */ + protected Paint mPaint; + + @Override + public void setUp() throws Exception { + super.setUp(); + // Create drawable bitmap for rendering into + mDestBitmap = Bitmap.createBitmap(SCREEN_WIDTH, SCREEN_HEIGHT, + Bitmap.Config.RGB_565); + // Set of drawing routines + mCanvas = new Canvas(mDestBitmap); + // Styles + mPaint = new Paint(); + // Ask subclass for number of iterations + mIterations = getIterations(); + } + + // A reasonable default + public int getIterations() { + return DEFAULT_ITERATIONS; + } + + public boolean isPerformanceOnly() { + return true; + } + + public int startPerformance(Intermediates intermediates) { + intermediates.setInternalIterations(mIterations * 10); + return 0; + } + } + + /** + * Tests time to decode a number of sizes of images. + */ + public static class DecodeBitmapTest extends GraphicsTestBase { + /** Number of times to run this test */ + private static final int DECODE_ITERATIONS = 10; + + /** Used to access package bitmap images */ + private Resources mResources; + + @Override + public void setUp() throws Exception { + super.setUp(); + + // For bitmap resources + Context context = getContext(); + Assert.assertNotNull(context); + mResources = context.getResources(); + Assert.assertNotNull(mResources); + } + + @Override + public int getIterations() { + return DECODE_ITERATIONS; + } + + public void testDecodeBitmap() { + for (int i = 0; i < DECODE_ITERATIONS; i++) { + BitmapFactory.decodeResource(mResources, R.drawable.test16x12); + BitmapFactory.decodeResource(mResources, R.drawable.test32x24); + BitmapFactory.decodeResource(mResources, R.drawable.test64x48); + BitmapFactory.decodeResource(mResources, R.drawable.test128x96); + BitmapFactory.decodeResource(mResources, R.drawable.test256x192); + BitmapFactory.decodeResource(mResources, R.drawable.test320x240); + } + } + } + + /** + * Base class for bitmap drawing tests + * + */ + public static abstract class DrawBitmapTest extends GraphicsTestBase { + /** Number of times to run each draw test */ + private static final int ITERATIONS = 1000; + + /** Bitmap to draw. Allocated by subclass's createBitmap() function. */ + private Bitmap mBitmap; + + @Override + public void setUp() throws Exception { + super.setUp(); + + // Invoke subclass's method to create the bitmap + mBitmap = createBitmap(); + } + + public int getIterations() { + return ITERATIONS; + } + + // Generic abstract function to create bitmap for any given subclass + public abstract Bitmap createBitmap(); + + // Provide convenience test code for all subsequent classes. + // Note: Though it would be convenient to declare all of the test*() methods here + // and just inherit them, our test harness doesn't support it. So we replicate + // a bit of code in each derived test case. + public void drawBitmapEven() { + for (int i = 0; i < ITERATIONS; i++) { + mCanvas.drawBitmap(mBitmap, 0.0f, 0.0f, mPaint); + } + } + + public void drawBitmapOdd() { + for (int i = 0; i < ITERATIONS; i++) { + mCanvas.drawBitmap(mBitmap, 1.0f, 0.0f, mPaint); + } + } + } + + + /** + * Test drawing of 7x7 image + */ + public static class DrawBitmap7x7 extends DrawBitmapTest { + + public Bitmap createBitmap() { + return Bitmap.createBitmap(7, 7, Bitmap.Config.RGB_565); + } + + public void testDrawBitmapEven() { + drawBitmapEven(); + } + + public void testDrawBitmapOdd() { + drawBitmapOdd(); + } + } + + /** + * Test drawing of 15x15 image + */ + public static class DrawBitmap15x15 extends DrawBitmapTest { + + public Bitmap createBitmap() { + return Bitmap.createBitmap(15, 15, Bitmap.Config.RGB_565); + } + + public void testDrawBitmapEven() { + drawBitmapEven(); + } + + public void testDrawBitmapOdd() { + drawBitmapOdd(); + } + } + + /** + * Test drawing of 31x31 image + */ + public static class DrawBitmap31x31 extends DrawBitmapTest { + + public Bitmap createBitmap() { + return Bitmap.createBitmap(31, 31, Bitmap.Config.RGB_565); + } + + public void testDrawBitmapEven() { + drawBitmapEven(); + } + + public void testDrawBitmapOdd() { + drawBitmapOdd(); + } + } + + /** + * Test drawing of 63x63 image + */ + public static class DrawBitmap63x63 extends DrawBitmapTest { + + public Bitmap createBitmap() { + return Bitmap.createBitmap(63, 63, Bitmap.Config.RGB_565); + } + + public void testDrawBitmapEven() { + drawBitmapEven(); + } + + public void testDrawBitmapOdd() { + drawBitmapOdd(); + } + } + + /** + * Test drawing of 127x127 image + */ + public static class DrawBitmap127x127 extends DrawBitmapTest { + + public Bitmap createBitmap() { + return Bitmap.createBitmap(127, 127, Bitmap.Config.RGB_565); + } + + public void testDrawBitmapEven() { + drawBitmapEven(); + } + + public void testDrawBitmapOdd() { + drawBitmapOdd(); + } + } + + /** + * Test drawing of 319x239 image + */ + public static class DrawBitmap319x239 extends DrawBitmapTest { + + public Bitmap createBitmap() { + return Bitmap.createBitmap(319, 239, Bitmap.Config.RGB_565); + } + + public void testDrawBitmapEven() { + drawBitmapEven(); + } + + public void testDrawBitmapOdd() { + drawBitmapOdd(); + } + } + + /** + * Test drawing of 319x479 image + */ + public static class DrawBitmap319x479 extends DrawBitmapTest { + + public Bitmap createBitmap() { + return Bitmap.createBitmap(319, 479, Bitmap.Config.RGB_565); + } + + public void testDrawBitmapEven() { + drawBitmapEven(); + } + + public void testDrawBitmapOdd() { + drawBitmapOdd(); + } + } + + /** + * Test drawing of 8x8 image + */ + public static class DrawBitmap8x8 extends DrawBitmapTest { + + public Bitmap createBitmap() { + return Bitmap.createBitmap(8, 8, Bitmap.Config.RGB_565); + } + + public void testDrawBitmapEven() { + drawBitmapEven(); + } + + public void testDrawBitmapOdd() { + drawBitmapOdd(); + } + } + + /** + * Test drawing of 16x16 image + */ + public static class DrawBitmap16x16 extends DrawBitmapTest { + + public Bitmap createBitmap() { + return Bitmap.createBitmap(16, 16, Bitmap.Config.RGB_565); + } + + public void testDrawBitmapEven() { + drawBitmapEven(); + } + + public void testDrawBitmapOdd() { + drawBitmapOdd(); + } + } + + /** + * Test drawing of 32x32 image + */ + public static class DrawBitmap32x32 extends DrawBitmapTest { + + public Bitmap createBitmap() { + return Bitmap.createBitmap(32, 32, Bitmap.Config.RGB_565); + } + + public void testDrawBitmapEven() { + drawBitmapEven(); + } + + public void testDrawBitmapOdd() { + drawBitmapOdd(); + } + } + + /** + * Test drawing of 64x64 image + */ + public static class DrawBitmap64x64 extends DrawBitmapTest { + + public Bitmap createBitmap() { + return Bitmap.createBitmap(64, 64, Bitmap.Config.RGB_565); + } + + public void testDrawBitmapEven() { + drawBitmapEven(); + } + + public void testDrawBitmapOdd() { + drawBitmapOdd(); + } + } + + /** + * Test drawing of 128x128 image + */ + public static class DrawBitmap128x128 extends DrawBitmapTest { + + public Bitmap createBitmap() { + return Bitmap.createBitmap(128, 128, Bitmap.Config.RGB_565); + } + + public void testDrawBitmapEven() { + drawBitmapEven(); + } + + public void testDrawBitmapOdd() { + drawBitmapOdd(); + } + } + + /** + * Test drawing of 320x240 image + */ + public static class DrawBitmap320x240 extends DrawBitmapTest { + + public Bitmap createBitmap() { + return Bitmap.createBitmap(320, 240, Bitmap.Config.RGB_565); + } + + public void testDrawBitmapEven() { + drawBitmapEven(); + } + + public void testDrawBitmapOdd() { + drawBitmapOdd(); + } + } + + /** + * Test drawing of 320x480 image + */ + public static class DrawBitmap320x480 extends DrawBitmapTest { + + public Bitmap createBitmap() { + return Bitmap.createBitmap(320, 480, Bitmap.Config.RGB_565); + } + + public void testDrawBitmapEven() { + drawBitmapEven(); + } + + public void testDrawBitmapOdd() { + drawBitmapOdd(); + } + } +} diff --git a/tests/AndroidTests/src/com/android/unit_tests/HashMapTest.java b/tests/AndroidTests/src/com/android/unit_tests/HashMapTest.java new file mode 100644 index 0000000000000000000000000000000000000000..b4d15c9d25b01470072f796737247d4f50d65c0f --- /dev/null +++ b/tests/AndroidTests/src/com/android/unit_tests/HashMapTest.java @@ -0,0 +1,185 @@ +/* + * Copyright (C) 2007 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.android.unit_tests; + +import java.util.Collection; +import java.util.HashMap; +import java.util.Set; + +import android.test.PerformanceTestBase; +import android.test.PerformanceTestCase; + +public class HashMapTest extends PerformanceTestBase { + public static final int ITERATIONS = 1000; + public HashMap mMap; + public String[] mKeys; + + @Override + @SuppressWarnings("unchecked") + protected void setUp() throws Exception { + super.setUp(); + mMap = new HashMap(); + mKeys = new String[ITERATIONS]; + + for (int i = ITERATIONS - 1; i >= 0; i--) { + mKeys[i] = Integer.toString(i, 16); + mMap.put(mKeys[i], i); + } + } + + @Override + public int startPerformance(PerformanceTestCase.Intermediates intermediates) { + intermediates.setInternalIterations(ITERATIONS); + return 0; + } + + public void testHashMapGet() { + int num; + for (int i = ITERATIONS - 1; i >= 0; i--) { + num = (Integer) mMap.get(mKeys[i]); + num = (Integer) mMap.get(mKeys[i]); + num = (Integer) mMap.get(mKeys[i]); + num = (Integer) mMap.get(mKeys[i]); + num = (Integer) mMap.get(mKeys[i]); + num = (Integer) mMap.get(mKeys[i]); + num = (Integer) mMap.get(mKeys[i]); + num = (Integer) mMap.get(mKeys[i]); + num = (Integer) mMap.get(mKeys[i]); + num = (Integer) mMap.get(mKeys[i]); + } + } + + public void testHashMapKeySet() { + Set keyset; + for (int i = ITERATIONS - 1; i >= 0; i--) { + keyset = mMap.keySet(); + keyset = mMap.keySet(); + keyset = mMap.keySet(); + keyset = mMap.keySet(); + keyset = mMap.keySet(); + keyset = mMap.keySet(); + keyset = mMap.keySet(); + keyset = mMap.keySet(); + keyset = mMap.keySet(); + keyset = mMap.keySet(); + } + } + + public void testHashMapEntrySet() { + Set keyset; + for (int i = ITERATIONS - 1; i >= 0; i--) { + keyset = mMap.entrySet(); + keyset = mMap.entrySet(); + keyset = mMap.entrySet(); + keyset = mMap.entrySet(); + keyset = mMap.entrySet(); + keyset = mMap.entrySet(); + keyset = mMap.entrySet(); + keyset = mMap.entrySet(); + keyset = mMap.entrySet(); + keyset = mMap.entrySet(); + + + } + } + + public void testHashMapValues() { + Collection c; + for (int i = ITERATIONS - 1; i >= 0; i--) { + c = mMap.values(); + c = mMap.values(); + c = mMap.values(); + c = mMap.values(); + c = mMap.values(); + c = mMap.values(); + c = mMap.values(); + c = mMap.values(); + c = mMap.values(); + c = mMap.values(); + + + } + } + + public void testHashMapSize() { + int len; + for (int i = ITERATIONS - 1; i >= 0; i--) { + len = mMap.size(); + len = mMap.size(); + len = mMap.size(); + len = mMap.size(); + len = mMap.size(); + len = mMap.size(); + len = mMap.size(); + len = mMap.size(); + len = mMap.size(); + len = mMap.size(); + + + } + } + + public void testHashMapContainsValue() { + boolean flag; + for (int i = ITERATIONS - 1; i >= 0; i--) { + flag = mMap.containsValue(i); + flag = mMap.containsValue(i); + flag = mMap.containsValue(i); + flag = mMap.containsValue(i); + flag = mMap.containsValue(i); + flag = mMap.containsValue(i); + flag = mMap.containsValue(i); + flag = mMap.containsValue(i); + flag = mMap.containsValue(i); + flag = mMap.containsValue(i); + + + } + } + + public void testHashMapRemove() { + for (int i = ITERATIONS - 1; i >= 0; i--) { + mMap.remove(mKeys[i]); + mMap.remove(mKeys[i]); + mMap.remove(mKeys[i]); + mMap.remove(mKeys[i]); + mMap.remove(mKeys[i]); + mMap.remove(mKeys[i]); + mMap.remove(mKeys[i]); + mMap.remove(mKeys[i]); + mMap.remove(mKeys[i]); + mMap.remove(mKeys[i]); + } + } + + + public void testHashMapClone() { + HashMap cMap; + for (int i = ITERATIONS - 1; i >= 0; i--) { + cMap = (HashMap) mMap.clone(); + cMap = (HashMap) mMap.clone(); + cMap = (HashMap) mMap.clone(); + cMap = (HashMap) mMap.clone(); + cMap = (HashMap) mMap.clone(); + cMap = (HashMap) mMap.clone(); + cMap = (HashMap) mMap.clone(); + cMap = (HashMap) mMap.clone(); + cMap = (HashMap) mMap.clone(); + cMap = (HashMap) mMap.clone(); + } + } +} diff --git a/tests/AndroidTests/src/com/android/unit_tests/HashSetTest.java b/tests/AndroidTests/src/com/android/unit_tests/HashSetTest.java new file mode 100644 index 0000000000000000000000000000000000000000..80d3d8de2c0a4b95586dbc24a2c8251ef9c54474 --- /dev/null +++ b/tests/AndroidTests/src/com/android/unit_tests/HashSetTest.java @@ -0,0 +1,207 @@ +/* + * Copyright (C) 2007 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.android.unit_tests; + +import android.test.PerformanceTestBase; +import android.test.PerformanceTestCase; + +import java.util.HashSet; +import java.util.Iterator; + +/** + * Implements basic performance test functionality for HashSets + */ + +public class HashSetTest extends PerformanceTestBase { + public static final int ITERATIONS = 1000; + public static HashSet sSet; + + @Override + protected void setUp() throws Exception { + super.setUp(); + sSet = new HashSet(); + for (int i = ITERATIONS - 1; i >= 0; i--) { + sSet.add(i); + } + } + + @Override + public int startPerformance(PerformanceTestCase.Intermediates intermediates) { + intermediates.setInternalIterations(ITERATIONS); + return 0; + } + + /** + * + * Tests performance for the HashSet method Add(Object arg 0) + * + */ + + @SuppressWarnings("unchecked") + public void testHashSetAdd() { + HashSet set = new HashSet(); + for (int i = ITERATIONS - 1; i >= 0; i--) { + set.add(i); + set.add(i); + set.add(i); + set.add(i); + set.add(i); + set.add(i); + set.add(i); + set.add(i); + set.add(i); + set.add(i); + } + + } + + /** + * + * Tests performance of HashSet method contains(Object arg 0) + * + */ + + public void testHashSetContains() { + Integer index = new Integer(500); + boolean flag; + HashSet set = sSet; + for (int i = ITERATIONS - 1; i >= 0; i--) { + flag = set.contains(index); + flag = set.contains(index); + flag = set.contains(index); + flag = set.contains(index); + flag = set.contains(index); + flag = set.contains(index); + flag = set.contains(index); + flag = set.contains(index); + flag = set.contains(index); + } + } + + /** + * + * Tests performance of HashSet method size() + * + */ + + public void testHashSetSize() { + int num; + HashSet set = sSet; + for (int i = ITERATIONS - 1; i >= 0; i--) { + num = set.size(); + num = set.size(); + num = set.size(); + num = set.size(); + num = set.size(); + num = set.size(); + num = set.size(); + num = set.size(); + num = set.size(); + } + } + + /** + * + * Tests performance of the HashSet method -iterator() + * + */ + + public void testHashSetIterator() { + Iterator iterator; + HashSet set = sSet; + for (int i = ITERATIONS - 1; i >= 0; i--) { + iterator = set.iterator(); + iterator = set.iterator(); + iterator = set.iterator(); + iterator = set.iterator(); + iterator = set.iterator(); + iterator = set.iterator(); + iterator = set.iterator(); + iterator = set.iterator(); + iterator = set.iterator(); + } + } + + /** + * + * Tests performance for the HashSet method Remove(Object arg 0) + * + */ + + @SuppressWarnings("unchecked") + public void testHashSetRemove() { + HashSet set = new HashSet(sSet); + for (int i = ITERATIONS - 1; i >= 0; i--) { + set.remove(i); + set.remove(i); + set.remove(i); + set.remove(i); + set.remove(i); + set.remove(i); + set.remove(i); + set.remove(i); + set.remove(i); + set.remove(i); + } + } + + /** + * + * Tests performance for the HashSet method isEmpty(Object arg 0) + * + */ + + public void testHashSetIsEmpty() { + HashSet set = sSet; + boolean flag; + for (int i = ITERATIONS - 1; i >= 0; i--) { + flag = set.isEmpty(); + flag = set.isEmpty(); + flag = set.isEmpty(); + flag = set.isEmpty(); + flag = set.isEmpty(); + flag = set.isEmpty(); + flag = set.isEmpty(); + flag = set.isEmpty(); + flag = set.isEmpty(); + flag = set.isEmpty(); + } + } + + /** + * + * Tests performance for the HashSet method clone() + * + */ + + public void testHashSetClone() { + HashSet hSet = sSet; + Object set; + for (int i = ITERATIONS - 1; i > 0; i--) { + set = hSet.clone(); + set = hSet.clone(); + set = hSet.clone(); + set = hSet.clone(); + set = hSet.clone(); + set = hSet.clone(); + set = hSet.clone(); + set = hSet.clone(); + set = hSet.clone(); + set = hSet.clone(); + } + } +} diff --git a/tests/AndroidTests/src/com/android/unit_tests/HashtableTest.java b/tests/AndroidTests/src/com/android/unit_tests/HashtableTest.java new file mode 100644 index 0000000000000000000000000000000000000000..42bec11a3dfb0025ed8f91205f8a5fcba47c80f0 --- /dev/null +++ b/tests/AndroidTests/src/com/android/unit_tests/HashtableTest.java @@ -0,0 +1,357 @@ +/* + * Copyright (C) 2007 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.android.unit_tests; + +import android.test.PerformanceTestBase; +import android.test.PerformanceTestCase; + +import java.util.Hashtable; +import java.util.Set; +import java.util.Enumeration; + +/** + * Implements basic performance test functionality for java.util.Hashtable + */ + +public class HashtableTest extends PerformanceTestBase { + public static final int ITERATIONS = 1000; + public Hashtable sTable; + public String[] sKeys; + + @Override + @SuppressWarnings("unchecked") + protected void setUp() throws Exception { + super.setUp(); + sTable = new Hashtable(); + sKeys = new String[ITERATIONS]; + for (int i = ITERATIONS - 1; i >= 0; i--) { + sKeys[i] = Integer.toString(i, 16); + sTable.put(sKeys[i], i); + } + } + + @Override + public int startPerformance(PerformanceTestCase.Intermediates intermediates) { + intermediates.setInternalIterations(ITERATIONS); + return 0; + } + + @SuppressWarnings("unchecked") + public void testHashtablePut() { + Hashtable hTable = new Hashtable(); + for (int i = ITERATIONS - 1; i >= 0; i--) { + hTable.put(i, i); + hTable.put(i, i); + hTable.put(i, i); + hTable.put(i, i); + hTable.put(i, i); + hTable.put(i, i); + hTable.put(i, i); + hTable.put(i, i); + hTable.put(i, i); + hTable.put(i, i); + } + } + + public void testHashtableGet() { + int value; + String[] keys = sKeys; + Hashtable hTable = sTable; + for (int i = ITERATIONS - 1; i >= 0; i--) { + value = hTable.get(keys[i]); + value = hTable.get(keys[i]); + value = hTable.get(keys[i]); + value = hTable.get(keys[i]); + value = hTable.get(keys[i]); + value = hTable.get(keys[i]); + value = hTable.get(keys[i]); + value = hTable.get(keys[i]); + value = hTable.get(keys[i]); + value = hTable.get(keys[i]); + } + } + + public void testHashtablekeyset() { + Set keyset; + Hashtable hTable = sTable; + for (int i = ITERATIONS - 1; i >= 0; i--) { + keyset = hTable.keySet(); + keyset = hTable.keySet(); + keyset = hTable.keySet(); + keyset = hTable.keySet(); + keyset = hTable.keySet(); + keyset = hTable.keySet(); + keyset = hTable.keySet(); + keyset = hTable.keySet(); + keyset = hTable.keySet(); + keyset = hTable.keySet(); + } + } + + /** + * + */ + + public void testHashtableEntrySet() { + Set keyset; + Hashtable hTable = sTable; + for (int i = ITERATIONS - 1; i >= 0; i--) { + keyset = hTable.entrySet(); + keyset = hTable.entrySet(); + keyset = hTable.entrySet(); + keyset = hTable.entrySet(); + keyset = hTable.entrySet(); + keyset = hTable.entrySet(); + keyset = hTable.entrySet(); + keyset = hTable.entrySet(); + keyset = hTable.entrySet(); + keyset = hTable.entrySet(); + } + } + + public void testHashtableSize() { + int len; + Hashtable hTable = sTable; + for (int i = ITERATIONS - 1; i >= 0; i--) { + len = hTable.size(); + len = hTable.size(); + len = hTable.size(); + len = hTable.size(); + len = hTable.size(); + len = hTable.size(); + len = hTable.size(); + len = hTable.size(); + len = hTable.size(); + len = hTable.size(); + } + } + + public void testHashtableContainsValue() { + boolean flag; + Hashtable hTable = sTable; + for (int i = ITERATIONS - 1; i >= 0; i--) { + flag = hTable.containsValue(i); + flag = hTable.containsValue(i); + flag = hTable.containsValue(i); + flag = hTable.containsValue(i); + flag = hTable.containsValue(i); + flag = hTable.containsValue(i); + flag = hTable.containsValue(i); + flag = hTable.containsValue(i); + flag = hTable.containsValue(i); + flag = hTable.containsValue(i); + } + } + + @SuppressWarnings("unchecked") + public void testHashtableRemove() { + Hashtable hTable = new Hashtable(sTable); + String[] keys = sKeys; + for (int i = ITERATIONS - 1; i >= 0; i--) { + hTable.remove(keys[i]); + hTable.remove(keys[i]); + hTable.remove(keys[i]); + hTable.remove(keys[i]); + hTable.remove(keys[i]); + hTable.remove(keys[i]); + hTable.remove(keys[i]); + hTable.remove(keys[i]); + hTable.remove(keys[i]); + hTable.remove(keys[i]); + } + } + + public void testHashtableContains() { + Hashtable hTable = sTable; + boolean flag; + + for (int i = ITERATIONS - 1; i >= 0; i--) { + flag = hTable.contains(i); + flag = hTable.contains(i); + flag = hTable.contains(i); + flag = hTable.contains(i); + flag = hTable.contains(i); + flag = hTable.contains(i); + flag = hTable.contains(i); + flag = hTable.contains(i); + flag = hTable.contains(i); + flag = hTable.contains(i); + } + } + + public void testHashtableContainsKey() { + Hashtable hTable = sTable; + boolean flag; + + for (int i = ITERATIONS - 1; i >= 0; i--) { + flag = hTable.containsKey(i); + flag = hTable.containsKey(i); + flag = hTable.containsKey(i); + flag = hTable.containsKey(i); + flag = hTable.containsKey(i); + flag = hTable.containsKey(i); + flag = hTable.containsKey(i); + flag = hTable.containsKey(i); + flag = hTable.containsKey(i); + flag = hTable.containsKey(i); + } + } + + public void testHashtableIsEmpty() { + Hashtable hTable = sTable; + boolean flag; + for (int i = ITERATIONS - 1; i >= 0; i--) { + flag = hTable.isEmpty(); + flag = hTable.isEmpty(); + flag = hTable.isEmpty(); + flag = hTable.isEmpty(); + flag = hTable.isEmpty(); + flag = hTable.isEmpty(); + flag = hTable.isEmpty(); + flag = hTable.isEmpty(); + flag = hTable.isEmpty(); + flag = hTable.isEmpty(); + } + } + + public void testHashtableKeys() { + Hashtable hTable = sTable; + Enumeration keys; + for (int i = ITERATIONS - 1; i >= 0; i--) { + keys = hTable.keys(); + keys = hTable.keys(); + keys = hTable.keys(); + keys = hTable.keys(); + keys = hTable.keys(); + keys = hTable.keys(); + keys = hTable.keys(); + keys = hTable.keys(); + keys = hTable.keys(); + keys = hTable.keys(); + } + } + + public void testHashtableElements() { + Hashtable hTable = sTable; + Enumeration elements; + for (int i = ITERATIONS - 1; i >= 0; i--) { + elements = hTable.elements(); + elements = hTable.elements(); + elements = hTable.elements(); + elements = hTable.elements(); + elements = hTable.elements(); + elements = hTable.elements(); + elements = hTable.elements(); + elements = hTable.elements(); + elements = hTable.elements(); + elements = hTable.elements(); + } + } + + public void testHashtableHashCode() { + int index; + Hashtable hTable = sTable; + for (int i = ITERATIONS - 1; i >= 0; i--) { + index = hTable.hashCode(); + index = hTable.hashCode(); + index = hTable.hashCode(); + index = hTable.hashCode(); + index = hTable.hashCode(); + index = hTable.hashCode(); + index = hTable.hashCode(); + index = hTable.hashCode(); + index = hTable.hashCode(); + index = hTable.hashCode(); + } + } + + public void testHashtableEquals() { + boolean flag; + Hashtable hTable = sTable; + for (int i = ITERATIONS - 1; i >= 0; i--) { + flag = hTable.equals(hTable); + flag = hTable.equals(hTable); + flag = hTable.equals(hTable); + flag = hTable.equals(hTable); + flag = hTable.equals(hTable); + flag = hTable.equals(hTable); + flag = hTable.equals(hTable); + flag = hTable.equals(hTable); + flag = hTable.equals(hTable); + flag = hTable.equals(hTable); + } + } + + public void testHashtableToString() { + String str; + Hashtable hTable = sTable; + for (int i = ITERATIONS - 1; i >= 0; i--) { + str = hTable.toString(); + str = hTable.toString(); + str = hTable.toString(); + str = hTable.toString(); + str = hTable.toString(); + str = hTable.toString(); + str = hTable.toString(); + str = hTable.toString(); + str = hTable.toString(); + str = hTable.toString(); + } + } + + @SuppressWarnings("unchecked") + public void testHashtablePutAll() { + Hashtable hTable = new Hashtable(); + Hashtable hTable1 = sTable; + for (int i = ITERATIONS - 1; i >= 0; i--) { + hTable.putAll(hTable1); + hTable.putAll(hTable1); + hTable.putAll(hTable1); + hTable.putAll(hTable1); + hTable.putAll(hTable1); + hTable.putAll(hTable1); + hTable.putAll(hTable1); + hTable.putAll(hTable1); + hTable.putAll(hTable1); + hTable.putAll(hTable1); + } + } + + /** + * + * clone() returns a Hashtable .. It should return Object as per the + * specification. + * + */ + + public void testHashtableClone() { + Hashtable hashTable; + Hashtable hTable = sTable; + for (int i = ITERATIONS - 1; i >= 0; i--) { + hashTable = (Hashtable) hTable.clone(); + hashTable = (Hashtable) hTable.clone(); + hashTable = (Hashtable) hTable.clone(); + hashTable = (Hashtable) hTable.clone(); + hashTable = (Hashtable) hTable.clone(); + hashTable = (Hashtable) hTable.clone(); + hashTable = (Hashtable) hTable.clone(); + hashTable = (Hashtable) hTable.clone(); + hashTable = (Hashtable) hTable.clone(); + hashTable = (Hashtable) hTable.clone(); + } + } +} diff --git a/tests/AndroidTests/src/com/android/unit_tests/HeapTest.java b/tests/AndroidTests/src/com/android/unit_tests/HeapTest.java new file mode 100644 index 0000000000000000000000000000000000000000..d21e6a3739844e67b6332b098d2aa4265da75746 --- /dev/null +++ b/tests/AndroidTests/src/com/android/unit_tests/HeapTest.java @@ -0,0 +1,631 @@ +/* + * Copyright (C) 2007 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.android.unit_tests; + +import android.test.suitebuilder.annotation.LargeTest; +import android.test.suitebuilder.annotation.MediumTest; +import android.test.suitebuilder.annotation.SmallTest; +import android.util.Log; +import android.test.suitebuilder.annotation.Suppress; +import dalvik.system.VMRuntime; +import junit.framework.TestCase; + +import java.lang.ref.PhantomReference; +import java.lang.ref.ReferenceQueue; +import java.lang.ref.SoftReference; +import java.lang.ref.WeakReference; +import java.util.LinkedList; +import java.util.Random; + + +public class HeapTest extends TestCase { + + private static final String TAG = "HeapTest"; + + /** + * Returns a WeakReference to an object that has no + * other references. This is done in a separate method + * to ensure that the Object's address isn't sitting in + * a stale local register. + */ + private WeakReference newRef() { + return new WeakReference(new Object()); + } + + /** + * Allocates the specified number of bytes. This is done in a separate method + * to ensure that the Object's address isn't sitting in a stale local register. + */ + private void allocateMemory(int size) { + byte[] b = new byte[size]; + } + + @MediumTest + public void testMinimumHeapSize() throws Exception { + VMRuntime r = VMRuntime.getRuntime(); + final boolean RUN_FLAKY = false; + + long origSize = r.getMinimumHeapSize(); + if (RUN_FLAKY) { + /* Check that the default value is zero. This will break if anyone + * in this process sets the minimum heap size to a positive value + * before calling this test. + */ + assertTrue(origSize == 0); + } + + long size = 4 * 1024 * 1024; + long oldSize = r.setMinimumHeapSize(size); + assertTrue(oldSize == origSize); + + long newSize = r.getMinimumHeapSize(); + /* This will fail if the maximum heap size (-Xmx) is smaller than 4MB. + */ + assertTrue(newSize == size); + + /* Make sure that getting the size doesn't change anything. + */ + newSize = r.getMinimumHeapSize(); + assertTrue(newSize == size); + + /* This test is flaky; if the heap is already large and fragmented, + * it can fail. It can also fail if another thread causes a GC + * at the wrong time. + */ + if (RUN_FLAKY) { + /* Increase the minimum size, allocate a big object, and make sure that + * a GC didn't happen. + */ + WeakReference ref = newRef(); + assertNotNull(ref.get()); + + r.setMinimumHeapSize(8 * 1024 * 1024); + allocateMemory(4 * 1024 * 1024); + + /* If a GC happened, this reference will be null. + */ + assertNotNull(ref.get()); + } + + /* Restore the original setting. + */ + r.setMinimumHeapSize(origSize); + newSize = r.getMinimumHeapSize(); + assertTrue(newSize == origSize); + + /* Clean up any large stuff we've allocated, + * and re-establish the normal utilization ratio. + */ + Runtime.getRuntime().gc(); + } + + private static void makeRefs(Object objects[], SoftReference refs[]) { + for (int i = 0; i < objects.length; i++) { + objects[i] = (Object) new byte[8 * 1024]; + refs[i] = new SoftReference(objects[i]); + } + } + + private static int checkRefs(SoftReference refs[], int last) { + int i; + int numCleared = 0; + for (i = 0; i < refs.length; i++) { + Object o = refs[i].get(); + if (o == null) { + numCleared++; + } + } + if (numCleared != last) { + Log.i(TAG, "****** " + numCleared + "/" + i + " cleared ******"); + } + return numCleared; + } + + private static void clearRefs(Object objects[], int skip) { + for (int i = 0; i < objects.length; i += skip) { + objects[i] = null; + } + } + + private static void clearRefs(Object objects[]) { + clearRefs(objects, 1); + } + + private static void checkRefs(T objects[], SoftReference refs[]) { + boolean ok = true; + + for (int i = 0; i < objects.length; i++) { + if (refs[i].get() != objects[i]) { + ok = false; + } + } + if (!ok) { + throw new RuntimeException("Test failed: soft refs not cleared"); + } + } + + @MediumTest + public void testGcSoftRefs() throws Exception { + final int NUM_REFS = 128; + + Object objects[] = new Object[NUM_REFS]; + SoftReference refs[] = new SoftReference[objects.length]; + + /* Create a bunch of objects and a parallel array + * of SoftReferences. + */ + makeRefs(objects, refs); + Runtime.getRuntime().gc(); + + /* Let go of some of the hard references to the objects so that + * the references can be cleared. + */ + clearRefs(objects, 3); + + /* Collect all softly-reachable objects. + */ + VMRuntime.getRuntime().gcSoftReferences(); + Runtime.getRuntime().runFinalization(); + + /* Make sure that the objects were collected. + */ + checkRefs(objects, refs); + + /* Remove more hard references and re-check. + */ + clearRefs(objects, 2); + VMRuntime.getRuntime().gcSoftReferences(); + Runtime.getRuntime().runFinalization(); + checkRefs(objects, refs); + + /* Remove the rest of the references and re-check. + */ + /* Remove more hard references and re-check. + */ + clearRefs(objects); + VMRuntime.getRuntime().gcSoftReferences(); + Runtime.getRuntime().runFinalization(); + checkRefs(objects, refs); + } + + public void xxtestSoftRefPartialClean() throws Exception { + final int NUM_REFS = 128; + + Object objects[] = new Object[NUM_REFS]; + SoftReference refs[] = new SoftReference[objects.length]; + + /* Create a bunch of objects and a parallel array + * of SoftReferences. + */ + makeRefs(objects, refs); + Runtime.getRuntime().gc(); + + /* Let go of the hard references to the objects so that + * the references can be cleared. + */ + clearRefs(objects); + + /* Start creating a bunch of temporary and permanent objects + * to drive GC. + */ + final int NUM_OBJECTS = 64 * 1024; + Object junk[] = new Object[NUM_OBJECTS]; + Random random = new Random(); + + int i = 0; + int mod = 0; + int totalSize = 0; + int cleared = -1; + while (i < junk.length && totalSize < 8 * 1024 * 1024) { + int r = random.nextInt(64 * 1024) + 128; + Object o = (Object) new byte[r]; + if (++mod % 16 == 0) { + junk[i++] = o; + totalSize += r * 4; + } + cleared = checkRefs(refs, cleared); + } + } + + private static void makeRefs(Object objects[], WeakReference refs[]) { + for (int i = 0; i < objects.length; i++) { + objects[i] = new Object(); + refs[i] = new WeakReference(objects[i]); + } + } + + private static void checkRefs(T objects[], WeakReference refs[]) { + boolean ok = true; + + for (int i = 0; i < objects.length; i++) { + if (refs[i].get() != objects[i]) { + ok = false; + } + } + if (!ok) { + throw new RuntimeException("Test failed: " + + "weak refs not cleared"); + } + } + + @MediumTest + public void testWeakRefs() throws Exception { + final int NUM_REFS = 16; + + Object objects[] = new Object[NUM_REFS]; + WeakReference refs[] = new WeakReference[objects.length]; + + /* Create a bunch of objects and a parallel array + * of WeakReferences. + */ + makeRefs(objects, refs); + Runtime.getRuntime().gc(); + checkRefs(objects, refs); + + /* Clear out every other strong reference. + */ + for (int i = 0; i < objects.length; i += 2) { + objects[i] = null; + } + Runtime.getRuntime().gc(); + checkRefs(objects, refs); + + /* Clear out the rest of them. + */ + for (int i = 0; i < objects.length; i++) { + objects[i] = null; + } + Runtime.getRuntime().gc(); + checkRefs(objects, refs); + } + + private static void makeRefs(Object objects[], PhantomReference refs[], + ReferenceQueue queue) { + for (int i = 0; i < objects.length; i++) { + objects[i] = new Object(); + refs[i] = new PhantomReference(objects[i], queue); + } + } + + static void checkRefs(T objects[], PhantomReference refs[], + ReferenceQueue queue) { + boolean ok = true; + + /* Make sure that the reference that should be on + * the queue are marked as enqueued. Once we + * pull them off the queue, they will no longer + * be marked as enqueued. + */ + for (int i = 0; i < objects.length; i++) { + if (objects[i] == null && refs[i] != null) { + if (!refs[i].isEnqueued()) { + ok = false; + } + } + } + if (!ok) { + throw new RuntimeException("Test failed: " + + "phantom refs not marked as enqueued"); + } + + /* Make sure that all of the references on the queue + * are supposed to be there. + */ + PhantomReference ref; + while ((ref = (PhantomReference) queue.poll()) != null) { + /* Find the list index that corresponds to this reference. + */ + int i; + for (i = 0; i < objects.length; i++) { + if (refs[i] == ref) { + break; + } + } + if (i == objects.length) { + throw new RuntimeException("Test failed: " + + "unexpected ref on queue"); + } + if (objects[i] != null) { + throw new RuntimeException("Test failed: " + + "reference enqueued for strongly-reachable " + + "object"); + } + refs[i] = null; + + /* TODO: clear doesn't do much, since we're losing the + * strong ref to the ref object anyway. move the ref + * into another list. + */ + ref.clear(); + } + + /* We've visited all of the enqueued references. + * Make sure that there aren't any other references + * that should have been enqueued. + * + * NOTE: there is a race condition here; this assumes + * that the VM has serviced all outstanding reference + * enqueue() calls. + */ + for (int i = 0; i < objects.length; i++) { + if (objects[i] == null && refs[i] != null) { +// System.out.println("HeapTest/PhantomRefs: refs[" + i + +// "] should be enqueued"); + ok = false; + } + } + if (!ok) { + throw new RuntimeException("Test failed: " + + "phantom refs not enqueued"); + } + } + + @MediumTest + public void testPhantomRefs() throws Exception { + final int NUM_REFS = 16; + + Object objects[] = new Object[NUM_REFS]; + PhantomReference refs[] = new PhantomReference[objects.length]; + ReferenceQueue queue = new ReferenceQueue(); + + /* Create a bunch of objects and a parallel array + * of PhantomReferences. + */ + makeRefs(objects, refs, queue); + Runtime.getRuntime().gc(); + checkRefs(objects, refs, queue); + + /* Clear out every other strong reference. + */ + for (int i = 0; i < objects.length; i += 2) { + objects[i] = null; + } + // System.out.println("HeapTest/PhantomRefs: cleared evens"); + Runtime.getRuntime().gc(); + Runtime.getRuntime().runFinalization(); + checkRefs(objects, refs, queue); + + /* Clear out the rest of them. + */ + for (int i = 0; i < objects.length; i++) { + objects[i] = null; + } + // System.out.println("HeapTest/PhantomRefs: cleared all"); + Runtime.getRuntime().gc(); + Runtime.getRuntime().runFinalization(); + checkRefs(objects, refs, queue); + } + + private static int sNumFinalized = 0; + private static final Object sLock = new Object(); + + private static class FinalizableObject { + protected void finalize() { + // System.out.println("gc from finalize()"); + Runtime.getRuntime().gc(); + synchronized (sLock) { + sNumFinalized++; + } + } + } + + private static void makeRefs(FinalizableObject objects[], + WeakReference refs[]) { + for (int i = 0; i < objects.length; i++) { + objects[i] = new FinalizableObject(); + refs[i] = new WeakReference(objects[i]); + } + } + + @LargeTest + public void testWeakRefsAndFinalizers() throws Exception { + final int NUM_REFS = 16; + + FinalizableObject objects[] = new FinalizableObject[NUM_REFS]; + WeakReference refs[] = new WeakReference[objects.length]; + int numCleared; + + /* Create a bunch of objects and a parallel array + * of WeakReferences. + */ + makeRefs(objects, refs); + Runtime.getRuntime().gc(); + checkRefs(objects, refs); + + /* Clear out every other strong reference. + */ + sNumFinalized = 0; + numCleared = 0; + for (int i = 0; i < objects.length; i += 2) { + objects[i] = null; + numCleared++; + } + // System.out.println("HeapTest/WeakRefsAndFinalizers: cleared evens"); + Runtime.getRuntime().gc(); + Runtime.getRuntime().runFinalization(); + checkRefs(objects, refs); + if (sNumFinalized != numCleared) { + throw new RuntimeException("Test failed: " + + "expected " + numCleared + " finalizations, saw " + + sNumFinalized); + } + + /* Clear out the rest of them. + */ + sNumFinalized = 0; + numCleared = 0; + for (int i = 0; i < objects.length; i++) { + if (objects[i] != null) { + objects[i] = null; + numCleared++; + } + } + // System.out.println("HeapTest/WeakRefsAndFinalizers: cleared all"); + Runtime.getRuntime().gc(); + Runtime.getRuntime().runFinalization(); + checkRefs(objects, refs); + if (sNumFinalized != numCleared) { + throw new RuntimeException("Test failed: " + + "expected " + numCleared + " finalizations, saw " + + sNumFinalized); + } + } + + @MediumTest + public void testOomeLarge() throws Exception { + /* Just shy of the typical max heap size so that it will actually + * try to allocate it instead of short-circuiting. + */ + final int SIXTEEN_MB = (16 * 1024 * 1024 - 32); + + Boolean sawEx = false; + byte a[]; + + try { + a = new byte[SIXTEEN_MB]; + } catch (OutOfMemoryError oom) { + //Log.i(TAG, "HeapTest/OomeLarge caught " + oom); + sawEx = true; + } + + if (!sawEx) { + throw new RuntimeException("Test failed: " + + "OutOfMemoryError not thrown"); + } + } + + //See bug 1308253 for reasons. + @Suppress + public void disableTestOomeSmall() throws Exception { + final int SIXTEEN_MB = (16 * 1024 * 1024); + final int LINK_SIZE = 6 * 4; // estimated size of a LinkedList's node + + Boolean sawEx = false; + + LinkedList list = new LinkedList(); + + /* Allocate progressively smaller objects to fill up the entire heap. + */ + int objSize = 1 * 1024 * 1024; + while (objSize >= LINK_SIZE) { + try { + for (int i = 0; i < SIXTEEN_MB / objSize; i++) { + list.add((Object)new byte[objSize]); + } + } catch (OutOfMemoryError oom) { + sawEx = true; + } + + if (!sawEx) { + throw new RuntimeException("Test failed: " + + "OutOfMemoryError not thrown while filling heap"); + } + sawEx = false; + + objSize = (objSize * 4) / 5; + } + } + + @SmallTest + public void testExternalOomeLarge() { + /* Just shy of the typical max heap size so that it will actually + * try to allocate it instead of short-circuiting. + */ + final int HUGE_SIZE = (16 * 1024 * 1024 - 32); + + assertFalse(VMRuntime.getRuntime().trackExternalAllocation(HUGE_SIZE)); + } + + /** + * "Allocates" external memory in progressively smaller chunks until there's + * only roughly 16 bytes left. + * + * @return the number of bytes allocated + */ + private long allocateMaxExternal() { + final VMRuntime runtime = VMRuntime.getRuntime(); + final int SIXTEEN_MB = (16 * 1024 * 1024); + final int MIN_SIZE = 16; + long totalAllocated = 0; + boolean success; + + success = false; + try { + /* "Allocate" progressively smaller chunks to "fill up" the entire heap. + */ + int objSize = 1 * 1024 * 1024; + while (objSize >= MIN_SIZE) { + boolean sawFailure = false; + for (int i = 0; i < SIXTEEN_MB / objSize; i++) { + if (runtime.trackExternalAllocation(objSize)) { + totalAllocated += objSize; + } else { + sawFailure = true; + break; + } + } + + if (!sawFailure) { + throw new RuntimeException("Test failed: " + + "no failure while filling heap"); + } + + objSize = (objSize * 4) / 5; + } + success = true; + } finally { + if (!success) { + runtime.trackExternalFree(totalAllocated); + totalAllocated = 0; + } + } + return totalAllocated; + } + + public void xxtest00ExternalOomeSmall() { + VMRuntime.getRuntime().trackExternalFree(allocateMaxExternal()); + } + + /** + * Allocates as much external memory as possible, then allocates from the heap + * until an OOME is caught. + * + * It's nice to run this test while the real heap is small, hence the '00' in its + * name to force it to run before testOomeSmall(). + */ + public void xxtest00CombinedOomeSmall() { + long totalAllocated = 0; + boolean sawEx = false; + try { + totalAllocated = allocateMaxExternal(); + LinkedList list = new LinkedList(); + try { + while (true) { + list.add((Object)new byte[8192]); + } + /*NOTREACHED*/ + } catch (OutOfMemoryError oom) { + sawEx = true; + } + } finally { + VMRuntime.getRuntime().trackExternalFree(totalAllocated); + } + assertTrue(sawEx); + } + + //TODO: test external alloc debugging/inspection +} diff --git a/tests/AndroidTests/src/com/android/unit_tests/HtmlTest.java b/tests/AndroidTests/src/com/android/unit_tests/HtmlTest.java new file mode 100644 index 0000000000000000000000000000000000000000..26a3ae0f84e46770070cbf18d5a5964ec9ec46a3 --- /dev/null +++ b/tests/AndroidTests/src/com/android/unit_tests/HtmlTest.java @@ -0,0 +1,156 @@ +/* + * Copyright (C) 2007 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.android.unit_tests; + +import android.graphics.Typeface; +import android.test.suitebuilder.annotation.MediumTest; +import android.test.suitebuilder.annotation.SmallTest; +import android.text.*; +import android.text.style.*; + +import junit.framework.TestCase; + +/** + * HtmlTest tests the Spanned-to-HTML converter + */ +public class HtmlTest extends TestCase { + @MediumTest + public void testColor() throws Exception { + Spanned s; + ForegroundColorSpan[] colors; + + s = Html.fromHtml("something"); + colors = s.getSpans(0, s.length(), ForegroundColorSpan.class); + assertEquals(colors[0].getForegroundColor(), 0xFF00FF00); + + s = Html.fromHtml("something"); + colors = s.getSpans(0, s.length(), ForegroundColorSpan.class); + assertEquals(colors[0].getForegroundColor(), 0xFF000080); + + s = Html.fromHtml("something"); + colors = s.getSpans(0, s.length(), ForegroundColorSpan.class); + assertEquals(colors.length, 0); + } + + @SmallTest + public void testParagraphs() throws Exception { + SpannableString s; + + s = new SpannableString("Hello world"); + assertEquals(Html.toHtml(s), "

              Hello world

              \n"); + + s = new SpannableString("Hello world\nor something"); + assertEquals(Html.toHtml(s), "

              Hello world
              \nor something

              \n"); + + s = new SpannableString("Hello world\n\nor something"); + assertEquals(Html.toHtml(s), "

              Hello world

              \n

              or something

              \n"); + + s = new SpannableString("Hello world\n\n\nor something"); + assertEquals(Html.toHtml(s), "

              Hello world

              \n

              or something

              \n"); + } + + @SmallTest + public void testBlockquote() throws Exception { + SpannableString s; + + s = new SpannableString("Hello world"); + s.setSpan(new QuoteSpan(), 0, s.length(), Spannable.SPAN_PARAGRAPH); + assertEquals(Html.toHtml(s), "

              Hello world

              \n
              \n"); + + s = new SpannableString("Hello\n\nworld"); + s.setSpan(new QuoteSpan(), 0, 7, Spannable.SPAN_PARAGRAPH); + assertEquals(Html.toHtml(s), "

              Hello

              \n
              \n

              world

              \n"); + } + + @SmallTest + public void testEntities() throws Exception { + SpannableString s; + + s = new SpannableString("Hello <&> world"); + assertEquals(Html.toHtml(s), "

              Hello <&> world

              \n"); + + s = new SpannableString("Hello \u03D5 world"); + assertEquals(Html.toHtml(s), "

              Hello ϕ world

              \n"); + + s = new SpannableString("Hello world"); + assertEquals(Html.toHtml(s), "

              Hello  world

              \n"); + } + + @SmallTest + public void testMarkup() throws Exception { + SpannableString s; + + s = new SpannableString("Hello bold world"); + s.setSpan(new StyleSpan(Typeface.BOLD), 6, s.length() - 6, + Spannable.SPAN_EXCLUSIVE_INCLUSIVE); + assertEquals(Html.toHtml(s), "

              Hello bold world

              \n"); + + s = new SpannableString("Hello italic world"); + s.setSpan(new StyleSpan(Typeface.ITALIC), 6, s.length() - 6, + Spannable.SPAN_EXCLUSIVE_INCLUSIVE); + assertEquals(Html.toHtml(s), "

              Hello italic world

              \n"); + + s = new SpannableString("Hello monospace world"); + s.setSpan(new TypefaceSpan("monospace"), 6, s.length() - 6, + Spannable.SPAN_EXCLUSIVE_INCLUSIVE); + assertEquals(Html.toHtml(s), "

              Hello monospace world

              \n"); + + s = new SpannableString("Hello superscript world"); + s.setSpan(new SuperscriptSpan(), 6, s.length() - 6, + Spannable.SPAN_EXCLUSIVE_INCLUSIVE); + assertEquals(Html.toHtml(s), "

              Hello superscript world

              \n"); + + s = new SpannableString("Hello subscript world"); + s.setSpan(new SubscriptSpan(), 6, s.length() - 6, + Spannable.SPAN_EXCLUSIVE_INCLUSIVE); + assertEquals(Html.toHtml(s), "

              Hello subscript world

              \n"); + + s = new SpannableString("Hello underline world"); + s.setSpan(new UnderlineSpan(), 6, s.length() - 6, + Spannable.SPAN_EXCLUSIVE_INCLUSIVE); + assertEquals(Html.toHtml(s), "

              Hello underline world

              \n"); + + s = new SpannableString("Hello struck world"); + s.setSpan(new StrikethroughSpan(), 6, s.length() - 6, + Spannable.SPAN_EXCLUSIVE_INCLUSIVE); + assertEquals(Html.toHtml(s), "

              Hello struck world

              \n"); + + s = new SpannableString("Hello linky world"); + s.setSpan(new URLSpan("http://www.google.com"), 6, s.length() - 6, + Spannable.SPAN_EXCLUSIVE_INCLUSIVE); + assertEquals(Html.toHtml(s), + "

              Hello linky world

              \n"); + } + + @SmallTest + public void testImg() throws Exception { + Spanned s; + + s = Html.fromHtml("yesno"); + + assertEquals("

              yesno

              \n", + Html.toHtml(s)); + } + + @SmallTest + public void testUtf8() throws Exception { + Spanned s; + + s = Html.fromHtml("

              \u0124\u00eb\u0142\u0142o, world!

              "); + assertEquals("

              Ĥëłło, world!

              \n", Html.toHtml(s)); + } +} diff --git a/tests/AndroidTests/src/com/android/unit_tests/InflateTest.java b/tests/AndroidTests/src/com/android/unit_tests/InflateTest.java new file mode 100644 index 0000000000000000000000000000000000000000..d7c9d60d0935d96fdb20e3f4ea06c37fc810588c --- /dev/null +++ b/tests/AndroidTests/src/com/android/unit_tests/InflateTest.java @@ -0,0 +1,154 @@ +/* + * Copyright (C) 2006 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.android.unit_tests; + +import android.content.Context; +import android.content.res.Resources; +import android.test.AndroidTestCase; +import android.test.PerformanceTestCase; +import android.test.suitebuilder.annotation.SmallTest; +import android.util.AttributeSet; +import android.view.LayoutInflater; +import android.view.View; + +import java.util.Map; + +public class InflateTest extends AndroidTestCase implements PerformanceTestCase { + private LayoutInflater mInflater; + private Resources mResources; + private View mView; + + @Override + protected void setUp() throws Exception { + super.setUp(); + + mInflater = LayoutInflater.from(mContext); + mResources = mContext.getResources(); + + // to try to make things consistent, before doing timing + // do an initial instantiation of the layout and then clear + // out the layout cache. +// mInflater.inflate(mResId, null, null); +// mResources.flushLayoutCache(); + } + + public int startPerformance(PerformanceTestCase.Intermediates intermediates) { + return 0; + } + + public boolean isPerformanceOnly() { + return false; + } + + public void inflateTest(int resourceId) { + mView = mInflater.inflate(resourceId, null); + mResources.flushLayoutCache(); + } + + public void inflateCachedTest(int resourceId) { + // Make sure this layout is in the cache. + mInflater.inflate(resourceId, null); + + mInflater.inflate(resourceId, null); + } + + @SmallTest + public void testLayout1() throws Exception { + inflateTest(R.layout.layout_one); + } + + @SmallTest + public void testLayout2() throws Exception { + inflateTest(R.layout.layout_two); + } + + @SmallTest + public void testLayout3() throws Exception { + inflateTest(R.layout.layout_three); + } + + @SmallTest + public void testLayout4() throws Exception { + inflateTest(R.layout.layout_four); + } + + @SmallTest + public void testLayout5() throws Exception { + inflateTest(R.layout.layout_five); + } + + @SmallTest + public void testLayout6() throws Exception { + inflateTest(R.layout.layout_six); + } + + @SmallTest + public void testCachedLayout1() throws Exception { + inflateCachedTest(R.layout.layout_one); + } + + @SmallTest + public void testCachedLayout2() throws Exception { + inflateCachedTest(R.layout.layout_two); + } + + @SmallTest + public void testCachedLayout3() throws Exception { + inflateCachedTest(R.layout.layout_three); + } + + @SmallTest + public void testCachedLayout4() throws Exception { + inflateCachedTest(R.layout.layout_four); + } + + @SmallTest + public void testCachedLayout5() throws Exception { + inflateCachedTest(R.layout.layout_five); + } + + @SmallTest + public void testCachedLayout6() throws Exception { + inflateCachedTest(R.layout.layout_six); + } + +// public void testLayoutTag() throws Exception { +// public void setUp +// (Context +// context){ +// setUp(context, R.layout.layout_tag); +// } +// public void run +// () +// { +// super.run(); +// if (!"MyTag".equals(mView.getTag())) { +// throw new RuntimeException("Incorrect tag: " + mView.getTag()); +// } +// } +// } + + public static class ViewOne extends View { + public ViewOne(Context context) { + super(context); + } + + public ViewOne(Context context, AttributeSet attrs) { + super(context, attrs); + } + } +} diff --git a/tests/AndroidTests/src/com/android/unit_tests/InstanceofTest.java b/tests/AndroidTests/src/com/android/unit_tests/InstanceofTest.java new file mode 100644 index 0000000000000000000000000000000000000000..1f82df8d389836fd8e4d94373b5c355bec187b24 --- /dev/null +++ b/tests/AndroidTests/src/com/android/unit_tests/InstanceofTest.java @@ -0,0 +1,141 @@ +/* + * Copyright (C) 2006 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.android.unit_tests; + +import junit.framework.TestCase; +import android.test.suitebuilder.annotation.MediumTest; + + +public class InstanceofTest extends TestCase { + + protected A mA; + protected ChildOfAOne mOne; + protected ChildOfAOne mTwo; + protected ChildOfAOne mThree; + protected ChildOfAOne mFour; + protected ChildOfAFive mFive; + + @Override + protected void setUp() throws Exception { + super.setUp(); + + mA = new A(); + mOne = new ChildOfAOne(); + mTwo = new ChildOfATwo(); + mThree = new ChildOfAThree(); + mFour = new ChildOfAFour(); + mFive = new ChildOfAFive(); + } + + + @MediumTest + public void testNoInterface() throws Exception { + A a = mA; + for (int i = 0; i < 100000; i++) { + assertFalse("m_a should not be a ChildOfAFive", a instanceof ChildOfAFive); + } + } + + @MediumTest + public void testDerivedOne() throws Exception { + InterfaceOne one = mOne; + for (int i = 0; i < 100000; i++) { + assertFalse("m_one should not be a ChildOfAFive", one instanceof ChildOfAFive); + } + } + + @MediumTest + public void testDerivedTwo() throws Exception { + InterfaceTwo two = mTwo; + for (int i = 0; i < 100000; i++) { + assertFalse("m_two should not be a ChildOfAFive", two instanceof ChildOfAFive); + } + } + + @MediumTest + public void testDerivedThree() throws Exception { + InterfaceThree three = mThree; + for (int i = 0; i < 100000; i++) { + assertFalse("m_three should not be a ChildOfAFive", three instanceof ChildOfAFive); + } + } + + @MediumTest + public void testDerivedFour() throws Exception { + InterfaceFour four = mFour; + for (int i = 0; i < 100000; i++) { + assertFalse("m_four should not be a ChildOfAFive", four instanceof ChildOfAFive); + } + } + + @MediumTest + public void testSuccessClass() throws Exception { + ChildOfAOne five = mFive; + for (int i = 0; i < 100000; i++) { + assertTrue("m_five is suppose to be a ChildOfAFive", five instanceof ChildOfAFive); + } + } + + @MediumTest + public void testSuccessInterface() throws Exception { + ChildOfAFive five = mFive; + for (int i = 0; i < 100000; i++) { + assertTrue("m_five is suppose to be a InterfaceFour", five instanceof InterfaceFour); + } + } + + @MediumTest + public void testFailInterface() throws Exception { + InterfaceOne one = mFive; + for (int i = 0; i < 100000; i++) { + assertFalse("m_five does not implement InterfaceFive", one instanceof InterfaceFive); + } + } + + private interface InterfaceOne { + } + + private interface InterfaceTwo { + } + + private interface InterfaceThree { + } + + private interface InterfaceFour { + } + + private interface InterfaceFive { + } + + private static class A { + } + + private static class ChildOfAOne extends A implements InterfaceOne, InterfaceTwo, InterfaceThree, InterfaceFour { + } + + private static class ChildOfATwo extends ChildOfAOne { + } + + private static class ChildOfAThree extends ChildOfATwo { + } + + private static class ChildOfAFour extends ChildOfAThree { + } + + private static class ChildOfAFive extends ChildOfAFour { + } +} diff --git a/tests/AndroidTests/src/com/android/unit_tests/JavaPerformanceTests.java b/tests/AndroidTests/src/com/android/unit_tests/JavaPerformanceTests.java new file mode 100644 index 0000000000000000000000000000000000000000..e778d533699a8e0ba711ed1e53d77fe2c478ad4b --- /dev/null +++ b/tests/AndroidTests/src/com/android/unit_tests/JavaPerformanceTests.java @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2007 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.android.unit_tests; + +/** + * + */ +public class JavaPerformanceTests { + + public static String[] children() { + return new String[] { + StringTest.class.getName(), + HashMapTest.class.getName(), + ArrayListTest.class.getName(), + TreeMapTest.class.getName(), + TreeSetTest.class.getName(), + HashSetTest.class.getName(), + HashtableTest.class.getName(), + VectorTest.class.getName(), + LinkedListTest.class.getName(), + MathTest.class.getName(), + }; + } +} diff --git a/tests/AndroidTests/src/com/android/unit_tests/JniLibTest.java b/tests/AndroidTests/src/com/android/unit_tests/JniLibTest.java new file mode 100644 index 0000000000000000000000000000000000000000..6b740ba127db0fe4bbed14109048e1d326528879 --- /dev/null +++ b/tests/AndroidTests/src/com/android/unit_tests/JniLibTest.java @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2006 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.android.unit_tests; + +import android.test.suitebuilder.annotation.Suppress; +import android.util.Log; +import junit.framework.TestCase; + + +@Suppress +public class JniLibTest extends TestCase { + + @Override + protected void setUp() throws Exception { + super.setUp(); + /* + * This causes the native shared library to be loaded when the + * class is first used. The library is only loaded once, even if + * multiple classes include this line. + * + * The library must be in java.library.path, which is derived from + * LD_LIBRARY_PATH. The actual library name searched for will be + * "libjni_lib_test.so" under Linux, but may be different on other + * platforms. + */ + try { + System.loadLibrary("jni_lib_test"); + } catch (UnsatisfiedLinkError ule) { + Log.e("JniLibTest", "WARNING: Could not load jni_lib_test natives"); + } + } + + private static native int nativeStaticThing(float f); + private native void nativeThing(int val); + + public void testNativeCall() { + Log.i("JniLibTest", "JNI search path is " + + System.getProperty("java.library.path")); + Log.i("JniLibTest", "'jni_lib_test' becomes '" + + System.mapLibraryName("jni_lib_test") + "'"); + + int result = nativeStaticThing(1234.5f); + nativeThing(result); + } +} diff --git a/tests/AndroidTests/src/com/android/unit_tests/LabelView.java b/tests/AndroidTests/src/com/android/unit_tests/LabelView.java new file mode 100644 index 0000000000000000000000000000000000000000..ac297766faf974e3cc9d688c4ad4910822ee0894 --- /dev/null +++ b/tests/AndroidTests/src/com/android/unit_tests/LabelView.java @@ -0,0 +1,191 @@ +/* + * Copyright (C) 2007 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.android.unit_tests; + +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.view.View; + +/** + * Example of how to write a custom subclass of View. LabelView + * is used to draw simple text views. Note that it does not handle + * styled text or right-to-left writing systems. + * + */ +public class LabelView extends View { + /** + * Constructor. This version is only needed if you will be instantiating + * the object manually (not from a layout XML file). + * @param context the application environment + */ + public LabelView(Context context) { + super(context); + initLabelView(); + } + + /** + * Construct object, initializing with any attributes we understand from a + * layout file. These attributes are defined in + * SDK/assets/res/any/classes.xml. + * + * @see android.view.View#View(android.content.Context, android.util.AttributeSet) + public LabelView(Context context, AttributeSet attrs) { + super(context, attrs); + initLabelView(); + + Resources.StyledAttributes a = context.obtainStyledAttributes(attrs, + R.styleable.LabelView); + + CharSequence s = a.getString(R.styleable.LabelView_text); + if (s != null) { + setText(s.toString()); + } + + ColorStateList textColor = a.getColorList(R.styleable. + LabelView_textColor); + if (textColor != null) { + setTextColor(textColor.getDefaultColor(0)); + } + + int textSize = a.getInt(R.styleable.LabelView_textSize, 0); + if (textSize > 0) { + setTextSize(textSize); + } + + a.recycle(); + } + + */ + private void initLabelView() { + mTextPaint = new Paint(); + mTextPaint.setAntiAlias(true); + mTextPaint.setTextSize(16); + mTextPaint.setColor(0xFF000000); + + mPaddingLeft = 3; + mPaddingTop = 3; + mPaddingRight = 3; + mPaddingBottom = 3; + } + + /** + * Sets the text to display in this label + * @param text The text to display. This will be drawn as one line. + */ + public void setText(String text) { + mText = text; + requestLayout(); + invalidate(); + } + + /** + * Sets the text size for this label + * @param size Font size + */ + public void setTextSize(int size) { + mTextPaint.setTextSize(size); + requestLayout(); + invalidate(); + } + + /** + * Sets the text color for this label + * @param color ARGB value for the text + */ + public void setTextColor(int color) { + mTextPaint.setColor(color); + invalidate(); + } + + + /** + * @see android.view.View#measure(int, int) + */ + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + setMeasuredDimension(measureWidth(widthMeasureSpec), + measureHeight(heightMeasureSpec)); + } + + /** + * Determines the width of this view + * @param measureSpec A measureSpec packed into an int + * @return The width of the view, honoring constraints from measureSpec + */ + private int measureWidth(int measureSpec) { + int result; + int specMode = MeasureSpec.getMode(measureSpec); + int specSize = MeasureSpec.getSize(measureSpec); + + if (specMode == MeasureSpec.EXACTLY) { + // We were told how big to be + result = specSize; + } else { + // Measure the text + result = (int) mTextPaint.measureText(mText) + mPaddingLeft + + mPaddingRight; + if (specMode == MeasureSpec.AT_MOST) { + // Respect AT_MOST value if that was what is called for by measureSpec + result = Math.min(result, specSize); + } + } + + return result; + } + + /** + * Determines the height of this view + * @param measureSpec A measureSpec packed into an int + * @return The height of the view, honoring constraints from measureSpec + */ + private int measureHeight(int measureSpec) { + int result; + int specMode = MeasureSpec.getMode(measureSpec); + int specSize = MeasureSpec.getSize(measureSpec); + + mAscent = (int) mTextPaint.ascent(); + if (specMode == MeasureSpec.EXACTLY) { + // We were told how big to be + result = specSize; + } else { + // Measure the text (beware: ascent is a negative number) + result = (int) (-mAscent + mTextPaint.descent()) + mPaddingTop + + mPaddingBottom; + if (specMode == MeasureSpec.AT_MOST) { + // Respect AT_MOST value if that was what is called for by measureSpec + result = Math.min(result, specSize); + } + } + return result; + } + + /** + * Render the text + * + * @see android.view.View#onDraw(android.graphics.Canvas) + */ + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + canvas.drawText(mText, mPaddingLeft, mPaddingTop - mAscent, mTextPaint); + } + + private Paint mTextPaint; + private String mText; + private int mAscent; +} diff --git a/tests/AndroidTests/src/com/android/unit_tests/LinkedListTest.java b/tests/AndroidTests/src/com/android/unit_tests/LinkedListTest.java new file mode 100644 index 0000000000000000000000000000000000000000..ca470cd3cbd5b223ae459bbd5a9791d7d9ff70ee --- /dev/null +++ b/tests/AndroidTests/src/com/android/unit_tests/LinkedListTest.java @@ -0,0 +1,529 @@ +/* + * Copyright (C) 2007 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.android.unit_tests; + +import android.test.PerformanceTestBase; +import android.test.PerformanceTestCase; +import java.util.LinkedList; +import java.util.ListIterator; + +/** + * This class contains performance tests for methods in java.util.LinkedList + * + */ +@SuppressWarnings("unchecked") +public class LinkedListTest extends PerformanceTestBase { + public static final int ITERATIONS = 1000; + LinkedList mLinkedList; + + @Override + protected void setUp() throws Exception { + super.setUp(); + mLinkedList = new LinkedList(); + for (int i = ITERATIONS - 1; i >= 0; i--) { + mLinkedList.add(i); + } + } + + @Override + public int startPerformance(PerformanceTestCase.Intermediates intermediates) { + intermediates.setInternalIterations(ITERATIONS); + return 0; + } + + public void testLinkedListAdd() { + LinkedList list = new LinkedList(); + for (int i = ITERATIONS - 1; i >= 0; i--) { + list.add(i); + list.add(i); + list.add(i); + list.add(i); + list.add(i); + list.add(i); + list.add(i); + list.add(i); + list.add(i); + list.add(i); + } + } + + public void testLinkedListAdd1() { + LinkedList list = new LinkedList(); + for (int i = ITERATIONS - 1; i >= 0; i--) { + list.add(0, i); + list.add(0, i); + list.add(0, i); + list.add(0, i); + list.add(0, i); + list.add(0, i); + list.add(0, i); + list.add(0, i); + list.add(0, i); + list.add(0, i); + } + } + + public void testLinkedListToArray() { + Object array; + LinkedList list = mLinkedList; + for (int i = ITERATIONS - 1; i >= 0; i--) { + array = list.toArray(); + array = list.toArray(); + array = list.toArray(); + array = list.toArray(); + array = list.toArray(); + array = list.toArray(); + array = list.toArray(); + array = list.toArray(); + array = list.toArray(); + array = list.toArray(); + } + } + + public void testLinkedListSize() { + LinkedList list = mLinkedList; + int len; + for (int i = ITERATIONS - 1; i >= 0; i--) { + len = list.size(); + len = list.size(); + len = list.size(); + len = list.size(); + len = list.size(); + len = list.size(); + len = list.size(); + len = list.size(); + len = list.size(); + len = list.size(); + } + } + + public void testLinkedListGet() { + int element; + LinkedList list = mLinkedList; + for (int i = ITERATIONS - 1; i >= 0; i--) { + element = list.get(i); + element = list.get(i); + element = list.get(i); + element = list.get(i); + element = list.get(i); + element = list.get(i); + element = list.get(i); + element = list.get(i); + element = list.get(i); + element = list.get(i); + } + } + + public void testLinkedListContains() { + boolean flag; + LinkedList list = mLinkedList; + for (int i = ITERATIONS - 1; i >= 0; i--) { + flag = list.contains(i); + flag = list.contains(i); + flag = list.contains(i); + flag = list.contains(i); + flag = list.contains(i); + flag = list.contains(i); + flag = list.contains(i); + flag = list.contains(i); + flag = list.contains(i); + flag = list.contains(i); + } + } + + public void testLinkedListToArray1() { + Integer[] rArray = new Integer[100]; + Integer[] array; + LinkedList list = mLinkedList; + for (int i = ITERATIONS - 1; i >= 0; i--) { + array = list.toArray(rArray); + array = list.toArray(rArray); + array = list.toArray(rArray); + array = list.toArray(rArray); + array = list.toArray(rArray); + array = list.toArray(rArray); + array = list.toArray(rArray); + array = list.toArray(rArray); + array = list.toArray(rArray); + array = list.toArray(rArray); + } + } + + public void testLinkedListSet() { + LinkedList list = mLinkedList; + int value1 = 500, value2 = 0; + for (int i = ITERATIONS - 1; i >= 0; i--) { + list.set(value1, value2); + list.set(value1, value2); + list.set(value1, value2); + list.set(value1, value2); + list.set(value1, value2); + list.set(value1, value2); + list.set(value1, value2); + list.set(value1, value2); + list.set(value1, value2); + list.set(value1, value2); + } + } + + public void testLinkedListIndexOf() { + int index; + LinkedList list = mLinkedList; + for (int i = ITERATIONS - 1; i >= 0; i--) { + index = list.indexOf(0); + index = list.indexOf(0); + index = list.indexOf(0); + index = list.indexOf(0); + index = list.indexOf(0); + index = list.indexOf(0); + index = list.indexOf(0); + index = list.indexOf(0); + index = list.indexOf(0); + index = list.indexOf(0); + + } + } + + public void testLinkedListLastIndexOf() { + int index; + LinkedList list = mLinkedList; + for (int i = ITERATIONS - 1; i >= 0; i--) { + index = list.lastIndexOf(0); + index = list.lastIndexOf(0); + index = list.lastIndexOf(0); + index = list.lastIndexOf(0); + index = list.lastIndexOf(0); + index = list.lastIndexOf(0); + index = list.lastIndexOf(0); + index = list.lastIndexOf(0); + index = list.lastIndexOf(0); + index = list.lastIndexOf(0); + } + } + + public void testLinkedListRemove() { + int index; + LinkedList list = new LinkedList(mLinkedList); + for (int i = 10; i > 0; i--) { + index = list.remove(); + index = list.remove(); + index = list.remove(); + index = list.remove(); + index = list.remove(); + index = list.remove(); + index = list.remove(); + index = list.remove(); + index = list.remove(); + index = list.remove(); + } + } + + public void testLinkedListRemove1() { + int index; + LinkedList list = new LinkedList(mLinkedList); + for (int i = 10; i > 0; i--) { + index = list.remove(0); + index = list.remove(0); + index = list.remove(0); + index = list.remove(0); + index = list.remove(0); + index = list.remove(0); + index = list.remove(0); + index = list.remove(0); + index = list.remove(0); + index = list.remove(0); + } + } + + public void testLinkedListRemoveFirst() { + int index; + LinkedList list = new LinkedList(mLinkedList); + for (int i = 10; i > 0; i--) { + index = list.removeFirst(); + index = list.removeFirst(); + index = list.removeFirst(); + index = list.removeFirst(); + index = list.removeFirst(); + index = list.removeFirst(); + index = list.removeFirst(); + index = list.removeFirst(); + index = list.removeFirst(); + index = list.removeFirst(); + } + } + + public void testLinkedListRemoveLast() { + int index; + LinkedList list = new LinkedList(mLinkedList); + for (int i = 10; i > 0; i--) { + index = list.removeLast(); + index = list.removeLast(); + index = list.removeLast(); + index = list.removeLast(); + index = list.removeLast(); + index = list.removeLast(); + index = list.removeLast(); + index = list.removeLast(); + index = list.removeLast(); + index = list.removeLast(); + } + } + + public void testLinkedListAddAll() { + LinkedList mList = mLinkedList; + boolean flag; + LinkedList list = new LinkedList(); + for (int i = 10; i > 0; i--) { + flag = list.addAll(mList); + flag = list.addAll(mList); + flag = list.addAll(mList); + flag = list.addAll(mList); + flag = list.addAll(mList); + flag = list.addAll(mList); + flag = list.addAll(mList); + flag = list.addAll(mList); + flag = list.addAll(mList); + flag = list.addAll(mList); + } + } + + public void testLinkedListRemove2() { + LinkedList list; + String s = new String("a"); + list = new LinkedList(); + for (int j = 1000; j > 0; j--) { + list.add("a"); + list.add("b"); + } + boolean flag; + for (int i = 10; i > 0; i--) { + flag = list.remove(s); + flag = list.remove(s); + flag = list.remove(s); + flag = list.remove(s); + flag = list.remove(s); + flag = list.remove(s); + flag = list.remove(s); + flag = list.remove(s); + flag = list.remove(s); + flag = list.remove(s); + } + } + + public void testLinkedListAddAll1() { + LinkedList mList = new LinkedList(); + int pos = 0; + boolean flag; + LinkedList list = mLinkedList; + for (int i = 0; i < 10; i++) { + flag = mList.addAll(pos, list); + flag = mList.addAll(pos, list); + flag = mList.addAll(pos, list); + flag = mList.addAll(pos, list); + flag = mList.addAll(pos, list); + flag = mList.addAll(pos, list); + flag = mList.addAll(pos, list); + flag = mList.addAll(pos, list); + flag = mList.addAll(pos, list); + flag = mList.addAll(pos, list); + } + } + + public void testLinkedListClone() { + Object rObj; + LinkedList list = mLinkedList; + for (int i = 100; i > 0; i--) { + rObj = list.clone(); + rObj = list.clone(); + rObj = list.clone(); + rObj = list.clone(); + rObj = list.clone(); + rObj = list.clone(); + rObj = list.clone(); + rObj = list.clone(); + rObj = list.clone(); + rObj = list.clone(); + } + } + + public void testLinkedListHashcode() { + int element; + LinkedList list = mLinkedList; + for (int i = ITERATIONS - 1; i >= 0; i--) { + element = list.hashCode(); + element = list.hashCode(); + element = list.hashCode(); + element = list.hashCode(); + element = list.hashCode(); + element = list.hashCode(); + element = list.hashCode(); + element = list.hashCode(); + element = list.hashCode(); + element = list.hashCode(); + } + } + + public void testLinkedListElement() { + int element; + LinkedList list = mLinkedList; + for (int i = ITERATIONS - 1; i >= 0; i--) { + element = list.element(); + element = list.element(); + element = list.element(); + element = list.element(); + element = list.element(); + element = list.element(); + element = list.element(); + element = list.element(); + element = list.element(); + element = list.element(); + } + } + + public void testLinkedListToString() { + String str; + LinkedList list = mLinkedList; + for (int i = ITERATIONS - 1; i >= 0; i--) { + str = list.toString(); + str = list.toString(); + str = list.toString(); + str = list.toString(); + str = list.toString(); + str = list.toString(); + str = list.toString(); + str = list.toString(); + str = list.toString(); + str = list.toString(); + } + } + + public void testLinkedListIsEmpty() { + boolean flag; + LinkedList list = mLinkedList; + for (int i = ITERATIONS - 1; i >= 0; i--) { + flag = list.isEmpty(); + flag = list.isEmpty(); + flag = list.isEmpty(); + flag = list.isEmpty(); + flag = list.isEmpty(); + flag = list.isEmpty(); + flag = list.isEmpty(); + flag = list.isEmpty(); + flag = list.isEmpty(); + flag = list.isEmpty(); + } + } + + public void testLinkedListOffer() { + LinkedList list = new LinkedList(); + for (int i = ITERATIONS - 1; i >= 0; i--) { + list.offer(i); + list.offer(i); + list.offer(i); + list.offer(i); + list.offer(i); + list.offer(i); + list.offer(i); + list.offer(i); + list.offer(i); + list.offer(i); + } + } + + public void testLinkedListPeek() { + int element; + LinkedList list = mLinkedList; + for (int i = ITERATIONS - 1; i >= 0; i--) { + element = list.peek(); + element = list.peek(); + element = list.peek(); + element = list.peek(); + element = list.peek(); + element = list.peek(); + element = list.peek(); + element = list.peek(); + element = list.peek(); + element = list.peek(); + } + } + + public void testLinkedListPoll() { + int element; + LinkedList list = new LinkedList(mLinkedList); + for (int i = 10; i > 0; i--) { + element = list.poll(); + element = list.poll(); + element = list.poll(); + element = list.poll(); + element = list.poll(); + element = list.poll(); + element = list.poll(); + element = list.poll(); + element = list.poll(); + element = list.poll(); + } + } + + public void testLinkedListAddLast() { + LinkedList list = new LinkedList(); + for (int i = ITERATIONS - 1; i >= 0; i--) { + list.addLast(i); + list.addLast(i); + list.addLast(i); + list.addLast(i); + list.addLast(i); + list.addLast(i); + list.addLast(i); + list.addLast(i); + list.addLast(i); + list.addLast(i); + } + } + + public void testLinkedListAddFirst() { + LinkedList list = new LinkedList(); + for (int i = ITERATIONS - 1; i >= 0; i--) { + list.addFirst(i); + list.addFirst(i); + list.addFirst(i); + list.addFirst(i); + list.addFirst(i); + list.addFirst(i); + list.addFirst(i); + list.addFirst(i); + list.addFirst(i); + list.addFirst(i); + } + } + + public void testLinkedListIterator() { + ListIterator iterator; + LinkedList list = mLinkedList; + for (int i = ITERATIONS - 1; i >= 0; i--) { + iterator = list.listIterator(); + iterator = list.listIterator(); + iterator = list.listIterator(); + iterator = list.listIterator(); + iterator = list.listIterator(); + iterator = list.listIterator(); + iterator = list.listIterator(); + iterator = list.listIterator(); + iterator = list.listIterator(); + iterator = list.listIterator(); + } + } +} diff --git a/tests/AndroidTests/src/com/android/unit_tests/LinkifyTest.java b/tests/AndroidTests/src/com/android/unit_tests/LinkifyTest.java new file mode 100644 index 0000000000000000000000000000000000000000..83e07584be71009415229948fbeaf56630dbd72a --- /dev/null +++ b/tests/AndroidTests/src/com/android/unit_tests/LinkifyTest.java @@ -0,0 +1,68 @@ +/* + * 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.android.unit_tests; + +import android.test.AndroidTestCase; +import android.test.suitebuilder.annotation.MediumTest; +import android.test.suitebuilder.annotation.SmallTest; +import android.text.*; +import android.text.method.*; +import android.text.style.*; +import android.text.util.*; +import android.widget.*; + +/** + * LinkifyTest tests {@link Linkify}. + */ +public class LinkifyTest extends AndroidTestCase { + + @SmallTest + public void testNothing() throws Exception { + TextView tv; + + tv = new TextView(getContext()); + tv.setText("Hey, foo@google.com, call 415-555-1212."); + + assertFalse(tv.getMovementMethod() instanceof LinkMovementMethod); + assertTrue(tv.getUrls().length == 0); + } + + @MediumTest + public void testNormal() throws Exception { + TextView tv; + + tv = new TextView(getContext()); + tv.setAutoLinkMask(Linkify.ALL); + tv.setText("Hey, foo@google.com, call 415-555-1212."); + + assertTrue(tv.getMovementMethod() instanceof LinkMovementMethod); + assertTrue(tv.getUrls().length == 2); + } + + @SmallTest + public void testUnclickable() throws Exception { + TextView tv; + + tv = new TextView(getContext()); + tv.setAutoLinkMask(Linkify.ALL); + tv.setLinksClickable(false); + tv.setText("Hey, foo@google.com, call 415-555-1212."); + + assertFalse(tv.getMovementMethod() instanceof LinkMovementMethod); + assertTrue(tv.getUrls().length == 2); + } +} diff --git a/tests/AndroidTests/src/com/android/unit_tests/LocalSocketTest.java b/tests/AndroidTests/src/com/android/unit_tests/LocalSocketTest.java new file mode 100644 index 0000000000000000000000000000000000000000..0b8ec7408b6e90058a7e88f1c2d5f690e9a1c032 --- /dev/null +++ b/tests/AndroidTests/src/com/android/unit_tests/LocalSocketTest.java @@ -0,0 +1,171 @@ +/* + * Copyright (C) 2007 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.android.unit_tests; + +import android.net.Credentials; +import android.net.LocalServerSocket; +import android.net.LocalSocket; +import android.net.LocalSocketAddress; +import android.test.MoreAsserts; +import android.test.suitebuilder.annotation.SmallTest; +import junit.framework.TestCase; + +import java.io.FileDescriptor; +import java.io.IOException; + +public class LocalSocketTest extends TestCase { + + @SmallTest + public void testBasic() throws Exception { + LocalServerSocket ss; + LocalSocket ls; + LocalSocket ls1; + + ss = new LocalServerSocket("com.android.unit_tests.LocalSocketTest"); + + ls = new LocalSocket(); + + ls.connect(new LocalSocketAddress("com.android.unit_tests.LocalSocketTest")); + + ls1 = ss.accept(); + + // Test trivial read and write + ls.getOutputStream().write(42); + + assertEquals(42, ls1.getInputStream().read()); + + // Test getting credentials + Credentials c = ls1.getPeerCredentials(); + + MoreAsserts.assertNotEqual(0, c.getPid()); + + // Test sending and receiving file descriptors + ls.setFileDescriptorsForSend( + new FileDescriptor[]{FileDescriptor.in}); + + ls.getOutputStream().write(42); + + assertEquals(42, ls1.getInputStream().read()); + + FileDescriptor[] out = ls1.getAncillaryFileDescriptors(); + + assertEquals(1, out.length); + + // Test multible byte write and available() + ls1.getOutputStream().write(new byte[]{0, 1, 2, 3, 4, 5}, 1, 5); + + assertEquals(1, ls.getInputStream().read()); + assertEquals(4, ls.getInputStream().available()); + + byte[] buffer = new byte[16]; + int countRead; + + countRead = ls.getInputStream().read(buffer, 1, 15); + + assertEquals(4, countRead); + assertEquals(2, buffer[1]); + assertEquals(3, buffer[2]); + assertEquals(4, buffer[3]); + assertEquals(5, buffer[4]); + + // Try various array-out-of-bound cases + try { + ls.getInputStream().read(buffer, 1, 16); + fail("expected exception"); + } catch (ArrayIndexOutOfBoundsException ex) { + // excpected + } + + try { + ls.getOutputStream().write(buffer, 1, 16); + fail("expected exception"); + } catch (ArrayIndexOutOfBoundsException ex) { + // excpected + } + + try { + ls.getOutputStream().write(buffer, -1, 15); + fail("expected exception"); + } catch (ArrayIndexOutOfBoundsException ex) { + // excpected + } + + try { + ls.getOutputStream().write(buffer, 0, -1); + fail("expected exception"); + } catch (ArrayIndexOutOfBoundsException ex) { + // excpected + } + + try { + ls.getInputStream().read(buffer, -1, 15); + fail("expected exception"); + } catch (ArrayIndexOutOfBoundsException ex) { + // excpected + } + + try { + ls.getInputStream().read(buffer, 0, -1); + fail("expected exception"); + } catch (ArrayIndexOutOfBoundsException ex) { + // excpected + } + + // Try read of length 0 + ls.getOutputStream().write(42); + countRead = ls1.getInputStream().read(buffer, 0, 0); + assertEquals(0, countRead); + assertEquals(42, ls1.getInputStream().read()); + + ss.close(); + + ls.close(); + + // Try write on closed socket + + try { + ls.getOutputStream().write(42); + fail("expected exception"); + } catch (IOException ex) { + // Expected + } + + // Try read on closed socket + + try { + ls.getInputStream().read(); + fail("expected exception"); + } catch (IOException ex) { + // Expected + } + + // Try write on socket whose peer has closed + + try { + ls1.getOutputStream().write(42); + fail("expected exception"); + } catch (IOException ex) { + // Expected + } + + // Try read on socket whose peer has closed + + assertEquals(-1, ls1.getInputStream().read()); + + ls1.close(); + } +} diff --git a/tests/AndroidTests/src/com/android/unit_tests/LocationManagerTest.java b/tests/AndroidTests/src/com/android/unit_tests/LocationManagerTest.java new file mode 100644 index 0000000000000000000000000000000000000000..47c7522a7960d57bb4b134fb7663f6ba0a93b00b --- /dev/null +++ b/tests/AndroidTests/src/com/android/unit_tests/LocationManagerTest.java @@ -0,0 +1,132 @@ +/* + * Copyright (C) 2006 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.android.unit_tests; + +import android.content.Context; +import android.location.Criteria; +import android.location.Location; +import android.location.LocationManager; +import android.location.LocationProvider; +import android.test.AndroidTestCase; +import android.test.suitebuilder.annotation.Suppress; +import android.util.Log; + +@Suppress +public class LocationManagerTest extends AndroidTestCase { + private static final String LOG_TAG = "LocationManagerTest"; + + private LocationManager manager; + + @Override + public void setUp() throws Exception { + super.setUp(); + manager = (LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE); + assertNotNull(manager); + } + + public void testGetBogusProvider() { + LocationProvider p = manager.getProvider("bogus"); + assertNull(p); + } + + public void testGetNetworkProvider() { + LocationProvider p = manager.getProvider("network"); + assertNotNull(p); + } + + public void testGetGpsProvider() { + LocationProvider p = manager.getProvider("gps"); + assertNotNull(p); + } + + public void testGetBestProviderEmptyCriteria() { + String p = manager.getBestProvider(new Criteria(), true); + assertNotNull(p); + } + + public void testGetBestProviderPowerCriteria() { + Criteria c = new Criteria(); + c.setPowerRequirement(Criteria.POWER_HIGH); + String p = manager.getBestProvider(c, true); + assertNotNull(p); + + c.setPowerRequirement(Criteria.POWER_MEDIUM); + p = manager.getBestProvider(c, true); + assertNotNull(p); + + c.setPowerRequirement(Criteria.POWER_LOW); + p = manager.getBestProvider(c, true); + assertNotNull(p); + + c.setPowerRequirement(Criteria.NO_REQUIREMENT); + p = manager.getBestProvider(c, true); + assertNotNull(p); + } + + public void testGpsTracklog() { + LocationProvider p = manager.getProvider("gps"); + assertNotNull(p); + + // TODO: test requestUpdates method + } + + public void testLocationConversions() { + String loc1 = Location.convert(-80.075, Location.FORMAT_DEGREES); + Log.i(LOG_TAG, "Input = " + (-80.075) + ", output = " + loc1); + assertEquals("-80.075", loc1); + + String loc1b = Location.convert(-80.0, Location.FORMAT_DEGREES); + Log.i(LOG_TAG, "Input = " + (-80.0) + ", output = " + loc1b); + assertEquals("-80", loc1b); + + String loc2 = Location.convert(-80.085, Location.FORMAT_DEGREES); + Log.i(LOG_TAG, "Input = " + (-80.085) + ", output = " + loc2); + assertEquals("-80.085", loc2); + + String loc3 = Location.convert(-80.085, Location.FORMAT_MINUTES); + Log.i(LOG_TAG, "Input = " + (-80.085) + ", output = " + loc3); + assertEquals("-80:5.1", loc3); + + String loc4 = Location.convert(-80.085, Location.FORMAT_SECONDS); + Log.i(LOG_TAG, "Input = " + (-80.085) + ", output = " + loc4); + assertEquals("-80:5:6", loc4); + + String loc5 = Location.convert(5 + 0.5f / 60.0f, Location.FORMAT_MINUTES); + Log.i(LOG_TAG, "Input = 5:0.5, output = " + loc5); + int index = loc5.indexOf(':'); + String loc5a = loc5.substring(0, index); + Log.i(LOG_TAG, "loc5a = " + loc5a); + assertTrue(loc5a.equals("5")); + String loc5b = loc5.substring(index + 1); + Log.i(LOG_TAG, "loc5b = " + loc5b); + double minutes = Double.parseDouble(loc5b); + Log.i(LOG_TAG, "minutes = " + minutes); + assertTrue(Math.abs(minutes - 0.5) < 0.0001); + + String loc6 = Location.convert(0.1, Location.FORMAT_DEGREES); + Log.i(LOG_TAG, "loc6 = " + loc6); + assertEquals(loc6, "0.1"); + + String loc7 = Location.convert(0.1, Location.FORMAT_MINUTES); + Log.i(LOG_TAG, "loc7 = " + loc7); + assertEquals(loc7, "0:6"); + + String loc8 = Location.convert(0.1, Location.FORMAT_SECONDS); + Log.i(LOG_TAG, "loc8 = " + loc8); + assertEquals(loc8, "0:6:0"); + } +} diff --git a/tests/AndroidTests/src/com/android/unit_tests/LogTest.java b/tests/AndroidTests/src/com/android/unit_tests/LogTest.java new file mode 100644 index 0000000000000000000000000000000000000000..786c4b97c7bb6fe558cf88ef00b1841d0944b5b1 --- /dev/null +++ b/tests/AndroidTests/src/com/android/unit_tests/LogTest.java @@ -0,0 +1,152 @@ +package com.android.unit_tests; + +import junit.framework.Assert; +import junit.framework.TestCase; + +import android.os.SystemProperties; +import android.test.PerformanceTestCase; +import android.test.suitebuilder.annotation.Suppress; +import android.util.Log; + +//This is an empty TestCase. +@Suppress +public class LogTest extends TestCase { + private static final String PROPERTY_TAG = "log.tag.LogTest"; + private static final String LOG_TAG = "LogTest"; + + + // TODO: remove this test once we uncomment out the following test. + public void testLogTestDummy() { + return; + } + + + /* TODO: This test is commented out because we will not be able to set properities. Fix the test. + public void testIsLoggable() { + // First clear any SystemProperty setting for our test key. + SystemProperties.set(PROPERTY_TAG, null); + + String value = SystemProperties.get(PROPERTY_TAG); + Assert.assertTrue(value == null || value.length() == 0); + + // Check to make sure that all levels expect for INFO, WARN, ERROR, and ASSERT are loggable. + Assert.assertFalse(Log.isLoggable(LOG_TAG, Log.VERBOSE)); + Assert.assertFalse(Log.isLoggable(LOG_TAG, Log.DEBUG)); + Assert.assertTrue(Log.isLoggable(LOG_TAG, Log.INFO)); + Assert.assertTrue(Log.isLoggable(LOG_TAG, Log.WARN)); + Assert.assertTrue(Log.isLoggable(LOG_TAG, Log.ERROR)); + Assert.assertTrue(Log.isLoggable(LOG_TAG, Log.ASSERT)); + + // Set the log level to be VERBOSE for this tag. + SystemProperties.set(PROPERTY_TAG, "VERBOSE"); + + // Test to make sure all log levels >= VERBOSE are loggable. + Assert.assertTrue(Log.isLoggable(LOG_TAG, Log.VERBOSE)); + Assert.assertTrue(Log.isLoggable(LOG_TAG, Log.DEBUG)); + Assert.assertTrue(Log.isLoggable(LOG_TAG, Log.INFO)); + Assert.assertTrue(Log.isLoggable(LOG_TAG, Log.WARN)); + Assert.assertTrue(Log.isLoggable(LOG_TAG, Log.ERROR)); + Assert.assertTrue(Log.isLoggable(LOG_TAG, Log.ASSERT)); + + // Set the log level to be DEBUG for this tag. + SystemProperties.set(PROPERTY_TAG, "DEBUG"); + + // Test to make sure all log levels >= DEBUG are loggable. + Assert.assertFalse(Log.isLoggable(LOG_TAG, Log.VERBOSE)); + Assert.assertTrue(Log.isLoggable(LOG_TAG, Log.DEBUG)); + Assert.assertTrue(Log.isLoggable(LOG_TAG, Log.INFO)); + Assert.assertTrue(Log.isLoggable(LOG_TAG, Log.WARN)); + Assert.assertTrue(Log.isLoggable(LOG_TAG, Log.ERROR)); + Assert.assertTrue(Log.isLoggable(LOG_TAG, Log.ASSERT)); + + // Set the log level to be INFO for this tag. + SystemProperties.set(PROPERTY_TAG, "INFO"); + + // Test to make sure all log levels >= INFO are loggable. + Assert.assertFalse(Log.isLoggable(LOG_TAG, Log.VERBOSE)); + Assert.assertFalse(Log.isLoggable(LOG_TAG, Log.DEBUG)); + Assert.assertTrue(Log.isLoggable(LOG_TAG, Log.INFO)); + Assert.assertTrue(Log.isLoggable(LOG_TAG, Log.WARN)); + Assert.assertTrue(Log.isLoggable(LOG_TAG, Log.ERROR)); + Assert.assertTrue(Log.isLoggable(LOG_TAG, Log.ASSERT)); + + // Set the log level to be WARN for this tag. + SystemProperties.set(PROPERTY_TAG, "WARN"); + + // Test to make sure all log levels >= WARN are loggable. + Assert.assertFalse(Log.isLoggable(LOG_TAG, Log.VERBOSE)); + Assert.assertFalse(Log.isLoggable(LOG_TAG, Log.DEBUG)); + Assert.assertFalse(Log.isLoggable(LOG_TAG, Log.INFO)); + Assert.assertTrue(Log.isLoggable(LOG_TAG, Log.WARN)); + Assert.assertTrue(Log.isLoggable(LOG_TAG, Log.ERROR)); + Assert.assertTrue(Log.isLoggable(LOG_TAG, Log.ASSERT)); + + // Set the log level to be ERROR for this tag. + SystemProperties.set(PROPERTY_TAG, "ERROR"); + + // Test to make sure all log levels >= ERROR are loggable. + Assert.assertFalse(Log.isLoggable(LOG_TAG, Log.VERBOSE)); + Assert.assertFalse(Log.isLoggable(LOG_TAG, Log.DEBUG)); + Assert.assertFalse(Log.isLoggable(LOG_TAG, Log.INFO)); + Assert.assertFalse(Log.isLoggable(LOG_TAG, Log.WARN)); + Assert.assertTrue(Log.isLoggable(LOG_TAG, Log.ERROR)); + Assert.assertTrue(Log.isLoggable(LOG_TAG, Log.ASSERT)); + + // Set the log level to be ASSERT for this tag. + SystemProperties.set(PROPERTY_TAG, "ASSERT"); + + // Test to make sure all log levels >= ASSERT are loggable. + Assert.assertFalse(Log.isLoggable(LOG_TAG, Log.VERBOSE)); + Assert.assertFalse(Log.isLoggable(LOG_TAG, Log.DEBUG)); + Assert.assertFalse(Log.isLoggable(LOG_TAG, Log.INFO)); + Assert.assertFalse(Log.isLoggable(LOG_TAG, Log.WARN)); + Assert.assertFalse(Log.isLoggable(LOG_TAG, Log.ERROR)); + Assert.assertTrue(Log.isLoggable(LOG_TAG, Log.ASSERT)); + + // Set the log level to be SUPPRESS for this tag. + SystemProperties.set(PROPERTY_TAG, "SUPPRESS"); + + // Test to make sure all log levels >= ASSERT are loggable. + Assert.assertFalse(Log.isLoggable(LOG_TAG, Log.VERBOSE)); + Assert.assertFalse(Log.isLoggable(LOG_TAG, Log.DEBUG)); + Assert.assertFalse(Log.isLoggable(LOG_TAG, Log.INFO)); + Assert.assertFalse(Log.isLoggable(LOG_TAG, Log.WARN)); + Assert.assertFalse(Log.isLoggable(LOG_TAG, Log.ERROR)); + Assert.assertFalse(Log.isLoggable(LOG_TAG, Log.ASSERT)); + } + */ + + public static class PerformanceTest extends TestCase implements PerformanceTestCase { + private static final int ITERATIONS = 1000; + + @Override + public void setUp() { + SystemProperties.set(LOG_TAG, "VERBOSE"); + } + + public boolean isPerformanceOnly() { + return true; + } + + public int startPerformance(PerformanceTestCase.Intermediates intermediates) { + intermediates.setInternalIterations(ITERATIONS * 10); + return 0; + } + + public void testIsLoggable() { + boolean canLog = false; + for (int i = ITERATIONS - 1; i >= 0; i--) { + canLog = Log.isLoggable(LOG_TAG, Log.VERBOSE); + canLog = Log.isLoggable(LOG_TAG, Log.VERBOSE); + canLog = Log.isLoggable(LOG_TAG, Log.VERBOSE); + canLog = Log.isLoggable(LOG_TAG, Log.VERBOSE); + canLog = Log.isLoggable(LOG_TAG, Log.VERBOSE); + canLog = Log.isLoggable(LOG_TAG, Log.VERBOSE); + canLog = Log.isLoggable(LOG_TAG, Log.VERBOSE); + canLog = Log.isLoggable(LOG_TAG, Log.VERBOSE); + canLog = Log.isLoggable(LOG_TAG, Log.VERBOSE); + canLog = Log.isLoggable(LOG_TAG, Log.VERBOSE); + } + } + } +} diff --git a/tests/AndroidTests/src/com/android/unit_tests/MathTest.java b/tests/AndroidTests/src/com/android/unit_tests/MathTest.java new file mode 100644 index 0000000000000000000000000000000000000000..caf2d209bc18d5cfabcb7a8ab9b8377259873e48 --- /dev/null +++ b/tests/AndroidTests/src/com/android/unit_tests/MathTest.java @@ -0,0 +1,380 @@ +/* + * Copyright (C) 2007 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.android.unit_tests; + +import android.test.PerformanceTestBase; +import android.test.PerformanceTestCase; + +/** + * + * Implements basic performance test functionality for java.lang.Math + * + */ + +public class MathTest extends PerformanceTestBase { + public static final int ITERATIONS = 1000; + public static final double sDouble1 = -2450.50; + public static final double sDouble2 = -500; + public static final float sFloat = 300.50f; + public static final int sInt = 90; + + @Override + public int startPerformance(PerformanceTestCase.Intermediates intermediates) { + intermediates.setInternalIterations(ITERATIONS); + return 0; + } + + public void testDoubleAbs() { + double result; + for (int i = ITERATIONS - 1; i >= 0; i--) { + result = Math.abs(sDouble1); + result = Math.abs(sDouble1); + result = Math.abs(sDouble1); + result = Math.abs(sDouble1); + result = Math.abs(sDouble1); + result = Math.abs(sDouble1); + result = Math.abs(sDouble1); + result = Math.abs(sDouble1); + result = Math.abs(sDouble1); + result = Math.abs(sDouble1); + } + } + + public void testFloatAbs() { + float result; + for (int i = ITERATIONS - 1; i >= 0; i--) { + result = Math.abs(sFloat); + result = Math.abs(sFloat); + result = Math.abs(sFloat); + result = Math.abs(sFloat); + result = Math.abs(sFloat); + result = Math.abs(sFloat); + result = Math.abs(sFloat); + result = Math.abs(sFloat); + result = Math.abs(sFloat); + result = Math.abs(sFloat); + } + } + + public void testMathSin() { + double result; + for (int i = ITERATIONS - 1; i >= 0; i--) { + result = Math.sin(sDouble1); + result = Math.sin(sDouble1); + result = Math.sin(sDouble1); + result = Math.sin(sDouble1); + result = Math.sin(sDouble1); + result = Math.sin(sDouble1); + result = Math.sin(sDouble1); + result = Math.sin(sDouble1); + result = Math.sin(sDouble1); + result = Math.sin(sDouble1); + } + } + + public void testMathCos() { + double result; + for (int i = ITERATIONS - 1; i >= 0; i--) { + result = Math.cos(sDouble1); + result = Math.cos(sDouble1); + result = Math.cos(sDouble1); + result = Math.cos(sDouble1); + result = Math.cos(sDouble1); + result = Math.cos(sDouble1); + result = Math.cos(sDouble1); + result = Math.cos(sDouble1); + result = Math.cos(sDouble1); + result = Math.cos(sDouble1); + } + } + + public void testMathTan() { + double result; + for (int i = ITERATIONS - 1; i >= 0; i--) { + result = Math.tan(sDouble1); + result = Math.tan(sDouble1); + result = Math.tan(sDouble1); + result = Math.tan(sDouble1); + result = Math.tan(sDouble1); + result = Math.tan(sDouble1); + result = Math.tan(sDouble1); + result = Math.tan(sDouble1); + result = Math.tan(sDouble1); + result = Math.tan(sDouble1); + } + } + + public void testMathASin() { + double result; + for (int i = ITERATIONS - 1; i >= 0; i--) { + result = Math.asin(sDouble1); + result = Math.asin(sDouble1); + result = Math.asin(sDouble1); + result = Math.asin(sDouble1); + result = Math.asin(sDouble1); + result = Math.asin(sDouble1); + result = Math.asin(sDouble1); + result = Math.asin(sDouble1); + result = Math.asin(sDouble1); + result = Math.asin(sDouble1); + } + } + + public void testMathACos() { + double result; + for (int i = ITERATIONS - 1; i >= 0; i--) { + result = Math.acos(sDouble1); + result = Math.acos(sDouble1); + result = Math.acos(sDouble1); + result = Math.acos(sDouble1); + result = Math.acos(sDouble1); + result = Math.acos(sDouble1); + result = Math.acos(sDouble1); + result = Math.acos(sDouble1); + result = Math.acos(sDouble1); + result = Math.acos(sDouble1); + } + } + + public void testMathATan() { + double result; + for (int i = ITERATIONS - 1; i >= 0; i--) { + result = Math.atan(sDouble1); + result = Math.atan(sDouble1); + result = Math.atan(sDouble1); + result = Math.atan(sDouble1); + result = Math.atan(sDouble1); + result = Math.atan(sDouble1); + result = Math.atan(sDouble1); + result = Math.atan(sDouble1); + result = Math.atan(sDouble1); + result = Math.atan(sDouble1); + } + } + + public void testMathLog() { + double result; + for (int i = ITERATIONS - 1; i >= 0; i--) { + result = Math.log(sDouble1); + result = Math.log(sDouble1); + result = Math.log(sDouble1); + result = Math.log(sDouble1); + result = Math.log(sDouble1); + result = Math.log(sDouble1); + result = Math.log(sDouble1); + result = Math.log(sDouble1); + result = Math.log(sDouble1); + result = Math.log(sDouble1); + } + } + + public void testMathSqrt() { + double result; + for (int i = ITERATIONS - 1; i >= 0; i--) { + result = Math.sqrt(sDouble1); + result = Math.sqrt(sDouble1); + result = Math.sqrt(sDouble1); + result = Math.sqrt(sDouble1); + result = Math.sqrt(sDouble1); + result = Math.sqrt(sDouble1); + result = Math.sqrt(sDouble1); + result = Math.sqrt(sDouble1); + result = Math.sqrt(sDouble1); + result = Math.sqrt(sDouble1); + } + } + + public void testMathCeil() { + double result; + for (int i = ITERATIONS - 1; i >= 0; i--) { + result = Math.ceil(sDouble1); + result = Math.ceil(sDouble1); + result = Math.ceil(sDouble1); + result = Math.ceil(sDouble1); + result = Math.ceil(sDouble1); + result = Math.ceil(sDouble1); + result = Math.ceil(sDouble1); + result = Math.ceil(sDouble1); + result = Math.ceil(sDouble1); + result = Math.ceil(sDouble1); + } + } + + public void testMathRound() { + double result; + for (int i = ITERATIONS - 1; i >= 0; i--) { + result = Math.round(sDouble1); + result = Math.round(sDouble1); + result = Math.round(sDouble1); + result = Math.round(sDouble1); + result = Math.round(sDouble1); + result = Math.round(sDouble1); + result = Math.round(sDouble1); + result = Math.round(sDouble1); + result = Math.round(sDouble1); + result = Math.round(sDouble1); + } + } + + public void testMathFloor() { + double result; + for (int i = ITERATIONS - 1; i >= 0; i--) { + result = Math.floor(sDouble1); + result = Math.floor(sDouble1); + result = Math.floor(sDouble1); + result = Math.floor(sDouble1); + result = Math.floor(sDouble1); + result = Math.floor(sDouble1); + result = Math.floor(sDouble1); + result = Math.floor(sDouble1); + result = Math.floor(sDouble1); + result = Math.floor(sDouble1); + } + } + + public void testMathExp() { + double result; + for (int i = ITERATIONS - 1; i >= 0; i--) { + result = Math.exp(sDouble1); + result = Math.exp(sDouble1); + result = Math.exp(sDouble1); + result = Math.exp(sDouble1); + result = Math.exp(sDouble1); + result = Math.exp(sDouble1); + result = Math.exp(sDouble1); + result = Math.exp(sDouble1); + result = Math.exp(sDouble1); + result = Math.exp(sDouble1); + } + } + + /** + * + */ + + public void testMathPow() { + double result; + for (int i = ITERATIONS - 1; i >= 0; i--) { + result = Math.pow(sDouble1, sDouble2); + result = Math.pow(sDouble1, sDouble2); + result = Math.pow(sDouble1, sDouble2); + result = Math.pow(sDouble1, sDouble2); + result = Math.pow(sDouble1, sDouble2); + result = Math.pow(sDouble1, sDouble2); + result = Math.pow(sDouble1, sDouble2); + result = Math.pow(sDouble1, sDouble2); + result = Math.pow(sDouble1, sDouble2); + result = Math.pow(sDouble1, sDouble2); + } + } + + public void testMathMax() { + double result; + for (int i = ITERATIONS - 1; i >= 0; i--) { + result = Math.max(sDouble1, sDouble2); + result = Math.max(sDouble1, sDouble2); + result = Math.max(sDouble1, sDouble2); + result = Math.max(sDouble1, sDouble2); + result = Math.max(sDouble1, sDouble2); + result = Math.max(sDouble1, sDouble2); + result = Math.max(sDouble1, sDouble2); + result = Math.max(sDouble1, sDouble2); + result = Math.max(sDouble1, sDouble2); + result = Math.max(sDouble1, sDouble2); + } + } + + public void testMathMin() { + double result; + for (int i = ITERATIONS - 1; i >= 0; i--) { + result = Math.min(sDouble1, sDouble2); + result = Math.min(sDouble1, sDouble2); + result = Math.min(sDouble1, sDouble2); + result = Math.min(sDouble1, sDouble2); + result = Math.min(sDouble1, sDouble2); + result = Math.min(sDouble1, sDouble2); + result = Math.min(sDouble1, sDouble2); + result = Math.min(sDouble1, sDouble2); + result = Math.min(sDouble1, sDouble2); + result = Math.min(sDouble1, sDouble2); + } + } + + public void testMathRandom() { + double result; + for (int i = ITERATIONS - 1; i >= 0; i--) { + result = Math.random(); + result = Math.random(); + result = Math.random(); + result = Math.random(); + result = Math.random(); + result = Math.random(); + result = Math.random(); + result = Math.random(); + result = Math.random(); + result = Math.random(); + } + } + + public void testMathIEEERemainder() { + double result; + for (int i = ITERATIONS - 1; i >= 0; i--) { + result = Math.IEEEremainder(sDouble1, sDouble2); + result = Math.IEEEremainder(sDouble1, sDouble2); + result = Math.IEEEremainder(sDouble1, sDouble2); + result = Math.IEEEremainder(sDouble1, sDouble2); + result = Math.IEEEremainder(sDouble1, sDouble2); + result = Math.IEEEremainder(sDouble1, sDouble2); + result = Math.IEEEremainder(sDouble1, sDouble2); + result = Math.IEEEremainder(sDouble1, sDouble2); + result = Math.IEEEremainder(sDouble1, sDouble2); + result = Math.IEEEremainder(sDouble1, sDouble2); + } + } + + public void testMathToDegrees() { + double result; + for (int i = ITERATIONS - 1; i >= 0; i--) { + result = Math.toDegrees(sDouble1); + result = Math.toDegrees(sDouble1); + result = Math.toDegrees(sDouble1); + result = Math.toDegrees(sDouble1); + result = Math.toDegrees(sDouble1); + result = Math.toDegrees(sDouble1); + result = Math.toDegrees(sDouble1); + result = Math.toDegrees(sDouble1); + result = Math.toDegrees(sDouble1); + result = Math.toDegrees(sDouble1); + } + } + + public void testMathToRadians() { + double result; + for (int i = ITERATIONS - 1; i >= 0; i--) { + result = Math.toRadians(sDouble1); + result = Math.toRadians(sDouble1); + result = Math.toRadians(sDouble1); + result = Math.toRadians(sDouble1); + result = Math.toRadians(sDouble1); + result = Math.toRadians(sDouble1); + result = Math.toRadians(sDouble1); + result = Math.toRadians(sDouble1); + result = Math.toRadians(sDouble1); + result = Math.toRadians(sDouble1); + } + } +} diff --git a/tests/AndroidTests/src/com/android/unit_tests/MenuTest.java b/tests/AndroidTests/src/com/android/unit_tests/MenuTest.java new file mode 100644 index 0000000000000000000000000000000000000000..d184543dfb2598d796b7d63fbb7d44353c7b606b --- /dev/null +++ b/tests/AndroidTests/src/com/android/unit_tests/MenuTest.java @@ -0,0 +1,290 @@ +/* + * Copyright (C) 2006 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.android.unit_tests; + +import com.android.internal.view.menu.MenuBuilder; + +import junit.framework.Assert; + +import android.test.AndroidTestCase; +import android.test.MoreAsserts; +import android.test.suitebuilder.annotation.LargeTest; +import android.test.suitebuilder.annotation.SmallTest; +import android.view.KeyEvent; +import android.view.Menu; +import android.view.MenuItem; +import android.view.SubMenu; + +public class MenuTest extends AndroidTestCase { + + private MenuBuilder mMenu; + + public void setUp() throws Exception { + super.setUp(); + mMenu = new MenuBuilder(super.getContext()); + } + + @SmallTest + public void testItemId() { + final int id = 512; + final MenuItem item = mMenu.add(0, id, 0, "test"); + + Assert.assertEquals(id, item.getItemId()); + Assert.assertEquals(item, mMenu.findItem(id)); + Assert.assertEquals(0, mMenu.findItemIndex(id)); + } + + @SmallTest + public void testGroupId() { + final int groupId = 541; + final int item1Index = 1; + final int item2Index = 3; + + mMenu.add(0, 0, item1Index - 1, "ignore"); + final MenuItem item = mMenu.add(groupId, 0, item1Index, "test"); + mMenu.add(0, 0, item2Index - 1, "ignore"); + final MenuItem item2 = mMenu.add(groupId, 0, item2Index, "test2"); + + Assert.assertEquals(groupId, item.getGroupId()); + Assert.assertEquals(groupId, item2.getGroupId()); + Assert.assertEquals(item1Index, mMenu.findGroupIndex(groupId)); + Assert.assertEquals(item2Index, mMenu.findGroupIndex(groupId, item1Index + 1)); + } + + @SmallTest + public void testGroup() { + // This test does the following + // 1. Create a grouped item in the menu + // 2. Check that findGroupIndex() finds the grouped item. + // 3. Check that findGroupIndex() doesn't find a non-existent group. + + final int GROUP_ONE = Menu.FIRST; + final int GROUP_TWO = Menu.FIRST + 1; + + mMenu.add(GROUP_ONE, 0, 0, "Menu text"); + Assert.assertEquals(mMenu.findGroupIndex(GROUP_ONE), 0); + Assert.assertEquals(mMenu.findGroupIndex(GROUP_TWO), -1); + //TODO: expand this test case to do multiple groups, + //adding and removing, hiding and showing, etc. + } + + @SmallTest + public void testIsShortcutWithAlpha() throws Exception { + mMenu.setQwertyMode(true); + mMenu.add(0, 0, 0, "test").setShortcut('2', 'a'); + Assert.assertTrue(mMenu.isShortcutKey(KeyEvent.KEYCODE_A, + makeKeyEvent(KeyEvent.KEYCODE_A, 0))); + Assert.assertFalse(mMenu.isShortcutKey(KeyEvent.KEYCODE_B, + makeKeyEvent(KeyEvent.KEYCODE_B, 0))); + } + + @SmallTest + public void testIsShortcutWithNumeric() throws Exception { + mMenu.setQwertyMode(false); + mMenu.add(0, 0, 0, "test").setShortcut('2', 'a'); + Assert.assertTrue(mMenu.isShortcutKey(KeyEvent.KEYCODE_2, + makeKeyEvent(KeyEvent.KEYCODE_2, 0))); + Assert.assertFalse(mMenu.isShortcutKey(KeyEvent.KEYCODE_A, + makeKeyEvent(KeyEvent.KEYCODE_A, 0))); + } + + @SmallTest + public void testIsShortcutWithAlt() throws Exception { + mMenu.setQwertyMode(true); + mMenu.add(0, 0, 0, "test").setShortcut('2', 'a'); + Assert.assertTrue(mMenu.isShortcutKey(KeyEvent.KEYCODE_A, + makeKeyEvent(KeyEvent.KEYCODE_A, + KeyEvent.META_ALT_ON))); + Assert.assertFalse(mMenu.isShortcutKey(KeyEvent.KEYCODE_A, + makeKeyEvent(KeyEvent.KEYCODE_A, + KeyEvent.META_SYM_ON))); + } + + @SmallTest + public void testIsNotShortcutWithShift() throws Exception { + mMenu.setQwertyMode(true); + mMenu.add(0, 0, 0, "test").setShortcut('2', 'a'); + Assert.assertFalse(mMenu.isShortcutKey(KeyEvent.KEYCODE_A, + makeKeyEvent(KeyEvent.KEYCODE_A, + KeyEvent.META_SHIFT_ON))); + } + + @SmallTest + public void testIsNotShortcutWithSym() throws Exception { + mMenu.setQwertyMode(true); + mMenu.add(0, 0, 0, "test").setShortcut('2', 'a'); + Assert.assertFalse(mMenu.isShortcutKey(KeyEvent.KEYCODE_A, + makeKeyEvent(KeyEvent.KEYCODE_A, + KeyEvent.META_SYM_ON))); + } + + @LargeTest + public void testIsNotShortcutWithMultipleMetas() throws Exception { + mMenu.setQwertyMode(true); + mMenu.add(0, 0, 0, "test").setShortcut('2', 'a'); + Assert.assertFalse(mMenu.isShortcutKey( + 'a', + makeKeyEvent(KeyEvent.KEYCODE_A, KeyEvent.META_SYM_ON & KeyEvent.META_ALT_ON))); + Assert.assertFalse(mMenu.isShortcutKey( + 'a', makeKeyEvent(KeyEvent.KEYCODE_A, KeyEvent.META_SYM_ON))); + Assert.assertFalse(mMenu.isShortcutKey( + 'a', makeKeyEvent(KeyEvent.KEYCODE_A, KeyEvent.META_SHIFT_ON))); + } + + @SmallTest + public void testIsShortcutWithUpperCaseAlpha() throws Exception { + mMenu.setQwertyMode(true); + mMenu.add(0, 0, 0, "test").setShortcut('2', 'A'); + Assert.assertTrue(mMenu.isShortcutKey(KeyEvent.KEYCODE_A, + makeKeyEvent(KeyEvent.KEYCODE_A, 0))); + } + + @SmallTest + public void testIsShortcutWithBackspace() throws Exception { + mMenu.setQwertyMode(true); + mMenu.add(0, 0, 0, "test").setShortcut('2', '\b'); + Assert.assertTrue(mMenu.isShortcutKey(KeyEvent.KEYCODE_DEL, + makeKeyEvent(KeyEvent.KEYCODE_DEL, 0))); + } + + @SmallTest + public void testIsShortcutWithNewline() throws Exception { + mMenu.setQwertyMode(true); + mMenu.add(0, 0, 0, "test").setShortcut('2', '\n'); + Assert.assertTrue(mMenu.isShortcutKey(KeyEvent.KEYCODE_ENTER, + makeKeyEvent(KeyEvent.KEYCODE_ENTER, 0))); + } + + @SmallTest + public void testOrder() { + final String a = "a", b = "b", c = "c"; + final int firstOrder = 7, midOrder = 8, lastOrder = 9; + + mMenu.add(0, 0, lastOrder, c); + mMenu.add(0, 0, firstOrder, a); + mMenu.add(0, 0, midOrder, b); + + Assert.assertEquals(firstOrder, mMenu.getItem(0).getOrder()); + Assert.assertEquals(a, mMenu.getItem(0).getTitle()); + Assert.assertEquals(midOrder, mMenu.getItem(1).getOrder()); + Assert.assertEquals(b, mMenu.getItem(1).getTitle()); + Assert.assertEquals(lastOrder, mMenu.getItem(2).getOrder()); + Assert.assertEquals(c, mMenu.getItem(2).getTitle()); + } + + @SmallTest + public void testTitle() { + final String title = "test"; + final MenuItem stringItem = mMenu.add(title); + final MenuItem resItem = mMenu.add(R.string.menu_test); + + Assert.assertEquals(title, stringItem.getTitle()); + Assert.assertEquals(getContext().getResources().getString(R.string.menu_test), resItem + .getTitle()); + } + + @SmallTest + public void testCheckable() { + final int groupId = 1; + final MenuItem item1 = mMenu.add(groupId, 1, 0, "item1"); + final MenuItem item2 = mMenu.add(groupId, 2, 0, "item2"); + + // Set to exclusive + mMenu.setGroupCheckable(groupId, true, true); + Assert.assertTrue("Item was not set to checkable", item1.isCheckable()); + item1.setChecked(true); + Assert.assertTrue("Item did not get checked", item1.isChecked()); + Assert.assertFalse("Item was not unchecked due to exclusive checkable", item2.isChecked()); + mMenu.findItem(2).setChecked(true); + Assert.assertTrue("Item did not get checked", item2.isChecked()); + Assert.assertFalse("Item was not unchecked due to exclusive checkable", item1.isChecked()); + + // Multiple non-exlusive checkable items + mMenu.setGroupCheckable(groupId, true, false); + Assert.assertTrue("Item was not set to checkable", item1.isCheckable()); + item1.setChecked(false); + Assert.assertFalse("Item did not get unchecked", item1.isChecked()); + item1.setChecked(true); + Assert.assertTrue("Item did not get checked", item1.isChecked()); + mMenu.findItem(2).setChecked(true); + Assert.assertTrue("Item did not get checked", item2.isChecked()); + Assert.assertTrue("Item was unchecked when it shouldnt have been", item1.isChecked()); + } + + @SmallTest + public void testVisibility() { + final MenuItem item1 = mMenu.add(0, 1, 0, "item1"); + final MenuItem item2 = mMenu.add(0, 2, 0, "item2"); + + // Should start as visible + Assert.assertTrue("Item did not start as visible", item1.isVisible()); + Assert.assertTrue("Item did not start as visible", item2.isVisible()); + + // Hide + item1.setVisible(false); + Assert.assertFalse("Item did not become invisible", item1.isVisible()); + mMenu.findItem(2).setVisible(false); + Assert.assertFalse("Item did not become invisible", item2.isVisible()); + } + + @SmallTest + public void testSubMenu() { + final SubMenu subMenu = mMenu.addSubMenu(0, 0, 0, "submenu"); + final MenuItem subMenuItem = subMenu.getItem(); + final MenuItem item1 = subMenu.add(0, 1, 0, "item1"); + final MenuItem item2 = subMenu.add(0, 2, 0, "item2"); + + // findItem should recurse into submenus + Assert.assertEquals(item1, mMenu.findItem(1)); + Assert.assertEquals(item2, mMenu.findItem(2)); + } + + @SmallTest + public void testRemove() { + final int groupId = 1; + final MenuItem item1 = mMenu.add(groupId, 1, 0, "item1"); + final MenuItem item2 = mMenu.add(groupId, 2, 0, "item2"); + final MenuItem item3 = mMenu.add(groupId, 3, 0, "item3"); + final MenuItem item4 = mMenu.add(groupId, 4, 0, "item4"); + final MenuItem item5 = mMenu.add(groupId, 5, 0, "item5"); + final MenuItem item6 = mMenu.add(0, 6, 0, "item6"); + + Assert.assertEquals(item1, mMenu.findItem(1)); + mMenu.removeItemAt(0); + Assert.assertNull(mMenu.findItem(1)); + + Assert.assertEquals(item2, mMenu.findItem(2)); + mMenu.removeItem(2); + Assert.assertNull(mMenu.findItem(2)); + + Assert.assertEquals(item3, mMenu.findItem(3)); + Assert.assertEquals(item4, mMenu.findItem(4)); + Assert.assertEquals(item5, mMenu.findItem(5)); + mMenu.removeGroup(groupId); + Assert.assertNull(mMenu.findItem(3)); + Assert.assertNull(mMenu.findItem(4)); + Assert.assertNull(mMenu.findItem(5)); + + Assert.assertEquals(item6, mMenu.findItem(6)); + mMenu.clear(); + Assert.assertNull(mMenu.findItem(6)); + } + + private KeyEvent makeKeyEvent(int keyCode, int metaState) { + return new KeyEvent(0L, 0L, KeyEvent.ACTION_DOWN, keyCode, 0, metaState); + } +} diff --git a/tests/AndroidTests/src/com/android/unit_tests/MonitorTest.java b/tests/AndroidTests/src/com/android/unit_tests/MonitorTest.java new file mode 100644 index 0000000000000000000000000000000000000000..2f3df10828aba0721c31434716611e659b20e6ee --- /dev/null +++ b/tests/AndroidTests/src/com/android/unit_tests/MonitorTest.java @@ -0,0 +1,469 @@ +/* + * Copyright (C) 2007 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.android.unit_tests; + +import junit.framework.TestCase; +import android.test.suitebuilder.annotation.MediumTest; +import android.test.suitebuilder.annotation.LargeTest; +import android.test.suitebuilder.annotation.SmallTest; + +public class MonitorTest extends TestCase { + + @MediumTest + public void testWaitArgumentsTest() throws Exception { + /* Try some valid arguments. These should all + * return very quickly. + */ + try { + synchronized (this) { + /* millisecond version */ + wait(1); + wait(10); + + /* millisecond + nanosecond version */ + wait(0, 1); + wait(0, 999999); + wait(1, 1); + wait(1, 999999); + } + } catch (InterruptedException ex) { + throw new RuntimeException("good Object.wait() interrupted", + ex); + } catch (Exception ex) { + throw new RuntimeException("Unexpected exception when calling" + + "Object.wait() with good arguments", ex); + } + + /* Try some invalid arguments. + */ + boolean sawException = false; + try { + synchronized (this) { + wait(-1); + } + } catch (InterruptedException ex) { + throw new RuntimeException("bad Object.wait() interrupted", ex); + } catch (IllegalArgumentException ex) { + sawException = true; + } catch (Exception ex) { + throw new RuntimeException("Unexpected exception when calling" + + "Object.wait() with bad arguments", ex); + } + if (!sawException) { + throw new RuntimeException("bad call to Object.wait() should " + + "have thrown IllegalArgumentException"); + } + + sawException = false; + try { + synchronized (this) { + wait(0, -1); + } + } catch (InterruptedException ex) { + throw new RuntimeException("bad Object.wait() interrupted", ex); + } catch (IllegalArgumentException ex) { + sawException = true; + } catch (Exception ex) { + throw new RuntimeException("Unexpected exception when calling" + + "Object.wait() with bad arguments", ex); + } + if (!sawException) { + throw new RuntimeException("bad call to Object.wait() should " + + "have thrown IllegalArgumentException"); + } + + sawException = false; + try { + synchronized (this) { + /* The legal range of nanos is 0-999999. */ + wait(0, 1000000); + } + } catch (InterruptedException ex) { + throw new RuntimeException("bad Object.wait() interrupted", ex); + } catch (IllegalArgumentException ex) { + sawException = true; + } catch (Exception ex) { + throw new RuntimeException("Unexpected exception when calling" + + "Object.wait() with bad arguments", ex); + } + if (!sawException) { + throw new RuntimeException("bad call to Object.wait() should " + + "have thrown IllegalArgumentException"); + } + } + + private class Interrupter extends Thread { + Waiter waiter; + + Interrupter(String name, Waiter waiter) { + super(name); + this.waiter = waiter; + } + + public void run() { + try { + run_inner(); + } catch (Throwable t) { + MonitorTest.errorException = t; + MonitorTest.testThread.interrupt(); + } + } + + void run_inner() { + waiter.spin = true; + // System.out.println("InterruptTest: starting waiter"); + waiter.start(); + + try { + Thread.currentThread().sleep(500); + } catch (InterruptedException ex) { + throw new RuntimeException("Test sleep interrupted.", ex); + } + + /* Waiter is spinning, and its monitor should still be thin. + */ + // System.out.println("Test interrupting waiter"); + waiter.interrupt(); + waiter.spin = false; + + for (int i = 0; i < 3; i++) { + /* Wait for the waiter to start waiting. + */ + synchronized (waiter.interrupterLock) { + try { + waiter.interrupterLock.wait(); + } catch (InterruptedException ex) { + throw new RuntimeException("Test wait interrupted.", ex); + } + } + + /* Before interrupting, grab the waiter lock, which + * guarantees that the waiter is already sitting in wait(). + */ + synchronized (waiter) { + //System.out.println("Test interrupting waiter (" + i + ")"); + waiter.interrupt(); + } + } + + // System.out.println("Test waiting for waiter to die."); + try { + waiter.join(); + } catch (InterruptedException ex) { + throw new RuntimeException("Test join interrupted.", ex); + } + // System.out.println("InterruptTest done."); + } + } + + private class Waiter extends Thread { + Object interrupterLock = new Object(); + Boolean spin = false; + + Waiter(String name) { + super(name); + } + + public void run() { + try { + run_inner(); + } catch (Throwable t) { + MonitorTest.errorException = t; + MonitorTest.testThread.interrupt(); + } + } + + void run_inner() { + // System.out.println("Waiter spinning"); + while (spin) { + // We're going to get interrupted while we spin. + } + if (interrupted()) { + // System.out.println("Waiter done spinning; interrupted."); + } else { + throw new RuntimeException("Thread not interrupted " + + "during spin"); + } + + synchronized (this) { + Boolean sawEx = false; + + try { + synchronized (interrupterLock) { + interrupterLock.notify(); + } + // System.out.println("Waiter calling wait()"); + this.wait(); + } catch (InterruptedException ex) { + sawEx = true; + // System.out.println("wait(): Waiter caught " + ex); + } + // System.out.println("wait() finished"); + + if (!sawEx) { + throw new RuntimeException("Thread not interrupted " + + "during wait()"); + } + } + synchronized (this) { + Boolean sawEx = false; + + try { + synchronized (interrupterLock) { + interrupterLock.notify(); + } + // System.out.println("Waiter calling wait(1000)"); + this.wait(1000); + } catch (InterruptedException ex) { + sawEx = true; + // System.out.println("wait(1000): Waiter caught " + ex); + } + // System.out.println("wait(1000) finished"); + + if (!sawEx) { + throw new RuntimeException("Thread not interrupted " + + "during wait(1000)"); + } + } + synchronized (this) { + Boolean sawEx = false; + + try { + synchronized (interrupterLock) { + interrupterLock.notify(); + } + // System.out.println("Waiter calling wait(1000, 5000)"); + this.wait(1000, 5000); + } catch (InterruptedException ex) { + sawEx = true; + // System.out.println("wait(1000, 5000): Waiter caught " + ex); + } + // System.out.println("wait(1000, 5000) finished"); + + if (!sawEx) { + throw new RuntimeException("Thread not interrupted " + + "during wait(1000, 5000)"); + } + } + + // System.out.println("Waiter returning"); + } + } + + private static Throwable errorException; + private static Thread testThread; + + @MediumTest + public void testInterruptTest() throws Exception { + + + testThread = Thread.currentThread(); + errorException = null; + + Waiter waiter = new Waiter("InterruptTest Waiter"); + Interrupter interrupter = + new Interrupter("InterruptTest Interrupter", waiter); + interrupter.start(); + + try { + interrupter.join(); + waiter.join(); + } catch (InterruptedException ex) { + throw new RuntimeException("Test join interrupted.", ex); + } + + if (errorException != null) { + throw new RuntimeException("InterruptTest failed", + errorException); + } + + + + + } + + private static void deepWait(int depth, Object lock) { + synchronized (lock) { + if (depth > 0) { + deepWait(depth - 1, lock); + } else { + String threadName = Thread.currentThread().getName(); + try { + // System.out.println(threadName + " waiting"); + lock.wait(); + // System.out.println(threadName + " done waiting"); + } catch (InterruptedException ex) { + // System.out.println(threadName + " interrupted."); + } + } + } + } + + private class Worker extends Thread { + Object lock; + int id; + + Worker(int id, Object lock) { + super("Worker(" + id + ")"); + this.id = id; + this.lock = lock; + } + + public void run() { + int iterations = 0; + + while (MonitorTest.running) { + MonitorTest.deepWait(id, lock); + iterations++; + } + // System.out.println(getName() + " done after " + iterations + " iterations."); + } + } + + private static Object commonLock = new Object(); + private static Boolean running = false; + + + @LargeTest + public void testNestedMonitors() throws Exception { + final int NUM_WORKERS = 5; + + Worker w[] = new Worker[NUM_WORKERS]; + int i; + + for (i = 0; i < NUM_WORKERS; i++) { + w[i] = new Worker(i * 2 - 1, new Object()); + } + + running = true; + + // System.out.println("NestedMonitors: starting workers"); + for (i = 0; i < NUM_WORKERS; i++) { + w[i].start(); + } + + try { + Thread.currentThread().sleep(1000); + } catch (InterruptedException ex) { + // System.out.println("Test sleep interrupted."); + } + + for (i = 0; i < 100; i++) { + for (int j = 0; j < NUM_WORKERS; j++) { + synchronized (w[j].lock) { + w[j].lock.notify(); + } + } + } + + // System.out.println("NesterMonitors: stopping workers"); + running = false; + for (i = 0; i < NUM_WORKERS; i++) { + synchronized (w[i].lock) { + w[i].lock.notifyAll(); + } + } + } + + private static class CompareAndExchange extends Thread { + static Object toggleLock = null; + static int toggle = -1; + static Boolean running = false; + + public void run() { + toggleLock = new Object(); + toggle = -1; + + Worker w1 = new Worker(0, 1); + Worker w2 = new Worker(2, 3); + Worker w3 = new Worker(4, 5); + Worker w4 = new Worker(6, 7); + + running = true; + + // System.out.println("CompareAndExchange: starting workers"); + + w1.start(); + w2.start(); + w3.start(); + w4.start(); + + try { + this.sleep(10000); + } catch (InterruptedException ex) { + // System.out.println(getName() + " interrupted."); + } + + // System.out.println("MonitorTest: stopping workers"); + running = false; + + toggleLock = null; + } + + class Worker extends Thread { + int i1; + int i2; + + Worker(int i1, int i2) { + super("Worker(" + i1 + ", " + i2 + ")"); + this.i1 = i1; + this.i2 = i2; + } + + public void run() { + int iterations = 0; + + /* Latch this because run() may set the static field to + * null at some point. + */ + Object toggleLock = CompareAndExchange.toggleLock; + + // System.out.println(getName() + " running"); + try { + while (CompareAndExchange.running) { + synchronized (toggleLock) { + int test; + int check; + + if (CompareAndExchange.toggle == i1) { + this.sleep(5 + i2); + CompareAndExchange.toggle = test = i2; + } else { + this.sleep(5 + i1); + CompareAndExchange.toggle = test = i1; + } + if ((check = CompareAndExchange.toggle) != test) { +// System.out.println("Worker(" + i1 + ", " + +// i2 + ") " + "test " + test + +// " != toggle " + check); + throw new RuntimeException( + "locked value changed"); + } + } + + iterations++; + } + } catch (InterruptedException ex) { + // System.out.println(getName() + " interrupted."); + } + +// System.out.println(getName() + " done after " + +// iterations + " iterations."); + } + } + } +} diff --git a/tests/AndroidTests/src/com/android/unit_tests/ParentalControlTest.java b/tests/AndroidTests/src/com/android/unit_tests/ParentalControlTest.java new file mode 100644 index 0000000000000000000000000000000000000000..d4d2a8257186ab4a3aabea181dca133ad1f47df1 --- /dev/null +++ b/tests/AndroidTests/src/com/android/unit_tests/ParentalControlTest.java @@ -0,0 +1,57 @@ +/* + * 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.android.unit_tests; + +import com.google.android.net.ParentalControl; +import com.google.android.net.ParentalControlState; + +import android.os.SystemClock; +import android.test.AndroidTestCase; +import android.test.suitebuilder.annotation.SmallTest; +import android.util.Log; + +import junit.framework.Assert; + +public class ParentalControlTest extends AndroidTestCase { + + private boolean mOnResultCalled = false; + + public class Callback implements ParentalControl.Callback { + public void onResult(ParentalControlState state) { + synchronized (ParentalControlTest.class) { + mOnResultCalled = true; + ParentalControlTest.class.notifyAll(); + } + } + } + + @SmallTest + public void testParentalControlCallback() { + synchronized (ParentalControlTest.class) { + ParentalControl.getParentalControlState(new Callback(), null); + try { + long start = SystemClock.uptimeMillis(); + ParentalControlTest.class.wait(20 * 1000); + long end = SystemClock.uptimeMillis(); + Log.d("AndroidTests", "ParentalControlTest callback took " + (end-start) + " ms."); + } catch (InterruptedException ex) { + } + } + + Assert.assertTrue(mOnResultCalled); + } +} diff --git a/tests/AndroidTests/src/com/android/unit_tests/PerformanceTests.java b/tests/AndroidTests/src/com/android/unit_tests/PerformanceTests.java new file mode 100644 index 0000000000000000000000000000000000000000..9e5454011c5bec93f77fe41666eb0a71aefb4c84 --- /dev/null +++ b/tests/AndroidTests/src/com/android/unit_tests/PerformanceTests.java @@ -0,0 +1,1223 @@ +/* + * Copyright (C) 2007 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.android.unit_tests; + +import android.os.Debug; +import junit.framework.Assert; +import android.test.PerformanceTestBase; +import android.test.PerformanceTestCase; +import org.apache.harmony.dalvik.NativeTestTarget; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.concurrent.atomic.AtomicInteger; + +public class PerformanceTests { + public static String[] children() { + return new String[] { + //StringEquals2.class.getName(), + //StringEquals10.class.getName(), + //StringEquals20.class.getName(), + //StringEquals200.class.getName(), + //StringEquals200U.class.getName(), + //StringCompareTo10.class.getName(), + //StringCompareTo200.class.getName(), + StringLength.class.getName(), + StringCrawl.class.getName(), + Ackermann.class.getName(), + AddTest.class.getName(), +// AddMemberVariableTest.class.getName(), + ArrayListIterator.class.getName(), + BoundsCheckTest.class.getName(), +// EmptyClassBaseTest.class.getName(), + EmptyJniStaticMethod0.class.getName(), + EmptyJniStaticMethod6.class.getName(), + EmptyJniStaticMethod6L.class.getName(), + FibonacciFast.class.getName(), + FibonacciSlow.class.getName(), +// LoopTests.class.getName(), +// HashMapTest.class.getName(), +// InterfaceTests.class.getName(), + LocalVariableAccess.class.getName(), + MemeberVariableAccess.class.getName(), + NestedLoop.class.getName(), +// StringConcatenationTests.class.getName(), +// ArrayListBase.class.getName(), + SynchronizedGetAndSetInt.class.getName(), + + /* this will not work on JamVM -- lacks atomic ops */ + AtomicGetAndSetInt.class.getName(), + }; + } + + public static class SizeTest { + private int mSize; + + public SizeTest(int size) { + mSize = size; + } + + public int size() { + return mSize; + } + } + + public static class LocalVariableAccess extends PerformanceTestBase { + private static final int ITERATIONS = 100000; + + public int startPerformance(PerformanceTestCase.Intermediates intermediates) { + intermediates.setInternalIterations(ITERATIONS * 20); + return 0; + } + + public void testRun() { + boolean variable = false; + boolean local = true; + for (int i = ITERATIONS - 1; i >= 0; i--) { + local = variable; + local = variable; + local = variable; + local = variable; + local = variable; // 5 + local = variable; + local = variable; + local = variable; + local = variable; + local = variable; // 10 + local = variable; + local = variable; + local = variable; + local = variable; + local = variable; // 15 + local = variable; + local = variable; + local = variable; + local = variable; + local = variable; // 20 + } + } + } + + /* This test is intentionally misspelled. Please do not rename it. Thanks! */ + public static class MemeberVariableAccess extends PerformanceTestBase { + private static final int ITERATIONS = 100000; + + public volatile boolean mMember = false; + + public int startPerformance(PerformanceTestCase.Intermediates intermediates) { + intermediates.setInternalIterations(ITERATIONS * 20); + return 0; + } + + public void testRun() { + boolean local = true; + for (int i = ITERATIONS - 1; i >= 0; i--) { + local = mMember; + local = mMember; + local = mMember; + local = mMember; + local = mMember; // 5 + local = mMember; + local = mMember; + local = mMember; + local = mMember; + local = mMember; // 10 + local = mMember; + local = mMember; + local = mMember; + local = mMember; + local = mMember; // 15 + local = mMember; + local = mMember; + local = mMember; + local = mMember; + local = mMember; // 20 + } + } + } + + public static class ArrayListIterator extends PerformanceTestBase { + private static final int ITERATIONS = 10000; + private ArrayList mList; + private String[] mKeys; + private Iterator mIterator; + + public void setUp() throws Exception { + super.setUp(); + mList = new ArrayList(); + mKeys = new String[ITERATIONS]; + + for (int i = ITERATIONS - 1; i >= 0; i--) { + mKeys[i] = Integer.toString(i, 16); + mList.add(mKeys[i]); + } + } + + public int startPerformance(PerformanceTestCase.Intermediates intermediates) { + intermediates.setInternalIterations(ITERATIONS); + return 0; + } + + public void testRun() { + mIterator = mList.iterator(); + while (mIterator.hasNext()) { + mIterator.next(); + } + } + } + + public static class Ackermann extends PerformanceTestBase { + public static final int ITERATIONS = 100; + public int startPerformance(PerformanceTestCase.Intermediates intermediates) { + intermediates.setInternalIterations(ITERATIONS); + return 0; + } + + public void testRun() { + for (int i = ITERATIONS - 1; i >= 0; i--) { + ackermann(3, 13); + } + } + + private int ackermann(int m, int n) { + if (m == 0) + return n + 1; + if (n == 0) + return ackermann(m - 1, 1); + return ackermann(m, n - 1); + } + } + + public static class FibonacciSlow extends PerformanceTestBase { + public void setUp() throws Exception { + super.setUp(); + Assert.assertEquals(0, fibonacci(0)); + Assert.assertEquals(1, fibonacci(1)); + Assert.assertEquals(1, fibonacci(2)); + Assert.assertEquals(2, fibonacci(3)); + Assert.assertEquals(6765, fibonacci(20)); + } + + public void tearDown() { + } + + public int startPerformance(PerformanceTestCase.Intermediates intermediates) { + return 0; + } + + public void testRun() { + fibonacci(20); + } + + private long fibonacci(long n) { + if (n == 0) + return 0; + if (n == 1) + return 1; + return fibonacci(n - 2) + fibonacci(n - 1); + } + } + + public static class FibonacciFast extends PerformanceTestBase { + public void setUp() throws Exception { + super.setUp(); + Assert.assertEquals(0, fibonacci(0)); + Assert.assertEquals(1, fibonacci(1)); + Assert.assertEquals(1, fibonacci(2)); + Assert.assertEquals(2, fibonacci(3)); + Assert.assertEquals(6765, fibonacci(20)); + } + + public void tearDown() { + } + + public int startPerformance(PerformanceTestCase.Intermediates intermediates) { + return 0; + } + + public void testRun() { + fibonacci(5000); + } + + private long fibonacci(long n) { + if (n == 0) + return 0; + if (n == 1) + return 1; + + int x = 0; + int y = 1; + for (int i = 0; i < n - 1; i++) { + y = y + x; + x = y - x; + } + + return y; + } + } + + public static class HashMapTest extends PerformanceTestBase { + private static final int ITERATIONS = 10000; + private HashMap mMap; + private String[] mKeys; + + public void setUp() throws Exception { + super.setUp(); + mMap = new HashMap(); + mKeys = new String[ITERATIONS]; + + for (int i = ITERATIONS - 1; i >= 0; i--) { + mKeys[i] = Integer.toString(i, 16); + mMap.put(mKeys[i], i); + } + } + + public void tearDown() { + } + + public int startPerformance(PerformanceTestCase.Intermediates intermediates) { + intermediates.setInternalIterations(ITERATIONS); + return 0; + } + + public void testHashMapContainsKey() { + for (int i = ITERATIONS - 1; i >= 0; i--) { + mMap.containsKey(mKeys[i]); + } + } + + public void testHashMapIterator() { + Iterator iterator; + + iterator = mMap.entrySet().iterator(); + while (iterator.hasNext()) { + iterator.next(); + } + } + + public void testHashMapPut() { + HashMap map = new HashMap(); + String[] keys = mKeys; + for (int i = ITERATIONS - 1; i >= 0; i--) { + map.put(keys[i], i); + } + } + } + + interface IA { + void funcA0(); + void funcA1(); + void funcA2(); + void funcA3(); + } + interface IAB extends IA { + void funcAB0(); + void funcAB1(); + void funcAB2(); + void funcAB3(); + } + interface IABC extends IAB { + void funcABC0(); + void funcABC1(); + void funcABC2(); + void funcABC3(); + } + interface IB { + void funcB0(); + void funcB1(); + void funcB2(); + void funcB3(); + } + interface IC { + void funcC0(); + void funcC1(); + void funcC2(); + void funcC3(); + } + + static class Alphabet implements Cloneable, IB, IABC, IC, Runnable { + public void funcA0() { + } + public void funcA1() { + } + public void funcA2() { + } + public void funcA3() { + } + public void funcAB0() { + } + public void funcAB1() { + } + public void funcAB2() { + } + public void funcAB3() { + } + public void funcABC0() { + } + public void funcABC1() { + } + public void funcABC2() { + } + public void funcABC3() { + } + public void funcB0() { + } + public void funcB1() { + } + public void funcB2() { + } + public void funcB3() { + } + public void funcC0() { + } + public void funcC1() { + } + public void funcC2() { + } + public void funcC3() { + } + public void run() { + } + }; + + public static class InterfaceTests extends PerformanceTestBase { + private static final int ITERATIONS = 10000; + + public int startPerformance(PerformanceTestCase.Intermediates intermediates) { + intermediates.setInternalIterations(ITERATIONS * 10); + return 0; + } + + /* call method directly */ + public void testInterfaceCalls0() { + Alphabet alpha = new Alphabet(); + + for (int i = ITERATIONS - 1; i >= 0; i--) { + alpha.funcABC1(); + alpha.funcABC1(); + alpha.funcABC1(); + alpha.funcABC1(); + alpha.funcABC1(); + alpha.funcABC1(); + alpha.funcABC1(); + alpha.funcABC1(); + alpha.funcABC1(); + alpha.funcABC1(); + } + } + + /* call method through interface reference */ + public void testInterfaceCalls1() { + Alphabet alpha = new Alphabet(); + IABC iabc = alpha; + + for (int i = ITERATIONS - 1; i >= 0; i--) { + iabc.funcABC1(); + iabc.funcABC1(); + iabc.funcABC1(); + iabc.funcABC1(); + iabc.funcABC1(); + iabc.funcABC1(); + iabc.funcABC1(); + iabc.funcABC1(); + iabc.funcABC1(); + iabc.funcABC1(); + } + } + + public void testInstanceOfTrivial() { + Alphabet alpha = new Alphabet(); + IABC iabc = alpha; + boolean val; + + for (int i = ITERATIONS - 1; i >= 0; i--) { + val = iabc instanceof Alphabet; + val = iabc instanceof Alphabet; + val = iabc instanceof Alphabet; + val = iabc instanceof Alphabet; + val = iabc instanceof Alphabet; + val = iabc instanceof Alphabet; + val = iabc instanceof Alphabet; + val = iabc instanceof Alphabet; + val = iabc instanceof Alphabet; + val = iabc instanceof Alphabet; + } + } + + public void testInstanceOfInterface() { + Alphabet alpha = new Alphabet(); + IABC iabc = alpha; + boolean val; + + for (int i = ITERATIONS - 1; i >= 0; i--) { + val = iabc instanceof IA; + val = iabc instanceof IA; + val = iabc instanceof IA; + val = iabc instanceof IA; + val = iabc instanceof IA; + val = iabc instanceof IA; + val = iabc instanceof IA; + val = iabc instanceof IA; + val = iabc instanceof IA; + val = iabc instanceof IA; + } + } + + public void testInstanceOfNot() { + Alphabet alpha = new Alphabet(); + IABC iabc = alpha; + boolean val; + + for (int i = ITERATIONS - 1; i >= 0; i--) { + val = iabc instanceof EmptyInterface; + val = iabc instanceof EmptyInterface; + val = iabc instanceof EmptyInterface; + val = iabc instanceof EmptyInterface; + val = iabc instanceof EmptyInterface; + val = iabc instanceof EmptyInterface; + val = iabc instanceof EmptyInterface; + val = iabc instanceof EmptyInterface; + val = iabc instanceof EmptyInterface; + val = iabc instanceof EmptyInterface; + } + } + } + + public static class NestedLoop extends PerformanceTestBase { + private static final int ITERATIONS = 10; + private static final int LOOPS = 5; + + public int startPerformance(PerformanceTestCase.Intermediates intermediates) { + intermediates.setInternalIterations(ITERATIONS * LOOPS); + return 0; + } + + public void testRun() { + int x = 0; + for (int a = 0; a < ITERATIONS; a++) { + for (int b = 0; b < ITERATIONS; b++) { + for (int c = 0; c < ITERATIONS; c++) { + for (int d = 0; d < ITERATIONS; d++) { + for (int e = 0; e < ITERATIONS; e++) { + x++; + } + } + } + } + } + } + } + + public static class StringConcatenationTests extends PerformanceTestBase { + private static final int ITERATIONS = 1000; + + public int startPerformance(PerformanceTestCase.Intermediates intermediates) { + intermediates.setInternalIterations(ITERATIONS); + return 0; + } + + public void testStringConcatenation1() { + StringBuffer buffer = new StringBuffer(); + for (int i = ITERATIONS - 1; i >= 0; i--) { + buffer.append("Hello World!\n"); + } + buffer = null; + } + + public void testStringConcatenation2() { + String string = ""; + for (int i = ITERATIONS - 1; i >= 0; i--) { + string += "Hello World!\n"; + } + string = null; + } + } + + public static class StringLength extends PerformanceTestBase { + private static final int ITERATIONS = 10000; + private static final String TEST_STRING = "This is the string we use for testing..."; // 40 chars + + public int startPerformance(PerformanceTestCase.Intermediates intermediates) { + intermediates.setInternalIterations(ITERATIONS * 10); + return 0; + } + + public void testRun() { + String testStr = TEST_STRING; + int length; + + for (int i = ITERATIONS - 1; i >= 0; i--) { + length = testStr.length(); + length = testStr.length(); + length = testStr.length(); + length = testStr.length(); + length = testStr.length(); + length = testStr.length(); + length = testStr.length(); + length = testStr.length(); + length = testStr.length(); + length = testStr.length(); + } + } + } + + public static class EmptyJniStaticMethod0 extends PerformanceTestBase { + private static final int ITERATIONS = 10000; + + public int startPerformance(PerformanceTestCase.Intermediates intermediates) { + intermediates.setInternalIterations(ITERATIONS * 10); + return 0; + } + + public void testRun() { + int a, b, c, d, e, f; + + a = b = c = d = e = f = 0; + + for (int i = ITERATIONS - 1; i >= 0; i--) { + NativeTestTarget.emptyJniStaticMethod0(); + NativeTestTarget.emptyJniStaticMethod0(); + NativeTestTarget.emptyJniStaticMethod0(); + NativeTestTarget.emptyJniStaticMethod0(); + NativeTestTarget.emptyJniStaticMethod0(); + NativeTestTarget.emptyJniStaticMethod0(); + NativeTestTarget.emptyJniStaticMethod0(); + NativeTestTarget.emptyJniStaticMethod0(); + NativeTestTarget.emptyJniStaticMethod0(); + NativeTestTarget.emptyJniStaticMethod0(); + } + } + } + public static class EmptyJniStaticMethod6 extends PerformanceTestBase { + private static final int ITERATIONS = 10000; + + public int startPerformance(PerformanceTestCase.Intermediates intermediates) { + intermediates.setInternalIterations(ITERATIONS * 10); + return 0; + } + + public void testRun() { + int a, b, c, d, e, f; + + a = b = c = d = e = f = 0; + + for (int i = ITERATIONS - 1; i >= 0; i--) { + NativeTestTarget.emptyJniStaticMethod6(a, b, c, d, e, f); + NativeTestTarget.emptyJniStaticMethod6(a, b, c, d, e, f); + NativeTestTarget.emptyJniStaticMethod6(a, b, c, d, e, f); + NativeTestTarget.emptyJniStaticMethod6(a, b, c, d, e, f); + NativeTestTarget.emptyJniStaticMethod6(a, b, c, d, e, f); + NativeTestTarget.emptyJniStaticMethod6(a, b, c, d, e, f); + NativeTestTarget.emptyJniStaticMethod6(a, b, c, d, e, f); + NativeTestTarget.emptyJniStaticMethod6(a, b, c, d, e, f); + NativeTestTarget.emptyJniStaticMethod6(a, b, c, d, e, f); + NativeTestTarget.emptyJniStaticMethod6(a, b, c, d, e, f); + } + } + } + public static class EmptyJniStaticMethod6L extends PerformanceTestBase { + private static final int ITERATIONS = 10000; + + public int startPerformance(PerformanceTestCase.Intermediates intermediates) { + intermediates.setInternalIterations(ITERATIONS * 10); + return 0; + } + + public void testRun() { + String a = null; + String[] b = null; + int[][] c = null; + Object d = null; + Object[] e = null; + Object[][][][] f = null; + + for (int i = ITERATIONS - 1; i >= 0; i--) { + NativeTestTarget.emptyJniStaticMethod6L(a, b, c, d, e, f); + NativeTestTarget.emptyJniStaticMethod6L(a, b, c, d, e, f); + NativeTestTarget.emptyJniStaticMethod6L(a, b, c, d, e, f); + NativeTestTarget.emptyJniStaticMethod6L(a, b, c, d, e, f); + NativeTestTarget.emptyJniStaticMethod6L(a, b, c, d, e, f); + NativeTestTarget.emptyJniStaticMethod6L(a, b, c, d, e, f); + NativeTestTarget.emptyJniStaticMethod6L(a, b, c, d, e, f); + NativeTestTarget.emptyJniStaticMethod6L(a, b, c, d, e, f); + NativeTestTarget.emptyJniStaticMethod6L(a, b, c, d, e, f); + NativeTestTarget.emptyJniStaticMethod6L(a, b, c, d, e, f); + } + } + } + + public static class StringCrawl extends PerformanceTestBase { + private static final int ITERATIONS = 10000; + private static final String TEST_STRING = "This is the string we use for testing..."; // 40 chars + + public int startPerformance(PerformanceTestCase.Intermediates intermediates) { + intermediates.setInternalIterations(ITERATIONS * TEST_STRING.length()); + return 0; + } + + public void testRun() { + String testStr = TEST_STRING; + char ch; + for (int i = ITERATIONS - 1; i >= 0; i--) { + /* this is the wrong way to walk through a string */ + for (int j = 0; j < testStr.length(); j++) { + ch = testStr.charAt(j); + } + } + } + } + + public static class AddTest extends PerformanceTestBase { + private static final int ITERATIONS = 10000; + + public int startPerformance(PerformanceTestCase.Intermediates intermediates) { + intermediates.setInternalIterations(ITERATIONS * 20); + return 0; + } + + public void testRun() { + int j = 0; + for (int i = ITERATIONS - 1; i >= 0; i--) { + j++; + j++; + j++; + j++; + j++; + j++; + j++; + j++; + j++; + j++; + j++; + j++; + j++; + j++; + j++; + j++; + j++; + j++; + j++; + j++; + } + } + } + + public static class AddMemberVariableTest extends PerformanceTestBase { + private static final int ITERATIONS = 10000; + private int j; + + public void setUp() throws Exception { + super.setUp(); + j = 0; + } + + public int startPerformance(PerformanceTestCase.Intermediates intermediates) { + intermediates.setInternalIterations(ITERATIONS * 10); + return 0; + } + + public void testAddMemberVariableTest() { + for (int i = ITERATIONS - 1; i >= 0; i--) { + j++; + j++; + j++; + j++; + j++; + j++; + j++; + j++; + j++; + j++; + } + } + + public void testAddMemberVariableInMethodTest() { + for (int i = ITERATIONS - 1; i >= 0; i--) { + add(); + add(); + add(); + add(); + add(); + add(); + add(); + add(); + add(); + add(); + } + } + + public void add() { + j++; + } + } + + private interface EmptyInterface { + public void emptyVirtual(); + + } + + private static class EmptyClass implements EmptyInterface { + public void emptyVirtual() { + } + + public static void emptyStatic() { + } + } + + public static class EmptyClassBaseTest extends PerformanceTestBase { + protected EmptyInterface mEmptyInterface; + protected EmptyClass mEmptyClass; + + public void setUp() throws Exception { + super.setUp(); + mEmptyClass = new EmptyClass(); + mEmptyInterface = mEmptyClass; + } + private static final int ITERATIONS = 10000; + + public int startPerformance(PerformanceTestCase.Intermediates intermediates) { + intermediates.setInternalIterations(ITERATIONS * 10); + return 0; + } + + public void testEmptyVirtualMethod() { + //EmptyClass emtpyClass = mEmptyClass; + for (int i = ITERATIONS - 1; i >= 0; i--) { + mEmptyClass.emptyVirtual(); + mEmptyClass.emptyVirtual(); + mEmptyClass.emptyVirtual(); + mEmptyClass.emptyVirtual(); + mEmptyClass.emptyVirtual(); + mEmptyClass.emptyVirtual(); + mEmptyClass.emptyVirtual(); + mEmptyClass.emptyVirtual(); + mEmptyClass.emptyVirtual(); + mEmptyClass.emptyVirtual(); + } + } + + public void testEmptyVirtualMethodTestInLocal() { + EmptyClass empty = mEmptyClass; + for (int i = ITERATIONS - 1; i >= 0; i--) { + empty.emptyVirtual(); + empty.emptyVirtual(); + empty.emptyVirtual(); + empty.emptyVirtual(); + empty.emptyVirtual(); + empty.emptyVirtual(); + empty.emptyVirtual(); + empty.emptyVirtual(); + empty.emptyVirtual(); + empty.emptyVirtual(); + } + } + + public void testEmptyStaticMethod () { + for (int i = ITERATIONS - 1; i >= 0; i--) { + EmptyClass.emptyStatic(); + EmptyClass.emptyStatic(); + EmptyClass.emptyStatic(); + EmptyClass.emptyStatic(); + EmptyClass.emptyStatic(); + EmptyClass.emptyStatic(); + EmptyClass.emptyStatic(); + EmptyClass.emptyStatic(); + EmptyClass.emptyStatic(); + EmptyClass.emptyStatic(); + } + } + + public void testEmptyJniStaticMethod0() { + + for (int i = ITERATIONS - 1; i >= 0; i--) { + NativeTestTarget.emptyJniStaticMethod0(); + NativeTestTarget.emptyJniStaticMethod0(); + NativeTestTarget.emptyJniStaticMethod0(); + NativeTestTarget.emptyJniStaticMethod0(); + NativeTestTarget.emptyJniStaticMethod0(); + NativeTestTarget.emptyJniStaticMethod0(); + NativeTestTarget.emptyJniStaticMethod0(); + NativeTestTarget.emptyJniStaticMethod0(); + NativeTestTarget.emptyJniStaticMethod0(); + NativeTestTarget.emptyJniStaticMethod0(); + } + } + + public void testEmptyJniStaticMethod6() { + int a, b, c, d, e, f; + + a = b = c = d = e = f = 0; + + for (int i = ITERATIONS - 1; i >= 0; i--) { + NativeTestTarget.emptyJniStaticMethod6(a, b, c, d, e, f); + NativeTestTarget.emptyJniStaticMethod6(a, b, c, d, e, f); + NativeTestTarget.emptyJniStaticMethod6(a, b, c, d, e, f); + NativeTestTarget.emptyJniStaticMethod6(a, b, c, d, e, f); + NativeTestTarget.emptyJniStaticMethod6(a, b, c, d, e, f); + NativeTestTarget.emptyJniStaticMethod6(a, b, c, d, e, f); + NativeTestTarget.emptyJniStaticMethod6(a, b, c, d, e, f); + NativeTestTarget.emptyJniStaticMethod6(a, b, c, d, e, f); + NativeTestTarget.emptyJniStaticMethod6(a, b, c, d, e, f); + NativeTestTarget.emptyJniStaticMethod6(a, b, c, d, e, f); + } + } + + public void testEmptyInternalStaticMethod() { + /* + * The method called is a VM-internal method with no extra + * wrapping. + */ + for (int i = ITERATIONS - 1; i >= 0; i--) { + NativeTestTarget.emptyInternalStaticMethod(); + NativeTestTarget.emptyInternalStaticMethod(); + NativeTestTarget.emptyInternalStaticMethod(); + NativeTestTarget.emptyInternalStaticMethod(); + NativeTestTarget.emptyInternalStaticMethod(); + NativeTestTarget.emptyInternalStaticMethod(); + NativeTestTarget.emptyInternalStaticMethod(); + NativeTestTarget.emptyInternalStaticMethod(); + NativeTestTarget.emptyInternalStaticMethod(); + NativeTestTarget.emptyInternalStaticMethod(); + } + } + + public void testEmptyInlineStaticMethod() { + /* + * The method called is a VM-internal method that gets + * specially "inlined" in a bytecode transformation. + */ + for (int i = ITERATIONS - 1; i >= 0; i--) { + NativeTestTarget.emptyInlineMethod(); + NativeTestTarget.emptyInlineMethod(); + NativeTestTarget.emptyInlineMethod(); + NativeTestTarget.emptyInlineMethod(); + NativeTestTarget.emptyInlineMethod(); + NativeTestTarget.emptyInlineMethod(); + NativeTestTarget.emptyInlineMethod(); + NativeTestTarget.emptyInlineMethod(); + NativeTestTarget.emptyInlineMethod(); + NativeTestTarget.emptyInlineMethod(); + } + } + + public void testEmptyInterfaceMethodTest() { + EmptyInterface emptyInterface = mEmptyInterface; + for (int i = ITERATIONS - 1; i >= 0; i--) { + emptyInterface.emptyVirtual(); + emptyInterface.emptyVirtual(); + emptyInterface.emptyVirtual(); + emptyInterface.emptyVirtual(); + emptyInterface.emptyVirtual(); + emptyInterface.emptyVirtual(); + emptyInterface.emptyVirtual(); + emptyInterface.emptyVirtual(); + emptyInterface.emptyVirtual(); + emptyInterface.emptyVirtual(); + } + } + } + + public static class LoopTests extends PerformanceTestBase { + private static final int ITERATIONS = 10000; + private SizeTest mSizeTest = new SizeTest(ITERATIONS); + + public int startPerformance(PerformanceTestCase.Intermediates intermediates) { + intermediates.setInternalIterations(ITERATIONS); + return 0; + } + + public void testForLoopTest() { + int i = 0; + for (; i < 10000; i++) { + } + } + + public void testWhileLoopTest() { + int i = 0; + + while (i < 10000) { + i++; + } + } + + public void testForLoopSizeCalledInside() { + for (int i = 0; i < mSizeTest.size(); i++) { + } + } + + public void testForLoopSizeCalledOutside() { + final int size = mSizeTest.size(); + for (int i = 0; i < size; i++) { + } + } + } + + public static class BoundsCheckTest extends PerformanceTestBase { + private static final int ITERATIONS = 10000; + public int startPerformance(PerformanceTestCase.Intermediates intermediates) { + intermediates.setInternalIterations(ITERATIONS * 10); + return 0; + } + + public void testRun() { + int[] data = new int[1]; + + for (int i = ITERATIONS - 1; i >= 0; i--) { + data[0] = i; + data[0] = i; + data[0] = i; + data[0] = i; + data[0] = i; + data[0] = i; + data[0] = i; + data[0] = i; + data[0] = i; + data[0] = i; + } + } + } + + public static class ArrayListBase extends PerformanceTestBase { + public void setUp() throws Exception { + super.setUp(); + mList = new ArrayList(); + mList.add(0); + mList.add(1); + mList.add(2); + mList.add(3); + mList.add(4); + mList.add(5); + mList.add(6); + mList.add(7); + mList.add(8); + mList.add(9); + } + + public int startPerformance(PerformanceTestCase.Intermediates intermediates) { + intermediates.setInternalIterations(100); + return 0; + } + + ArrayList mList; + + public void testForArrayList() { + int i = 0; + int res = 0; + for (; i < 100; i++) { + for (int j = 0; j < mList.size(); j++) { + res += mList.get(j); + } + } + } + + public void testForLocalArrayList() { + int i = 0; + int res = 0; + for (; i < 100; i++) { + final List list = mList; + final int N = list.size(); + for (int j = 0; j < N; j++) { + res += list.get(j); + } + } + } + + public void testForEachArrayList() { + int i = 0; + int res = 0; + for (; i < 100; i++) { + for (Integer v : mList) { + res += v; + } + } + } + } + + public static class SynchronizedGetAndSetInt extends PerformanceTestBase { + private static final int ITERATIONS = 100000; + + public int mMember = 0; + + public int startPerformance(PerformanceTestCase.Intermediates intermediates) { + intermediates.setInternalIterations(ITERATIONS); + return 0; + } + + public void testRun() { + int result = 0; + for (int i = ITERATIONS - 1; i >= 0; i--) { + synchronized (this) { + result = mMember; + mMember = i; + } + } + } + } + + public static class AtomicGetAndSetInt extends PerformanceTestBase { + private static final int ITERATIONS = 100000; + + public AtomicInteger mMember = new AtomicInteger(0); + + public int startPerformance(PerformanceTestCase.Intermediates intermediates) { + intermediates.setInternalIterations(ITERATIONS); + return 0; + } + + public void testRun() { + int result = 0; + for (int i = ITERATIONS - 1; i >= 0; i--) { + result = mMember.getAndSet(i); + } + } + } + + public static abstract class StringEquals extends PerformanceTestBase { + private static final int ITERATIONS = 10000; + + protected String mString1, mString2; + public void setUp() throws Exception { + super.setUp(); + } + + public int startPerformance(PerformanceTestCase.Intermediates intermediates) { + intermediates.setInternalIterations(ITERATIONS * 10); + return 0; + } + + public void testRun() { + String string1 = mString1; + String string2 = mString2; + + for (int i = ITERATIONS - 1; i >= 0; i--) { + string1.equals(string2); + string1.equals(string2); + string1.equals(string2); + string1.equals(string2); + string1.equals(string2); + string1.equals(string2); + string1.equals(string2); + string1.equals(string2); + string1.equals(string2); + string1.equals(string2); + } + } + } + + public static class StringEquals2 extends StringEquals { + public void setUp() throws Exception { + mString1 = "01"; + mString2 = "0x"; + } + } + public static class StringEquals10 extends StringEquals { + public void setUp() throws Exception { + mString1 = "0123456789"; + mString2 = "012345678x"; + } + } + public static class StringEquals20 extends StringEquals { + public void setUp() throws Exception { + mString1 = "01234567890123456789"; + mString2 = "0123456789012345678x"; + } + } + + public static class StringEquals200 extends StringEquals { + public void setUp() throws Exception { + mString1 = "0123456789012345678901234567890123456789" + + "0123456789012345678901234567890123456789" + + "0123456789012345678901234567890123456789" + + "0123456789012345678901234567890123456789" + + "0123456789012345678901234567890123456789"; + mString2 = "0123456789012345678901234567890123456789" + + "0123456789012345678901234567890123456789" + + "0123456789012345678901234567890123456789" + + "0123456789012345678901234567890123456789" + + "012345678901234567890123456789012345678x"; + } + } + public static class StringEquals200U extends StringEquals { + /* make one of the strings non-word aligned (bad memcmp case) */ + public void setUp() throws Exception { + String tmpStr; + mString1 = "0123456789012345678901234567890123456789" + + "0123456789012345678901234567890123456789" + + "0123456789012345678901234567890123456789" + + "0123456789012345678901234567890123456789" + + "0123456789012345678901234567890123456789"; + tmpStr = "z0123456789012345678901234567890123456789" + + "0123456789012345678901234567890123456789" + + "0123456789012345678901234567890123456789" + + "0123456789012345678901234567890123456789" + + "012345678901234567890123456789012345678x"; + mString2 = tmpStr.substring(1); + } + } + + public static abstract class StringCompareTo extends PerformanceTestBase { + private static final int ITERATIONS = 10000; + + protected String mString1, mString2; + + public int startPerformance(PerformanceTestCase.Intermediates intermediates) { + intermediates.setInternalIterations(ITERATIONS * 10); + return 0; + } + + public void testRun() { + String string1 = mString1; + String string2 = mString2; + + for (int i = ITERATIONS - 1; i >= 0; i--) { + string1.compareTo(string2); + string1.compareTo(string2); + string1.compareTo(string2); + string1.compareTo(string2); + string1.compareTo(string2); + string1.compareTo(string2); + string1.compareTo(string2); + string1.compareTo(string2); + string1.compareTo(string2); + string1.compareTo(string2); + } + } + } + public static class StringCompareTo10 extends StringCompareTo { + public void setUp() throws Exception { + mString1 = "0123456789"; + mString2 = "012345678x"; + } + } + public static class StringCompareTo200 extends StringCompareTo { + public void setUp() throws Exception { + mString1 = "0123456789012345678901234567890123456789" + + "0123456789012345678901234567890123456789" + + "0123456789012345678901234567890123456789" + + "0123456789012345678901234567890123456789" + + "0123456789012345678901234567890123456789"; + mString2 = "0123456789012345678901234567890123456789" + + "0123456789012345678901234567890123456789" + + "0123456789012345678901234567890123456789" + + "0123456789012345678901234567890123456789" + + "012345678901234567890123456789012345678x"; + } + } +} + diff --git a/tests/AndroidTests/src/com/android/unit_tests/RegexTest.java b/tests/AndroidTests/src/com/android/unit_tests/RegexTest.java new file mode 100644 index 0000000000000000000000000000000000000000..8f55044aec61a0f807cf2b0f3a3fc61783edc2c2 --- /dev/null +++ b/tests/AndroidTests/src/com/android/unit_tests/RegexTest.java @@ -0,0 +1,124 @@ +/* + * Copyright (C) 2007 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.android.unit_tests; + +import android.test.suitebuilder.annotation.SmallTest; +import android.text.util.Regex; +import junit.framework.TestCase; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class RegexTest extends TestCase { + + @SmallTest + public void testTldPattern() throws Exception { + boolean t; + + t = Regex.TOP_LEVEL_DOMAIN_PATTERN.matcher("com").matches(); + assertTrue("Missed valid TLD", t); + + t = Regex.TOP_LEVEL_DOMAIN_PATTERN.matcher("xer").matches(); + assertFalse("Matched invalid TLD!", t); + } + + @SmallTest + public void testUrlPattern() throws Exception { + boolean t; + + t = Regex.WEB_URL_PATTERN.matcher("http://www.google.com").matches(); + assertTrue("Valid URL", t); + + t = Regex.WEB_URL_PATTERN.matcher("ftp://www.example.com").matches(); + assertFalse("Matched invalid protocol", t); + + t = Regex.WEB_URL_PATTERN.matcher("http://www.example.com:8080").matches(); + assertTrue("Didn't match valid URL with port", t); + + t = Regex.WEB_URL_PATTERN.matcher("http://www.example.com:8080/?foo=bar").matches(); + assertTrue("Didn't match valid URL with port and query args", t); + + t = Regex.WEB_URL_PATTERN.matcher("http://www.example.com:8080/~user/?foo=bar").matches(); + assertTrue("Didn't match valid URL with ~", t); + } + + @SmallTest + public void testIpPattern() throws Exception { + boolean t; + + t = Regex.IP_ADDRESS_PATTERN.matcher("172.29.86.3").matches(); + assertTrue("Valid IP", t); + + t = Regex.IP_ADDRESS_PATTERN.matcher("1234.4321.9.9").matches(); + assertFalse("Invalid IP", t); + } + + @SmallTest + public void testDomainPattern() throws Exception { + boolean t; + + t = Regex.DOMAIN_NAME_PATTERN.matcher("mail.example.com").matches(); + assertTrue("Valid domain", t); + + t = Regex.DOMAIN_NAME_PATTERN.matcher("__+&42.xer").matches(); + assertFalse("Invalid domain", t); + } + + @SmallTest + public void testPhonePattern() throws Exception { + boolean t; + + t = Regex.PHONE_PATTERN.matcher("(919) 555-1212").matches(); + assertTrue("Valid phone", t); + + t = Regex.PHONE_PATTERN.matcher("2334 9323/54321").matches(); + assertFalse("Invalid phone", t); + + String[] tests = { + "Me: 16505551212 this\n", + "Me: 6505551212 this\n", + "Me: 5551212 this\n", + + "Me: 1-650-555-1212 this\n", + "Me: (650) 555-1212 this\n", + "Me: +1 (650) 555-1212 this\n", + "Me: +1-650-555-1212 this\n", + "Me: 650-555-1212 this\n", + "Me: 555-1212 this\n", + + "Me: 1.650.555.1212 this\n", + "Me: (650) 555.1212 this\n", + "Me: +1 (650) 555.1212 this\n", + "Me: +1.650.555.1212 this\n", + "Me: 650.555.1212 this\n", + "Me: 555.1212 this\n", + + "Me: 1 650 555 1212 this\n", + "Me: (650) 555 1212 this\n", + "Me: +1 (650) 555 1212 this\n", + "Me: +1 650 555 1212 this\n", + "Me: 650 555 1212 this\n", + "Me: 555 1212 this\n", + }; + + for (String test : tests) { + Matcher m = Regex.PHONE_PATTERN.matcher(test); + + assertTrue("Valid phone " + test, m.find()); + } + } +} diff --git a/tests/AndroidTests/src/com/android/unit_tests/SMSTest.java b/tests/AndroidTests/src/com/android/unit_tests/SMSTest.java new file mode 100644 index 0000000000000000000000000000000000000000..ce0b53d864e3a361885bb6b5ed67c86ff2a6fc5c --- /dev/null +++ b/tests/AndroidTests/src/com/android/unit_tests/SMSTest.java @@ -0,0 +1,277 @@ +/* + * Copyright (C) 2006 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.android.unit_tests; + +import com.android.internal.telephony.gsm.GsmAlphabet; +import com.android.internal.telephony.gsm.SmsHeader; +import com.android.internal.util.HexDump; +import android.telephony.gsm.SmsMessage; +import android.test.AndroidTestCase; +import android.test.suitebuilder.annotation.SmallTest; + +import java.util.Iterator; + +public class SMSTest extends AndroidTestCase { + + @SmallTest + public void testOne() throws Exception { + String pdu = "07914151551512f2040B916105551511f100006060605130308A04D4F29C0E"; + + SmsMessage sms = SmsMessage.createFromPdu(HexDump.hexStringToByteArray(pdu)); + + assertEquals("+14155551212", sms.getServiceCenterAddress()); + assertEquals("+16505551111", sms.getOriginatingAddress()); + assertEquals("Test", sms.getMessageBody()); + //assertTrue(sms.scTimeMillis == 1152223383000L); + + pdu = "07914151551512f2040B916105551511f100036060924180008A0DA" + + "8695DAC2E8FE9296A794E07"; + + sms = SmsMessage.createFromPdu(HexDump.hexStringToByteArray(pdu)); + + assertEquals("+14155551212", sms.getServiceCenterAddress()); + assertEquals("+16505551111", sms.getOriginatingAddress()); + assertEquals("(Subject)Test", sms.getMessageBody()); + + /* lines[0] = "+CMT: ,45"; + lines[1] = "07914140279510F6440A8111110301003BF56070624111958A8C0B05040B8423F" + + "000033702010106276170706C69636174696F6E2F766E642E7761702E6D6D732D" + + "6D65737361676500AF848D018BB4848C8298524D66616E304A6D7135514141416" + + "57341414141546741414E4E304141414141008D908918802B3136353032343836" + + "3137392F545950453D504C4D4E009646573A20008A808E0222C788058103093A7" + + "F836874"; + + sms = SMSMessage.createFromPdu(mContext, lines); + */ + + pdu = "07914140279510F6440A8111110301003BF56080207130138A8C0B05040B8423F" + + "000032A02010106276170706C69636174696F6E2F766E642E7761702E6D6D732D" + + "6D65737361676500AF848D0185B4848C8298524E453955304A6D7135514141426" + + "66C414141414D7741414236514141414141008D908918802B3135313232393737" + + "3638332F545950453D504C4D4E008A808E022B918805810306977F83687474703" + + "A2F2F36"; + + sms = SmsMessage.createFromPdu(HexDump.hexStringToByteArray(pdu)); + + SmsHeader header = sms.getUserDataHeader(); + assertNotNull(header); + + Iterator elements = header.getElements().iterator(); + assertNotNull(elements); + + + pdu = "07914140279510F6440A8111110301003BF56080207130238A3B0B05040B8423F" + + "000032A0202362E3130322E3137312E3135302F524E453955304A6D7135514141" + + "42666C414141414D774141423651414141414100"; + sms = SmsMessage.createFromPdu(HexDump.hexStringToByteArray(pdu)); + + header = sms.getUserDataHeader(); + assertNotNull(header); + + elements = header.getElements().iterator(); + assertNotNull(elements); + + /* + * UCS-2 encoded SMS + */ + + pdu = "07912160130300F4040B914151245584F600087010807121352B10212200A900AE00680065006C006C006F"; + + sms = SmsMessage.createFromPdu(HexDump.hexStringToByteArray(pdu)); + assertEquals("\u2122\u00a9\u00aehello", sms.getMessageBody()); + + // Entire alphabet (minus the escape character) + + /**** + lines[0] = "+CMT: "; + lines[1] = "0001000A8114455245680000808080604028180E888462C168381E90886442A9582E988C06C0E9783EA09068442A994EA8946AC56AB95EB0986C46ABD96EB89C6EC7EBF97EC0A070482C1A8FC8A472C96C3A9FD0A8744AAD5AAFD8AC76CBED7ABFE0B0784C2E9BCFE8B47ACD6EBBDFF0B87C4EAFDBEFF8BC7ECFEFFBFF"; + sms = SMSMessage.createFromPdu(mContext, lines); + + System.out.println("full alphabet message body len: " + + sms.getMessageBody().length()); + + System.out.println("'" + sms.getMessageBody() +"'"); + + assertTrue(sms.getMessageBody().length() == 128); + ****/ + + /* + * Multi-part text SMS with data in septets + */ + pdu = "07916163838408F6440B816105224431F700007060217175830AA0050003" + + "00020162B1582C168BC562B1582C168BC562B1582C168BC562B1582C" + + "168BC562B1582C168BC562B1582C168BC562B1582C168BC562B1582C" + + "168BC562B1582C168BC562B1582C168BC562B1582C168BC562B1582C" + + "168BC562B1582C168BC562B1582C168BC562B1582C168BC562B1582C" + + "168BC562B1582C168BC562B1582C168BC562B1582C168BC562"; + sms = SmsMessage.createFromPdu(HexDump.hexStringToByteArray(pdu)); + assertEquals(sms.getMessageBody(), + "1111111111111111111111111111111111111111" + + "1111111111111111111111111111111111111111" + + "1111111111111111111111111111111111111111" + + "111111111111111111111111111111111"); + + pdu = "07916163838408F6440B816105224431F700007060217185000A23050003" + + "00020262B1582C168BC96432994C2693C96432994C2693C96432990C"; + sms = SmsMessage.createFromPdu(HexDump.hexStringToByteArray(pdu)); + assertEquals("1111111222222222222222222222", sms.getMessageBody()); + } + + @SmallTest + public void testCPHSVoiceMail() throws Exception { + // "set MWI flag" + + String pdu = "07912160130310F20404D0110041006060627171118A0120"; + + SmsMessage sms = SmsMessage.createFromPdu(HexDump.hexStringToByteArray(pdu)); + + assertTrue(sms.isReplace()); + assertEquals("_@", sms.getOriginatingAddress()); + assertEquals(" ", sms.getMessageBody()); + assertTrue(sms.isMWISetMessage()); + + // "clear mwi flag" + + pdu = "07912160130310F20404D0100041006021924193352B0120"; + + sms = SmsMessage.createFromPdu(HexDump.hexStringToByteArray(pdu)); + + assertTrue(sms.isMWIClearMessage()); + + // "clear MWI flag" + + pdu = "07912160130310F20404D0100041006060627161058A0120"; + + sms = SmsMessage.createFromPdu(HexDump.hexStringToByteArray(pdu)); + +// System.out.println("originating address: " +// + (int) (sms.getOriginatingAddress().charAt(0)) + " " +// + (int) (sms.getOriginatingAddress().charAt(1))); + + assertTrue(sms.isReplace()); + assertEquals("\u0394@", sms.getOriginatingAddress()); + assertEquals(" ", sms.getMessageBody()); + assertTrue(sms.isMWIClearMessage()); + } + + @SmallTest + public void testCingularVoiceMail() throws Exception { + // "set MWI flag" + + String pdu = "07912180958750F84401800500C87020026195702B06040102000200"; + SmsMessage sms = SmsMessage.createFromPdu(HexDump.hexStringToByteArray(pdu)); + + assertTrue(sms.isMWISetMessage()); + assertTrue(sms.isMwiDontStore()); + + // "clear mwi flag" + + pdu = "07912180958750F84401800500C07020027160112B06040102000000"; + sms = SmsMessage.createFromPdu(HexDump.hexStringToByteArray(pdu)); + + assertTrue(sms.isMWIClearMessage()); + assertTrue(sms.isMwiDontStore()); + } + +// public void testTwo() throws Exception { +// // FIXME need an SMS-SUBMIT test +// +// System.out.println( +// "SMS SUBMIT: " + SmsMessage.getSubmitPdu(null, "+14155551212", "test", false)); +// } + + @SmallTest + public void testEmailGateway() throws Exception { + // email gateway sms test + String pdu = "07914151551512f204038105f300007011103164638a28e6f71b50c687db" + + "7076d9357eb7412f7a794e07cdeb6275794c07bde8e5391d247e93f3"; + + SmsMessage sms = SmsMessage.createFromPdu(HexDump.hexStringToByteArray(pdu)); + + assertEquals("+14155551212", sms.getServiceCenterAddress()); + assertTrue(sms.isEmail()); + assertEquals("foo@example.com", sms.getEmailFrom()); + assertEquals("foo@example.com", sms.getDisplayOriginatingAddress()); + assertEquals("test subject", sms.getPseudoSubject()); + assertEquals("test body", sms.getDisplayMessageBody()); + assertEquals("test body", sms.getEmailBody()); + + // email gateway sms test, including gsm extended character set. + pdu = "07914151551512f204038105f400007011103105458a29e6f71b50c687db" + + "7076d9357eb741af0d0a442fcfe9c23739bfe16d289bdee6b5f1813629"; + + sms = SmsMessage.createFromPdu(HexDump.hexStringToByteArray(pdu)); + + assertEquals("+14155551212", sms.getServiceCenterAddress()); + assertTrue(sms.isEmail()); + assertEquals("foo@example.com", sms.getDisplayOriginatingAddress()); + assertEquals("foo@example.com", sms.getEmailFrom()); + assertEquals("{ testBody[^~\\] }", sms.getDisplayMessageBody()); + assertEquals("{ testBody[^~\\] }", sms.getEmailBody()); + } + + @SmallTest + public void testExtendedCharacterTable() throws Exception { + String pdu = "07914151551512f2040B916105551511f100006080615131728A44D4F29C0E2" + + "AE3E96537B94C068DD16179784C2FCB41F4B0985D06B958ADD00FB0E94536AF9749" + + "74DA6D281BA00E95E26D509B946FC3DBF87A25D56A04"; + + SmsMessage sms = SmsMessage.createFromPdu(HexDump.hexStringToByteArray(pdu)); + + assertEquals("+14155551212", sms.getServiceCenterAddress()); + assertEquals("+16505551111", sms.getOriginatingAddress()); + assertEquals("Test extended character table .,-!?@~_\\/&\"';^|:()<{}>[]=%*+#", sms.getMessageBody()); + } + + @SmallTest + public void testDecode() throws Exception { + byte[] septets = new byte[(7 * 128 + 7) / 8]; + + int bitOffset = 0; + + for (int i = 0; i < 128; i++) { + int v; + if (i == 0x1b) { + // extended escape char + v = 0; + } else { + v = i; + } + + int byteOffset = bitOffset / 8; + int shift = bitOffset % 8; + + septets[byteOffset] |= v << shift; + + if (shift > 1) { + septets[byteOffset + 1] = (byte) (v >> (8 - shift)); + } + + bitOffset += 7; + } + + String decoded = GsmAlphabet.gsm7BitPackedToString(septets, 0, 128); + byte[] reEncoded = GsmAlphabet.stringToGsm7BitPacked(decoded); + + // reEncoded has the count septets byte at the front + assertEquals(reEncoded.length, septets.length + 1); + + for (int i = 0; i < septets.length; i++) { + assertEquals(reEncoded[i + 1], septets[i]); + } + } +} diff --git a/tests/AndroidTests/src/com/android/unit_tests/SSLTest.java b/tests/AndroidTests/src/com/android/unit_tests/SSLTest.java new file mode 100644 index 0000000000000000000000000000000000000000..94811801b55ebcbd67513a60d68d12619e0f9de9 --- /dev/null +++ b/tests/AndroidTests/src/com/android/unit_tests/SSLTest.java @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2006 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.android.unit_tests; + +import android.net.SSLCertificateSocketFactory; +import android.test.suitebuilder.annotation.Suppress; +import junit.framework.TestCase; + +import java.io.InputStream; +import java.io.OutputStream; +import java.net.Socket; + +//This test relies on network resources. +@Suppress +public class SSLTest extends TestCase { + public void testCertificate() throws Exception { + // test www.fortify.net/sslcheck.html + Socket ssl = SSLCertificateSocketFactory.getDefault().createSocket("www.fortify.net",443); + assertNotNull(ssl); + + OutputStream out = ssl.getOutputStream(); + assertNotNull(out); + + InputStream in = ssl.getInputStream(); + assertNotNull(in); + + String get = "GET /sslcheck.html HTTP/1.1\r\nHost: 68.178.217.222\r\n\r\n"; + + // System.out.println("going for write..."); + out.write(get.getBytes()); + + byte[] b = new byte[1024]; + // System.out.println("going for read..."); + int ret = in.read(b); + + // System.out.println(new String(b)); + } +} diff --git a/tests/AndroidTests/src/com/android/unit_tests/SafeSaxTest.java b/tests/AndroidTests/src/com/android/unit_tests/SafeSaxTest.java new file mode 100644 index 0000000000000000000000000000000000000000..d488a29bdf02ace92f6cbc6f8a42b5d7c42308db --- /dev/null +++ b/tests/AndroidTests/src/com/android/unit_tests/SafeSaxTest.java @@ -0,0 +1,539 @@ +/* + * Copyright (C) 2007 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.android.unit_tests; + +import android.graphics.Bitmap; +import android.sax.Element; +import android.sax.ElementListener; +import android.sax.EndTextElementListener; +import android.sax.RootElement; +import android.sax.StartElementListener; +import android.sax.TextElementListener; +import android.test.AndroidTestCase; +import android.test.suitebuilder.annotation.LargeTest; +import android.test.suitebuilder.annotation.SmallTest; +import android.text.format.Time; +import android.util.Log; +import android.util.Xml; +import com.android.internal.util.XmlUtils; +import org.xml.sax.Attributes; +import org.xml.sax.ContentHandler; +import org.xml.sax.SAXException; +import org.xml.sax.helpers.DefaultHandler; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; + +public class SafeSaxTest extends AndroidTestCase { + + private static final String TAG = SafeSaxTest.class.getName(); + + private static final String ATOM_NAMESPACE = "http://www.w3.org/2005/Atom"; + private static final String MEDIA_NAMESPACE = "http://search.yahoo.com/mrss/"; + private static final String YOUTUBE_NAMESPACE = "http://gdata.youtube.com/schemas/2007"; + private static final String GDATA_NAMESPACE = "http://schemas.google.com/g/2005"; + + private static class ElementCounter implements ElementListener { + int starts = 0; + int ends = 0; + + public void start(Attributes attributes) { + starts++; + } + + public void end() { + ends++; + } + } + + private static class TextElementCounter implements TextElementListener { + int starts = 0; + String bodies = ""; + + public void start(Attributes attributes) { + starts++; + } + + public void end(String body) { + this.bodies += body; + } + } + + @SmallTest + public void testListener() throws Exception { + String xml = "\n" + + "\n" + + "a\n" + + "\n" + + "\n" + + "b\n" + + "\n" + + "\n"; + + RootElement root = new RootElement(ATOM_NAMESPACE, "feed"); + Element entry = root.requireChild(ATOM_NAMESPACE, "entry"); + Element id = entry.requireChild(ATOM_NAMESPACE, "id"); + + ElementCounter rootCounter = new ElementCounter(); + ElementCounter entryCounter = new ElementCounter(); + TextElementCounter idCounter = new TextElementCounter(); + + root.setElementListener(rootCounter); + entry.setElementListener(entryCounter); + id.setTextElementListener(idCounter); + + Xml.parse(xml, root.getContentHandler()); + + assertEquals(1, rootCounter.starts); + assertEquals(1, rootCounter.ends); + assertEquals(2, entryCounter.starts); + assertEquals(2, entryCounter.ends); + assertEquals(2, idCounter.starts); + assertEquals("ab", idCounter.bodies); + } + + @SmallTest + public void testMissingRequiredChild() throws Exception { + String xml = ""; + RootElement root = new RootElement("feed"); + root.requireChild("entry"); + + try { + Xml.parse(xml, root.getContentHandler()); + fail("expected exception not thrown"); + } catch (SAXException e) { + // Expected. + } + } + + @SmallTest + public void testMixedContent() throws Exception { + String xml = ""; + + RootElement root = new RootElement("feed"); + root.setEndTextElementListener(new EndTextElementListener() { + public void end(String body) { + } + }); + + try { + Xml.parse(xml, root.getContentHandler()); + fail("expected exception not thrown"); + } catch (SAXException e) { + // Expected. + } + } + + @LargeTest + public void testPerformance() throws Exception { + InputStream in = mContext.getResources().openRawResource(R.raw.youtube); + byte[] xmlBytes; + try { + ByteArrayOutputStream out = new ByteArrayOutputStream(); + byte[] buffer = new byte[1024]; + int length; + while ((length = in.read(buffer)) != -1) { + out.write(buffer, 0, length); + } + xmlBytes = out.toByteArray(); + } finally { + in.close(); + } + + Log.i("***", "File size: " + (xmlBytes.length / 1024) + "k"); + + VideoAdapter videoAdapter = new VideoAdapter(); + ContentHandler handler = newContentHandler(videoAdapter); + for (int i = 0; i < 2; i++) { + pureSaxTest(new ByteArrayInputStream(xmlBytes)); + saxyModelTest(new ByteArrayInputStream(xmlBytes)); + saxyModelTest(new ByteArrayInputStream(xmlBytes), handler); + } + } + + private static void pureSaxTest(InputStream inputStream) throws IOException, SAXException { + long start = System.currentTimeMillis(); + VideoAdapter videoAdapter = new VideoAdapter(); + Xml.parse(inputStream, Xml.Encoding.UTF_8, new YouTubeContentHandler(videoAdapter)); + long elapsed = System.currentTimeMillis() - start; + Log.i(TAG, "pure SAX: " + elapsed + "ms"); + } + + private static void saxyModelTest(InputStream inputStream) throws IOException, SAXException { + long start = System.currentTimeMillis(); + VideoAdapter videoAdapter = new VideoAdapter(); + Xml.parse(inputStream, Xml.Encoding.UTF_8, newContentHandler(videoAdapter)); + long elapsed = System.currentTimeMillis() - start; + Log.i(TAG, "Saxy Model: " + elapsed + "ms"); + } + + private static void saxyModelTest(InputStream inputStream, ContentHandler contentHandler) + throws IOException, SAXException { + long start = System.currentTimeMillis(); + Xml.parse(inputStream, Xml.Encoding.UTF_8, contentHandler); + long elapsed = System.currentTimeMillis() - start; + Log.i(TAG, "Saxy Model (preloaded): " + elapsed + "ms"); + } + + private static class VideoAdapter { + public void addVideo(YouTubeVideo video) { + } + } + + private static ContentHandler newContentHandler(VideoAdapter videoAdapter) { + return new HandlerFactory().newContentHandler(videoAdapter); + } + + private static class HandlerFactory { + YouTubeVideo video; + + public ContentHandler newContentHandler(VideoAdapter videoAdapter) { + RootElement root = new RootElement(ATOM_NAMESPACE, "feed"); + + final VideoListener videoListener = new VideoListener(videoAdapter); + + Element entry = root.getChild(ATOM_NAMESPACE, "entry"); + + entry.setElementListener(videoListener); + + entry.getChild(ATOM_NAMESPACE, "id") + .setEndTextElementListener(new EndTextElementListener() { + public void end(String body) { + video.videoId = body; + } + }); + + entry.getChild(ATOM_NAMESPACE, "published") + .setEndTextElementListener(new EndTextElementListener() { + public void end(String body) { + // TODO(tomtaylor): programmatically get the timezone + video.dateAdded = new Time(Time.TIMEZONE_UTC); + video.dateAdded.parse3339(body); + } + }); + + Element author = entry.getChild(ATOM_NAMESPACE, "author"); + author.getChild(ATOM_NAMESPACE, "name") + .setEndTextElementListener(new EndTextElementListener() { + public void end(String body) { + video.authorName = body; + } + }); + + Element mediaGroup = entry.getChild(MEDIA_NAMESPACE, "group"); + + mediaGroup.getChild(MEDIA_NAMESPACE, "thumbnail") + .setStartElementListener(new StartElementListener() { + public void start(Attributes attributes) { + String url = attributes.getValue("", "url"); + if (video.thumbnailUrl == null && url.length() > 0) { + video.thumbnailUrl = url; + } + } + }); + + mediaGroup.getChild(MEDIA_NAMESPACE, "content") + .setStartElementListener(new StartElementListener() { + public void start(Attributes attributes) { + String url = attributes.getValue("", "url"); + if (url != null) { + video.videoUrl = url; + } + } + }); + + mediaGroup.getChild(MEDIA_NAMESPACE, "player") + .setStartElementListener(new StartElementListener() { + public void start(Attributes attributes) { + String url = attributes.getValue("", "url"); + if (url != null) { + video.playbackUrl = url; + } + } + }); + + mediaGroup.getChild(MEDIA_NAMESPACE, "title") + .setEndTextElementListener(new EndTextElementListener() { + public void end(String body) { + video.title = body; + } + }); + + mediaGroup.getChild(MEDIA_NAMESPACE, "category") + .setEndTextElementListener(new EndTextElementListener() { + public void end(String body) { + video.category = body; + } + }); + + mediaGroup.getChild(MEDIA_NAMESPACE, "description") + .setEndTextElementListener(new EndTextElementListener() { + public void end(String body) { + video.description = body; + } + }); + + mediaGroup.getChild(MEDIA_NAMESPACE, "keywords") + .setEndTextElementListener(new EndTextElementListener() { + public void end(String body) { + video.tags = body; + } + }); + + mediaGroup.getChild(YOUTUBE_NAMESPACE, "duration") + .setStartElementListener(new StartElementListener() { + public void start(Attributes attributes) { + String seconds = attributes.getValue("", "seconds"); + video.lengthInSeconds + = XmlUtils.convertValueToInt(seconds, 0); + } + }); + + mediaGroup.getChild(YOUTUBE_NAMESPACE, "statistics") + .setStartElementListener(new StartElementListener() { + public void start(Attributes attributes) { + String viewCount = attributes.getValue("", "viewCount"); + video.viewCount + = XmlUtils.convertValueToInt(viewCount, 0); + } + }); + + entry.getChild(GDATA_NAMESPACE, "rating") + .setStartElementListener(new StartElementListener() { + public void start(Attributes attributes) { + String average = attributes.getValue("", "average"); + video.rating = average == null + ? 0.0f : Float.parseFloat(average); + } + }); + + return root.getContentHandler(); + } + + class VideoListener implements ElementListener { + + final VideoAdapter videoAdapter; + + public VideoListener(VideoAdapter videoAdapter) { + this.videoAdapter = videoAdapter; + } + + public void start(Attributes attributes) { + video = new YouTubeVideo(); + } + + public void end() { + videoAdapter.addVideo(video); + video = null; + } + } + } + + private static class YouTubeContentHandler extends DefaultHandler { + + final VideoAdapter videoAdapter; + + YouTubeVideo video = null; + StringBuilder builder = null; + + public YouTubeContentHandler(VideoAdapter videoAdapter) { + this.videoAdapter = videoAdapter; + } + + @Override + public void startElement(String uri, String localName, String qName, + Attributes attributes) throws SAXException { + if (uri.equals(ATOM_NAMESPACE)) { + if (localName.equals("entry")) { + video = new YouTubeVideo(); + return; + } + + if (video == null) { + return; + } + + if (!localName.equals("id") + && !localName.equals("published") + && !localName.equals("name")) { + return; + } + this.builder = new StringBuilder(); + return; + + } + + if (video == null) { + return; + } + + if (uri.equals(MEDIA_NAMESPACE)) { + if (localName.equals("thumbnail")) { + String url = attributes.getValue("", "url"); + if (video.thumbnailUrl == null && url.length() > 0) { + video.thumbnailUrl = url; + } + return; + } + + if (localName.equals("content")) { + String url = attributes.getValue("", "url"); + if (url != null) { + video.videoUrl = url; + } + return; + } + + if (localName.equals("player")) { + String url = attributes.getValue("", "url"); + if (url != null) { + video.playbackUrl = url; + } + return; + } + + if (localName.equals("title") + || localName.equals("category") + || localName.equals("description") + || localName.equals("keywords")) { + this.builder = new StringBuilder(); + return; + } + + return; + } + + if (uri.equals(YOUTUBE_NAMESPACE)) { + if (localName.equals("duration")) { + video.lengthInSeconds = XmlUtils.convertValueToInt( + attributes.getValue("", "seconds"), 0); + return; + } + + if (localName.equals("statistics")) { + video.viewCount = XmlUtils.convertValueToInt( + attributes.getValue("", "viewCount"), 0); + return; + } + + return; + } + + if (uri.equals(GDATA_NAMESPACE)) { + if (localName.equals("rating")) { + String average = attributes.getValue("", "average"); + video.rating = average == null + ? 0.0f : Float.parseFloat(average); + } + } + } + + @Override + public void characters(char text[], int start, int length) + throws SAXException { + if (builder != null) { + builder.append(text, start, length); + } + } + + String takeText() { + try { + return builder.toString(); + } finally { + builder = null; + } + } + + @Override + public void endElement(String uri, String localName, String qName) + throws SAXException { + if (video == null) { + return; + } + + if (uri.equals(ATOM_NAMESPACE)) { + if (localName.equals("published")) { + // TODO(tomtaylor): programmatically get the timezone + video.dateAdded = new Time(Time.TIMEZONE_UTC); + video.dateAdded.parse3339(takeText()); + return; + } + + if (localName.equals("name")) { + video.authorName = takeText(); + return; + } + + if (localName.equals("id")) { + video.videoId = takeText(); + return; + } + + if (localName.equals("entry")) { + // Add the video! + videoAdapter.addVideo(video); + video = null; + return; + } + + return; + } + + if (uri.equals(MEDIA_NAMESPACE)) { + if (localName.equals("description")) { + video.description = takeText(); + return; + } + + if (localName.equals("keywords")) { + video.tags = takeText(); + return; + } + + if (localName.equals("category")) { + video.category = takeText(); + return; + } + + if (localName.equals("title")) { + video.title = takeText(); + } + } + } + } + + private static class YouTubeVideo { + public String videoId; // the id used to lookup on YouTube + public String videoUrl; // the url to play the video + public String playbackUrl; // the url to share for users to play video + public String thumbnailUrl; // the url of the thumbnail image + public String title; + public Bitmap bitmap; // cached bitmap of the thumbnail + public int lengthInSeconds; + public int viewCount; // number of times the video has been viewed + public float rating; // ranges from 0.0 to 5.0 + public Boolean triedToLoadThumbnail; + public String authorName; + public Time dateAdded; + public String category; + public String tags; + public String description; + } +} + diff --git a/tests/AndroidTests/src/com/android/unit_tests/SearchManagerTest.java b/tests/AndroidTests/src/com/android/unit_tests/SearchManagerTest.java new file mode 100644 index 0000000000000000000000000000000000000000..09e3b0290a8bddf55bcb5512deebcfba4051a289 --- /dev/null +++ b/tests/AndroidTests/src/com/android/unit_tests/SearchManagerTest.java @@ -0,0 +1,542 @@ +/* + * Copyright (C) 2006 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.android.unit_tests; + +import com.android.unit_tests.activity.LocalActivity; + +import android.app.Activity; +import android.app.ISearchManager; +import android.app.SearchManager; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageManager; +import android.content.pm.ProviderInfo; +import android.content.pm.ResolveInfo; +import android.content.res.Resources; +import android.content.res.XmlResourceParser; +import android.os.ServiceManager; +import android.server.search.SearchableInfo; +import android.server.search.SearchableInfo.ActionKeyInfo; +import android.test.ActivityInstrumentationTestCase; +import android.test.MoreAsserts; +import android.test.mock.MockContext; +import android.test.mock.MockPackageManager; +import android.test.suitebuilder.annotation.LargeTest; +import android.test.suitebuilder.annotation.MediumTest; +import android.util.AndroidRuntimeException; +import android.view.KeyEvent; + +import java.util.ArrayList; +import java.util.List; + +/** + * To launch this test from the command line: + * + * adb shell am instrument -w \ + * -e class com.android.unit_tests.SearchManagerTest \ + * com.android.unit_tests/android.test.InstrumentationTestRunner + */ +public class SearchManagerTest extends ActivityInstrumentationTestCase { + + // If non-zero, enable a set of tests that start and stop the search manager. + // This is currently disabled because it's causing an unwanted jump from the unit test + // activity into the contacts activity. We'll put this back after we disable that jump. + private static final int TEST_SEARCH_START = 0; + + /* + * Bug list of test ideas. + * + * testSearchManagerInterfaceAvailable() + * Exercise the interface obtained + * + * testSearchManagerAvailable() + * Exercise the interface obtained + * + * testSearchManagerInvocations() + * FIX - make it work again + * stress test with a very long string + * + * SearchableInfo tests + * Mock the context so I can provide very specific input data + * Confirm OK with "zero" searchables + * Confirm "good" metadata read properly + * Confirm "bad" metadata skipped properly + * Confirm ordering of searchables + * Confirm "good" actionkeys + * confirm "bad" actionkeys are rejected + * confirm XML ordering enforced (will fail today - bug in SearchableInfo) + * findActionKey works + * getIcon works + * + * SearchManager tests + * confirm proper identification of "default" activity based on policy, not hardcoded contacts + * + * SearchBar tests + * Maybe have to do with framework / unittest runner - need instrumented activity? + * How can we unit test the suggestions content providers? + * Should I write unit tests for any of them? + * Test scenarios: + * type-BACK (cancel) + * type-GO (send) + * type-navigate-click (suggestion) + * type-action + * type-navigate-action (suggestion) + */ + + /** + * Local copy of activity context + */ + Context mContext; + + public SearchManagerTest() { + super("com.android.unit_tests", LocalActivity.class); + } + + /** + * Setup any common data for the upcoming tests. + */ + @Override + public void setUp() throws Exception { + super.setUp(); + + Activity testActivity = getActivity(); + mContext = (Context)testActivity; + } + + /** + * The goal of this test is to confirm that we can obtain + * a search manager interface. + */ + @MediumTest + public void testSearchManagerInterfaceAvailable() { + ISearchManager searchManager1 = ISearchManager.Stub.asInterface( + ServiceManager.getService(Context.SEARCH_SERVICE)); + assertNotNull(searchManager1); + } + + /** + * The goal of this test is to confirm that we can *only* obtain a search manager + * interface from an Activity context. + */ + @MediumTest + public void testSearchManagerContextRestrictions() { + SearchManager searchManager1 = (SearchManager) + mContext.getSystemService(Context.SEARCH_SERVICE); + assertNotNull(searchManager1); + + Context applicationContext = mContext.getApplicationContext(); + // this should fail, because you can't get a SearchManager from a non-Activity context + try { + applicationContext.getSystemService(Context.SEARCH_SERVICE); + assertFalse("Shouldn't retrieve SearchManager from a non-Activity context", true); + } catch (AndroidRuntimeException e) { + // happy here - we should catch this. + } + } + + /** + * The goal of this test is to confirm that we can obtain + * a search manager at any time, and that for any given context, + * it is a singleton. + */ + @LargeTest + public void testSearchManagerAvailable() { + SearchManager searchManager1 = (SearchManager) + mContext.getSystemService(Context.SEARCH_SERVICE); + assertNotNull(searchManager1); + SearchManager searchManager2 = (SearchManager) + mContext.getSystemService(Context.SEARCH_SERVICE); + assertNotNull(searchManager2); + assertSame( searchManager1, searchManager2 ); + } + + /** + * The goal of this test is to confirm that we can start and then + * stop a simple search. + */ + + @MediumTest + public void testSearchManagerInvocations() { + SearchManager searchManager = (SearchManager) + mContext.getSystemService(Context.SEARCH_SERVICE); + assertNotNull(searchManager); + + // TODO: make a real component name, or remove this need + final ComponentName cn = new ComponentName("", ""); + + if (TEST_SEARCH_START != 0) { + // These tests should simply run to completion w/o exceptions + searchManager.startSearch(null, false, cn, null, false); + searchManager.stopSearch(); + + searchManager.startSearch("", false, cn, null, false); + searchManager.stopSearch(); + + searchManager.startSearch("test search string", false, cn, null, false); + searchManager.stopSearch(); + + searchManager.startSearch("test search string", true, cn, null, false); + searchManager.stopSearch(); + } + } + + /** + * The goal of this test is to confirm proper operation of the + * SearchableInfo helper class. + * + * TODO: The metadata source needs to be mocked out because adding + * searchability metadata via this test is causing it to leak into the + * real system. So for now I'm just going to test for existence of the + * GoogleSearch app (which is searchable). + */ + @LargeTest + public void testSearchableGoogleSearch() { + // test basic array & hashmap + SearchableInfo.buildSearchableList(mContext); + + // test linkage from another activity + // TODO inject this via mocking into the package manager. + // TODO for now, just check for searchable GoogleSearch app (this isn't really a unit test) + ComponentName thisActivity = new ComponentName( + "com.android.googlesearch", + "com.android.googlesearch.GoogleSearch"); + + SearchableInfo si = SearchableInfo.getSearchableInfo(mContext, thisActivity); + assertNotNull(si); + assertTrue(si.mSearchable); + assertEquals(thisActivity, si.mSearchActivity); + + Context appContext = si.getActivityContext(mContext); + assertNotNull(appContext); + MoreAsserts.assertNotEqual(appContext, mContext); + assertEquals("Google Search", appContext.getString(si.getHintId())); + assertEquals("Google", appContext.getString(si.getLabelId())); + } + + /** + * Test that non-searchable activities return no searchable info (this would typically + * trigger the use of the default searchable e.g. contacts) + */ + @LargeTest + public void testNonSearchable() { + // test basic array & hashmap + SearchableInfo.buildSearchableList(mContext); + + // confirm that we return null for non-searchy activities + ComponentName nonActivity = new ComponentName( + "com.android.unit_tests", + "com.android.unit_tests.NO_SEARCH_ACTIVITY"); + SearchableInfo si = SearchableInfo.getSearchableInfo(mContext, nonActivity); + assertNull(si); + } + + /** + * This is an attempt to run the searchable info list with a mocked context. Here are some + * things I'd like to test. + * + * Confirm OK with "zero" searchables + * Confirm "good" metadata read properly + * Confirm "bad" metadata skipped properly + * Confirm ordering of searchables + * Confirm "good" actionkeys + * confirm "bad" actionkeys are rejected + * confirm XML ordering enforced (will fail today - bug in SearchableInfo) + * findActionKey works + * getIcon works + + */ + @LargeTest + public void testSearchableMocked() { + MyMockPackageManager mockPM = new MyMockPackageManager(mContext.getPackageManager()); + MyMockContext mockContext = new MyMockContext(mContext, mockPM); + ArrayList searchables; + int count; + + // build item list with real-world source data + mockPM.setSearchablesMode(MyMockPackageManager.SEARCHABLES_PASSTHROUGH); + SearchableInfo.buildSearchableList(mockContext); + // tests with "real" searchables (deprecate, this should be a unit test) + searchables = SearchableInfo.getSearchablesList(); + count = searchables.size(); + assertTrue(count >= 1); // this isn't really a unit test + checkSearchables(searchables); + + // build item list with mocked search data + // this round of tests confirms good operations with "zero" searchables found + // This should return either a null pointer or an empty list + mockPM.setSearchablesMode(MyMockPackageManager.SEARCHABLES_MOCK_ZERO); + SearchableInfo.buildSearchableList(mockContext); + searchables = SearchableInfo.getSearchablesList(); + if (searchables != null) { + count = searchables.size(); + assertTrue(count == 0); + } + } + + /** + * Generic health checker for an array of searchables. + * + * This is designed to pass for any semi-legal searchable, without knowing much about + * the format of the underlying data. It's fairly easy for a non-compliant application + * to provide meta-data that will pass here (e.g. a non-existent suggestions authority). + * + * @param searchables The list of searchables to examine. + */ + private void checkSearchables(ArrayList searchablesList) { + assertNotNull(searchablesList); + int count = searchablesList.size(); + for (int ii = 0; ii < count; ii++) { + SearchableInfo si = searchablesList.get(ii); + assertNotNull(si); + assertTrue(si.mSearchable); + assertTrue(si.getLabelId() != 0); // This must be a useable string + assertNotEmpty(si.mSearchActivity.getClassName()); + assertNotEmpty(si.mSearchActivity.getPackageName()); + if (si.getSuggestAuthority() != null) { + // The suggestion fields are largely optional, so we'll just confirm basic health + assertNotEmpty(si.getSuggestAuthority()); + assertNullOrNotEmpty(si.getSuggestPath()); + assertNullOrNotEmpty(si.getSuggestSelection()); + assertNullOrNotEmpty(si.getSuggestIntentAction()); + assertNullOrNotEmpty(si.getSuggestIntentData()); + } + /* Add a way to get the entire action key list, then explicitly test its elements */ + /* For now, test the most common action key (CALL) */ + ActionKeyInfo ai = si.findActionKey(KeyEvent.KEYCODE_CALL); + if (ai != null) { + assertEquals(ai.mKeyCode, KeyEvent.KEYCODE_CALL); + // one of these three fields must be non-null & non-empty + boolean m1 = (ai.mQueryActionMsg != null) && (ai.mQueryActionMsg.length() > 0); + boolean m2 = (ai.mSuggestActionMsg != null) && (ai.mSuggestActionMsg.length() > 0); + boolean m3 = (ai.mSuggestActionMsgColumn != null) && + (ai.mSuggestActionMsgColumn.length() > 0); + assertTrue(m1 || m2 || m3); + } + + /* + * Find ways to test these: + * + * private int mSearchMode + * private Drawable mIcon + */ + + /* + * Explicitly not tested here: + * + * Can be null, so not much to see: + * public String mSearchHint + * private String mZeroQueryBanner + * + * To be deprecated/removed, so don't bother: + * public boolean mFilterMode + * public boolean mQuickStart + * private boolean mIconResized + * private int mIconResizeWidth + * private int mIconResizeHeight + * + * All of these are "internal" working variables, not part of any contract + * private ActivityInfo mActivityInfo + * private Rect mTempRect + * private String mSuggestProviderPackage + * private String mCacheActivityContext + */ + } + } + + /** + * Combo assert for "string not null and not empty" + */ + private void assertNotEmpty(final String s) { + assertNotNull(s); + MoreAsserts.assertNotEqual(s, ""); + } + + /** + * Combo assert for "string null or (not null and not empty)" + */ + private void assertNullOrNotEmpty(final String s) { + if (s != null) { + MoreAsserts.assertNotEqual(s, ""); + } + } + + /** + * This is a mock for context. Used to perform a true unit test on SearchableInfo. + * + */ + private class MyMockContext extends MockContext { + + protected Context mRealContext; + protected PackageManager mPackageManager; + + /** + * Constructor. + * + * @param realContext Please pass in a real context for some pass-throughs to function. + */ + MyMockContext(Context realContext, PackageManager packageManager) { + mRealContext = realContext; + mPackageManager = packageManager; + } + + /** + * Resources. Pass through for now. + */ + @Override + public Resources getResources() { + return mRealContext.getResources(); + } + + /** + * Package manager. Pass through for now. + */ + @Override + public PackageManager getPackageManager() { + return mPackageManager; + } + + /** + * Package manager. Pass through for now. + */ + @Override + public Context createPackageContext(String packageName, int flags) + throws PackageManager.NameNotFoundException { + return mRealContext.createPackageContext(packageName, flags); + } + } + +/** + * This is a mock for package manager. Used to perform a true unit test on SearchableInfo. + * + */ + private class MyMockPackageManager extends MockPackageManager { + + public final static int SEARCHABLES_PASSTHROUGH = 0; + public final static int SEARCHABLES_MOCK_ZERO = 1; + public final static int SEARCHABLES_MOCK_ONEGOOD = 2; + public final static int SEARCHABLES_MOCK_ONEGOOD_ONEBAD = 3; + + protected PackageManager mRealPackageManager; + protected int mSearchablesMode; + + public MyMockPackageManager(PackageManager realPM) { + mRealPackageManager = realPM; + mSearchablesMode = SEARCHABLES_PASSTHROUGH; + } + + /** + * Set the mode for various tests. + */ + public void setSearchablesMode(int newMode) { + switch (newMode) { + case SEARCHABLES_PASSTHROUGH: + case SEARCHABLES_MOCK_ZERO: + mSearchablesMode = newMode; + break; + + default: + throw new UnsupportedOperationException(); + } + } + + /** + * Find activities that support a given intent. + * + * Retrieve all activities that can be performed for the given intent. + * + * @param intent The desired intent as per resolveActivity(). + * @param flags Additional option flags. The most important is + * MATCH_DEFAULT_ONLY, to limit the resolution to only + * those activities that support the CATEGORY_DEFAULT. + * + * @return A List containing one entry for each matching + * Activity. These are ordered from best to worst match -- that + * is, the first item in the list is what is returned by + * resolveActivity(). If there are no matching activities, an empty + * list is returned. + */ + @Override + public List queryIntentActivities(Intent intent, int flags) { + assertNotNull(intent); + assertEquals(intent.getAction(), Intent.ACTION_SEARCH); + switch (mSearchablesMode) { + case SEARCHABLES_PASSTHROUGH: + return mRealPackageManager.queryIntentActivities(intent, flags); + case SEARCHABLES_MOCK_ZERO: + return null; + default: + throw new UnsupportedOperationException(); + } + } + + /** + * Retrieve an XML file from a package. This is a low-level API used to + * retrieve XML meta data. + * + * @param packageName The name of the package that this xml is coming from. + * Can not be null. + * @param resid The resource identifier of the desired xml. Can not be 0. + * @param appInfo Overall information about packageName. This + * may be null, in which case the application information will be retrieved + * for you if needed; if you already have this information around, it can + * be much more efficient to supply it here. + * + * @return Returns an XmlPullParser allowing you to parse out the XML + * data. Returns null if the xml resource could not be found for any + * reason. + */ + @Override + public XmlResourceParser getXml(String packageName, int resid, ApplicationInfo appInfo) { + assertNotNull(packageName); + MoreAsserts.assertNotEqual(packageName, ""); + MoreAsserts.assertNotEqual(resid, 0); + switch (mSearchablesMode) { + case SEARCHABLES_PASSTHROUGH: + return mRealPackageManager.getXml(packageName, resid, appInfo); + case SEARCHABLES_MOCK_ZERO: + default: + throw new UnsupportedOperationException(); + } + } + + /** + * Find a single content provider by its base path name. + * + * @param name The name of the provider to find. + * @param flags Additional option flags. Currently should always be 0. + * + * @return ContentProviderInfo Information about the provider, if found, + * else null. + */ + @Override + public ProviderInfo resolveContentProvider(String name, int flags) { + assertNotNull(name); + MoreAsserts.assertNotEqual(name, ""); + assertEquals(flags, 0); + switch (mSearchablesMode) { + case SEARCHABLES_PASSTHROUGH: + return mRealPackageManager.resolveContentProvider(name, flags); + case SEARCHABLES_MOCK_ZERO: + default: + throw new UnsupportedOperationException(); + } + } + } +} + diff --git a/tests/AndroidTests/src/com/android/unit_tests/SerializationTest.java b/tests/AndroidTests/src/com/android/unit_tests/SerializationTest.java new file mode 100644 index 0000000000000000000000000000000000000000..4b6414433564617415224330cc448738f30076ab --- /dev/null +++ b/tests/AndroidTests/src/com/android/unit_tests/SerializationTest.java @@ -0,0 +1,47 @@ +/* + * 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.android.unit_tests; + +import junit.framework.TestCase; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.Serializable; +import android.test.suitebuilder.annotation.SmallTest; + +/** + * Tests serialization of user-level classes. + */ +public class SerializationTest extends TestCase { + + static class MySerializable implements Serializable {} + + @SmallTest + public void testSerialization() throws IOException, ClassNotFoundException { + ByteArrayOutputStream bout = new ByteArrayOutputStream(); + ObjectOutputStream oout = new ObjectOutputStream(bout); + oout.writeObject(new MySerializable()); + oout.close(); + + ByteArrayInputStream bin = new ByteArrayInputStream(bout.toByteArray()); + Object o = new ObjectInputStream(bin).readObject(); + assertTrue(o instanceof MySerializable); + } +} diff --git a/tests/AndroidTests/src/com/android/unit_tests/SettingsProviderTest.java b/tests/AndroidTests/src/com/android/unit_tests/SettingsProviderTest.java new file mode 100644 index 0000000000000000000000000000000000000000..8b1db9772d45c9d665bba7744b803dee594aa781 --- /dev/null +++ b/tests/AndroidTests/src/com/android/unit_tests/SettingsProviderTest.java @@ -0,0 +1,147 @@ +/* + * 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.android.unit_tests; + +import android.content.ContentResolver; +import android.content.ContentUris; +import android.content.ContentValues; +import android.content.Intent; +import android.database.Cursor; +import android.net.Uri; +import android.provider.Settings; +import android.test.AndroidTestCase; +import android.test.suitebuilder.annotation.MediumTest; + +/** Unit test for SettingsProvider. */ +public class SettingsProviderTest extends AndroidTestCase { + @MediumTest + public void testNameValueCache() { + ContentResolver r = getContext().getContentResolver(); + Settings.Gservices.putString(r, "test_service", "Value"); + assertEquals("Value", Settings.Gservices.getString(r, "test_service")); + + // Make sure the value can be overwritten. + Settings.Gservices.putString(r, "test_service", "New"); + assertEquals("New", Settings.Gservices.getString(r, "test_service")); + + // Also that delete works. + assertEquals(1, r.delete(Settings.Gservices.getUriFor("test_service"), null, null)); + assertEquals(null, Settings.Gservices.getString(r, "test_service")); + + // Try all the same things in the System table + Settings.System.putString(r, "test_setting", "Value"); + assertEquals("Value", Settings.System.getString(r, "test_setting")); + + Settings.System.putString(r, "test_setting", "New"); + assertEquals("New", Settings.System.getString(r, "test_setting")); + + assertEquals(1, r.delete(Settings.System.getUriFor("test_setting"), null, null)); + assertEquals(null, Settings.System.getString(r, "test_setting")); + } + + @MediumTest + public void testRowNameContentUri() { + ContentResolver r = getContext().getContentResolver(); + + assertEquals("content://settings/system/test_setting", + Settings.System.getUriFor("test_setting").toString()); + assertEquals("content://settings/gservices/test_service", + Settings.Gservices.getUriFor("test_service").toString()); + + // These tables use the row name (not ID) as their content URI. + Uri tables[] = { Settings.System.CONTENT_URI, Settings.Gservices.CONTENT_URI }; + for (Uri table : tables) { + ContentValues v = new ContentValues(); + v.put(Settings.System.NAME, "test_key"); + v.put(Settings.System.VALUE, "Test"); + Uri uri = r.insert(table, v); + assertEquals(table.toString() + "/test_key", uri.toString()); + + // Query with a specific URI and no WHERE clause succeeds. + Cursor c = r.query(uri, null, null, null, null); + try { + assertTrue(c.moveToNext()); + assertEquals("test_key", c.getString(c.getColumnIndex(Settings.System.NAME))); + assertEquals("Test", c.getString(c.getColumnIndex(Settings.System.VALUE))); + assertFalse(c.moveToNext()); + } finally { + c.close(); + } + + // Query with a specific URI and a WHERE clause fails. + try { + r.query(uri, null, "1", null, null); + fail("UnsupportedOperationException expected"); + } catch (UnsupportedOperationException e) { + if (!e.toString().contains("WHERE clause")) throw e; + } + + // Query with a tablewide URI and a WHERE clause succeeds. + c = r.query(table, null, "name='test_key'", null, null); + try { + assertTrue(c.moveToNext()); + assertEquals("test_key", c.getString(c.getColumnIndex(Settings.System.NAME))); + assertEquals("Test", c.getString(c.getColumnIndex(Settings.System.VALUE))); + assertFalse(c.moveToNext()); + } finally { + c.close(); + } + + v = new ContentValues(); + v.put(Settings.System.VALUE, "Toast"); + assertEquals(1, r.update(uri, v, null, null)); + + c = r.query(uri, null, null, null, null); + try { + assertTrue(c.moveToNext()); + assertEquals("test_key", c.getString(c.getColumnIndex(Settings.System.NAME))); + assertEquals("Toast", c.getString(c.getColumnIndex(Settings.System.VALUE))); + assertFalse(c.moveToNext()); + } finally { + c.close(); + } + + assertEquals(1, r.delete(uri, null, null)); + } + + assertEquals(null, Settings.System.getString(r, "test_key")); + assertEquals(null, Settings.Gservices.getString(r, "test_key")); + } + + @MediumTest + public void testRowNumberContentUri() { + ContentResolver r = getContext().getContentResolver(); + + // The bookmarks table (and everything else) uses standard row number content URIs. + Uri uri = Settings.Bookmarks.add(r, new Intent("TEST"), + "Test Title", "Test Folder", '*', 123); + + assertTrue(ContentUris.parseId(uri) > 0); + + assertEquals("TEST", Settings.Bookmarks.getIntentForShortcut(r, '*').getAction()); + + ContentValues v = new ContentValues(); + v.put(Settings.Bookmarks.INTENT, "#Intent;action=TOAST;end"); + assertEquals(1, r.update(uri, v, null, null)); + + assertEquals("TOAST", Settings.Bookmarks.getIntentForShortcut(r, '*').getAction()); + + assertEquals(1, r.delete(uri, null, null)); + + assertEquals(null, Settings.Bookmarks.getIntentForShortcut(r, '*')); + } +} diff --git a/tests/AndroidTests/src/com/android/unit_tests/SimplePullParserTest.java b/tests/AndroidTests/src/com/android/unit_tests/SimplePullParserTest.java new file mode 100644 index 0000000000000000000000000000000000000000..9758298ff48b57c342a6bf4175e3fa9712d44b3d --- /dev/null +++ b/tests/AndroidTests/src/com/android/unit_tests/SimplePullParserTest.java @@ -0,0 +1,132 @@ +/* + * Copyright (C) 2007 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.android.unit_tests; + +import com.google.android.util.SimplePullParser; +import junit.framework.TestCase; +import android.test.suitebuilder.annotation.SmallTest; + +public class SimplePullParserTest extends TestCase { + @SmallTest + public void testTwoLevels() throws Exception { + String xml = "" + + "\n" + + " \n" + + " \n" + + ""; + SimplePullParser parser = new SimplePullParser(xml); + int depth0 = parser.getDepth(); + assertEquals(0, depth0); + assertEquals("top", parser.nextTag(depth0)); + assertEquals(1, parser.getIntAttribute(null, "a")); + assertEquals("hello", parser.getStringAttribute(null, "b")); + + int depth1 = parser.getDepth(); + assertEquals(1, depth1); + assertEquals("next", parser.nextTag(depth1)); + assertEquals(2, parser.getIntAttribute(null, "c")); + assertEquals("there", parser.getStringAttribute(null, "d")); + assertEquals("next", parser.nextTag(depth1)); + assertEquals(3, parser.getIntAttribute(null, "c")); + assertEquals("bye", parser.getStringAttribute(null, "d")); + assertNull(parser.nextTag(depth1)); + + assertNull(parser.nextTag(depth0)); + } + + @SmallTest + public void testAttributes() throws Exception { + String xml = ""; + SimplePullParser parser = new SimplePullParser(xml); + int depth = parser.getDepth(); + parser.nextTag(depth); + + assertEquals(2, parser.numAttributes()); + assertEquals("a", parser.getAttributeName(0)); + assertEquals("b", parser.getAttributeName(1)); + + assertEquals(1, parser.getIntAttribute(null, "a")); + assertEquals(5, parser.getIntAttribute(null, "c", 5)); + assertEquals("hello", parser.getStringAttribute(null, "b")); + assertEquals("not", parser.getStringAttribute(null, "d", "not")); + } + + @SmallTest + public void testRecovery() throws Exception { + String xml = "" + + "\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + ""; + SimplePullParser parser = new SimplePullParser(xml); + assertEquals(0, parser.getDepth()); + assertEquals("top", parser.nextTag(0)); + assertEquals(1, parser.getDepth()); + assertEquals("middle", parser.nextTag(1)); + assertEquals(2, parser.getDepth()); + assertEquals("inner", parser.nextTag(2)); + // Now skip some elements. + assertEquals("middle2", parser.nextTag(1)); + } + + @SmallTest + public void testCdata() throws Exception { + StringBuilder cdataBuilder; + String xml = "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + ""; + SimplePullParser parser = new SimplePullParser(xml); + assertEquals("top", parser.nextTag(0)); + + // We can ignore cdata by not passing a cdata builder. + assertEquals("next0", parser.nextTag(1)); + + // We can get the most recent cdata by passing an empty cdata builder. + cdataBuilder = new StringBuilder(); + assertSame(SimplePullParser.TEXT_TAG, parser.nextTagOrText(1, cdataBuilder)); + assertEquals("data1", cdataBuilder.toString()); + assertEquals("next1", parser.nextTag(1)); + + // We can join multiple cdatas by reusing a builder. + cdataBuilder = new StringBuilder(); + assertSame(SimplePullParser.TEXT_TAG, parser.nextTagOrText(1, cdataBuilder)); + assertEquals("next2", parser.nextTag(1)); + assertSame(SimplePullParser.TEXT_TAG, parser.nextTagOrText(1, cdataBuilder)); + assertEquals("data2data3", cdataBuilder.toString()); + assertEquals("next3", parser.nextTag(1)); + + // We can read all of the remaining cdata while ignoring any elements. + cdataBuilder = new StringBuilder(); + parser.readRemainingText(1, cdataBuilder); + assertEquals("data4data5", cdataBuilder.toString()); + } +} diff --git a/tests/AndroidTests/src/com/android/unit_tests/SmsProviderTest.java b/tests/AndroidTests/src/com/android/unit_tests/SmsProviderTest.java new file mode 100644 index 0000000000000000000000000000000000000000..0e2f0c54619ab1636240bcd2f246169a3e74378d --- /dev/null +++ b/tests/AndroidTests/src/com/android/unit_tests/SmsProviderTest.java @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2006 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.android.unit_tests; + +import android.content.ContentResolver; +import android.content.ContentValues; +import android.database.Cursor; +import android.net.Uri; +import android.provider.Telephony.Sms; +import android.test.AndroidTestCase; +import android.test.suitebuilder.annotation.LargeTest; + +import java.util.GregorianCalendar; + +public class SmsProviderTest extends AndroidTestCase { + + @LargeTest + public void testProvider() throws Exception { + // This test does the following + // 1. Insert 10 messages from the same number at different times. + // + // . Delete the messages and make sure that they were deleted. + + long now = System.currentTimeMillis(); + + Uri[] urls = new Uri[10]; + String[] dates = new String[]{ + Long.toString(new GregorianCalendar(1970, 1, 1, 0, 0, 0).getTimeInMillis()), + Long.toString(new GregorianCalendar(1971, 2, 13, 16, 35, 3).getTimeInMillis()), + Long.toString(new GregorianCalendar(1978, 10, 22, 0, 1, 0).getTimeInMillis()), + Long.toString(new GregorianCalendar(1980, 1, 11, 10, 22, 30).getTimeInMillis()), + Long.toString(now - (5 * 24 * 60 * 60 * 1000)), + Long.toString(now - (2 * 24 * 60 * 60 * 1000)), + Long.toString(now - (5 * 60 * 60 * 1000)), + Long.toString(now - (30 * 60 * 1000)), + Long.toString(now - (5 * 60 * 1000)), + Long.toString(now) + }; + + ContentValues map = new ContentValues(); + map.put("address", "+15045551337"); + map.put("read", 0); + + ContentResolver contentResolver = mContext.getContentResolver(); + + for (int i = 0; i < urls.length; i++) { + map.put("body", "Test " + i + " !"); + map.put("date", dates[i]); + urls[i] = contentResolver.insert(Sms.Inbox.CONTENT_URI, map); + assertNotNull(urls[i]); + } + + Cursor c = contentResolver.query(Sms.Inbox.CONTENT_URI, null, null, null, "date"); + + //DatabaseUtils.dumpCursor(c); + + for (Uri url : urls) { + int count = contentResolver.delete(url, null, null); + assertEquals(1, count); + } + } +} diff --git a/tests/AndroidTests/src/com/android/unit_tests/SpannedTest.java b/tests/AndroidTests/src/com/android/unit_tests/SpannedTest.java new file mode 100644 index 0000000000000000000000000000000000000000..9e3f483fe179f99185091706ace81b6cb25d18e1 --- /dev/null +++ b/tests/AndroidTests/src/com/android/unit_tests/SpannedTest.java @@ -0,0 +1,187 @@ +/* + * 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.android.unit_tests; + +import android.graphics.Typeface; +import android.os.Parcel; +import android.test.suitebuilder.annotation.SmallTest; +import android.text.*; +import android.text.style.*; +import android.util.Log; + +import junit.framework.TestCase; + +/** + * SpannedTest tests some features of Spanned + */ +public class SpannedTest extends TestCase { + private int mExpect; + + @SmallTest + public void testSpannableString() throws Exception { + checkPriority(new SpannableString("the quick brown fox")); + } + + @SmallTest + public void testSpannableStringBuilder() throws Exception { + checkPriority2(new SpannableStringBuilder("the quick brown fox")); + } + + @SmallTest + public void testAppend() throws Exception { + Object o = new Object(); + SpannableString ss = new SpannableString("Test"); + ss.setSpan(o, 0, ss.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); + + SpannableStringBuilder ssb = new SpannableStringBuilder(); + ssb.append(ss); + assertEquals(0, ssb.getSpanStart(o)); + assertEquals(4, ssb.getSpanEnd(o)); + assertEquals(1, ssb.getSpans(0, 4, Object.class).length); + + ssb.insert(0, ss); + assertEquals(4, ssb.getSpanStart(o)); + assertEquals(8, ssb.getSpanEnd(o)); + assertEquals(0, ssb.getSpans(0, 4, Object.class).length); + assertEquals(1, ssb.getSpans(4, 8, Object.class).length); + } + + @SmallTest + public void testWrapParcel() { + SpannableString s = new SpannableString("Hello there world"); + CharacterStyle mark = new StyleSpan(Typeface.BOLD); + s.setSpan(mark, 1, 2, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); + s.setSpan(CharacterStyle.wrap(mark), 3, 7, + Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); + s.setSpan(new TextAppearanceSpan("mono", 0, -1, null, null), 7, 8, + Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); + s.setSpan(CharacterStyle.wrap(new TypefaceSpan("mono")), 8, 9, + Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); + + Parcel p = Parcel.obtain(); + TextUtils.writeToParcel(s, p, 0); + p.setDataPosition(0); + + Spanned s2 = (Spanned) TextUtils.CHAR_SEQUENCE_CREATOR. + createFromParcel(p); + StyleSpan[] style; + + style = s2.getSpans(1, 2, StyleSpan.class); + assertEquals(1, style.length); + assertEquals(1, s2.getSpanStart(style[0])); + assertEquals(2, s2.getSpanEnd(style[0])); + + style = s2.getSpans(3, 7, StyleSpan.class); + assertEquals(1, style.length); + assertEquals(3, s2.getSpanStart(style[0])); + assertEquals(7, s2.getSpanEnd(style[0])); + + TextAppearanceSpan[] appearance = s2.getSpans(7, 8, + TextAppearanceSpan.class); + assertEquals(1, appearance.length); + assertEquals(7, s2.getSpanStart(appearance[0])); + assertEquals(8, s2.getSpanEnd(appearance[0])); + + TypefaceSpan[] tf = s2.getSpans(8, 9, TypefaceSpan.class); + assertEquals(1, tf.length); + assertEquals(8, s2.getSpanStart(tf[0])); + assertEquals(9, s2.getSpanEnd(tf[0])); + } + + private void checkPriority(Spannable s) { + s.setSpan(new Object(), 0, 1, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE | + (5 << Spannable.SPAN_PRIORITY_SHIFT)); + s.setSpan(new Object(), 0, 1, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE | + (10 << Spannable.SPAN_PRIORITY_SHIFT)); + s.setSpan(new Object(), 0, 1, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE | + (0 << Spannable.SPAN_PRIORITY_SHIFT)); + s.setSpan(new Object(), 0, 1, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE | + (15 << Spannable.SPAN_PRIORITY_SHIFT)); + s.setSpan(new Object(), 0, 1, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE | + (3 << Spannable.SPAN_PRIORITY_SHIFT)); + s.setSpan(new Object(), 0, 1, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE | + (6 << Spannable.SPAN_PRIORITY_SHIFT)); + s.setSpan(new Object(), 0, 1, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE | + (0 << Spannable.SPAN_PRIORITY_SHIFT)); + + Object[] spans = s.getSpans(0, s.length(), Object.class); + + for (int i = 0; i < spans.length - 1; i++) { + assertEquals((s.getSpanFlags(spans[i]) & Spanned.SPAN_PRIORITY) >= + (s.getSpanFlags(spans[i + 1]) & Spanned.SPAN_PRIORITY), + true); + } + + mExpect = 0; + + s.setSpan(new Watcher(2), 0, s.length(), + Spannable.SPAN_INCLUSIVE_INCLUSIVE | + (2 << Spannable.SPAN_PRIORITY_SHIFT)); + s.setSpan(new Watcher(4), 0, s.length(), + Spannable.SPAN_INCLUSIVE_INCLUSIVE | + (4 << Spannable.SPAN_PRIORITY_SHIFT)); + s.setSpan(new Watcher(1), 0, s.length(), + Spannable.SPAN_INCLUSIVE_INCLUSIVE | + (1 << Spannable.SPAN_PRIORITY_SHIFT)); + s.setSpan(new Watcher(3), 0, s.length(), + Spannable.SPAN_INCLUSIVE_INCLUSIVE | + (3 << Spannable.SPAN_PRIORITY_SHIFT)); + + mExpect = 4; + s.setSpan(new Object(), 0, 1, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); + assertEquals(mExpect, 0); + } + + private void checkPriority2(SpannableStringBuilder ssb) { + checkPriority(ssb); + + mExpect = 4; + ssb.insert(3, "something"); + assertEquals(mExpect, 0); + } + + private class Watcher implements SpanWatcher, TextWatcher { + private int mSequence; + + public Watcher(int sequence) { + mSequence = sequence; + } + + public void onSpanChanged(Spannable b, Object o, int s, int e, + int st, int en) { } + public void onSpanRemoved(Spannable b, Object o, int s, int e) { } + + public void onSpanAdded(Spannable b, Object o, int s, int e) { + if (mExpect != 0) { + assertEquals(mSequence, mExpect); + mExpect = mSequence - 1; + } + } + + public void beforeTextChanged(CharSequence s, int start, int count, + int after) { } + public void onTextChanged(CharSequence s, int start, int before, + int count) { + if (mExpect != 0) { + assertEquals(mSequence, mExpect); + mExpect = mSequence - 1; + } + } + + public void afterTextChanged(Editable s) { } + } +} diff --git a/tests/AndroidTests/src/com/android/unit_tests/StringTest.java b/tests/AndroidTests/src/com/android/unit_tests/StringTest.java new file mode 100644 index 0000000000000000000000000000000000000000..dc40a0af9326581489572f5c83da96d827fd8505 --- /dev/null +++ b/tests/AndroidTests/src/com/android/unit_tests/StringTest.java @@ -0,0 +1,951 @@ +/* + * Copyright (C) 2007 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.android.unit_tests; + +import java.util.Locale; + +import android.test.PerformanceTestBase; +import android.test.PerformanceTestCase; + +public class StringTest extends PerformanceTestBase { + public static final int ITERATIONS = 1000; + public static final String STATIC_STRING_01 = "Hello Android"; + public static final String STATIC_STRING_02 = + "Remember, today is the tomorrow you worried about yesterday"; + public static final char[] STATIC_CHAR_ARRAY = + {'N', 'A', 'N', 'D', 'R', 'O', 'I', 'D'}; + public static StringBuffer STATIC_SBUF = new StringBuffer(STATIC_STRING_02); + + @Override + public int startPerformance(PerformanceTestCase.Intermediates intermediates) { + intermediates.setInternalIterations(ITERATIONS); + return 0; + } + + /** Create an empty String object* */ + + public void testStringCreate() { + String rString; + for (int i = ITERATIONS - 1; i >= 0; i--) { + rString = new String(); + rString = new String(); + rString = new String(); + rString = new String(); + rString = new String(); + rString = new String(); + rString = new String(); + rString = new String(); + rString = new String(); + rString = new String(); + } + } + + /** Create an initialised String object* */ + + public void testStringCreate1() { + String rString, str = STATIC_STRING_01; + for (int i = ITERATIONS - 1; i >= 0; i--) { + rString = new String(str); + rString = new String(str); + rString = new String(str); + rString = new String(str); + rString = new String(str); + rString = new String(str); + rString = new String(str); + rString = new String(str); + rString = new String(str); + rString = new String(str); // 10 + } + } + + /** equals() with for loop* */ + public void testStringEquals() { + String mString = new String(STATIC_STRING_01); + String str = STATIC_STRING_01; + boolean result; + for (int i = ITERATIONS - 1; i >= 0; i--) { + result = mString.equals(str); + result = mString.equals(str); + result = mString.equals(str); + result = mString.equals(str); + result = mString.equals(str); + result = mString.equals(str); + result = mString.equals(str); + result = mString.equals(str); + result = mString.equals(str); + result = mString.equals(str); + } + } + + /** + * ContentEquals- Comparing the content of a String with that of a String + * Buffer* + */ + + public void testStringContentEquals() { + StringBuffer sBuf = new StringBuffer(STATIC_STRING_01); + String str = STATIC_STRING_01; + boolean result; + for (int i = ITERATIONS - 1; i >= 0; i--) { + result = str.contentEquals(sBuf); + result = str.contentEquals(sBuf); + result = str.contentEquals(sBuf); + result = str.contentEquals(sBuf); + result = str.contentEquals(sBuf); + result = str.contentEquals(sBuf); + result = str.contentEquals(sBuf); + result = str.contentEquals(sBuf); + result = str.contentEquals(sBuf); + result = str.contentEquals(sBuf); + } + } + + /** Compare string objects lexicographically using compareTo() with for loop* */ + + public void testStringCompareTo() { + String str1 = new String(STATIC_STRING_01); + String str2 = STATIC_STRING_01; + int result; + for (int i = ITERATIONS - 1; i >= 0; i--) { + result = str1.compareTo(str2); + result = str1.compareTo(str2); + result = str1.compareTo(str2); + result = str1.compareTo(str2); + result = str1.compareTo(str2); + result = str1.compareTo(str2); + result = str1.compareTo(str2); + result = str1.compareTo(str2); + result = str1.compareTo(str2); + result = str1.compareTo(str2); + } + + } + + /** Compare string objects using compareToIgnorecase() with for loop* */ + + public void testStringCompareToIgnoreCase() { + String mString = new String(STATIC_STRING_01); + String str2 = STATIC_STRING_01; + int result; + for (int i = ITERATIONS - 1; i >= 0; i--) { + result = mString.compareToIgnoreCase(str2); + result = mString.compareToIgnoreCase(str2); + result = mString.compareToIgnoreCase(str2); + result = mString.compareToIgnoreCase(str2); + result = mString.compareToIgnoreCase(str2); + result = mString.compareToIgnoreCase(str2); + result = mString.compareToIgnoreCase(str2); + result = mString.compareToIgnoreCase(str2); + result = mString.compareToIgnoreCase(str2); + result = mString.compareToIgnoreCase(str2); + } + } + + /** startsWith * */ + + public void testStringstartsWith() { + boolean result; + String str1 = STATIC_STRING_02, str2 = "Rem"; + for (int i = ITERATIONS - 1; i >= 0; i--) { + result = str1.startsWith(str2); + result = str1.startsWith(str2); + result = str1.startsWith(str2); + result = str1.startsWith(str2); + result = str1.startsWith(str2); + result = str1.startsWith(str2); + result = str1.startsWith(str2); + result = str1.startsWith(str2); + result = str1.startsWith(str2); + result = str1.startsWith(str2); + } + } + + /** startsWith(String seq, int begin) * */ + + public void testStringstartsWith1() { + String str1 = STATIC_STRING_02, str2 = "tom"; + int pos = 10; + boolean result; + for (int i = ITERATIONS - 1; i >= 0; i--) { + result = str1.startsWith(str2, pos); + result = str1.startsWith(str2, pos); + result = str1.startsWith(str2, pos); + result = str1.startsWith(str2, pos); + result = str1.startsWith(str2, pos); + result = str1.startsWith(str2, pos); + result = str1.startsWith(str2, pos); + result = str1.startsWith(str2, pos); + result = str1.startsWith(str2, pos); + result = str1.startsWith(str2, pos); + } + } + + /** endsWith * */ + + public void testStringendsWith() { + String str = STATIC_STRING_02, str1 = "day"; + boolean result; + for (int i = ITERATIONS - 1; i >= 0; i--) { + result = str.endsWith(str1); + result = str.endsWith(str1); + result = str.endsWith(str1); + result = str.endsWith(str1); + result = str.endsWith(str1); + result = str.endsWith(str1); + result = str.endsWith(str1); + result = str.endsWith(str1); + result = str.endsWith(str1); + result = str.endsWith(str1); + } + } + + /** + * indexOf to determine whether a string contains a substring + */ + public void testStringindexOf() { + boolean result; + String str = STATIC_STRING_02, str1 = "tomo"; + for (int i = ITERATIONS - 1; i >= 0; i--) { + result = str.indexOf(str1) > 0; + result = str.indexOf(str1) > 0; + result = str.indexOf(str1) > 0; + result = str.indexOf(str1) > 0; + result = str.indexOf(str1) > 0; + result = str.indexOf(str1) > 0; + result = str.indexOf(str1) > 0; + result = str.indexOf(str1) > 0; + result = str.indexOf(str1) > 0; + result = str.indexOf(str1) > 0; + } + } + + /** indexOf()* */ + + public void testStringindexOf1() { + int index; + String str = STATIC_STRING_02; + char c = 't'; + for (int i = ITERATIONS - 1; i >= 0; i--) { + index = str.indexOf(c); + index = str.indexOf(c); + index = str.indexOf(c); + index = str.indexOf(c); + index = str.indexOf(c); + index = str.indexOf(c); + index = str.indexOf(c); + index = str.indexOf(c); + index = str.indexOf(c); + index = str.indexOf(c); + } + + } + + /** indexOf(char c, int start)* */ + public void testStringindexOf2() { + int index, pos = 12; + String str = STATIC_STRING_02, str1 = "tom"; + for (int i = ITERATIONS - 1; i >= 0; i--) { + index = str.indexOf(str1, pos); + index = str.indexOf(str1, pos); + index = str.indexOf(str1, pos); + index = str.indexOf(str1, pos); + index = str.indexOf(str1, pos); + index = str.indexOf(str1, pos); + index = str.indexOf(str1, pos); + index = str.indexOf(str1, pos); + index = str.indexOf(str1, pos); + index = str.indexOf(str1, pos); + } + } + + /** lastIndexOf()* */ + + public void testStringlastIndexOf() { + int index; + char c = 't'; + String str = STATIC_STRING_02; + for (int i = ITERATIONS - 1; i >= 0; i--) { + index = str.lastIndexOf(c); + index = str.lastIndexOf(c); + index = str.lastIndexOf(c); + index = str.lastIndexOf(c); + index = str.lastIndexOf(c); + index = str.lastIndexOf(c); + index = str.lastIndexOf(c); + index = str.lastIndexOf(c); + index = str.lastIndexOf(c); + index = str.lastIndexOf(c); + } + } + + /** lastIndexOf()* */ + + public void testStringlastIndexOf1() { + int index, pos = 36; + String str = STATIC_STRING_02, str1 = "tom"; + for (int i = ITERATIONS - 1; i >= 0; i--) { + index = str.lastIndexOf(str1, pos); + index = str.lastIndexOf(str1, pos); + index = str.lastIndexOf(str1, pos); + index = str.lastIndexOf(str1, pos); + index = str.lastIndexOf(str1, pos); + index = str.lastIndexOf(str1, pos); + index = str.lastIndexOf(str1, pos); + index = str.lastIndexOf(str1, pos); + index = str.lastIndexOf(str1, pos); + index = str.lastIndexOf(str1, pos); + } + } + + /** + * contains() to determine whether a string contains a substring + */ + + public void testStringcontains() { + boolean result; + String str = STATIC_STRING_02, str1 = "tomo"; + for (int i = ITERATIONS - 1; i >= 0; i--) { + result = str.contains(str1); + result = str.contains(str1); + result = str.contains(str1); + result = str.contains(str1); + result = str.contains(str1); + result = str.contains(str1); + result = str.contains(str1); + result = str.contains(str1); + result = str.contains(str1); + result = str.contains(str1); + } + } + + /** substring(int start) */ + + public void testStringsubstring() { + String rString; + String str = STATIC_STRING_02; + int index = 10; + for (int i = ITERATIONS - 1; i >= 0; i--) { + rString = str.substring(index); + rString = str.substring(index); + rString = str.substring(index); + rString = str.substring(index); + rString = str.substring(index); + rString = str.substring(index); + rString = str.substring(index); + rString = str.substring(index); + rString = str.substring(index); + rString = str.substring(index); + } + } + + /** substring(int start, int end) in a for loop* */ + + public void testStringsubstring1() { + String rString; + String str = STATIC_STRING_02; + int start = 10, end = 48; + for (int i = ITERATIONS - 1; i >= 0; i--) { + rString = str.substring(start, end); + rString = str.substring(start, end); + rString = str.substring(start, end); + rString = str.substring(start, end); + rString = str.substring(start, end); + rString = str.substring(start, end); + rString = str.substring(start, end); + rString = str.substring(start, end); + rString = str.substring(start, end); + rString = str.substring(start, end); + } + } + + /** + * valueOf(char[] cArray) String representation of a character array + */ + public void testStringvalueOf() { + String rString; + char[] cArray = STATIC_CHAR_ARRAY; + for (int i = ITERATIONS - 1; i >= 0; i--) { + rString = String.valueOf(cArray); + rString = String.valueOf(cArray); + rString = String.valueOf(cArray); + rString = String.valueOf(cArray); + rString = String.valueOf(cArray); + rString = String.valueOf(cArray); + rString = String.valueOf(cArray); + rString = String.valueOf(cArray); + rString = String.valueOf(cArray); + rString = String.valueOf(cArray); + } + } + + /** valueOf(char[] cArray, int offset, int count)* */ + + public void testStringvalueOf1() { + String rString; + char[] cArray = STATIC_CHAR_ARRAY; + int start = 1, end = 7; + for (int i = ITERATIONS - 1; i >= 0; i--) { + rString = String.valueOf(cArray, start, end); + rString = String.valueOf(cArray, start, end); + rString = String.valueOf(cArray, start, end); + rString = String.valueOf(cArray, start, end); + rString = String.valueOf(cArray, start, end); + rString = String.valueOf(cArray, start, end); + rString = String.valueOf(cArray, start, end); + rString = String.valueOf(cArray, start, end); + rString = String.valueOf(cArray, start, end); + rString = String.valueOf(cArray, start, end); + } + } + + /** Convert a string to a char Array* */ + + public void testStringtoCharArray() { + char[] cArray; + String str = STATIC_STRING_02; + for (int i = ITERATIONS - 1; i >= 0; i--) { + cArray = str.toCharArray(); + cArray = str.toCharArray(); + cArray = str.toCharArray(); + cArray = str.toCharArray(); + cArray = str.toCharArray(); + cArray = str.toCharArray(); + cArray = str.toCharArray(); + cArray = str.toCharArray(); + cArray = str.toCharArray(); + cArray = str.toCharArray(); + } + } + + /** length()* */ + + public void testStringlength() { + int len; + String str = STATIC_STRING_02; + for (int i = ITERATIONS - 1; i >= 0; i--) { + len = str.length(); + len = str.length(); + len = str.length(); + len = str.length(); + len = str.length(); + len = str.length(); + len = str.length(); + len = str.length(); + len = str.length(); + len = str.length(); + } + } + + /** hashcode()* */ + + public void testStringhashCode() { + int index; + String str = STATIC_STRING_02; + for (int i = ITERATIONS - 1; i >= 0; i--) { + index = str.hashCode(); + index = str.hashCode(); + index = str.hashCode(); + index = str.hashCode(); + index = str.hashCode(); + index = str.hashCode(); + index = str.hashCode(); + index = str.hashCode(); + index = str.hashCode(); + index = str.hashCode(); + } + } + + /** replace()* */ + + public void testStringreplace() { + String rString; + String str = STATIC_STRING_02; + char c1 = ' ', c2 = ' '; + for (int i = ITERATIONS - 1; i >= 0; i--) { + rString = str.replace(c1, c2); + rString = str.replace(c1, c2); + rString = str.replace(c1, c2); + rString = str.replace(c1, c2); + rString = str.replace(c1, c2); + rString = str.replace(c1, c2); + rString = str.replace(c1, c2); + rString = str.replace(c1, c2); + rString = str.replace(c1, c2); + rString = str.replace(c1, c2); + } + } + + public void testStringreplaceAll() { + String rString; + String str = STATIC_STRING_02, str1 = " ", str2 = "/"; + for (int i = ITERATIONS - 1; i >= 0; i--) { + rString = str.replaceAll(str1, str2); + rString = str.replaceAll(str1, str2); + rString = str.replaceAll(str1, str2); + rString = str.replaceAll(str1, str2); + rString = str.replaceAll(str1, str2); + rString = str.replaceAll(str1, str2); + rString = str.replaceAll(str1, str2); + rString = str.replaceAll(str1, str2); + rString = str.replaceAll(str1, str2); + rString = str.replaceAll(str1, str2); + } + } + + /** Convert a StringBuffer to a String* */ + + public void testStringtoString() { + StringBuffer sBuf = new StringBuffer(STATIC_STRING_02); + + String rString; + for (int i = ITERATIONS - 1; i >= 0; i--) { + rString = sBuf.toString(); + rString = sBuf.toString(); + rString = sBuf.toString(); + rString = sBuf.toString(); + rString = sBuf.toString(); + rString = sBuf.toString(); + rString = sBuf.toString(); + rString = sBuf.toString(); + rString = sBuf.toString(); + rString = sBuf.toString(); + } + } + + /** Split a string into an array of strings* */ + + public void testStringsplit() { + String[] strings; + String str1 = STATIC_STRING_02, str = " "; + for (int i = ITERATIONS - 1; i >= 0; i--) { + strings = str1.split(str); + strings = str1.split(str); + strings = str1.split(str); + strings = str1.split(str); + strings = str1.split(str); + strings = str1.split(str); + strings = str1.split(str); + strings = str1.split(str); + strings = str1.split(str); + strings = str1.split(str); + + } + } + + /** Split a string into an array of strings* */ + + public void testStringsplit1() { + String str = STATIC_STRING_02, str1 = " "; + String[] strings; + int pos = 8; + for (int i = ITERATIONS - 1; i >= 0; i--) { + strings = str.split(str1, pos); + strings = str.split(str1, pos); + strings = str.split(str1, pos); + strings = str.split(str1, pos); + strings = str.split(str1, pos); + strings = str.split(str1, pos); + strings = str.split(str1, pos); + strings = str.split(str1, pos); + strings = str.split(str1, pos); + strings = str.split(str1, pos); + } + } + + public void testStringgetBytes() { + byte[] bytes; + String str = STATIC_STRING_02; + for (int i = ITERATIONS - 1; i >= 0; i--) { + bytes = str.getBytes(); + bytes = str.getBytes(); + bytes = str.getBytes(); + bytes = str.getBytes(); + bytes = str.getBytes(); + bytes = str.getBytes(); + bytes = str.getBytes(); + bytes = str.getBytes(); + bytes = str.getBytes(); + bytes = str.getBytes(); + } + } + + /** copyValueOf(char[] data) * */ + + public void testStringcopyValueOf() { + String rString; + char[] cArray = STATIC_CHAR_ARRAY; + for (int i = ITERATIONS - 1; i >= 0; i--) { + rString = String.copyValueOf(cArray); + rString = String.copyValueOf(cArray); + rString = String.copyValueOf(cArray); + rString = String.copyValueOf(cArray); + rString = String.copyValueOf(cArray); + rString = String.copyValueOf(cArray); + rString = String.copyValueOf(cArray); + rString = String.copyValueOf(cArray); + rString = String.copyValueOf(cArray); + rString = String.copyValueOf(cArray); + } + } + + /** copyValueOf(char[] data, int index, int count)* */ + + public void testStringcopyValueOf1() { + String rString; + int start = 1, end = 7; + char[] cArray = STATIC_CHAR_ARRAY; + for (int i = ITERATIONS - 1; i >= 0; i--) { + rString = String.copyValueOf(cArray, start, end); + rString = String.copyValueOf(cArray, start, end); + rString = String.copyValueOf(cArray, start, end); + rString = String.copyValueOf(cArray, start, end); + rString = String.copyValueOf(cArray, start, end); + rString = String.copyValueOf(cArray, start, end); + rString = String.copyValueOf(cArray, start, end); + rString = String.copyValueOf(cArray, start, end); + rString = String.copyValueOf(cArray, start, end); + rString = String.copyValueOf(cArray, start, end); + } + } + + /** trim()* */ + + public void testStringtrim() { + String mString = + new String( + " HELLO ANDROID "); + String rString; + for (int i = ITERATIONS - 1; i >= 0; i--) { + rString = mString.trim(); + rString = mString.trim(); + rString = mString.trim(); + rString = mString.trim(); + rString = mString.trim(); + rString = mString.trim(); + rString = mString.trim(); + rString = mString.trim(); + rString = mString.trim(); + rString = mString.trim(); + } + } + + /** getChars(int srcBegin, int srcEnd, char[] dst, int dstBegin)* */ + + public void testStringgetChars() { + char[] cArray = STATIC_CHAR_ARRAY; + String str = STATIC_STRING_01; + int value1 = 7, value2 = 12, value3 = 1; + for (int i = ITERATIONS - 1; i >= 0; i--) { + str.getChars(value1, value2, cArray, value3); + str.getChars(value1, value2, cArray, value3); + str.getChars(value1, value2, cArray, value3); + str.getChars(value1, value2, cArray, value3); + str.getChars(value1, value2, cArray, value3); + str.getChars(value1, value2, cArray, value3); + str.getChars(value1, value2, cArray, value3); + str.getChars(value1, value2, cArray, value3); + str.getChars(value1, value2, cArray, value3); + str.getChars(value1, value2, cArray, value3); + } + } + + /** toUpperCase()* */ + + public void testStringtoUpperCase() { + String rString, str = STATIC_STRING_02; + for (int i = ITERATIONS - 1; i >= 0; i--) { + rString = str.toUpperCase(); + rString = str.toUpperCase(); + rString = str.toUpperCase(); + rString = str.toUpperCase(); + rString = str.toUpperCase(); + rString = str.toUpperCase(); + rString = str.toUpperCase(); + rString = str.toUpperCase(); + rString = str.toUpperCase(); + rString = str.toUpperCase(); + } + } + + /** toUpperCase() with locale* */ + + public void testStringtoUpperCase1() { + Locale locale = new Locale("tr"); + String str = STATIC_STRING_02; + String rString; + for (int i = ITERATIONS - 1; i >= 0; i--) { + rString = str.toUpperCase(locale); + rString = str.toUpperCase(locale); + rString = str.toUpperCase(locale); + rString = str.toUpperCase(locale); + rString = str.toUpperCase(locale); + rString = str.toUpperCase(locale); + rString = str.toUpperCase(locale); + rString = str.toUpperCase(locale); + rString = str.toUpperCase(locale); + rString = str.toUpperCase(locale); + } + } + + /** toLowerCase* */ + + public void StringtoLowerCase() { + String rString, str = STATIC_STRING_02; + for (int i = ITERATIONS - 1; i >= 0; i--) { + rString = str.toLowerCase(); + rString = str.toLowerCase(); + rString = str.toLowerCase(); + rString = str.toLowerCase(); + rString = str.toLowerCase(); + rString = str.toLowerCase(); + rString = str.toLowerCase(); + rString = str.toLowerCase(); + rString = str.toLowerCase(); + rString = str.toLowerCase(); + } + } + + /** toLowerCase with locale* */ + + public void testStringtoLowerCase1() { + Locale locale = new Locale("tr"); + String rString, str = STATIC_STRING_02; + for (int i = ITERATIONS - 1; i >= 0; i--) { + rString = str.toLowerCase(locale); + rString = str.toLowerCase(locale); + rString = str.toLowerCase(locale); + rString = str.toLowerCase(locale); + rString = str.toLowerCase(locale); + rString = str.toLowerCase(locale); + rString = str.toLowerCase(locale); + rString = str.toLowerCase(locale); + rString = str.toLowerCase(locale); + rString = str.toLowerCase(locale); + } + } + + /** charAt()* */ + + public void testStringcharAt() { + String str = STATIC_STRING_02; + int index, pos = 21; + for (int i = ITERATIONS - 1; i >= 0; i--) { + index = str.charAt(pos); + index = str.charAt(pos); + index = str.charAt(pos); + index = str.charAt(pos); + index = str.charAt(pos); + index = str.charAt(pos); + index = str.charAt(pos); + index = str.charAt(pos); + index = str.charAt(pos); + index = str.charAt(pos); + } + } + + public void testStringConcat() { + String mString, str1 = STATIC_STRING_01, str2 = STATIC_STRING_02; + for (int i = ITERATIONS - 1; i >= 0; i--) { + mString = str1.concat(str2); + mString = str1.concat(str2); + mString = str1.concat(str2); + mString = str1.concat(str2); + mString = str1.concat(str2); + mString = str1.concat(str2); + mString = str1.concat(str2); + mString = str1.concat(str2); + mString = str1.concat(str2); + mString = str1.concat(str2); + } + } + + public void testStringBufferAppend() { + StringBuffer sBuf = new StringBuffer(" "); + for (int i = ITERATIONS - 1; i >= 0; i--) { + sBuf.append(i); + sBuf.append(i); + sBuf.append(i); + sBuf.append(i); + sBuf.append(i); + sBuf.append(i); + sBuf.append(i); + sBuf.append(i); + sBuf.append(i); + sBuf.append(i); + } + } + + public void testStringBufferInsert() { + StringBuffer sBuf = new StringBuffer(" "); + int index = sBuf.length(); + for (int i = ITERATIONS - 1; i >= 0; i--) { + sBuf.insert(index, i); + sBuf.insert(index, i); + sBuf.insert(index, i); + sBuf.insert(index, i); + sBuf.insert(index, i); + sBuf.insert(index, i); + sBuf.insert(index, i); + sBuf.insert(index, i); + sBuf.insert(index, i); + sBuf.insert(index, i); + } + } + + public void testStringBufferReverse() { + StringBuffer sBuf = STATIC_SBUF; + for (int i = ITERATIONS - 1; i >= 0; i--) { + sBuf.reverse(); + sBuf.reverse(); + sBuf.reverse(); + sBuf.reverse(); + sBuf.reverse(); + sBuf.reverse(); + sBuf.reverse(); + sBuf.reverse(); + sBuf.reverse(); + sBuf.reverse(); + } + } + + public void testStringBufferSubstring() { + StringBuffer sBuf = STATIC_SBUF; + String rString; + int index = 0; + for (int i = ITERATIONS - 1; i >= 0; i--) { + rString = sBuf.substring(index); + rString = sBuf.substring(index); + rString = sBuf.substring(index); + rString = sBuf.substring(index); + rString = sBuf.substring(index); + rString = sBuf.substring(index); + rString = sBuf.substring(index); + rString = sBuf.substring(index); + rString = sBuf.substring(index); + rString = sBuf.substring(index); + } + } + + public void testStringBufferSubstring1() { + StringBuffer sBuf = STATIC_SBUF; + String rString; + int start = 5, end = 25; + for (int i = ITERATIONS - 1; i >= 0; i--) { + rString = sBuf.substring(start, end); + rString = sBuf.substring(start, end); + rString = sBuf.substring(start, end); + rString = sBuf.substring(start, end); + rString = sBuf.substring(start, end); + rString = sBuf.substring(start, end); + rString = sBuf.substring(start, end); + rString = sBuf.substring(start, end); + rString = sBuf.substring(start, end); + rString = sBuf.substring(start, end); + } + } + + public void testStringBufferReplace() { + StringBuffer sBuf = STATIC_SBUF; + int start = 3, end = 6; + String str = "ind"; + for (int i = ITERATIONS - 1; i >= 0; i--) { + sBuf.replace(start, end, str); + sBuf.replace(start, end, str); + sBuf.replace(start, end, str); + sBuf.replace(start, end, str); + sBuf.replace(start, end, str); + sBuf.replace(start, end, str); + sBuf.replace(start, end, str); + sBuf.replace(start, end, str); + sBuf.replace(start, end, str); + sBuf.replace(start, end, str); + } + } + + public void testStringBufferIndexOf() { + StringBuffer sBuf = STATIC_SBUF; + String str = "t"; + int index; + for (int i = ITERATIONS - 1; i >= 0; i--) { + index = sBuf.indexOf(str); + index = sBuf.indexOf(str); + index = sBuf.indexOf(str); + index = sBuf.indexOf(str); + index = sBuf.indexOf(str); + index = sBuf.indexOf(str); + index = sBuf.indexOf(str); + index = sBuf.indexOf(str); + index = sBuf.indexOf(str); + index = sBuf.indexOf(str); + } + } + + public void testStringBufferIndexOf1() { + StringBuffer sBuf = STATIC_SBUF; + String str = "tom"; + int index, pos = 12; + for (int i = ITERATIONS - 1; i >= 0; i--) { + index = sBuf.indexOf(str, pos); + index = sBuf.indexOf(str, pos); + index = sBuf.indexOf(str, pos); + index = sBuf.indexOf(str, pos); + index = sBuf.indexOf(str, pos); + index = sBuf.indexOf(str, pos); + index = sBuf.indexOf(str, pos); + index = sBuf.indexOf(str, pos); + index = sBuf.indexOf(str, pos); + index = sBuf.indexOf(str, pos); + } + + } + + public void testStringBufferLastIndexOf() { + StringBuffer sBuf = STATIC_SBUF; + String str = "t"; + int index; + for (int i = ITERATIONS - 1; i >= 0; i--) { + index = sBuf.lastIndexOf(str); + index = sBuf.lastIndexOf(str); + index = sBuf.lastIndexOf(str); + index = sBuf.lastIndexOf(str); + index = sBuf.lastIndexOf(str); + index = sBuf.lastIndexOf(str); + index = sBuf.lastIndexOf(str); + index = sBuf.lastIndexOf(str); + index = sBuf.lastIndexOf(str); + index = sBuf.lastIndexOf(str); + } + } + + public void testStringBufferLastIndexOf1() { + StringBuffer sBuf = STATIC_SBUF; + int index, pos = 36; + String str = "tom"; + for (int i = ITERATIONS - 1; i >= 0; i--) { + index = sBuf.lastIndexOf(str, pos); + index = sBuf.lastIndexOf(str, pos); + index = sBuf.lastIndexOf(str, pos); + index = sBuf.lastIndexOf(str, pos); + index = sBuf.lastIndexOf(str, pos); + index = sBuf.lastIndexOf(str, pos); + index = sBuf.lastIndexOf(str, pos); + index = sBuf.lastIndexOf(str, pos); + index = sBuf.lastIndexOf(str, pos); + index = sBuf.lastIndexOf(str, pos); + } + } +} diff --git a/tests/AndroidTests/src/com/android/unit_tests/TestHttpClient.java b/tests/AndroidTests/src/com/android/unit_tests/TestHttpClient.java new file mode 100644 index 0000000000000000000000000000000000000000..9b5e655e493cc04402aef3a86e7f1e9a5c7205a7 --- /dev/null +++ b/tests/AndroidTests/src/com/android/unit_tests/TestHttpClient.java @@ -0,0 +1,116 @@ +/* + * $HeadURL: http://svn.apache.org/repos/asf/jakarta/httpcomponents/httpcore/tags/4.0-alpha6/module-main/src/test/java/org/apache/http/mockup/TestHttpClient.java $ + * $Revision: 576077 $ + * $Date: 2007-09-16 04:50:22 -0700 (Sun, 16 Sep 2007) $ + * + * ==================================================================== + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * . + * + */ + +package com.android.unit_tests; + +import java.io.IOException; + +import org.apache.http.ConnectionReuseStrategy; +import org.apache.http.HttpClientConnection; +import org.apache.http.HttpException; +import org.apache.http.HttpHost; +import org.apache.http.HttpRequest; +import org.apache.http.HttpResponse; +import org.apache.http.HttpVersion; +import org.apache.http.impl.DefaultConnectionReuseStrategy; +import org.apache.http.params.BasicHttpParams; +import org.apache.http.params.CoreConnectionPNames; +import org.apache.http.params.DefaultedHttpParams; +import org.apache.http.params.HttpParams; +import org.apache.http.params.CoreProtocolPNames; +import org.apache.http.protocol.BasicHttpProcessor; +import org.apache.http.protocol.HttpContext; +import org.apache.http.protocol.BasicHttpContext; +import org.apache.http.protocol.ExecutionContext; +import org.apache.http.protocol.HttpRequestExecutor; +import org.apache.http.protocol.RequestConnControl; +import org.apache.http.protocol.RequestContent; +import org.apache.http.protocol.RequestExpectContinue; +import org.apache.http.protocol.RequestTargetHost; +import org.apache.http.protocol.RequestUserAgent; + +public class TestHttpClient { + + private final HttpParams params; + private final BasicHttpProcessor httpproc; + private final HttpRequestExecutor httpexecutor; + private final ConnectionReuseStrategy connStrategy; + private final HttpContext context; + + public TestHttpClient() { + super(); + this.params = new BasicHttpParams(); + this.params + .setIntParameter(CoreConnectionPNames.SO_TIMEOUT, 5000) + .setBooleanParameter(CoreConnectionPNames.STALE_CONNECTION_CHECK, false) + .setParameter(CoreProtocolPNames.PROTOCOL_VERSION, HttpVersion.HTTP_1_1) + .setParameter(CoreProtocolPNames.USER_AGENT, "TEST-CLIENT/1.1"); + + this.httpproc = new BasicHttpProcessor(); + // Required protocol interceptors + this.httpproc.addInterceptor(new RequestContent()); + this.httpproc.addInterceptor(new RequestTargetHost()); + // Recommended protocol interceptors + this.httpproc.addInterceptor(new RequestConnControl()); + this.httpproc.addInterceptor(new RequestUserAgent()); + this.httpproc.addInterceptor(new RequestExpectContinue()); + + this.httpexecutor = new HttpRequestExecutor(); + this.connStrategy = new DefaultConnectionReuseStrategy(); + this.context = new BasicHttpContext(null); + } + + public HttpParams getParams() { + return this.params; + } + + public HttpResponse execute( + final HttpRequest request, + final HttpHost targetHost, + final HttpClientConnection conn) throws HttpException, IOException { + this.context.setAttribute(ExecutionContext.HTTP_REQUEST, request); + this.context.setAttribute(ExecutionContext.HTTP_TARGET_HOST, targetHost); + this.context.setAttribute(ExecutionContext.HTTP_CONNECTION, conn); + request.setParams( + new DefaultedHttpParams(request.getParams(), this.params)); + this.httpexecutor.preProcess(request, this.httpproc, this.context); + HttpResponse response = this.httpexecutor.execute(request, conn, this.context); + response.setParams( + new DefaultedHttpParams(response.getParams(), this.params)); + this.httpexecutor.postProcess(response, this.httpproc, this.context); + return response; + } + + public boolean keepAlive(final HttpResponse response) { + return this.connStrategy.keepAlive(response, this.context); + } + +} diff --git a/tests/AndroidTests/src/com/android/unit_tests/TestHttpServer.java b/tests/AndroidTests/src/com/android/unit_tests/TestHttpServer.java new file mode 100644 index 0000000000000000000000000000000000000000..aae21b35b7fab97dad27a6158524156e44db896a --- /dev/null +++ b/tests/AndroidTests/src/com/android/unit_tests/TestHttpServer.java @@ -0,0 +1,207 @@ +/* + * $HeadURL: http://svn.apache.org/repos/asf/jakarta/httpcomponents/httpcore/tags/4.0-alpha6/module-main/src/test/java/org/apache/http/mockup/TestHttpServer.java $ + * $Revision: 576077 $ + * $Date: 2007-09-16 04:50:22 -0700 (Sun, 16 Sep 2007) $ + * + * ==================================================================== + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * . + * + */ + +package com.android.unit_tests; + + +import java.io.IOException; +import java.io.InterruptedIOException; +import java.net.InetAddress; +import java.net.ServerSocket; +import java.net.Socket; + +import org.apache.http.ConnectionClosedException; +import org.apache.http.ConnectionReuseStrategy; +import org.apache.http.HttpException; +import org.apache.http.HttpResponseFactory; +import org.apache.http.HttpServerConnection; +import org.apache.http.impl.DefaultConnectionReuseStrategy; +import org.apache.http.impl.DefaultHttpResponseFactory; +import org.apache.http.impl.DefaultHttpServerConnection; +import org.apache.http.params.BasicHttpParams; +import org.apache.http.params.CoreConnectionPNames; +import org.apache.http.params.HttpParams; +import org.apache.http.params.CoreProtocolPNames; +import org.apache.http.protocol.BasicHttpProcessor; +import org.apache.http.protocol.HttpContext; +import org.apache.http.protocol.BasicHttpContext; +import org.apache.http.protocol.HttpExpectationVerifier; +import org.apache.http.protocol.HttpRequestHandler; +import org.apache.http.protocol.HttpRequestHandlerRegistry; +import org.apache.http.protocol.HttpService; +import org.apache.http.protocol.ResponseConnControl; +import org.apache.http.protocol.ResponseContent; +import org.apache.http.protocol.ResponseDate; +import org.apache.http.protocol.ResponseServer; + +public class TestHttpServer { + + private final HttpParams params; + private final BasicHttpProcessor httpproc; + private final ConnectionReuseStrategy connStrategy; + private final HttpResponseFactory responseFactory; + private final HttpRequestHandlerRegistry reqistry; + private final ServerSocket serversocket; + + private HttpExpectationVerifier expectationVerifier; + + private Thread listener; + private volatile boolean shutdown; + + public TestHttpServer() throws IOException { + super(); + this.params = new BasicHttpParams(); + this.params + .setIntParameter(CoreConnectionPNames.SO_TIMEOUT, 20000) + .setIntParameter(CoreConnectionPNames.SOCKET_BUFFER_SIZE, 8 * 1024) + .setBooleanParameter(CoreConnectionPNames.STALE_CONNECTION_CHECK, false) + .setBooleanParameter(CoreConnectionPNames.TCP_NODELAY, true) + .setParameter(CoreProtocolPNames.ORIGIN_SERVER, "TEST-SERVER/1.1"); + this.httpproc = new BasicHttpProcessor(); + this.httpproc.addInterceptor(new ResponseDate()); + this.httpproc.addInterceptor(new ResponseServer()); + this.httpproc.addInterceptor(new ResponseContent()); + this.httpproc.addInterceptor(new ResponseConnControl()); + this.connStrategy = new DefaultConnectionReuseStrategy(); + this.responseFactory = new DefaultHttpResponseFactory(); + this.reqistry = new HttpRequestHandlerRegistry(); + this.serversocket = new ServerSocket(0); + } + + public void registerHandler( + final String pattern, + final HttpRequestHandler handler) { + this.reqistry.register(pattern, handler); + } + + public void setExpectationVerifier(final HttpExpectationVerifier expectationVerifier) { + this.expectationVerifier = expectationVerifier; + } + + private HttpServerConnection acceptConnection() throws IOException { + Socket socket = this.serversocket.accept(); + DefaultHttpServerConnection conn = new DefaultHttpServerConnection(); + conn.bind(socket, this.params); + return conn; + } + + public int getPort() { + return this.serversocket.getLocalPort(); + } + + public InetAddress getInetAddress() { + return this.serversocket.getInetAddress(); + } + + public void start() { + if (this.listener != null) { + throw new IllegalStateException("Listener already running"); + } + this.listener = new Thread(new Runnable() { + + public void run() { + while (!shutdown && !Thread.interrupted()) { + try { + // Set up HTTP connection + HttpServerConnection conn = acceptConnection(); + // Set up the HTTP service + HttpService httpService = new HttpService( + httpproc, + connStrategy, + responseFactory); + httpService.setParams(params); + httpService.setExpectationVerifier(expectationVerifier); + httpService.setHandlerResolver(reqistry); + + // Start worker thread + Thread t = new WorkerThread(httpService, conn); + t.setDaemon(true); + t.start(); + } catch (InterruptedIOException ex) { + break; + } catch (IOException e) { + break; + } + } + } + + }); + this.listener.start(); + } + + public void shutdown() { + if (this.shutdown) { + return; + } + this.shutdown = true; + try { + this.serversocket.close(); + } catch (IOException ignore) {} + this.listener.interrupt(); + try { + this.listener.join(1000); + } catch (InterruptedException ignore) {} + } + + static class WorkerThread extends Thread { + + private final HttpService httpservice; + private final HttpServerConnection conn; + + public WorkerThread( + final HttpService httpservice, + final HttpServerConnection conn) { + super(); + this.httpservice = httpservice; + this.conn = conn; + } + + public void run() { + HttpContext context = new BasicHttpContext(null); + try { + while (!Thread.interrupted() && this.conn.isOpen()) { + this.httpservice.handleRequest(this.conn, context); + } + } catch (ConnectionClosedException ex) { + } catch (IOException ex) { + System.err.println("I/O error: " + ex.getMessage()); + } catch (HttpException ex) { + System.err.println("Unrecoverable HTTP protocol violation: " + ex.getMessage()); + } finally { + try { + this.conn.shutdown(); + } catch (IOException ignore) {} + } + } + + } + +} diff --git a/tests/AndroidTests/src/com/android/unit_tests/TestHttpService.java b/tests/AndroidTests/src/com/android/unit_tests/TestHttpService.java new file mode 100644 index 0000000000000000000000000000000000000000..6b57d13e18a56d5596733586de71ad64c7f736a0 --- /dev/null +++ b/tests/AndroidTests/src/com/android/unit_tests/TestHttpService.java @@ -0,0 +1,608 @@ +/* + * $HeadURL: http://svn.apache.org/repos/asf/jakarta/httpcomponents/httpcore/tags/4.0-alpha6/module-main/src/test/java/org/apache/http/protocol/TestHttpServiceAndExecutor.java $ + * $Revision: 576073 $ + * $Date: 2007-09-16 03:53:13 -0700 (Sun, 16 Sep 2007) $ + * ==================================================================== + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * . + * + */ + +package com.android.unit_tests; + +import org.apache.http.protocol.HttpExpectationVerifier; +import org.apache.http.protocol.HttpRequestHandler; +import android.test.PerformanceTestCase; +import android.test.suitebuilder.annotation.LargeTest; +import android.test.suitebuilder.annotation.MediumTest; + +import junit.framework.TestCase; + +import org.apache.http.Header; +import org.apache.http.HttpConnectionMetrics; +import org.apache.http.HttpEntity; +import org.apache.http.HttpEntityEnclosingRequest; +import org.apache.http.HttpException; +import org.apache.http.HttpHost; +import org.apache.http.HttpRequest; +import org.apache.http.HttpResponse; +import org.apache.http.HttpStatus; +import org.apache.http.HttpVersion; +import org.apache.http.entity.ByteArrayEntity; +import org.apache.http.entity.StringEntity; +import org.apache.http.impl.DefaultHttpClientConnection; +import org.apache.http.message.BasicHttpEntityEnclosingRequest; +import org.apache.http.message.BasicHttpRequest; +import org.apache.http.params.CoreProtocolPNames; +import org.apache.http.protocol.HttpContext; +import org.apache.http.util.EncodingUtils; +import org.apache.http.util.EntityUtils; + + +import java.io.IOException; +import java.net.Socket; +import java.net.URI; +import java.util.ArrayList; +import java.util.List; +import java.util.Random; + +public class TestHttpService extends TestCase implements PerformanceTestCase { + + public boolean isPerformanceOnly() { + // TODO Auto-generated method stub + return false; + } + + public int startPerformance(Intermediates intermediates) { + // TODO Auto-generated method stub + return 0; + } + + private TestHttpServer server; + private TestHttpClient client; + + protected void setUp() throws Exception { + this.server = new TestHttpServer(); + this.client = new TestHttpClient(); + } + + protected void tearDown() throws Exception { + if (server != null) { + this.server.shutdown(); + } + } + + /** + * This test case executes a series of simple GET requests + */ + @LargeTest + public void testSimpleBasicHttpRequests() throws Exception { + + int reqNo = 20; + + Random rnd = new Random(); + + // Prepare some random data + final List testData = new ArrayList(reqNo); + for (int i = 0; i < reqNo; i++) { + int size = rnd.nextInt(5000); + byte[] data = new byte[size]; + rnd.nextBytes(data); + testData.add(data); + } + + // Initialize the server-side request handler + this.server.registerHandler("*", new HttpRequestHandler() { + + public void handle( + final HttpRequest request, + final HttpResponse response, + final HttpContext context) throws HttpException, IOException { + + String s = request.getRequestLine().getUri(); + if (s.startsWith("/?")) { + s = s.substring(2); + } + int index = Integer.parseInt(s); + byte[] data = (byte []) testData.get(index); + ByteArrayEntity entity = new ByteArrayEntity(data); + response.setEntity(entity); + } + + }); + + this.server.start(); + + DefaultHttpClientConnection conn = new DefaultHttpClientConnection(); + HttpHost host = new HttpHost("localhost", this.server.getPort()); + + try { + for (int r = 0; r < reqNo; r++) { + if (!conn.isOpen()) { + Socket socket = new Socket(host.getHostName(), host.getPort()); + conn.bind(socket, this.client.getParams()); + } + + BasicHttpRequest get = new BasicHttpRequest("GET", "/?" + r); + HttpResponse response = this.client.execute(get, host, conn); + byte[] received = EntityUtils.toByteArray(response.getEntity()); + byte[] expected = (byte[]) testData.get(r); + + assertEquals(expected.length, received.length); + for (int i = 0; i < expected.length; i++) { + assertEquals(expected[i], received[i]); + } + if (!this.client.keepAlive(response)) { + conn.close(); + } + } + + //Verify the connection metrics + HttpConnectionMetrics cm = conn.getMetrics(); + assertEquals(reqNo, cm.getRequestCount()); + assertEquals(reqNo, cm.getResponseCount()); + + } finally { + conn.close(); + this.server.shutdown(); + } + } + + /** + * This test case executes a series of simple POST requests with content length + * delimited content. + */ + @LargeTest + public void testSimpleHttpPostsWithContentLength() throws Exception { + + int reqNo = 20; + + Random rnd = new Random(); + + // Prepare some random data + List testData = new ArrayList(reqNo); + for (int i = 0; i < reqNo; i++) { + int size = rnd.nextInt(5000); + byte[] data = new byte[size]; + rnd.nextBytes(data); + testData.add(data); + } + + // Initialize the server-side request handler + this.server.registerHandler("*", new HttpRequestHandler() { + + public void handle( + final HttpRequest request, + final HttpResponse response, + final HttpContext context) throws HttpException, IOException { + + if (request instanceof HttpEntityEnclosingRequest) { + HttpEntity incoming = ((HttpEntityEnclosingRequest) request).getEntity(); + byte[] data = EntityUtils.toByteArray(incoming); + + ByteArrayEntity outgoing = new ByteArrayEntity(data); + outgoing.setChunked(false); + response.setEntity(outgoing); + } else { + StringEntity outgoing = new StringEntity("No content"); + response.setEntity(outgoing); + } + } + + }); + + this.server.start(); + + DefaultHttpClientConnection conn = new DefaultHttpClientConnection(); + HttpHost host = new HttpHost("localhost", this.server.getPort()); + + try { + for (int r = 0; r < reqNo; r++) { + if (!conn.isOpen()) { + Socket socket = new Socket(host.getHostName(), host.getPort()); + conn.bind(socket, this.client.getParams()); + } + + BasicHttpEntityEnclosingRequest post = new BasicHttpEntityEnclosingRequest("POST", "/"); + byte[] data = (byte[]) testData.get(r); + ByteArrayEntity outgoing = new ByteArrayEntity(data); + post.setEntity(outgoing); + + HttpResponse response = this.client.execute(post, host, conn); + byte[] received = EntityUtils.toByteArray(response.getEntity()); + byte[] expected = (byte[]) testData.get(r); + + assertEquals(expected.length, received.length); + for (int i = 0; i < expected.length; i++) { + assertEquals(expected[i], received[i]); + } + if (!this.client.keepAlive(response)) { + conn.close(); + } + } + //Verify the connection metrics + HttpConnectionMetrics cm = conn.getMetrics(); + assertEquals(reqNo, cm.getRequestCount()); + assertEquals(reqNo, cm.getResponseCount()); + + } finally { + conn.close(); + this.server.shutdown(); + } + } + + /** + * This test case executes a series of simple POST requests with chunk + * coded content content. + */ + @LargeTest + public void testSimpleHttpPostsChunked() throws Exception { + + int reqNo = 20; + + Random rnd = new Random(); + + // Prepare some random data + List testData = new ArrayList(reqNo); + for (int i = 0; i < reqNo; i++) { + int size = rnd.nextInt(20000); + byte[] data = new byte[size]; + rnd.nextBytes(data); + testData.add(data); + } + + // Initialize the server-side request handler + this.server.registerHandler("*", new HttpRequestHandler() { + + public void handle( + final HttpRequest request, + final HttpResponse response, + final HttpContext context) throws HttpException, IOException { + + if (request instanceof HttpEntityEnclosingRequest) { + HttpEntity incoming = ((HttpEntityEnclosingRequest) request).getEntity(); + byte[] data = EntityUtils.toByteArray(incoming); + + ByteArrayEntity outgoing = new ByteArrayEntity(data); + outgoing.setChunked(true); + response.setEntity(outgoing); + } else { + StringEntity outgoing = new StringEntity("No content"); + response.setEntity(outgoing); + } + } + + }); + + this.server.start(); + + DefaultHttpClientConnection conn = new DefaultHttpClientConnection(); + HttpHost host = new HttpHost("localhost", this.server.getPort()); + + try { + for (int r = 0; r < reqNo; r++) { + if (!conn.isOpen()) { + Socket socket = new Socket(host.getHostName(), host.getPort()); + conn.bind(socket, this.client.getParams()); + } + + BasicHttpEntityEnclosingRequest post = new BasicHttpEntityEnclosingRequest("POST", "/"); + byte[] data = (byte[]) testData.get(r); + ByteArrayEntity outgoing = new ByteArrayEntity(data); + outgoing.setChunked(true); + post.setEntity(outgoing); + + HttpResponse response = this.client.execute(post, host, conn); + byte[] received = EntityUtils.toByteArray(response.getEntity()); + byte[] expected = (byte[]) testData.get(r); + + assertEquals(expected.length, received.length); + for (int i = 0; i < expected.length; i++) { + assertEquals(expected[i], received[i]); + } + if (!this.client.keepAlive(response)) { + conn.close(); + } + } + //Verify the connection metrics + HttpConnectionMetrics cm = conn.getMetrics(); + assertEquals(reqNo, cm.getRequestCount()); + assertEquals(reqNo, cm.getResponseCount()); + } finally { + conn.close(); + this.server.shutdown(); + } + } + + /** + * This test case executes a series of simple HTTP/1.0 POST requests. + */ + @LargeTest + public void testSimpleHttpPostsHTTP10() throws Exception { + + int reqNo = 20; + + Random rnd = new Random(); + + // Prepare some random data + List testData = new ArrayList(reqNo); + for (int i = 0; i < reqNo; i++) { + int size = rnd.nextInt(5000); + byte[] data = new byte[size]; + rnd.nextBytes(data); + testData.add(data); + } + + // Initialize the server-side request handler + this.server.registerHandler("*", new HttpRequestHandler() { + + public void handle( + final HttpRequest request, + final HttpResponse response, + final HttpContext context) throws HttpException, IOException { + + if (request instanceof HttpEntityEnclosingRequest) { + HttpEntity incoming = ((HttpEntityEnclosingRequest) request).getEntity(); + byte[] data = EntityUtils.toByteArray(incoming); + + ByteArrayEntity outgoing = new ByteArrayEntity(data); + outgoing.setChunked(false); + response.setEntity(outgoing); + } else { + StringEntity outgoing = new StringEntity("No content"); + response.setEntity(outgoing); + } + } + + }); + + this.server.start(); + + // Set protocol level to HTTP/1.0 + this.client.getParams().setParameter( + CoreProtocolPNames.PROTOCOL_VERSION, HttpVersion.HTTP_1_0); + + DefaultHttpClientConnection conn = new DefaultHttpClientConnection(); + HttpHost host = new HttpHost("localhost", this.server.getPort()); + + try { + for (int r = 0; r < reqNo; r++) { + if (!conn.isOpen()) { + Socket socket = new Socket(host.getHostName(), host.getPort()); + conn.bind(socket, this.client.getParams()); + } + + BasicHttpEntityEnclosingRequest post = new BasicHttpEntityEnclosingRequest("POST", "/"); + byte[] data = (byte[]) testData.get(r); + ByteArrayEntity outgoing = new ByteArrayEntity(data); + post.setEntity(outgoing); + + HttpResponse response = this.client.execute(post, host, conn); + assertEquals(HttpVersion.HTTP_1_0, response.getStatusLine().getProtocolVersion()); + byte[] received = EntityUtils.toByteArray(response.getEntity()); + byte[] expected = (byte[]) testData.get(r); + + assertEquals(expected.length, received.length); + for (int i = 0; i < expected.length; i++) { + assertEquals(expected[i], received[i]); + } + if (!this.client.keepAlive(response)) { + conn.close(); + } + } + + //Verify the connection metrics + HttpConnectionMetrics cm = conn.getMetrics(); + assertEquals(reqNo, cm.getRequestCount()); + assertEquals(reqNo, cm.getResponseCount()); + } finally { + conn.close(); + this.server.shutdown(); + } + } + + /** + * This test case executes a series of simple POST requests using + * the 'expect: continue' handshake. + */ + @LargeTest + public void testHttpPostsWithExpectContinue() throws Exception { + + int reqNo = 20; + + Random rnd = new Random(); + + // Prepare some random data + List testData = new ArrayList(reqNo); + for (int i = 0; i < reqNo; i++) { + int size = rnd.nextInt(5000); + byte[] data = new byte[size]; + rnd.nextBytes(data); + testData.add(data); + } + + // Initialize the server-side request handler + this.server.registerHandler("*", new HttpRequestHandler() { + + public void handle( + final HttpRequest request, + final HttpResponse response, + final HttpContext context) throws HttpException, IOException { + + if (request instanceof HttpEntityEnclosingRequest) { + HttpEntity incoming = ((HttpEntityEnclosingRequest) request).getEntity(); + byte[] data = EntityUtils.toByteArray(incoming); + + ByteArrayEntity outgoing = new ByteArrayEntity(data); + outgoing.setChunked(true); + response.setEntity(outgoing); + } else { + StringEntity outgoing = new StringEntity("No content"); + response.setEntity(outgoing); + } + } + + }); + + this.server.start(); + + // Activate 'expect: continue' handshake + this.client.getParams().setBooleanParameter(CoreProtocolPNames.USE_EXPECT_CONTINUE, true); + + DefaultHttpClientConnection conn = new DefaultHttpClientConnection(); + HttpHost host = new HttpHost("localhost", this.server.getPort()); + + try { + for (int r = 0; r < reqNo; r++) { + if (!conn.isOpen()) { + Socket socket = new Socket(host.getHostName(), host.getPort()); + conn.bind(socket, this.client.getParams()); + } + + BasicHttpEntityEnclosingRequest post = new BasicHttpEntityEnclosingRequest("POST", "/"); + byte[] data = (byte[]) testData.get(r); + ByteArrayEntity outgoing = new ByteArrayEntity(data); + outgoing.setChunked(true); + post.setEntity(outgoing); + + HttpResponse response = this.client.execute(post, host, conn); + byte[] received = EntityUtils.toByteArray(response.getEntity()); + byte[] expected = (byte[]) testData.get(r); + + assertEquals(expected.length, received.length); + for (int i = 0; i < expected.length; i++) { + assertEquals(expected[i], received[i]); + } + if (!this.client.keepAlive(response)) { + conn.close(); + } + } + + //Verify the connection metrics + HttpConnectionMetrics cm = conn.getMetrics(); + assertEquals(reqNo, cm.getRequestCount()); + assertEquals(reqNo, cm.getResponseCount()); + } finally { + conn.close(); + this.server.shutdown(); + } + } + + + /** + * This test case executes a series of simple POST requests that do not + * meet the target server expectations. + */ + @LargeTest + public void testHttpPostsWithExpectationVerification() throws Exception { + + int reqNo = 3; + + // Initialize the server-side request handler + this.server.registerHandler("*", new HttpRequestHandler() { + + public void handle( + final HttpRequest request, + final HttpResponse response, + final HttpContext context) throws HttpException, IOException { + + StringEntity outgoing = new StringEntity("No content"); + response.setEntity(outgoing); + } + + }); + + this.server.setExpectationVerifier(new HttpExpectationVerifier() { + + public void verify( + final HttpRequest request, + final HttpResponse response, + final HttpContext context) throws HttpException { + Header someheader = request.getFirstHeader("Secret"); + if (someheader != null) { + int secretNumber; + try { + secretNumber = Integer.parseInt(someheader.getValue()); + } catch (NumberFormatException ex) { + response.setStatusCode(HttpStatus.SC_BAD_REQUEST); + return; + } + if (secretNumber < 2) { + response.setStatusCode(HttpStatus.SC_EXPECTATION_FAILED); + ByteArrayEntity outgoing = new ByteArrayEntity( + EncodingUtils.getAsciiBytes("Wrong secret number")); + response.setEntity(outgoing); + } + } + } + + }); + + this.server.start(); + + // Activate 'expect: continue' handshake + this.client.getParams().setBooleanParameter(CoreProtocolPNames.USE_EXPECT_CONTINUE, true); + + DefaultHttpClientConnection conn = new DefaultHttpClientConnection(); + HttpHost host = new HttpHost("localhost", this.server.getPort()); + + try { + for (int r = 0; r < reqNo; r++) { + if (!conn.isOpen()) { + Socket socket = new Socket(host.getHostName(), host.getPort()); + conn.bind(socket, this.client.getParams()); + } + + BasicHttpEntityEnclosingRequest post = new BasicHttpEntityEnclosingRequest("POST", "/"); + post.addHeader("Secret", Integer.toString(r)); + ByteArrayEntity outgoing = new ByteArrayEntity( + EncodingUtils.getAsciiBytes("No content")); + post.setEntity(outgoing); + + HttpResponse response = this.client.execute(post, host, conn); + + HttpEntity entity = response.getEntity(); + assertNotNull(entity); + entity.consumeContent(); + + if (r < 2) { + assertEquals(HttpStatus.SC_EXPECTATION_FAILED, response.getStatusLine().getStatusCode()); + } else { + assertEquals(HttpStatus.SC_OK, response.getStatusLine().getStatusCode()); + } + + if (!this.client.keepAlive(response)) { + conn.close(); + } + } + //Verify the connection metrics + HttpConnectionMetrics cm = conn.getMetrics(); + assertEquals(reqNo, cm.getRequestCount()); + assertEquals(reqNo, cm.getResponseCount()); + } finally { + conn.close(); + this.server.shutdown(); + } + } + +} diff --git a/tests/AndroidTests/src/com/android/unit_tests/TextLayoutTest.java b/tests/AndroidTests/src/com/android/unit_tests/TextLayoutTest.java new file mode 100644 index 0000000000000000000000000000000000000000..8cfcd5e698ec5291c9904c0d0ef07dd622337d86 --- /dev/null +++ b/tests/AndroidTests/src/com/android/unit_tests/TextLayoutTest.java @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2006 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.android.unit_tests; + +import android.test.suitebuilder.annotation.SmallTest; +import android.text.DynamicLayout; +import android.text.Layout; +import android.text.StaticLayout; +import android.text.TextPaint; +import junit.framework.TestCase; + + +public class TextLayoutTest extends TestCase { + + protected String mString; + protected TextPaint mPaint; + + protected void setUp() throws Exception { + super.setUp(); + mString = "The quick brown fox"; + mPaint = new TextPaint(); + } + + @SmallTest + public void testStaticLayout() throws Exception { + Layout l = new StaticLayout(mString, mPaint, 200, + Layout.Alignment.ALIGN_NORMAL, 1, 0, + true); + } + + @SmallTest + public void testDynamicLayoutTest() throws Exception { + Layout l = new DynamicLayout(mString, mPaint, 200, + Layout.Alignment.ALIGN_NORMAL, 1, 0, + true); + } +} diff --git a/tests/AndroidTests/src/com/android/unit_tests/TextUtilsTest.java b/tests/AndroidTests/src/com/android/unit_tests/TextUtilsTest.java new file mode 100644 index 0000000000000000000000000000000000000000..8c1c91f4cd31d441f66cf4aab514afe215c585ef --- /dev/null +++ b/tests/AndroidTests/src/com/android/unit_tests/TextUtilsTest.java @@ -0,0 +1,358 @@ +/* + * 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.android.unit_tests; + +import com.google.android.collect.Lists; +import com.google.android.collect.Maps; + +import android.graphics.Paint; +import android.test.suitebuilder.annotation.LargeTest; +import android.test.suitebuilder.annotation.SmallTest; +import android.text.Spannable; +import android.text.SpannableString; +import android.text.Spanned; +import android.text.SpannedString; +import android.text.TextPaint; +import android.text.TextUtils; +import android.text.style.StyleSpan; +import android.text.util.Rfc822Validator; +import android.test.MoreAsserts; + +import junit.framework.TestCase; + +import java.util.List; +import java.util.Map; + +/** + * TextUtilsTest tests {@link TextUtils}. + */ +public class TextUtilsTest extends TestCase { + + @SmallTest + public void testBasic() throws Exception { + assertEquals("", TextUtils.concat()); + assertEquals("foo", TextUtils.concat("foo")); + assertEquals("foobar", TextUtils.concat("foo", "bar")); + assertEquals("foobarbaz", TextUtils.concat("foo", "bar", "baz")); + + SpannableString foo = new SpannableString("foo"); + foo.setSpan("foo", 1, 2, Spannable.SPAN_EXCLUSIVE_INCLUSIVE); + + SpannableString bar = new SpannableString("bar"); + bar.setSpan("bar", 1, 2, Spannable.SPAN_EXCLUSIVE_INCLUSIVE); + + SpannableString baz = new SpannableString("baz"); + baz.setSpan("baz", 1, 2, Spannable.SPAN_EXCLUSIVE_INCLUSIVE); + + assertEquals("foo", TextUtils.concat(foo).toString()); + assertEquals("foobar", TextUtils.concat(foo, bar).toString()); + assertEquals("foobarbaz", TextUtils.concat(foo, bar, baz).toString()); + + assertEquals(1, ((Spanned) TextUtils.concat(foo)).getSpanStart("foo")); + + assertEquals(1, ((Spanned) TextUtils.concat(foo, bar)).getSpanStart("foo")); + assertEquals(4, ((Spanned) TextUtils.concat(foo, bar)).getSpanStart("bar")); + + assertEquals(1, ((Spanned) TextUtils.concat(foo, bar, baz)).getSpanStart("foo")); + assertEquals(4, ((Spanned) TextUtils.concat(foo, bar, baz)).getSpanStart("bar")); + assertEquals(7, ((Spanned) TextUtils.concat(foo, bar, baz)).getSpanStart("baz")); + + assertTrue(TextUtils.concat("foo", "bar") instanceof String); + assertTrue(TextUtils.concat(foo, bar) instanceof SpannedString); + } + + @SmallTest + public void testTemplateString() throws Exception { + CharSequence result; + + result = TextUtils.expandTemplate("This is a ^1 of the ^2 broadcast ^3.", + "test", "emergency", "system"); + assertEquals("This is a test of the emergency broadcast system.", + result.toString()); + + result = TextUtils.expandTemplate("^^^1^^^2^3^a^1^^b^^^c", + "one", "two", "three"); + assertEquals("^one^twothree^aone^b^^c", + result.toString()); + + result = TextUtils.expandTemplate("^"); + assertEquals("^", result.toString()); + + result = TextUtils.expandTemplate("^^"); + assertEquals("^", result.toString()); + + result = TextUtils.expandTemplate("^^^"); + assertEquals("^^", result.toString()); + + result = TextUtils.expandTemplate("shorter ^1 values ^2.", "a", ""); + assertEquals("shorter a values .", result.toString()); + + try { + TextUtils.expandTemplate("Only ^1 value given, but ^2 used.", "foo"); + fail(); + } catch (IllegalArgumentException e) { + } + + try { + TextUtils.expandTemplate("^1 value given, and ^0 used.", "foo"); + fail(); + } catch (IllegalArgumentException e) { + } + + result = TextUtils.expandTemplate("^1 value given, and ^9 used.", + "one", "two", "three", "four", "five", + "six", "seven", "eight", "nine"); + assertEquals("one value given, and nine used.", result.toString()); + + try { + TextUtils.expandTemplate("^1 value given, and ^10 used.", + "one", "two", "three", "four", "five", + "six", "seven", "eight", "nine", "ten"); + fail(); + } catch (IllegalArgumentException e) { + } + + // putting carets in the values: expansion is not recursive. + + result = TextUtils.expandTemplate("^2", "foo", "^^"); + assertEquals("^^", result.toString()); + + result = TextUtils.expandTemplate("^^2", "foo", "1"); + assertEquals("^2", result.toString()); + + result = TextUtils.expandTemplate("^1", "value with ^2 in it", "foo"); + assertEquals("value with ^2 in it", result.toString()); + } + + /** Fail unless text+spans contains a span 'spanName' with the given start and end. */ + private void checkContains(Spanned text, String[] spans, String spanName, + int start, int end) throws Exception { + for (String i: spans) { + if (i.equals(spanName)) { + assertEquals(start, text.getSpanStart(i)); + assertEquals(end, text.getSpanEnd(i)); + return; + } + } + fail(); + } + + @SmallTest + public void testTemplateSpan() throws Exception { + SpannableString template; + Spanned result; + String[] spans; + + // ordinary replacement + + template = new SpannableString("a^1b"); + template.setSpan("before", 0, 1, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); + template.setSpan("during", 1, 3, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); + template.setSpan("after", 3, 4, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); + template.setSpan("during+after", 1, 4, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); + + result = (Spanned) TextUtils.expandTemplate(template, "foo"); + assertEquals(5, result.length()); + spans = result.getSpans(0, result.length(), String.class); + + // value is one character longer, so span endpoints should change. + assertEquals(4, spans.length); + checkContains(result, spans, "before", 0, 1); + checkContains(result, spans, "during", 1, 4); + checkContains(result, spans, "after", 4, 5); + checkContains(result, spans, "during+after", 1, 5); + + + // replacement with empty string + + result = (Spanned) TextUtils.expandTemplate(template, ""); + assertEquals(2, result.length()); + spans = result.getSpans(0, result.length(), String.class); + + // the "during" span should disappear. + assertEquals(3, spans.length); + checkContains(result, spans, "before", 0, 1); + checkContains(result, spans, "after", 1, 2); + checkContains(result, spans, "during+after", 1, 2); + } + + @SmallTest + public void testStringSplitterSimple() { + stringSplitterTestHelper("a,b,cde", new String[] {"a", "b", "cde"}); + } + + @SmallTest + public void testStringSplitterEmpty() { + stringSplitterTestHelper("", new String[] {}); + } + + @SmallTest + public void testStringSplitterWithLeadingEmptyString() { + stringSplitterTestHelper(",a,b,cde", new String[] {"", "a", "b", "cde"}); + } + + @SmallTest + public void testStringSplitterWithInternalEmptyString() { + stringSplitterTestHelper("a,b,,cde", new String[] {"a", "b", "", "cde"}); + } + + @SmallTest + public void testStringSplitterWithTrailingEmptyString() { + // A single trailing emtpy string should be ignored. + stringSplitterTestHelper("a,b,cde,", new String[] {"a", "b", "cde"}); + } + + private void stringSplitterTestHelper(String string, String[] expectedStrings) { + TextUtils.StringSplitter splitter = new TextUtils.SimpleStringSplitter(','); + splitter.setString(string); + List strings = Lists.newArrayList(); + for (String s : splitter) { + strings.add(s); + } + MoreAsserts.assertEquals(expectedStrings, strings.toArray(new String[]{})); + } + + @SmallTest + public void testTrim() { + String[] strings = { "abc", " abc", " abc", "abc ", "abc ", + " abc ", " abc ", "\nabc\n", "\nabc", "abc\n" }; + + for (String s : strings) { + assertEquals(s.trim().length(), TextUtils.getTrimmedLength(s)); + } + } + + //============================================================================================== + // Email validator + //============================================================================================== + + @SmallTest + public void testEmailValidator() { + Rfc822Validator validator = new Rfc822Validator("gmail.com"); + String[] validEmails = new String[] { + "a@b.com", "a@b.fr", "a+b@c.com", "a@b.info", + }; + + for (String email : validEmails) { + assertTrue(email + " should be a valid email address", validator.isValid(email)); + } + + String[] invalidEmails = new String[] { + "a", "a@b", "a b", "a@b.12" + }; + + for (String email : invalidEmails) { + assertFalse(email + " should not be a valid email address", validator.isValid(email)); + } + + Map fixes = Maps.newHashMap(); + fixes.put("a", ""); + fixes.put("a b", ""); + fixes.put("a@b", ""); + + for (Map.Entry e : fixes.entrySet()) { + assertEquals(e.getValue(), validator.fixText(e.getKey()).toString()); + } + } + + @LargeTest + public void testEllipsize() { + CharSequence s1 = "The quick brown fox jumps over \u00FEhe lazy dog."; + CharSequence s2 = new Wrapper(s1); + Spannable s3 = new SpannableString(s1); + s3.setSpan(new StyleSpan(0), 5, 10, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); + TextPaint p = new TextPaint(); + + for (int i = 0; i < 100; i++) { + for (int j = 0; j < 3; j++) { + TextUtils.TruncateAt kind = null; + + switch (j) { + case 0: + kind = TextUtils.TruncateAt.START; + break; + + case 1: + kind = TextUtils.TruncateAt.END; + break; + + case 2: + kind = TextUtils.TruncateAt.MIDDLE; + break; + } + + String out1 = TextUtils.ellipsize(s1, p, i, kind).toString(); + String out2 = TextUtils.ellipsize(s2, p, i, kind).toString(); + String out3 = TextUtils.ellipsize(s3, p, i, kind).toString(); + + String keep1 = TextUtils.ellipsize(s1, p, i, kind, true, null).toString(); + String keep2 = TextUtils.ellipsize(s2, p, i, kind, true, null).toString(); + String keep3 = TextUtils.ellipsize(s3, p, i, kind, true, null).toString(); + + String trim1 = keep1.replace("\uFEFF", ""); + + // Are all normal output strings identical? + assertEquals("wid " + i + " pass " + j, out1, out2); + assertEquals("wid " + i + " pass " + j, out2, out3); + + // Are preserved output strings identical? + assertEquals("wid " + i + " pass " + j, keep1, keep2); + assertEquals("wid " + i + " pass " + j, keep2, keep3); + + // Does trimming padding from preserved yield normal? + assertEquals("wid " + i + " pass " + j, out1, trim1); + + // Did preserved output strings preserve length? + assertEquals("wid " + i + " pass " + j, keep1.length(), s1.length()); + + // Does the output string actually fit in the space? + assertTrue("wid " + i + " pass " + j, p.measureText(out1) <= i); + + // Is the padded output the same width as trimmed output? + assertTrue("wid " + i + " pass " + j, p.measureText(keep1) == p.measureText(out1)); + } + } + } + + /** + * CharSequence wrapper for testing the cases where text is copied into + * a char array instead of working from a String or a Spanned. + */ + private static class Wrapper implements CharSequence { + private CharSequence mString; + + public Wrapper(CharSequence s) { + mString = s; + } + + public int length() { + return mString.length(); + } + + public char charAt(int off) { + return mString.charAt(off); + } + + public String toString() { + return mString.toString(); + } + + public CharSequence subSequence(int start, int end) { + return new Wrapper(mString.subSequence(start, end)); + } + } +} diff --git a/tests/AndroidTests/src/com/android/unit_tests/TextViewPerformanceTest.java b/tests/AndroidTests/src/com/android/unit_tests/TextViewPerformanceTest.java new file mode 100644 index 0000000000000000000000000000000000000000..6fa8f4fffbe82d47bc5bed373597a67205ce4ed5 --- /dev/null +++ b/tests/AndroidTests/src/com/android/unit_tests/TextViewPerformanceTest.java @@ -0,0 +1,132 @@ +/* + * Copyright (C) 2006 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.android.unit_tests; + +import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.test.AndroidTestCase; +import android.test.suitebuilder.annotation.MediumTest; +import android.test.suitebuilder.annotation.SmallTest; +import android.text.SpannedString; +import android.view.View; +import android.view.ViewGroup; +import android.widget.TextView; + +public class TextViewPerformanceTest extends AndroidTestCase { + + private String mString = "The quick brown fox"; + private Canvas mCanvas; + private PerformanceTextView mTextView; + private Paint mPaint; + private PerformanceLabelView mLabelView; + + @Override + protected void setUp() throws Exception { + super.setUp(); + + Bitmap mBitmap = Bitmap.createBitmap(320, 240, Bitmap.Config.RGB_565); + mCanvas = new Canvas(mBitmap); + + ViewGroup.LayoutParams p = new ViewGroup.LayoutParams(320, 240); + + mLabelView = new PerformanceLabelView(mContext); + mLabelView.setText(mString); + mLabelView.measure(View.MeasureSpec.AT_MOST | 320, View.MeasureSpec.AT_MOST | 240); + mLabelView.mySetFrame(320, 240); + mLabelView.setLayoutParams(p); + mLabelView.myDraw(mCanvas); + + mPaint = new Paint(); + mCanvas.save(); + mTextView = new PerformanceTextView(mContext); + mTextView.setLayoutParams(p); + mTextView.setText(mString); + mTextView.mySetFrame(320, 240); + mTextView.measure(View.MeasureSpec.AT_MOST | 320, View.MeasureSpec.AT_MOST | 240); + } + + @MediumTest + public void testDrawTextViewLine() throws Exception { + mTextView.myDraw(mCanvas); + mTextView.myDraw(mCanvas); + mTextView.myDraw(mCanvas); + mTextView.myDraw(mCanvas); + mTextView.myDraw(mCanvas); + mTextView.myDraw(mCanvas); + mTextView.myDraw(mCanvas); + mTextView.myDraw(mCanvas); + mTextView.myDraw(mCanvas); + mTextView.myDraw(mCanvas); + } + + @SmallTest + public void testSpan() throws Exception { + CharSequence charSeq = new SpannedString(mString); + mTextView.setText(charSeq); + + mTextView.myDraw(mCanvas); + mTextView.myDraw(mCanvas); + mTextView.myDraw(mCanvas); + mTextView.myDraw(mCanvas); + mTextView.myDraw(mCanvas); + mTextView.myDraw(mCanvas); + mTextView.myDraw(mCanvas); + mTextView.myDraw(mCanvas); + mTextView.myDraw(mCanvas); + mTextView.myDraw(mCanvas); + } + + @SmallTest + public void testCanvasDrawText() throws Exception { + mCanvas.drawText(mString, 30, 30, mPaint); + } + + @SmallTest + public void testLabelViewDraw() throws Exception { + mLabelView.myDraw(mCanvas); + } + + private class PerformanceTextView extends TextView { + public PerformanceTextView(Context context) { + super(context); + } + + final void myDraw(Canvas c) { + super.onDraw(c); + } + + final void mySetFrame(int w, int h) { + super.setFrame(0, 0, w, h); + } + } + + private class PerformanceLabelView extends LabelView { + public PerformanceLabelView(Context context) { + super(context); + } + + final void myDraw(Canvas c) { + super.onDraw(c); + } + + final void mySetFrame(int w, int h) { + super.setFrame(0, 0, w, h); + } + } +} diff --git a/tests/AndroidTests/src/com/android/unit_tests/TextViewTest.java b/tests/AndroidTests/src/com/android/unit_tests/TextViewTest.java new file mode 100644 index 0000000000000000000000000000000000000000..8e491181de99abfb2d70beacc8fe64060a9b25af --- /dev/null +++ b/tests/AndroidTests/src/com/android/unit_tests/TextViewTest.java @@ -0,0 +1,61 @@ +/* + * 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.android.unit_tests; + +import com.google.android.collect.Lists; +import com.google.android.collect.Maps; + +import android.test.AndroidTestCase; +import android.test.suitebuilder.annotation.SmallTest; +import android.text.GetChars; +import android.widget.TextView; + +/** + * TextViewTest tests {@link TextView}. + */ +public class TextViewTest extends AndroidTestCase { + + @SmallTest + public void testArray() throws Exception { + TextView tv = new TextView(mContext); + + char[] c = new char[] { 'H', 'e', 'l', 'l', 'o', ' ', + 'W', 'o', 'r', 'l', 'd', '!' }; + + tv.setText(c, 1, 4); + CharSequence oldText = tv.getText(); + + tv.setText(c, 4, 5); + CharSequence newText = tv.getText(); + + assertTrue(newText == oldText); + + assertEquals(5, newText.length()); + assertEquals('o', newText.charAt(0)); + assertEquals("o Wor", newText.toString()); + + assertEquals(" Wo", newText.subSequence(1, 4)); + + char[] c2 = new char[7]; + ((GetChars) newText).getChars(1, 4, c2, 2); + assertEquals('\0', c2[1]); + assertEquals(' ', c2[2]); + assertEquals('W', c2[3]); + assertEquals('o', c2[4]); + assertEquals('\0', c2[5]); + } +} diff --git a/tests/AndroidTests/src/com/android/unit_tests/ThreadBitmapTest.java b/tests/AndroidTests/src/com/android/unit_tests/ThreadBitmapTest.java new file mode 100644 index 0000000000000000000000000000000000000000..220bc99ebfdab87d12f7fbd09c1433197f636da9 --- /dev/null +++ b/tests/AndroidTests/src/com/android/unit_tests/ThreadBitmapTest.java @@ -0,0 +1,47 @@ +/* + * 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.android.unit_tests; + +import junit.framework.TestCase; +import android.graphics.Bitmap; +import android.test.suitebuilder.annotation.LargeTest; + +public class ThreadBitmapTest extends TestCase { + + @Override + protected void setUp() throws Exception { + } + + @LargeTest + public void testCreation() { + for (int i = 0; i < 200; i++) { + + new MThread().start(); + } + } + + class MThread extends Thread { + public Bitmap b; + + public MThread() { + b = Bitmap.createBitmap(300, 300, Bitmap.Config.RGB_565); + } + + public void run() {} + } +} + diff --git a/tests/AndroidTests/src/com/android/unit_tests/TimeTest.java b/tests/AndroidTests/src/com/android/unit_tests/TimeTest.java new file mode 100644 index 0000000000000000000000000000000000000000..110caa43d101a252bfdddf121a870c864805e6ab --- /dev/null +++ b/tests/AndroidTests/src/com/android/unit_tests/TimeTest.java @@ -0,0 +1,525 @@ +/* + * Copyright (C) 2006 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.android.unit_tests; + +import android.test.suitebuilder.annotation.SmallTest; +import android.test.suitebuilder.annotation.Suppress; +import android.text.format.Time; +import android.util.Log; + +import junit.framework.TestCase; + +public class TimeTest extends TestCase { + + @SmallTest + public void testNormalize0() throws Exception { + Time t = new Time(Time.TIMEZONE_UTC); + t.parse("20060432T010203"); + t.normalize(false /* use isDst */); +// System.out.println("got: " + t.year + '-' +// + t.month + '-' + t.monthDay +// + ' ' + t.hour + ':' + t.minute +// + ':' + t.second +// + "( " + t.isDst + ',' + t.gmtoff +// + ',' + t.weekDay +// + ',' + t.yearDay + ')'); + } + + private static class DateTest { + public int year1; + public int month1; + public int day1; + public int hour1; + public int minute1; + public int dst1; + + public int offset; + + public int year2; + public int month2; + public int day2; + public int hour2; + public int minute2; + public int dst2; + + public DateTest(int year1, int month1, int day1, int hour1, int minute1, int dst1, + int offset, int year2, int month2, int day2, int hour2, int minute2, + int dst2) { + this.year1 = year1; + this.month1 = month1; + this.day1 = day1; + this.hour1 = hour1; + this.minute1 = minute1; + this.dst1 = dst1; + this.offset = offset; + this.year2 = year2; + this.month2 = month2; + this.day2 = day2; + this.hour2 = hour2; + this.minute2 = minute2; + this.dst2 = dst2; + } + + public DateTest(int year1, int month1, int day1, int hour1, int minute1, + int offset, int year2, int month2, int day2, int hour2, int minute2) { + this.year1 = year1; + this.month1 = month1; + this.day1 = day1; + this.hour1 = hour1; + this.minute1 = minute1; + this.dst1 = -1; + this.offset = offset; + this.year2 = year2; + this.month2 = month2; + this.day2 = day2; + this.hour2 = hour2; + this.minute2 = minute2; + this.dst2 = -1; + } + } + + // These tests assume that DST changes on Nov 4, 2007 at 2am (to 1am). + + // The "offset" field in "dayTests" represents days. + // Use normalize(true) with these tests to change the date by 1 day. + private DateTest[] dayTests = { + // The month numbers are 0-relative, so Jan=0, Feb=1,...Dec=11 + + // Nov 4, 12am + 0 day = Nov 4, 12am + // Nov 5, 12am + 0 day = Nov 5, 12am + new DateTest(2007, 10, 4, 0, 0, 0, 2007, 10, 4, 0, 0), + new DateTest(2007, 10, 5, 0, 0, 0, 2007, 10, 5, 0, 0), + + // Nov 3, 12am + 1 day = Nov 4, 12am + // Nov 4, 12am + 1 day = Nov 5, 12am + // Nov 5, 12am + 1 day = Nov 6, 12am + new DateTest(2007, 10, 3, 0, 0, 1, 2007, 10, 4, 0, 0), + new DateTest(2007, 10, 4, 0, 0, 1, 2007, 10, 5, 0, 0), + new DateTest(2007, 10, 5, 0, 0, 1, 2007, 10, 6, 0, 0), + + // Nov 3, 1am + 1 day = Nov 4, 1am + // Nov 4, 1am + 1 day = Nov 5, 1am + // Nov 5, 1am + 1 day = Nov 6, 1am + new DateTest(2007, 10, 3, 1, 0, 1, 2007, 10, 4, 1, 0), + new DateTest(2007, 10, 4, 1, 0, 1, 2007, 10, 5, 1, 0), + new DateTest(2007, 10, 5, 1, 0, 1, 2007, 10, 6, 1, 0), + + // Nov 3, 2am + 1 day = Nov 4, 2am + // Nov 4, 2am + 1 day = Nov 5, 2am + // Nov 5, 2am + 1 day = Nov 6, 2am + new DateTest(2007, 10, 3, 2, 0, 1, 2007, 10, 4, 2, 0), + new DateTest(2007, 10, 4, 2, 0, 1, 2007, 10, 5, 2, 0), + new DateTest(2007, 10, 5, 2, 0, 1, 2007, 10, 6, 2, 0), + }; + + // The "offset" field in "minuteTests" represents minutes. + // Use normalize(false) with these tests. + private DateTest[] minuteTests = { + // The month numbers are 0-relative, so Jan=0, Feb=1,...Dec=11 + + // Nov 4, 12am + 0 minutes = Nov 4, 12am + // Nov 5, 12am + 0 minutes = Nov 5, 12am + new DateTest(2007, 10, 4, 0, 0, 0, 2007, 10, 4, 0, 0), + new DateTest(2007, 10, 5, 0, 0, 0, 2007, 10, 5, 0, 0), + + // Nov 3, 12am + 60 minutes = Nov 3, 1am + // Nov 4, 12am + 60 minutes = Nov 4, 1am + // Nov 5, 12am + 60 minutes = Nov 5, 1am + new DateTest(2007, 10, 3, 0, 0, 60, 2007, 10, 3, 1, 0), + new DateTest(2007, 10, 4, 0, 0, 60, 2007, 10, 4, 1, 0), + new DateTest(2007, 10, 5, 0, 0, 60, 2007, 10, 5, 1, 0), + + // Nov 3, 1am + 60 minutes = Nov 3, 2am + // Nov 4, 1am (PDT) + 30 minutes = Nov 4, 1:30am (PDT) + // Nov 4, 1am (PDT) + 60 minutes = Nov 4, 1am (PST) + new DateTest(2007, 10, 3, 1, 0, 60, 2007, 10, 3, 2, 0), + new DateTest(2007, 10, 4, 1, 0, 1, 30, 2007, 10, 4, 1, 30, 1), + new DateTest(2007, 10, 4, 1, 0, 1, 60, 2007, 10, 4, 1, 0, 0), + + // Nov 4, 1:30am (PDT) + 15 minutes = Nov 4, 1:45am (PDT) + // Nov 4, 1:30am (PDT) + 30 minutes = Nov 4, 1:00am (PST) + // Nov 4, 1:30am (PDT) + 60 minutes = Nov 4, 1:30am (PST) + new DateTest(2007, 10, 4, 1, 30, 1, 15, 2007, 10, 4, 1, 45, 1), + new DateTest(2007, 10, 4, 1, 30, 1, 30, 2007, 10, 4, 1, 0, 0), + new DateTest(2007, 10, 4, 1, 30, 1, 60, 2007, 10, 4, 1, 30, 0), + + // Nov 4, 1:30am (PST) + 15 minutes = Nov 4, 1:45am (PST) + // Nov 4, 1:30am (PST) + 30 minutes = Nov 4, 2:00am (PST) + // Nov 5, 1am + 60 minutes = Nov 5, 2am + new DateTest(2007, 10, 4, 1, 30, 0, 15, 2007, 10, 4, 1, 45, 0), + new DateTest(2007, 10, 4, 1, 30, 0, 30, 2007, 10, 4, 2, 0, 0), + new DateTest(2007, 10, 5, 1, 0, 60, 2007, 10, 5, 2, 0), + + // Nov 3, 2am + 60 minutes = Nov 3, 3am + // Nov 4, 2am + 30 minutes = Nov 4, 2:30am + // Nov 4, 2am + 60 minutes = Nov 4, 3am + // Nov 5, 2am + 60 minutes = Nov 5, 3am + new DateTest(2007, 10, 3, 2, 0, 60, 2007, 10, 3, 3, 0), + new DateTest(2007, 10, 4, 2, 0, 30, 2007, 10, 4, 2, 30), + new DateTest(2007, 10, 4, 2, 0, 60, 2007, 10, 4, 3, 0), + new DateTest(2007, 10, 5, 2, 0, 60, 2007, 10, 5, 3, 0), + }; + + @SmallTest + public void testNormalize1() throws Exception { + Time local = new Time("America/Los_Angeles"); + + int len = dayTests.length; + for (int index = 0; index < len; index++) { + DateTest test = dayTests[index]; + local.set(0, test.minute1, test.hour1, test.day1, test.month1, test.year1); + // call normalize() to make sure that isDst is set + local.normalize(false /* use isDst */); + local.monthDay += test.offset; + local.normalize(true /* ignore isDst */); + if (local.year != test.year2 || local.month != test.month2 + || local.monthDay != test.day2 || local.hour != test.hour2 + || local.minute != test.minute2) { + String expectedTime = String.format("%d-%02d-%02d %02d:%02d", + test.year2, test.month2, test.day2, test.hour2, test.minute2); + String actualTime = String.format("%d-%02d-%02d %02d:%02d", + local.year, local.month, local.monthDay, local.hour, local.minute); + throw new RuntimeException( + "day test index " + index + ", normalize(): expected local " + expectedTime + + " got: " + actualTime); + } + + local.set(0, test.minute1, test.hour1, test.day1, test.month1, test.year1); + // call normalize() to make sure that isDst is set + local.normalize(false /* use isDst */); + local.monthDay += test.offset; + long millis = local.toMillis(true /* ignore isDst */); + local.set(millis); + if (local.year != test.year2 || local.month != test.month2 + || local.monthDay != test.day2 || local.hour != test.hour2 + || local.minute != test.minute2) { + String expectedTime = String.format("%d-%02d-%02d %02d:%02d", + test.year2, test.month2, test.day2, test.hour2, test.minute2); + String actualTime = String.format("%d-%02d-%02d %02d:%02d", + local.year, local.month, local.monthDay, local.hour, local.minute); + throw new RuntimeException( + "day test index " + index + ", toMillis(): expected local " + expectedTime + + " got: " + actualTime); + } + } + + len = minuteTests.length; + for (int index = 0; index < len; index++) { + DateTest test = minuteTests[index]; + local.set(0, test.minute1, test.hour1, test.day1, test.month1, test.year1); + local.isDst = test.dst1; + // call normalize() to make sure that isDst is set + local.normalize(false /* use isDst */); + if (test.dst2 == -1) test.dst2 = local.isDst; + local.minute += test.offset; + local.normalize(false /* use isDst */); + if (local.year != test.year2 || local.month != test.month2 + || local.monthDay != test.day2 || local.hour != test.hour2 + || local.minute != test.minute2 || local.isDst != test.dst2) { + String expectedTime = String.format("%d-%02d-%02d %02d:%02d isDst: %d", + test.year2, test.month2, test.day2, test.hour2, test.minute2, + test.dst2); + String actualTime = String.format("%d-%02d-%02d %02d:%02d isDst: %d", + local.year, local.month, local.monthDay, local.hour, local.minute, + local.isDst); + throw new RuntimeException( + "minute test index " + index + ", normalize(): expected local " + expectedTime + + " got: " + actualTime); + } + + local.set(0, test.minute1, test.hour1, test.day1, test.month1, test.year1); + local.isDst = test.dst1; + // call normalize() to make sure that isDst is set + local.normalize(false /* use isDst */); + if (test.dst2 == -1) test.dst2 = local.isDst; + local.minute += test.offset; + long millis = local.toMillis(false /* use isDst */); + local.set(millis); + if (local.year != test.year2 || local.month != test.month2 + || local.monthDay != test.day2 || local.hour != test.hour2 + || local.minute != test.minute2 || local.isDst != test.dst2) { + String expectedTime = String.format("%d-%02d-%02d %02d:%02d isDst: %d", + test.year2, test.month2, test.day2, test.hour2, test.minute2, + test.dst2); + String actualTime = String.format("%d-%02d-%02d %02d:%02d isDst: %d", + local.year, local.month, local.monthDay, local.hour, local.minute, + local.isDst); + throw new RuntimeException( + "minute test index " + index + ", toMillis(): expected local " + expectedTime + + " got: " + actualTime); + } + } + } + + @SmallTest + public void testSwitchTimezone0() throws Exception { + Time t = new Time(Time.TIMEZONE_UTC); + t.parse("20061005T120000"); + t.switchTimezone("America/Los_Angeles"); + // System.out.println("got: " + t); + } + + @SmallTest + public void testCtor0() throws Exception { + Time t = new Time(Time.TIMEZONE_UTC); + assertEquals(Time.TIMEZONE_UTC, t.timezone); + } + + @SmallTest + public void testGetActualMaximum0() throws Exception { + Time t = new Time(Time.TIMEZONE_UTC); + int r = t.getActualMaximum(Time.SECOND); + // System.out.println("r=" + r); + } + + @SmallTest + public void testClear0() throws Exception { + Time t = new Time(Time.TIMEZONE_UTC); + t.clear(Time.TIMEZONE_UTC); + } + + @SmallTest + public void testCompare0() throws Exception { + Time a = new Time(Time.TIMEZONE_UTC); + Time b = new Time("America/Los_Angeles"); + int r = Time.compare(a, b); + // System.out.println("r=" + r); + } + + @SmallTest + public void testFormat0() throws Exception { + Time t = new Time(Time.TIMEZONE_UTC); + String r = t.format("%Y%m%dT%H%M%S"); + // System.out.println("r='" + r + "'"); + } + + @SmallTest + public void testToString0() throws Exception { + Time t = new Time(Time.TIMEZONE_UTC); + String r = t.toString(); + // System.out.println("r='" + r + "'"); + } + + @SmallTest + public void testGetCurrentTimezone0() throws Exception { + String r = Time.getCurrentTimezone(); + // System.out.println("r='" + r + "'"); + } + + @SmallTest + public void testSetToNow0() throws Exception { + Time t = new Time(Time.TIMEZONE_UTC); + t.setToNow(); + // System.out.println("t=" + t); + } + + @SmallTest + public void testMillis0() throws Exception { + Time t = new Time(Time.TIMEZONE_UTC); + t.set(0, 0, 0, 1, 1, 2006); + long r = t.toMillis(true /* ignore isDst */); + // System.out.println("r=" + r); + t.set(1, 0, 0, 1, 1, 2006); + r = t.toMillis(true /* ignore isDst */); + // System.out.println("r=" + r); + } + + @SmallTest + public void testMillis1() throws Exception { + Time t = new Time(Time.TIMEZONE_UTC); + t.set(1, 0, 0, 1, 0, 1970); + long r = t.toMillis(true /* ignore isDst */); + // System.out.println("r=" + r); + } + + @SmallTest + public void testParse0() throws Exception { + Time t = new Time(Time.TIMEZONE_UTC); + t.parse("12345678T901234"); + // System.out.println("t=" + t); + } + + @SmallTest + public void testSet0() throws Exception { + Time t = new Time(Time.TIMEZONE_UTC); + t.set(1000L); + // System.out.println("t.year=" + t.year); + // System.out.println("t=" + t); + t.set(2000L); + // System.out.println("t=" + t); + t.set(1000L * 60); + // System.out.println("t=" + t); + t.set((1000L * 60 * 60 * 24) + 1000L); + // System.out.println("t=" + t); + } + + @SmallTest + public void testSet1() throws Exception { + Time t = new Time(Time.TIMEZONE_UTC); + t.set(1, 2, 3, 4, 5, 6); + // System.out.println("t=" + t); + } + + // Timezones that cover the world. Some GMT offsets occur more than + // once in case some cities decide to change their GMT offset. + private static final String[] mTimeZones = { + "Pacific/Kiritimati", + "Pacific/Enderbury", + "Pacific/Fiji", + "Antarctica/South_Pole", + "Pacific/Norfolk", + "Pacific/Ponape", + "Asia/Magadan", + "Australia/Lord_Howe", + "Australia/Sydney", + "Australia/Adelaide", + "Asia/Tokyo", + "Asia/Seoul", + "Asia/Taipei", + "Asia/Singapore", + "Asia/Hong_Kong", + "Asia/Saigon", + "Asia/Bangkok", + "Indian/Cocos", + "Asia/Rangoon", + "Asia/Omsk", + "Antarctica/Mawson", + "Asia/Colombo", + "Asia/Calcutta", + "Asia/Oral", + "Asia/Kabul", + "Asia/Dubai", + "Asia/Tehran", + "Europe/Moscow", + "Asia/Baghdad", + "Africa/Mogadishu", + "Europe/Athens", + "Africa/Cairo", + "Europe/Rome", + "Europe/Berlin", + "Europe/Amsterdam", + "Africa/Tunis", + "Europe/London", + "Europe/Dublin", + "Atlantic/St_Helena", + "Africa/Monrovia", + "Africa/Accra", + "Atlantic/Azores", + "Atlantic/South_Georgia", + "America/Noronha", + "America/Sao_Paulo", + "America/Cayenne", + "America/St_Johns", + "America/Puerto_Rico", + "America/Aruba", + "America/New_York", + "America/Chicago", + "America/Denver", + "America/Los_Angeles", + "America/Anchorage", + "Pacific/Marquesas", + "America/Adak", + "Pacific/Honolulu", + "Pacific/Midway", + }; + + @Suppress + public void disableTestGetJulianDay() throws Exception { + Time time = new Time(); + + // For each day of the year, and for each timezone, get the Julian + // day for 12am and then check that if we change the time we get the + // same Julian day. + for (int monthDay = 1; monthDay <= 366; monthDay++) { + for (int zoneIndex = 0; zoneIndex < mTimeZones.length; zoneIndex++) { + // We leave the "month" as zero because we are changing the + // "monthDay" from 1 to 366. The call to normalize() will + // then change the "month" (but we don't really care). + time.set(0, 0, 0, monthDay, 0, 2008); + time.timezone = mTimeZones[zoneIndex]; + long millis = time.normalize(true); + if (zoneIndex == 0) { + Log.i("TimeTest", time.format("%B %d, %Y")); + } + + // This is the Julian day for 12am for this day of the year + int julianDay = Time.getJulianDay(millis, time.gmtoff); + + // Change the time during the day and check that we get the same + // Julian day. + for (int hour = 0; hour < 24; hour++) { + for (int minute = 0; minute < 60; minute += 15) { + time.set(0, minute, hour, monthDay, 0, 2008); + millis = time.normalize(true); + int day = Time.getJulianDay(millis, time.gmtoff); + if (day != julianDay) { + Log.e("TimeTest", "Julian day: " + day + " at time " + + time.hour + ":" + time.minute + + " != today's Julian day: " + julianDay + + " timezone: " + time.timezone); + } + assertEquals(day, julianDay); + } + } + } + } + } + + @Suppress + public void disableTestSetJulianDay() throws Exception { + Time time = new Time(); + + // For each day of the year in 2008, and for each timezone, + // test that we can set the Julian day correctly. + for (int monthDay = 1; monthDay <= 366; monthDay++) { + for (int zoneIndex = 0; zoneIndex < mTimeZones.length; zoneIndex++) { + // We leave the "month" as zero because we are changing the + // "monthDay" from 1 to 366. The call to normalize() will + // then change the "month" (but we don't really care). + time.set(0, 0, 0, monthDay, 0, 2008); + time.timezone = mTimeZones[zoneIndex]; + long millis = time.normalize(true); + if (zoneIndex == 0) { + Log.i("TimeTest", time.format("%B %d, %Y")); + } + int julianDay = Time.getJulianDay(millis, time.gmtoff); + + time.setJulianDay(julianDay); + + // Some places change daylight saving time at 12am and so there + // is no 12am on some days in some timezones. In those cases, + // the time is set to 1am. + // Examples: Africa/Cairo on April 25, 2008 + // America/Sao_Paulo on October 12, 2008 + // Atlantic/Azores on March 30, 2008 + assertTrue(time.hour == 0 || time.hour == 1); + assertEquals(0, time.minute); + assertEquals(0, time.second); + + millis = time.toMillis(false); + int day = Time.getJulianDay(millis, time.gmtoff); + if (day != julianDay) { + Log.i("TimeTest", "Error: gmtoff " + (time.gmtoff / 3600.0) + + " day " + julianDay + + " millis " + millis + + " " + time.format("%B %d, %Y") + " " + time.timezone); + } + assertEquals(day, julianDay); + } + } + } +} diff --git a/tests/AndroidTests/src/com/android/unit_tests/TimeUtilsTest.java b/tests/AndroidTests/src/com/android/unit_tests/TimeUtilsTest.java new file mode 100644 index 0000000000000000000000000000000000000000..6ba64fdeb173008be18d1945b5af6a951d45291f --- /dev/null +++ b/tests/AndroidTests/src/com/android/unit_tests/TimeUtilsTest.java @@ -0,0 +1,432 @@ +/* + * Copyright (C) 2008 Google Inc. + * + * 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.android.unit_tests; + +import junit.framework.TestCase; + +import android.util.TimeUtils; + +import java.util.Calendar; +import java.util.TimeZone; + +/** + * TimeUtilsTest tests the time zone guesser. + */ +public class TimeUtilsTest extends TestCase { + public void testMainstream() throws Exception { + String[] mainstream = new String[] { + "America/New_York", // Eastern + "America/Chicago", // Central + "America/Denver", // Mountain + "America/Los_Angeles", // Pacific + "America/Anchorage", // Alaska + "Pacific/Honolulu", // Hawaii, no DST + }; + + for (String name : mainstream) { + TimeZone tz = TimeZone.getTimeZone(name); + Calendar c = Calendar.getInstance(tz); + TimeZone guess; + + c.set(2008, Calendar.OCTOBER, 20, 12, 00, 00); + guess = guess(c, "us"); + assertEquals(name, guess.getID()); + + c.set(2009, Calendar.JANUARY, 20, 12, 00, 00); + guess = guess(c, "us"); + assertEquals(name, guess.getID()); + } + } + + public void testWeird() throws Exception { + String[] weird = new String[] { + "America/Phoenix", // Mountain, no DST + "America/Adak", // Same as Hawaii, but with DST + }; + + for (String name : weird) { + TimeZone tz = TimeZone.getTimeZone(name); + Calendar c = Calendar.getInstance(tz); + TimeZone guess; + + c.set(2008, Calendar.OCTOBER, 20, 12, 00, 00); + guess = guess(c, "us"); + assertEquals(name, guess.getID()); + } + } + + public void testOld() throws Exception { + String[] old = new String[] { + "America/Indiana/Indianapolis", // Eastern, formerly no DST + }; + + for (String name : old) { + TimeZone tz = TimeZone.getTimeZone(name); + Calendar c = Calendar.getInstance(tz); + TimeZone guess; + + c.set(2005, Calendar.OCTOBER, 20, 12, 00, 00); + guess = guess(c, "us"); + assertEquals(name, guess.getID()); + } + } + + public void testWorld() throws Exception { + String[] world = new String[] { + "ad", "Europe/Andorra", + "ae", "Asia/Dubai", + "af", "Asia/Kabul", + "ag", "America/Antigua", + "ai", "America/Anguilla", + "al", "Europe/Tirane", + "am", "Asia/Yerevan", + "an", "America/Curacao", + "ao", "Africa/Luanda", + "aq", "Antarctica/McMurdo", + "aq", "Antarctica/DumontDUrville", + "aq", "Antarctica/Casey", + "aq", "Antarctica/Davis", + "aq", "Antarctica/Mawson", + "aq", "Antarctica/Syowa", + "aq", "Antarctica/Rothera", + "aq", "Antarctica/Palmer", + "ar", "America/Argentina/Buenos_Aires", + "as", "Pacific/Pago_Pago", + "at", "Europe/Vienna", + "au", "Australia/Sydney", + "au", "Australia/Adelaide", + "au", "Australia/Perth", + "au", "Australia/Eucla", + "aw", "America/Aruba", + "ax", "Europe/Mariehamn", + "az", "Asia/Baku", + "ba", "Europe/Sarajevo", + "bb", "America/Barbados", + "bd", "Asia/Dhaka", + "be", "Europe/Brussels", + "bf", "Africa/Ouagadougou", + "bg", "Europe/Sofia", + "bh", "Asia/Bahrain", + "bi", "Africa/Bujumbura", + "bj", "Africa/Porto-Novo", + "bm", "Atlantic/Bermuda", + "bn", "Asia/Brunei", + "bo", "America/La_Paz", + "br", "America/Noronha", + "br", "America/Sao_Paulo", + "br", "America/Manaus", + "bs", "America/Nassau", + "bt", "Asia/Thimphu", + "bw", "Africa/Gaborone", + "by", "Europe/Minsk", + "bz", "America/Belize", + "ca", "America/St_Johns", + "ca", "America/Halifax", + "ca", "America/Toronto", + "ca", "America/Winnipeg", + "ca", "America/Edmonton", + "ca", "America/Vancouver", + "cc", "Indian/Cocos", + "cd", "Africa/Lubumbashi", + "cd", "Africa/Kinshasa", + "cf", "Africa/Bangui", + "cg", "Africa/Brazzaville", + "ch", "Europe/Zurich", + "ci", "Africa/Abidjan", + "ck", "Pacific/Rarotonga", + "cl", "America/Santiago", + "cl", "Pacific/Easter", + "cm", "Africa/Douala", + "cn", "Asia/Shanghai", + "co", "America/Bogota", + "cr", "America/Costa_Rica", + "cu", "America/Havana", + "cv", "Atlantic/Cape_Verde", + "cx", "Indian/Christmas", + "cy", "Asia/Nicosia", + "cz", "Europe/Prague", + "de", "Europe/Berlin", + "dj", "Africa/Djibouti", + "dk", "Europe/Copenhagen", + "dm", "America/Dominica", + "do", "America/Santo_Domingo", + "dz", "Africa/Algiers", + "ec", "America/Guayaquil", + "ec", "Pacific/Galapagos", + "ee", "Europe/Tallinn", + "eg", "Africa/Cairo", + "eh", "Africa/El_Aaiun", + "er", "Africa/Asmara", + "es", "Europe/Madrid", + "es", "Atlantic/Canary", + "et", "Africa/Addis_Ababa", + "fi", "Europe/Helsinki", + "fj", "Pacific/Fiji", + "fk", "Atlantic/Stanley", + "fm", "Pacific/Ponape", + "fm", "Pacific/Truk", + "fo", "Atlantic/Faroe", + "fr", "Europe/Paris", + "ga", "Africa/Libreville", + "gb", "Europe/London", + "gd", "America/Grenada", + "ge", "Asia/Tbilisi", + "gf", "America/Cayenne", + "gg", "Europe/Guernsey", + "gh", "Africa/Accra", + "gi", "Europe/Gibraltar", + "gl", "America/Danmarkshavn", + "gl", "America/Scoresbysund", + "gl", "America/Godthab", + "gl", "America/Thule", + "gm", "Africa/Banjul", + "gn", "Africa/Conakry", + "gp", "America/Guadeloupe", + "gq", "Africa/Malabo", + "gr", "Europe/Athens", + "gs", "Atlantic/South_Georgia", + "gt", "America/Guatemala", + "gu", "Pacific/Guam", + "gw", "Africa/Bissau", + "gy", "America/Guyana", + "hk", "Asia/Hong_Kong", + "hn", "America/Tegucigalpa", + "hr", "Europe/Zagreb", + "ht", "America/Port-au-Prince", + "hu", "Europe/Budapest", + "id", "Asia/Jayapura", + "id", "Asia/Makassar", + "id", "Asia/Jakarta", + "ie", "Europe/Dublin", + "il", "Asia/Jerusalem", + "im", "Europe/Isle_of_Man", + "in", "Asia/Calcutta", + "io", "Indian/Chagos", + "iq", "Asia/Baghdad", + "ir", "Asia/Tehran", + "is", "Atlantic/Reykjavik", + "it", "Europe/Rome", + "je", "Europe/Jersey", + "jm", "America/Jamaica", + "jo", "Asia/Amman", + "jp", "Asia/Tokyo", + "ke", "Africa/Nairobi", + "kg", "Asia/Bishkek", + "kh", "Asia/Phnom_Penh", + "ki", "Pacific/Kiritimati", + "ki", "Pacific/Enderbury", + "ki", "Pacific/Tarawa", + "km", "Indian/Comoro", + "kn", "America/St_Kitts", + "kp", "Asia/Pyongyang", + "kr", "Asia/Seoul", + "kw", "Asia/Kuwait", + "ky", "America/Cayman", + "kz", "Asia/Almaty", + "kz", "Asia/Aqtau", + "la", "Asia/Vientiane", + "lb", "Asia/Beirut", + "lc", "America/St_Lucia", + "li", "Europe/Vaduz", + "lk", "Asia/Colombo", + "lr", "Africa/Monrovia", + "ls", "Africa/Maseru", + "lt", "Europe/Vilnius", + "lu", "Europe/Luxembourg", + "lv", "Europe/Riga", + "ly", "Africa/Tripoli", + "ma", "Africa/Casablanca", + "mc", "Europe/Monaco", + "md", "Europe/Chisinau", + "me", "Europe/Podgorica", + "mg", "Indian/Antananarivo", + "mh", "Pacific/Majuro", + "mk", "Europe/Skopje", + "ml", "Africa/Bamako", + "mm", "Asia/Rangoon", + "mn", "Asia/Choibalsan", + "mn", "Asia/Hovd", + "mo", "Asia/Macau", + "mp", "Pacific/Saipan", + "mq", "America/Martinique", + "mr", "Africa/Nouakchott", + "ms", "America/Montserrat", + "mt", "Europe/Malta", + "mu", "Indian/Mauritius", + "mv", "Indian/Maldives", + "mw", "Africa/Blantyre", + "mx", "America/Mexico_City", + "mx", "America/Chihuahua", + "mx", "America/Tijuana", + "my", "Asia/Kuala_Lumpur", + "mz", "Africa/Maputo", + "na", "Africa/Windhoek", + "nc", "Pacific/Noumea", + "ne", "Africa/Niamey", + "nf", "Pacific/Norfolk", + "ng", "Africa/Lagos", + "ni", "America/Managua", + "nl", "Europe/Amsterdam", + "no", "Europe/Oslo", + "np", "Asia/Katmandu", + "nr", "Pacific/Nauru", + "nu", "Pacific/Niue", + "nz", "Pacific/Auckland", + "nz", "Pacific/Chatham", + "om", "Asia/Muscat", + "pa", "America/Panama", + "pe", "America/Lima", + "pf", "Pacific/Gambier", + "pf", "Pacific/Marquesas", + "pf", "Pacific/Tahiti", + "pg", "Pacific/Port_Moresby", + "ph", "Asia/Manila", + "pk", "Asia/Karachi", + "pl", "Europe/Warsaw", + "pm", "America/Miquelon", + "pn", "Pacific/Pitcairn", + "pr", "America/Puerto_Rico", + "ps", "Asia/Gaza", + "pt", "Europe/Lisbon", + "pt", "Atlantic/Azores", + "pw", "Pacific/Palau", + "py", "America/Asuncion", + "qa", "Asia/Qatar", + "re", "Indian/Reunion", + "ro", "Europe/Bucharest", + "rs", "Europe/Belgrade", + "ru", "Asia/Kamchatka", + "ru", "Asia/Magadan", + "ru", "Asia/Vladivostok", + "ru", "Asia/Yakutsk", + "ru", "Asia/Irkutsk", + "ru", "Asia/Krasnoyarsk", + "ru", "Asia/Novosibirsk", + "ru", "Asia/Yekaterinburg", + "ru", "Europe/Samara", + "ru", "Europe/Moscow", + "ru", "Europe/Kaliningrad", + "rw", "Africa/Kigali", + "sa", "Asia/Riyadh", + "sb", "Pacific/Guadalcanal", + "sc", "Indian/Mahe", + "sd", "Africa/Khartoum", + "se", "Europe/Stockholm", + "sg", "Asia/Singapore", + "sh", "Atlantic/St_Helena", + "si", "Europe/Ljubljana", + "sj", "Arctic/Longyearbyen", + "sk", "Europe/Bratislava", + "sl", "Africa/Freetown", + "sm", "Europe/San_Marino", + "sn", "Africa/Dakar", + "so", "Africa/Mogadishu", + "sr", "America/Paramaribo", + "st", "Africa/Sao_Tome", + "sv", "America/El_Salvador", + "sy", "Asia/Damascus", + "sz", "Africa/Mbabane", + "tc", "America/Grand_Turk", + "td", "Africa/Ndjamena", + "tf", "Indian/Kerguelen", + "tg", "Africa/Lome", + "th", "Asia/Bangkok", + "tj", "Asia/Dushanbe", + "tk", "Pacific/Fakaofo", + "tl", "Asia/Dili", + "tm", "Asia/Ashgabat", + "tn", "Africa/Tunis", + "to", "Pacific/Tongatapu", + "tr", "Europe/Istanbul", + "tt", "America/Port_of_Spain", + "tv", "Pacific/Funafuti", + "tw", "Asia/Taipei", + "tz", "Africa/Dar_es_Salaam", + "ua", "Europe/Kiev", + "ug", "Africa/Kampala", + "um", "Pacific/Wake", + "um", "Pacific/Johnston", + "um", "Pacific/Midway", + "us", "America/New_York", + "us", "America/Chicago", + "us", "America/Denver", + "us", "America/Los_Angeles", + "us", "America/Anchorage", + "us", "Pacific/Honolulu", + "uy", "America/Montevideo", + "uz", "Asia/Tashkent", + "va", "Europe/Vatican", + "vc", "America/St_Vincent", + "ve", "America/Caracas", + "vg", "America/Tortola", + "vi", "America/St_Thomas", + "vn", "Asia/Saigon", + "vu", "Pacific/Efate", + "wf", "Pacific/Wallis", + "ws", "Pacific/Apia", + "ye", "Asia/Aden", + "yt", "Indian/Mayotte", + "za", "Africa/Johannesburg", + "zm", "Africa/Lusaka", + "zw", "Africa/Harare", + }; + + for (int i = 0; i < world.length; i += 2) { + String country = world[i]; + String name = world[i + 1]; + + TimeZone tz = TimeZone.getTimeZone(name); + Calendar c = Calendar.getInstance(tz); + TimeZone guess; + + c.set(2009, Calendar.JULY, 20, 12, 00, 00); + guess = guess(c, country); + assertEquals(name, guess.getID()); + + c.set(2009, Calendar.JANUARY, 20, 12, 00, 00); + guess = guess(c, country); + assertEquals(name, guess.getID()); + } + } + + public void testWorldWeird() throws Exception { + String[] world = new String[] { + // Distinguisable from Sydney only when DST not in effect + "au", "Australia/Lord_Howe", + }; + + for (int i = 0; i < world.length; i += 2) { + String country = world[i]; + String name = world[i + 1]; + + TimeZone tz = TimeZone.getTimeZone(name); + Calendar c = Calendar.getInstance(tz); + TimeZone guess; + + c.set(2009, Calendar.JULY, 20, 12, 00, 00); + guess = guess(c, country); + assertEquals(name, guess.getID()); + } + } + + private static TimeZone guess(Calendar c, String country) { + return TimeUtils.getTimeZone(c.get(c.ZONE_OFFSET) + c.get(c.DST_OFFSET), + c.get(c.DST_OFFSET) != 0, + c.getTimeInMillis(), + country); + } +} diff --git a/tests/AndroidTests/src/com/android/unit_tests/TraceTest.java b/tests/AndroidTests/src/com/android/unit_tests/TraceTest.java new file mode 100644 index 0000000000000000000000000000000000000000..670508053717a3ef8994700dbeee1260ca39da84 --- /dev/null +++ b/tests/AndroidTests/src/com/android/unit_tests/TraceTest.java @@ -0,0 +1,215 @@ +/* + * Copyright (C) 2006 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.android.unit_tests; + +import android.os.Debug; +import android.test.AndroidTestCase; +import android.test.suitebuilder.annotation.LargeTest; +import android.test.suitebuilder.annotation.SmallTest; +import android.test.suitebuilder.annotation.Suppress; +import android.util.Log; + +/** + * This class is used to test the native tracing support. Run this test + * while tracing on the emulator and then run traceview to view the trace. + */ +public class TraceTest extends AndroidTestCase +{ + private static final String TAG = "TraceTest"; + private int eMethodCalls = 0; + private int fMethodCalls = 0; + private int gMethodCalls = 0; + + @SmallTest + public void testNativeTracingFromJava() + { + long start = System.currentTimeMillis(); + Debug.startNativeTracing(); + //nativeMethod(); + int count = 0; + for (int ii = 0; ii < 20; ii++) { + count = eMethod(); + } + Debug.stopNativeTracing(); + long end = System.currentTimeMillis(); + long elapsed = end - start; + Log.i(TAG, "elapsed millis: " + elapsed); + Log.i(TAG, "eMethod calls: " + eMethodCalls + + " fMethod calls: " + fMethodCalls + + " gMethod calls: " + gMethodCalls); + } + + // This should not run in the automated suite. + @Suppress + public void disableTestNativeTracingFromC() + { + long start = System.currentTimeMillis(); + nativeMethodAndStartTracing(); + long end = System.currentTimeMillis(); + long elapsed = end - start; + Log.i(TAG, "elapsed millis: " + elapsed); + } + + native void nativeMethod(); + native void nativeMethodAndStartTracing(); + + @LargeTest + public void testMethodTracing() + { + long start = System.currentTimeMillis(); + Debug.startMethodTracing("traceTest"); + topMethod(); + Debug.stopMethodTracing(); + long end = System.currentTimeMillis(); + long elapsed = end - start; + Log.i(TAG, "elapsed millis: " + elapsed); + } + + private void topMethod() { + aMethod(); + bMethod(); + cMethod(); + dMethod(5); + + Thread t1 = new aThread(); + t1.start(); + Thread t2 = new aThread(); + t2.start(); + Thread t3 = new aThread(); + t3.start(); + try { + t1.join(); + t2.join(); + t3.join(); + } catch (InterruptedException e) { + } + } + + private class aThread extends Thread { + @Override + public void run() { + aMethod(); + bMethod(); + cMethod(); + } + } + + /** Calls other methods to make some interesting trace data. + * + * @return a meaningless value + */ + private int aMethod() { + int count = 0; + for (int ii = 0; ii < 6; ii++) { + count += bMethod(); + } + for (int ii = 0; ii < 5; ii++) { + count += cMethod(); + } + for (int ii = 0; ii < 4; ii++) { + count += dMethod(ii); + } + return count; + } + + /** Calls another method to make some interesting trace data. + * + * @return a meaningless value + */ + private int bMethod() { + int count = 0; + for (int ii = 0; ii < 4; ii++) { + count += cMethod(); + } + return count; + } + + /** Executes a simple loop to make some interesting trace data. + * + * @return a meaningless value + */ + private int cMethod() { + int count = 0; + for (int ii = 0; ii < 1000; ii++) { + count += ii; + } + return count; + } + + /** Calls itself recursively to make some interesting trace data. + * + * @return a meaningless value + */ + private int dMethod(int level) { + int count = 0; + if (level > 0) { + count = dMethod(level - 1); + } + for (int ii = 0; ii < 100; ii++) { + count += ii; + } + if (level == 0) { + return count; + } + return dMethod(level - 1); + } + + public int eMethod() { + eMethodCalls += 1; + int count = fMethod(); + count += gMethod(3); + return count; + } + + public int fMethod() { + fMethodCalls += 1; + int count = 0; + for (int ii = 0; ii < 10; ii++) { + count += ii; + } + return count; + } + + public int gMethod(int level) { + gMethodCalls += 1; + int count = level; + if (level > 1) + count += gMethod(level - 1); + return count; + } + + /* + * This causes the native shared library to be loaded when the + * class is first used. The library is only loaded once, even if + * multiple classes include this line. + * + * The library must be in java.library.path, which is derived from + * LD_LIBRARY_PATH. The actual library name searched for will be + * "libtrace_test.so" under Linux, but may be different on other + * platforms. + */ + static { + Log.i(TAG, "Loading trace_test native library..."); + try { + System.loadLibrary("trace_test"); + Log.i(TAG, "Successfully loaded trace_test native library"); + } + catch (UnsatisfiedLinkError ule) { + Log.w(TAG, "Could not load trace_test native library"); + } + } +} diff --git a/tests/AndroidTests/src/com/android/unit_tests/TreeMapTest.java b/tests/AndroidTests/src/com/android/unit_tests/TreeMapTest.java new file mode 100644 index 0000000000000000000000000000000000000000..d77a81975f0b2760b867c604aa3b3ccc76e7d23e --- /dev/null +++ b/tests/AndroidTests/src/com/android/unit_tests/TreeMapTest.java @@ -0,0 +1,281 @@ +/* + * Copyright (C) 2007 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.android.unit_tests; + +import android.test.PerformanceTestBase; +import android.test.PerformanceTestCase; + +import java.util.Collection; +import java.util.Set; +import java.util.SortedMap; +import java.util.TreeMap; + +/** + * Implements basic performance test functionality for java.util.TreeMap + */ + +public class TreeMapTest extends PerformanceTestBase { + public static final int ITERATIONS = 1000; + public static TreeMap sMap; + public static String[] sKeys; + + @Override + @SuppressWarnings("unchecked") + protected void setUp() throws Exception { + super.setUp(); + sMap = new TreeMap(); + sKeys = new String[ITERATIONS]; + for (int i = ITERATIONS - 1; i >= 0; i--) { + sKeys[i] = Integer.toString(i, 16); + sMap.put(sKeys[i], i); + } + } + + @Override + public int startPerformance(PerformanceTestCase.Intermediates intermediates) { + intermediates.setInternalIterations(ITERATIONS); + return 0; + } + + @SuppressWarnings("unchecked") + public void testTreeMapPut() { + TreeMap map = new TreeMap(); + for (int i = ITERATIONS - 1; i >= 0; i--) { + map.put(i, i); + map.put(i, i); + map.put(i, i); + map.put(i, i); + map.put(i, i); + map.put(i, i); + map.put(i, i); + map.put(i, i); + map.put(i, i); + map.put(i, i); + } + } + + public void testTreeMapGet() { + int value; + TreeMap map = sMap; + String[] keys = sKeys; + for (int i = ITERATIONS - 1; i >= 0; i--) { + value = map.get(keys[i]); + value = map.get(keys[i]); + value = map.get(keys[i]); + value = map.get(keys[i]); + value = map.get(keys[i]); + value = map.get(keys[i]); + value = map.get(keys[i]); + value = map.get(keys[i]); + value = map.get(keys[i]); + value = map.get(keys[i]); + } + } + + public void testTreeMapFirstKey() { + String key; + TreeMap map = sMap; + for (int i = ITERATIONS - 1; i >= 0; i--) { + key = map.firstKey(); + key = map.firstKey(); + key = map.firstKey(); + key = map.firstKey(); + key = map.firstKey(); + key = map.firstKey(); + key = map.firstKey(); + key = map.firstKey(); + key = map.firstKey(); + key = map.firstKey(); + } + } + + public void testTreeMapKeySet() { + Set keyset; + TreeMap map = sMap; + for (int i = ITERATIONS - 1; i >= 0; i--) { + keyset = map.keySet(); + keyset = map.keySet(); + keyset = map.keySet(); + keyset = map.keySet(); + keyset = map.keySet(); + keyset = map.keySet(); + keyset = map.keySet(); + keyset = map.keySet(); + keyset = map.keySet(); + keyset = map.keySet(); + } + } + + public void testTreeMapEntrySet() { + Set keyset; + TreeMap map = sMap; + for (int i = ITERATIONS - 1; i >= 0; i--) { + keyset = map.entrySet(); + keyset = map.entrySet(); + keyset = map.entrySet(); + keyset = map.entrySet(); + keyset = map.entrySet(); + keyset = map.entrySet(); + keyset = map.entrySet(); + keyset = map.entrySet(); + keyset = map.entrySet(); + keyset = map.entrySet(); + } + } + + public void testTreeMapValues() { + Collection collection; + TreeMap map = sMap; + for (int i = ITERATIONS - 1; i >= 0; i--) { + collection = map.values(); + collection = map.values(); + collection = map.values(); + collection = map.values(); + collection = map.values(); + collection = map.values(); + collection = map.values(); + collection = map.values(); + collection = map.values(); + collection = map.values(); + } + } + + public void testTreeMapSize() { + int len; + TreeMap map = sMap; + for (int i = ITERATIONS - 1; i >= 0; i--) { + len = map.size(); + len = map.size(); + len = map.size(); + len = map.size(); + len = map.size(); + len = map.size(); + len = map.size(); + len = map.size(); + len = map.size(); + len = map.size(); + } + } + + public void testTreeMapContainsKey() { + boolean flag; + String key = sKeys[525]; + TreeMap map = sMap; + for (int i = ITERATIONS - 1; i >= 0; i--) { + flag = map.containsKey(key); + flag = map.containsKey(key); + flag = map.containsKey(key); + flag = map.containsKey(key); + flag = map.containsKey(key); + flag = map.containsKey(key); + flag = map.containsKey(key); + flag = map.containsKey(key); + flag = map.containsKey(key); + flag = map.containsKey(key); + } + } + + public void testTreeMapContainsValue() { + boolean flag; + TreeMap map = sMap; + for (int i = ITERATIONS - 1; i >= 0; i--) { + flag = map.containsValue(i); + flag = map.containsValue(i); + flag = map.containsValue(i); + flag = map.containsValue(i); + flag = map.containsValue(i); + flag = map.containsValue(i); + flag = map.containsValue(i); + flag = map.containsValue(i); + flag = map.containsValue(i); + flag = map.containsValue(i); + } + } + + public void testTreeMapHeadMap() { + SortedMap map; + String str = sKeys[100]; + TreeMap tMap = sMap; + for (int i = ITERATIONS - 1; i >= 0; i--) { + map = tMap.headMap(str); + map = tMap.headMap(str); + map = tMap.headMap(str); + map = tMap.headMap(str); + map = tMap.headMap(str); + map = tMap.headMap(str); + map = tMap.headMap(str); + map = tMap.headMap(str); + map = tMap.headMap(str); + map = tMap.headMap(str); + } + } + + public void testTreeMapSubMap() { + String str1 = sKeys[400]; + String str2 = sKeys[500]; + SortedMap map; + TreeMap tMap = sMap; + for (int i = ITERATIONS - 1; i >= 0; i--) { + map = tMap.subMap(str1, str2); + map = tMap.subMap(str1, str2); + map = tMap.subMap(str1, str2); + map = tMap.subMap(str1, str2); + map = tMap.subMap(str1, str2); + map = tMap.subMap(str1, str2); + map = tMap.subMap(str1, str2); + map = tMap.subMap(str1, str2); + map = tMap.subMap(str1, str2); + map = tMap.subMap(str1, str2); + } + } + + public void testTreeMapTailMap() { + String str = sKeys[900]; + TreeMap tMap = sMap; + SortedMap map; + for (int i = ITERATIONS - 1; i >= 0; i--) { + map = tMap.tailMap(str); + map = tMap.tailMap(str); + map = tMap.tailMap(str); + map = tMap.tailMap(str); + map = tMap.tailMap(str); + map = tMap.tailMap(str); + map = tMap.tailMap(str); + map = tMap.tailMap(str); + map = tMap.tailMap(str); + map = tMap.tailMap(str); + } + } + + @SuppressWarnings("unchecked") + public void testTreeMapRemove() { + TreeMap tMap = new TreeMap(sMap); + String[] keys = sKeys; + for (int i = ITERATIONS - 1; i >= 0; i--) { + tMap.remove(keys[i]); + tMap.remove(keys[i]); + tMap.remove(keys[i]); + tMap.remove(keys[i]); + tMap.remove(keys[i]); + tMap.remove(keys[i]); + tMap.remove(keys[i]); + tMap.remove(keys[i]); + tMap.remove(keys[i]); + tMap.remove(keys[i]); + } + } +} diff --git a/tests/AndroidTests/src/com/android/unit_tests/TreeSetTest.java b/tests/AndroidTests/src/com/android/unit_tests/TreeSetTest.java new file mode 100644 index 0000000000000000000000000000000000000000..60dfe9ae5c87a9cb7c09b4646a21c7772defc6a2 --- /dev/null +++ b/tests/AndroidTests/src/com/android/unit_tests/TreeSetTest.java @@ -0,0 +1,349 @@ +/* + * Copyright (C) 2007 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.android.unit_tests; + +import android.test.PerformanceTestBase; +import android.test.PerformanceTestCase; + +import java.util.TreeSet; +import java.util.SortedSet; +import java.util.Iterator; +import java.util.Comparator; + +/** + * Implements basic performance test functionality for java.util.TreeSet + */ + +public class TreeSetTest extends PerformanceTestBase { + public static final int ITERATIONS = 1000; + public static TreeSet sSet; + + @Override + protected void setUp() throws Exception { + super.setUp(); + sSet = new TreeSet(); + for (int i = ITERATIONS - 1; i >= 0; i--) { + sSet.add(i); + } + } + + @Override + public int startPerformance(PerformanceTestCase.Intermediates intermediates) { + intermediates.setInternalIterations(ITERATIONS); + return 0; + } + + /** + * + * Tests performance for the java.util.TreeSet method Add(Object arg 0) + * + */ + + @SuppressWarnings("unchecked") + public void testTreeSetAdd() { + TreeSet set = new TreeSet(); + for (int i = ITERATIONS - 1; i >= 0; i--) { + set.add(i); + set.add(i); + set.add(i); + set.add(i); + set.add(i); + set.add(i); + set.add(i); + set.add(i); + set.add(i); + set.add(i); + } + } + + /** + * + * Tests performance for the java.util.TreeSet method - first() + * + */ + + public void testTreeSetFirst() { + int value; + TreeSet set = sSet; + for (int i = ITERATIONS - 1; i >= 0; i--) { + value = set.first(); + value = set.first(); + value = set.first(); + value = set.first(); + value = set.first(); + value = set.first(); + value = set.first(); + value = set.first(); + value = set.first(); + } + } + + /** + * + * Tests performance for the java.util.TreeSet method - last() + * + */ + + public void testTreeSetLast() { + int value; + TreeSet set = sSet; + for (int i = ITERATIONS - 1; i >= 0; i--) { + value = set.last(); + value = set.last(); + value = set.last(); + value = set.last(); + value = set.last(); + value = set.last(); + value = set.last(); + value = set.last(); + value = set.last(); + } + } + + /** + * + * Tests performance of the java.util.TreeSet method- contains(Object arg0) + * + */ + + public void testTreeSetContains() { + Integer index = new Integer(500); + boolean flag; + TreeSet set = sSet; + for (int i = ITERATIONS - 1; i >= 0; i--) { + flag = set.contains(index); + flag = set.contains(index); + flag = set.contains(index); + flag = set.contains(index); + flag = set.contains(index); + flag = set.contains(index); + flag = set.contains(index); + flag = set.contains(index); + flag = set.contains(index); + } + } + + /** + * + * Tests performance for the java.util.TreeSet method - size() + * + */ + + public void testTreeSetSize() { + int value; + TreeSet set = sSet; + for (int i = ITERATIONS - 1; i >= 0; i--) { + value = set.size(); + value = set.size(); + value = set.size(); + value = set.size(); + value = set.size(); + value = set.size(); + value = set.size(); + value = set.size(); + value = set.size(); + } + } + + /** + * + * Tests performance for the java.util.TreeSet method - iterator() + * + */ + + public void testTreeSetIterator() { + Iterator iterator; + TreeSet set = sSet; + for (int i = ITERATIONS - 1; i >= 0; i--) { + iterator = set.iterator(); + iterator = set.iterator(); + iterator = set.iterator(); + iterator = set.iterator(); + iterator = set.iterator(); + iterator = set.iterator(); + iterator = set.iterator(); + iterator = set.iterator(); + iterator = set.iterator(); + } + } + + /** + * + * Tests performance for the java.util.TreeSet method - comparator() + * + */ + + public void testTreeSetComparator() { + Comparator comparator; + TreeSet set = sSet; + for (int i = ITERATIONS - 1; i >= 0; i--) { + comparator = set.comparator(); + comparator = set.comparator(); + comparator = set.comparator(); + comparator = set.comparator(); + comparator = set.comparator(); + comparator = set.comparator(); + comparator = set.comparator(); + comparator = set.comparator(); + comparator = set.comparator(); + } + } + + /** + * + * Tests performance for the java.util.TreeSet method - clone() + * + */ + + public void testTreeSetClone() { + Object obj; + TreeSet set = sSet; + for (int i = ITERATIONS - 1; i >= 0; i--) { + obj = set.clone(); + obj = set.clone(); + obj = set.clone(); + obj = set.clone(); + obj = set.clone(); + obj = set.clone(); + obj = set.clone(); + obj = set.clone(); + obj = set.clone(); + obj = set.clone(); + } + } + + /** + * + * Tests performance of the java.util.TreeSet method - remove(Object arg0) + * + */ + + @SuppressWarnings("unchecked") + public void testTreeSetRemove() { + TreeSet set = new TreeSet(sSet); + for (int i = ITERATIONS - 1; i >= 0; i--) { + set.remove(i); + set.remove(i); + set.remove(i); + set.remove(i); + set.remove(i); + set.remove(i); + set.remove(i); + set.remove(i); + set.remove(i); + set.remove(i); + } + } + + /** + * + * Tests performance of the java.util.TreeSet method- headSet(Integer arg0) + * + */ + + public void testTreeSetHeadSet() { + Integer value = new Integer(100); + SortedSet set; + TreeSet tSet = sSet; + for (int i = ITERATIONS - 1; i >= 0; i--) { + set = tSet.headSet(value); + set = tSet.headSet(value); + set = tSet.headSet(value); + set = tSet.headSet(value); + set = tSet.headSet(value); + set = tSet.headSet(value); + set = tSet.headSet(value); + set = tSet.headSet(value); + set = tSet.headSet(value); + set = tSet.headSet(value); + } + } + + /** + * + * Tests performance of subSet(Integer arg0, Integer arg1) - TreeSet + * + */ + + public void testTreeSetSubSet() { + Integer value = new Integer(400); + Integer nInt = new Integer(500); + SortedSet set; + TreeSet tSet = sSet; + for (int i = ITERATIONS - 1; i >= 0; i--) { + set = tSet.subSet(value, nInt); + set = tSet.subSet(value, nInt); + set = tSet.subSet(value, nInt); + set = tSet.subSet(value, nInt); + set = tSet.subSet(value, nInt); + set = tSet.subSet(value, nInt); + set = tSet.subSet(value, nInt); + set = tSet.subSet(value, nInt); + set = tSet.subSet(value, nInt); + set = tSet.subSet(value, nInt); + + } + + } + + /** + * + * Tests performance of tailSet(Integer arg0) - TreeSet + * + */ + + public void testTreeSetTailSet() { + Integer value = new Integer(900); + SortedSet set; + TreeSet tSet = sSet; + for (int i = ITERATIONS - 1; i >= 0; i--) { + set = tSet.tailSet(value); + set = tSet.tailSet(value); + set = tSet.tailSet(value); + set = tSet.tailSet(value); + set = tSet.tailSet(value); + set = tSet.tailSet(value); + set = tSet.tailSet(value); + set = tSet.tailSet(value); + set = tSet.tailSet(value); + set = tSet.tailSet(value); + } + } + + /** + * + * Tests performance for the java.util.TreeSet method - isEmpty() + * + */ + + public void testTreeSetIsEmpty() { + boolean flag; + TreeSet tSet = sSet; + for (int i = ITERATIONS - 1; i >= 0; i--) { + flag = tSet.isEmpty(); + flag = tSet.isEmpty(); + flag = tSet.isEmpty(); + flag = tSet.isEmpty(); + flag = tSet.isEmpty(); + flag = tSet.isEmpty(); + flag = tSet.isEmpty(); + flag = tSet.isEmpty(); + flag = tSet.isEmpty(); + flag = tSet.isEmpty(); + } + } +} diff --git a/tests/AndroidTests/src/com/android/unit_tests/UriMatcherTest.java b/tests/AndroidTests/src/com/android/unit_tests/UriMatcherTest.java new file mode 100644 index 0000000000000000000000000000000000000000..ce3ea75675aee31b3f4ab645daab095087a5f49c --- /dev/null +++ b/tests/AndroidTests/src/com/android/unit_tests/UriMatcherTest.java @@ -0,0 +1,95 @@ +/* + * Copyright (C) 2007 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.android.unit_tests; + +import android.content.UriMatcher; +import android.net.Uri; +import android.test.suitebuilder.annotation.SmallTest; +import junit.framework.TestCase; + +public class UriMatcherTest extends TestCase +{ + static final int ROOT = 0; + static final int PEOPLE = 1; + static final int PEOPLE_ID = 2; + static final int PEOPLE_PHONES = 3; + static final int PEOPLE_PHONES_ID = 4; + static final int PEOPLE_ADDRESSES = 5; + static final int PEOPLE_ADDRESSES_ID = 6; + static final int PEOPLE_CONTACTMETH = 7; + static final int PEOPLE_CONTACTMETH_ID = 8; + static final int CALLS = 9; + static final int CALLS_ID = 10; + static final int CALLERID = 11; + static final int CALLERID_TEXT = 12; + static final int FILTERRECENT = 13; + + @SmallTest + public void testContentUris() { + check("content://asdf", UriMatcher.NO_MATCH); + check("content://people", PEOPLE); + check("content://people/1", PEOPLE_ID); + check("content://people/asdf", UriMatcher.NO_MATCH); + check("content://people/2/phones", PEOPLE_PHONES); + check("content://people/2/phones/3", PEOPLE_PHONES_ID); + check("content://people/2/phones/asdf", UriMatcher.NO_MATCH); + check("content://people/2/addresses", PEOPLE_ADDRESSES); + check("content://people/2/addresses/3", PEOPLE_ADDRESSES_ID); + check("content://people/2/addresses/asdf", UriMatcher.NO_MATCH); + check("content://people/2/contact-methods", PEOPLE_CONTACTMETH); + check("content://people/2/contact-methods/3", PEOPLE_CONTACTMETH_ID); + check("content://people/2/contact-methods/asdf", UriMatcher.NO_MATCH); + check("content://calls", CALLS); + check("content://calls/1", CALLS_ID); + check("content://calls/asdf", UriMatcher.NO_MATCH); + check("content://caller-id", CALLERID); + check("content://caller-id/asdf", CALLERID_TEXT); + check("content://caller-id/1", CALLERID_TEXT); + check("content://filter-recent", FILTERRECENT); + } + + private static final UriMatcher mURLMatcher = new UriMatcher(ROOT); + + static + { + mURLMatcher.addURI("people", null, PEOPLE); + mURLMatcher.addURI("people", "#", PEOPLE_ID); + mURLMatcher.addURI("people", "#/phones", PEOPLE_PHONES); + mURLMatcher.addURI("people", "#/phones/blah", PEOPLE_PHONES_ID); + mURLMatcher.addURI("people", "#/phones/#", PEOPLE_PHONES_ID); + mURLMatcher.addURI("people", "#/addresses", PEOPLE_ADDRESSES); + mURLMatcher.addURI("people", "#/addresses/#", PEOPLE_ADDRESSES_ID); + mURLMatcher.addURI("people", "#/contact-methods", PEOPLE_CONTACTMETH); + mURLMatcher.addURI("people", "#/contact-methods/#", PEOPLE_CONTACTMETH_ID); + mURLMatcher.addURI("calls", null, CALLS); + mURLMatcher.addURI("calls", "#", CALLS_ID); + mURLMatcher.addURI("caller-id", null, CALLERID); + mURLMatcher.addURI("caller-id", "*", CALLERID_TEXT); + mURLMatcher.addURI("filter-recent", null, FILTERRECENT); + } + + void check(String uri, int expected) + { + int result = mURLMatcher.match(Uri.parse(uri)); + if (result != expected) { + String msg = "failed on " + uri; + msg += " expected " + expected + " got " + result; + throw new RuntimeException(msg); + } + } +} + diff --git a/tests/AndroidTests/src/com/android/unit_tests/UriTest.java b/tests/AndroidTests/src/com/android/unit_tests/UriTest.java new file mode 100644 index 0000000000000000000000000000000000000000..130beeb3d9893b1c0e10f121f2082424a6b1075a --- /dev/null +++ b/tests/AndroidTests/src/com/android/unit_tests/UriTest.java @@ -0,0 +1,502 @@ +/* + * Copyright (C) 2007 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.android.unit_tests; + +import android.net.Uri; +import android.content.ContentUris; +import android.os.Parcel; +import android.test.suitebuilder.annotation.SmallTest; +import junit.framework.TestCase; + +import java.io.File; +import java.util.Arrays; + +public class UriTest extends TestCase { + + @SmallTest + public void testToStringWithPathOnly() { + Uri.Builder builder = new Uri.Builder(); + + // Not a valid path, but this came from a user's test case. + builder.path("//foo"); + Uri uri = builder.build(); + assertEquals("//foo", uri.toString()); + } + + @SmallTest + public void testParcelling() { + parcelAndUnparcel(Uri.parse("foo:bob%20lee")); + parcelAndUnparcel(Uri.fromParts("foo", "bob lee", "fragment")); + parcelAndUnparcel(new Uri.Builder() + .scheme("http") + .authority("crazybob.org") + .path("/rss/") + .encodedQuery("a=b") + .fragment("foo") + .build()); + } + + private void parcelAndUnparcel(Uri u) { + Parcel p = Parcel.obtain(); + Uri.writeToParcel(p, u); + p.setDataPosition(0); + assertEquals(u, Uri.CREATOR.createFromParcel(p)); + + p.setDataPosition(0); + u = u.buildUpon().build(); + Uri.writeToParcel(p, u); + p.setDataPosition(0); + assertEquals(u, Uri.CREATOR.createFromParcel(p)); + } + + @SmallTest + public void testBuildUponOpaqueStringUri() { + Uri u = Uri.parse("bob:lee").buildUpon().scheme("robert").build(); + assertEquals("robert", u.getScheme()); + assertEquals("lee", u.getEncodedSchemeSpecificPart()); + assertEquals("lee", u.getSchemeSpecificPart()); + assertNull(u.getQuery()); + assertNull(u.getPath()); + assertNull(u.getAuthority()); + assertNull(u.getHost()); + } + + @SmallTest + public void testStringUri() { + assertEquals("bob lee", + Uri.parse("foo:bob%20lee").getSchemeSpecificPart()); + assertEquals("bob%20lee", + Uri.parse("foo:bob%20lee").getEncodedSchemeSpecificPart()); + assertEquals("/bob%20lee", + Uri.parse("foo:/bob%20lee").getEncodedPath()); + assertNull(Uri.parse("foo:bob%20lee").getPath()); + assertEquals("bob%20lee", + Uri.parse("foo:?bob%20lee").getEncodedQuery()); + assertNull(Uri.parse("foo:bar#?bob%20lee").getQuery()); + assertEquals("bob%20lee", + Uri.parse("foo:#bob%20lee").getEncodedFragment()); + } + + @SmallTest + public void testStringUriIsHierarchical() { + assertTrue(Uri.parse("bob").isHierarchical()); + assertFalse(Uri.parse("bob:").isHierarchical()); + } + + @SmallTest + public void testNullUriString() { + try { + Uri.parse(null); + fail(); + } catch (NullPointerException e) {} + } + + @SmallTest + public void testNullFile() { + try { + Uri.fromFile(null); + fail(); + } catch (NullPointerException e) {} + } + + @SmallTest + public void testCompareTo() { + Uri a = Uri.parse("foo:a"); + Uri b = Uri.parse("foo:b"); + Uri b2 = Uri.parse("foo:b"); + + assertTrue(a.compareTo(b) < 0); + assertTrue(b.compareTo(a) > 0); + assertEquals(0, b.compareTo(b2)); + } + + @SmallTest + public void testEqualsAndHashCode() { + + Uri a = Uri.parse("http://crazybob.org/test/?foo=bar#tee"); + + Uri b = new Uri.Builder() + .scheme("http") + .authority("crazybob.org") + .path("/test/") + .encodedQuery("foo=bar") + .fragment("tee") + .build(); + + // Try alternate builder methods. + Uri c = new Uri.Builder() + .scheme("http") + .encodedAuthority("crazybob.org") + .encodedPath("/test/") + .encodedQuery("foo=bar") + .encodedFragment("tee") + .build(); + + assertFalse(Uri.EMPTY.equals(null)); + + assertEquals(a, b); + assertEquals(b, c); + assertEquals(c, a); + + assertEquals(a.hashCode(), b.hashCode()); + assertEquals(b.hashCode(), c.hashCode()); + } + + @SmallTest + public void testAuthorityParsing() { + Uri uri = Uri.parse("http://localhost:42"); + assertEquals("localhost", uri.getHost()); + assertEquals(42, uri.getPort()); + + uri = Uri.parse("http://bob@localhost:42"); + assertEquals("bob", uri.getUserInfo()); + assertEquals("localhost", uri.getHost()); + assertEquals(42, uri.getPort()); + + uri = Uri.parse("http://bob%20lee@localhost:42"); + assertEquals("bob lee", uri.getUserInfo()); + assertEquals("bob%20lee", uri.getEncodedUserInfo()); + + uri = Uri.parse("http://localhost"); + assertEquals("localhost", uri.getHost()); + assertEquals(-1, uri.getPort()); + } + + @SmallTest + public void testBuildUponOpaqueUri() { + Uri a = Uri.fromParts("foo", "bar", "tee"); + Uri b = a.buildUpon().fragment("new").build(); + assertEquals("new", b.getFragment()); + assertEquals("bar", b.getSchemeSpecificPart()); + assertEquals("foo", b.getScheme()); + } + + @SmallTest + public void testBuildUponEncodedOpaqueUri() { + Uri a = new Uri.Builder() + .scheme("foo") + .encodedOpaquePart("bar") + .fragment("tee") + .build(); + Uri b = a.buildUpon().fragment("new").build(); + assertEquals("new", b.getFragment()); + assertEquals("bar", b.getSchemeSpecificPart()); + assertEquals("foo", b.getScheme()); + } + + @SmallTest + public void testPathSegmentDecoding() { + Uri uri = Uri.parse("foo://bar/a%20a/b%20b"); + assertEquals("a a", uri.getPathSegments().get(0)); + assertEquals("b b", uri.getPathSegments().get(1)); + } + + @SmallTest + public void testSms() { + Uri base = Uri.parse("content://sms"); + Uri appended = base.buildUpon() + .appendEncodedPath("conversations/addr=555-1212") + .build(); + assertEquals("content://sms/conversations/addr=555-1212", + appended.toString()); + assertEquals(2, appended.getPathSegments().size()); + assertEquals("conversations", appended.getPathSegments().get(0)); + assertEquals("addr=555-1212", appended.getPathSegments().get(1)); + } + + @SmallTest + public void testEncodeWithAllowedChars() { + String encoded = Uri.encode("Bob:/", "/"); + assertEquals(-1, encoded.indexOf(':')); + assertTrue(encoded.indexOf('/') > -1); + } + + @SmallTest + public void testEncodeDecode() { + code(null); + code(""); + code("Bob"); + code(":Bob"); + code("::Bob"); + code("Bob::Lee"); + code("Bob:Lee"); + code("Bob::"); + code("Bob:"); + code("::Bob::"); + } + + private void code(String s) { + assertEquals(s, Uri.decode(Uri.encode(s, null))); + } + + @SmallTest + public void testFile() { + File f = new File("/tmp/bob"); + + Uri uri = Uri.fromFile(f); + + assertEquals("file:///tmp/bob", uri.toString()); + } + + @SmallTest + public void testQueryParameters() { + Uri uri = Uri.parse("content://user"); + + assertEquals(null, uri.getQueryParameter("a")); + + uri = uri.buildUpon().appendQueryParameter("a", "b").build(); + + assertEquals("b", uri.getQueryParameter("a")); + + uri = uri.buildUpon().appendQueryParameter("a", "b2").build(); + + assertEquals(Arrays.asList("b", "b2"), uri.getQueryParameters("a")); + + uri = uri.buildUpon().appendQueryParameter("c", "d").build(); + + assertEquals(Arrays.asList("b", "b2"), uri.getQueryParameters("a")); + assertEquals("d", uri.getQueryParameter("c")); + } + + @SmallTest + public void testSchemeOnly() { + Uri uri = Uri.parse("empty:"); + assertEquals("empty", uri.getScheme()); + assertTrue(uri.isAbsolute()); + assertNull(uri.getPath()); + } + + @SmallTest + public void testEmptyPath() { + Uri uri = Uri.parse("content://user"); + assertEquals(0, uri.getPathSegments().size()); + } + + @SmallTest + public void testPathOperations() { + Uri uri = Uri.parse("content://user/a/b"); + + assertEquals(2, uri.getPathSegments().size()); + assertEquals("b", uri.getLastPathSegment()); + + Uri first = uri; + uri = uri.buildUpon().appendPath("c").build(); + + assertEquals(3, uri.getPathSegments().size()); + assertEquals("c", uri.getLastPathSegment()); + assertEquals("content://user/a/b/c", uri.toString()); + + uri = ContentUris.withAppendedId(uri, 100); + + assertEquals(4, uri.getPathSegments().size()); + assertEquals("100", uri.getLastPathSegment()); + assertEquals(100, ContentUris.parseId(uri)); + assertEquals("content://user/a/b/c/100", uri.toString()); + + // Make sure the original URI is still intact. + assertEquals(2, first.getPathSegments().size()); + assertEquals("b", first.getLastPathSegment()); + + try { + first.getPathSegments().get(2); + fail(); + } catch (IndexOutOfBoundsException e) {} + + assertEquals(null, Uri.EMPTY.getLastPathSegment()); + + Uri withC = Uri.parse("foo:/a/b/").buildUpon().appendPath("c").build(); + assertEquals("/a/b/c", withC.getPath()); + } + + @SmallTest + public void testOpaqueUri() { + Uri uri = Uri.parse("mailto:nobody"); + testOpaqueUri(uri); + + uri = uri.buildUpon().build(); + testOpaqueUri(uri); + + uri = Uri.fromParts("mailto", "nobody", null); + testOpaqueUri(uri); + + uri = uri.buildUpon().build(); + testOpaqueUri(uri); + + uri = new Uri.Builder() + .scheme("mailto") + .opaquePart("nobody") + .build(); + testOpaqueUri(uri); + + uri = uri.buildUpon().build(); + testOpaqueUri(uri); + } + + private void testOpaqueUri(Uri uri) { + assertEquals("mailto", uri.getScheme()); + assertEquals("nobody", uri.getSchemeSpecificPart()); + assertEquals("nobody", uri.getEncodedSchemeSpecificPart()); + + assertNull(uri.getFragment()); + assertTrue(uri.isAbsolute()); + assertTrue(uri.isOpaque()); + assertFalse(uri.isRelative()); + assertFalse(uri.isHierarchical()); + + assertNull(uri.getAuthority()); + assertNull(uri.getEncodedAuthority()); + assertNull(uri.getPath()); + assertNull(uri.getEncodedPath()); + assertNull(uri.getUserInfo()); + assertNull(uri.getEncodedUserInfo()); + assertNull(uri.getQuery()); + assertNull(uri.getEncodedQuery()); + assertNull(uri.getHost()); + assertEquals(-1, uri.getPort()); + + assertTrue(uri.getPathSegments().isEmpty()); + assertNull(uri.getLastPathSegment()); + + assertEquals("mailto:nobody", uri.toString()); + + Uri withFragment = uri.buildUpon().fragment("top").build(); + assertEquals("mailto:nobody#top", withFragment.toString()); + } + + @SmallTest + public void testHierarchicalUris() { + testHierarchical("http", "google.com", "/p1/p2", "query", "fragment"); + testHierarchical("file", null, "/p1/p2", null, null); + testHierarchical("content", "contact", "/p1/p2", null, null); + testHierarchical("http", "google.com", "/p1/p2", null, "fragment"); + testHierarchical("http", "google.com", "", null, "fragment"); + testHierarchical("http", "google.com", "", "query", "fragment"); + testHierarchical("http", "google.com", "", "query", null); + testHierarchical("http", null, "/", "query", null); + } + + private static void testHierarchical(String scheme, String authority, + String path, String query, String fragment) { + StringBuilder sb = new StringBuilder(); + + if (authority != null) { + sb.append("//").append(authority); + } + if (path != null) { + sb.append(path); + } + if (query != null) { + sb.append('?').append(query); + } + + String ssp = sb.toString(); + + if (scheme != null) { + sb.insert(0, scheme + ":"); + } + if (fragment != null) { + sb.append('#').append(fragment); + } + + String uriString = sb.toString(); + + Uri uri = Uri.parse(uriString); + + // Run these twice to test caching. + compareHierarchical( + uriString, ssp, uri, scheme, authority, path, query, fragment); + compareHierarchical( + uriString, ssp, uri, scheme, authority, path, query, fragment); + + // Test rebuilt version. + uri = uri.buildUpon().build(); + + // Run these twice to test caching. + compareHierarchical( + uriString, ssp, uri, scheme, authority, path, query, fragment); + compareHierarchical( + uriString, ssp, uri, scheme, authority, path, query, fragment); + + // The decoded and encoded versions of the inputs are all the same. + // We'll test the actual encoding decoding separately. + + // Test building with encoded versions. + Uri built = new Uri.Builder() + .scheme(scheme) + .encodedAuthority(authority) + .encodedPath(path) + .encodedQuery(query) + .encodedFragment(fragment) + .build(); + + compareHierarchical( + uriString, ssp, built, scheme, authority, path, query, fragment); + compareHierarchical( + uriString, ssp, built, scheme, authority, path, query, fragment); + + // Test building with decoded versions. + built = new Uri.Builder() + .scheme(scheme) + .authority(authority) + .path(path) + .query(query) + .fragment(fragment) + .build(); + + compareHierarchical( + uriString, ssp, built, scheme, authority, path, query, fragment); + compareHierarchical( + uriString, ssp, built, scheme, authority, path, query, fragment); + + // Rebuild. + built = built.buildUpon().build(); + + compareHierarchical( + uriString, ssp, built, scheme, authority, path, query, fragment); + compareHierarchical( + uriString, ssp, built, scheme, authority, path, query, fragment); + } + + private static void compareHierarchical(String uriString, String ssp, + Uri uri, + String scheme, String authority, String path, String query, + String fragment) { + assertEquals(scheme, uri.getScheme()); + assertEquals(authority, uri.getAuthority()); + assertEquals(authority, uri.getEncodedAuthority()); + assertEquals(path, uri.getPath()); + assertEquals(path, uri.getEncodedPath()); + assertEquals(query, uri.getQuery()); + assertEquals(query, uri.getEncodedQuery()); + assertEquals(fragment, uri.getFragment()); + assertEquals(fragment, uri.getEncodedFragment()); + assertEquals(ssp, uri.getSchemeSpecificPart()); + + if (scheme != null) { + assertTrue(uri.isAbsolute()); + assertFalse(uri.isRelative()); + } else { + assertFalse(uri.isAbsolute()); + assertTrue(uri.isRelative()); + } + + assertFalse(uri.isOpaque()); + assertTrue(uri.isHierarchical()); + + assertEquals(uriString, uri.toString()); + } +} diff --git a/tests/AndroidTests/src/com/android/unit_tests/UrlRulesTest.java b/tests/AndroidTests/src/com/android/unit_tests/UrlRulesTest.java new file mode 100644 index 0000000000000000000000000000000000000000..a7c19a780e7a3b65c4c1aa425ba05b0b6b74db9b --- /dev/null +++ b/tests/AndroidTests/src/com/android/unit_tests/UrlRulesTest.java @@ -0,0 +1,120 @@ +/* + * 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.android.unit_tests; + +import android.content.ContentResolver; +import android.provider.Settings; +import android.test.AndroidTestCase; +import android.test.suitebuilder.annotation.MediumTest; +import android.test.suitebuilder.annotation.SmallTest; + +import com.google.android.net.UrlRules; +import static com.google.android.net.UrlRules.Rule; + +/** Test loading and matching URL rewrite rules for UrlRules. */ +public class UrlRulesTest extends AndroidTestCase { + @SmallTest + public void testEmptyRules() { + UrlRules rules = new UrlRules(new Rule[] { }); + assertTrue(rules.matchRule("http://foo.bar/") == Rule.DEFAULT); + } + + @SmallTest + public void testInvalidRule() throws Exception { + try { + new Rule("rule", "foo bar"); + } catch (Exception e) { + // Re-throw any exception except the one we're looking for. + if (!e.toString().contains("Illegal rule: foo bar")) throw e; + } + } + + @SmallTest + public void testRewriteRule() throws UrlRules.RuleFormatException { + Rule rule = new Rule("test_rule", + "http://foo.bar/ rewrite http://bar.foo/"); + assertEquals("test_rule", rule.mName); + assertEquals("http://foo.bar/", rule.mPrefix); + assertEquals("http://bar.foo/", rule.mRewrite); + assertFalse(rule.mBlock); + assertEquals("http://bar.foo/bat", rule.apply("http://foo.bar/bat")); + } + + @SmallTest + public void testBlockRule() throws UrlRules.RuleFormatException { + Rule rule = new Rule("test_rule", + "http://foo.bar/ block"); + assertEquals("test_rule", rule.mName); + assertEquals("http://foo.bar/", rule.mPrefix); + assertTrue(rule.mRewrite == null); + assertTrue(rule.mBlock); + assertTrue(rule.apply("http://foo.bar/bat") == null); + } + + @SmallTest + public void testMatchRule() throws UrlRules.RuleFormatException { + UrlRules rules = new UrlRules(new Rule[] { + new Rule("12", "http://one.two/ rewrite http://buckle.my.shoe/"), + new Rule("34", "http://three.four/ rewrite http://close.the.door/"), + new Rule("56", "http://five.six/ rewrite http://pick.up.sticks/"), + }); + + assertTrue(rules.matchRule("https://one.two/") == Rule.DEFAULT); + assertTrue(rules.matchRule("http://one.two") == Rule.DEFAULT); + assertEquals("12", rules.matchRule("http://one.two/foo").mName); + + String u = "http://five.six/bar"; + assertEquals("http://pick.up.sticks/bar", rules.matchRule(u).apply(u)); + } + + @SmallTest + public void testAmbiguousMatch() throws UrlRules.RuleFormatException { + // Rule is the longest match wins. + UrlRules rules = new UrlRules(new Rule[] { + new Rule("1", "http://xyz/one rewrite http://rewrite/"), + new Rule("123", "http://xyz/onetwothree rewrite http://rewrite/"), + new Rule("12", "http://xyz/onetwo rewrite http://rewrite/"), + }); + + assertEquals("1", rules.matchRule("http://xyz/one").mName); + assertEquals("1", rules.matchRule("http://xyz/one...").mName); + assertEquals("12", rules.matchRule("http://xyz/onetwo...").mName); + assertEquals("123", rules.matchRule("http://xyz/onetwothree...").mName); + + } + + @MediumTest + public void testGservicesRules() { + // TODO: use a MockContentProvider/MockContentResolver instead. + ContentResolver r = getContext().getContentResolver(); + + // Update the digest, so the UrlRules cache is reloaded. + Settings.Gservices.putString(r, "digest", "testGservicesRules"); + Settings.Gservices.putString(r, "url:blank_test", ""); + Settings.Gservices.putString(r, "url:test", + "http://foo.bar/ rewrite http://bar.foo/"); + + UrlRules rules = UrlRules.getRules(r); // Don't crash, please. :) + assertTrue(rules.matchRule("http://bar.foo/") == Rule.DEFAULT); + + Rule rule = rules.matchRule("http://foo.bar/bat"); + assertEquals("test", rule.mName); + assertEquals("http://foo.bar/", rule.mPrefix); + assertEquals("http://bar.foo/", rule.mRewrite); + assertFalse(rule.mBlock); + } +} diff --git a/tests/AndroidTests/src/com/android/unit_tests/VectorTest.java b/tests/AndroidTests/src/com/android/unit_tests/VectorTest.java new file mode 100644 index 0000000000000000000000000000000000000000..22f97711a31f97375dd32db32331abe3a7eb9e4b --- /dev/null +++ b/tests/AndroidTests/src/com/android/unit_tests/VectorTest.java @@ -0,0 +1,555 @@ +/* + * Copyright (C) 2007 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.android.unit_tests; + +import android.test.PerformanceTestBase; +import android.test.PerformanceTestCase; + +import java.util.Vector; +import java.util.Enumeration; + +/** + * Basic Performance Tests for java.util.Vector + */ + +@SuppressWarnings("unchecked") +public class VectorTest extends PerformanceTestBase { + public static final int ITERATIONS = 1000; + private Vector mVector; + private Vector mStrVector; + private String mTestString = "Hello Android"; + + @Override + protected void setUp() throws Exception { + super.setUp(); + mVector = new Vector(); + mStrVector = new Vector(); + for (int i = ITERATIONS - 1; i >= 0; i--) { + assertTrue(mVector.add(i)); + assertTrue(mStrVector.add(Integer.toString(i))); + } + } + + @Override + public int startPerformance(PerformanceTestCase.Intermediates intermediates) { + intermediates.setInternalIterations(ITERATIONS); + return 0; + } + + public void testVectorAdd() { + Vector vector = new Vector(); + for (int i = ITERATIONS - 1; i >= 0; i--) { + vector.add(i); + vector.add(i); + vector.add(i); + vector.add(i); + vector.add(i); + vector.add(i); + vector.add(i); + vector.add(i); + vector.add(i); + vector.add(i); + } + } + + public void testVectorAdd1() { + Vector vector = new Vector(); + for (int i = ITERATIONS - 1; i >= 0; i--) { + vector.add(0, i); + vector.add(0, i); + vector.add(0, i); + vector.add(0, i); + vector.add(0, i); + vector.add(0, i); + vector.add(0, i); + vector.add(0, i); + vector.add(0, i); + vector.add(0, i); + } + } + + public void testVectorToArray() { + Object array; + Vector vector = mVector; + for (int i = ITERATIONS - 1; i >= 0; i--) { + array = vector.toArray(); + array = vector.toArray(); + array = vector.toArray(); + array = vector.toArray(); + array = vector.toArray(); + array = vector.toArray(); + array = vector.toArray(); + array = vector.toArray(); + array = vector.toArray(); + array = vector.toArray(); + } + } + + /** + * + */ + public void testVectorSize() { + Vector vector = mVector; + for (int i = ITERATIONS - 1; i >= 0; i--) { + int mLen; + mLen = vector.size(); + mLen = vector.size(); + mLen = vector.size(); + mLen = vector.size(); + mLen = vector.size(); + mLen = vector.size(); + mLen = vector.size(); + mLen = vector.size(); + mLen = vector.size(); + mLen = vector.size(); + } + } + + public void testVectorGet() { + int element; + Vector vector = mVector; + for (int i = ITERATIONS - 1; i >= 0; i--) { + element = vector.get(i); + element = vector.get(i); + element = vector.get(i); + element = vector.get(i); + element = vector.get(i); + element = vector.get(i); + element = vector.get(i); + element = vector.get(i); + element = vector.get(i); + element = vector.get(i); + } + + } + + public void testVectorContains() { + boolean flag; + Vector vector = mVector; + for (int i = ITERATIONS - 1; i >= 0; i--) { + flag = vector.contains(i); + flag = vector.contains(i); + flag = vector.contains(i); + flag = vector.contains(i); + flag = vector.contains(i); + flag = vector.contains(i); + flag = vector.contains(i); + flag = vector.contains(i); + flag = vector.contains(i); + flag = vector.contains(i); + } + } + + public void testVectorToArray1() { + Integer[] rArray = new Integer[100]; + Integer[] array; + Vector vector = mVector; + for (int i = ITERATIONS - 1; i >= 0; i--) { + array = vector.toArray(rArray); + array = vector.toArray(rArray); + array = vector.toArray(rArray); + array = vector.toArray(rArray); + array = vector.toArray(rArray); + array = vector.toArray(rArray); + array = vector.toArray(rArray); + array = vector.toArray(rArray); + array = vector.toArray(rArray); + array = vector.toArray(rArray); + } + } + + public void testVectorSet() { + Vector vector = mVector; + int pos = 5, value = 0; + for (int i = ITERATIONS - 1; i >= 0; i--) { + vector.set(pos, value); + vector.set(pos, value); + vector.set(pos, value); + vector.set(pos, value); + vector.set(pos, value); + vector.set(pos, value); + vector.set(pos, value); + vector.set(pos, value); + vector.set(pos, value); + vector.set(pos, value); + } + } + + public void testVectorIndexOf() { + int index, value = 0; + Vector vector = mVector; + for (int i = ITERATIONS - 1; i >= 0; i--) { + index = vector.indexOf(value); + index = vector.indexOf(value); + index = vector.indexOf(value); + index = vector.indexOf(value); + index = vector.indexOf(value); + index = vector.indexOf(value); + index = vector.indexOf(value); + index = vector.indexOf(value); + index = vector.indexOf(value); + index = vector.indexOf(value); + } + } + + public void testVectorLastIndexOf() { + int index, value = 0; + Vector vector = mVector; + for (int i = ITERATIONS - 1; i >= 0; i--) { + index = vector.lastIndexOf(value); + index = vector.lastIndexOf(value); + index = vector.lastIndexOf(value); + index = vector.lastIndexOf(value); + index = vector.lastIndexOf(value); + index = vector.lastIndexOf(value); + index = vector.lastIndexOf(value); + index = vector.lastIndexOf(value); + index = vector.lastIndexOf(value); + index = vector.lastIndexOf(value); + } + } + + public void testVectorRemove() { + int index, value = 0; + Vector vector = new Vector(mVector); + for (int i = 10; i > 0; i--) { + index = vector.remove(value); + index = vector.remove(value); + index = vector.remove(value); + index = vector.remove(value); + index = vector.remove(value); + index = vector.remove(value); + index = vector.remove(value); + index = vector.remove(value); + index = vector.remove(value); + index = vector.remove(value); + } + } + + public void testVectorRemoveElement() { + Vector vector = new Vector(mVector); + for (int i = 10; i > 0; i--) { + vector.removeElement(i); + vector.removeElement(i); + vector.removeElement(i); + vector.removeElement(i); + vector.removeElement(i); + vector.removeElement(i); + vector.removeElement(i); + vector.removeElement(i); + vector.removeElement(i); + vector.removeElement(i); + } + } + + public void VectorRemoveElementAt() { + Vector vector = new Vector(mVector); + for (int i = 10; i > 0; i--) { + vector.removeElementAt(i); + vector.removeElementAt(i); + vector.removeElementAt(i); + vector.removeElementAt(i); + vector.removeElementAt(i); + vector.removeElementAt(i); + vector.removeElementAt(i); + vector.removeElementAt(i); + vector.removeElementAt(i); + vector.removeElementAt(i); + } + } + + public void VectorAddAll() { + Vector vector = new Vector(), vector1 = mVector; + + boolean flag; + for (int i = 10; i > 0; i--) { + flag = vector.addAll(vector1); + flag = vector.addAll(vector1); + flag = vector.addAll(vector1); + flag = vector.addAll(vector1); + flag = vector.addAll(vector1); + flag = vector.addAll(vector1); + flag = vector.addAll(vector1); + flag = vector.addAll(vector1); + flag = vector.addAll(vector1); + flag = vector.addAll(vector1); + } + } + + public void VectorRemove1() { + Vector vector = mStrVector; + for (int j = 1000; j > 0; j--) { + vector.add("a"); + vector.add("b"); + } + String s = new String("a"); + boolean flag; + for (int i = 10; i > 0; i--) { + flag = vector.remove(s); + flag = vector.remove(s); + flag = vector.remove(s); + flag = vector.remove(s); + flag = vector.remove(s); + flag = vector.remove(s); + flag = vector.remove(s); + flag = vector.remove(s); + flag = vector.remove(s); + flag = vector.remove(s); + } + } + + public void testVectorAddAll1() { + Vector mEmptyVector = new Vector(); + boolean flag; + int pos = 0; + Vector vector1 = mVector; + Vector vector = mEmptyVector; + for (int i = 10; i > 0; i--) { + flag = vector.addAll(pos, vector1); + flag = vector.addAll(pos, vector1); + flag = vector.addAll(pos, vector1); + flag = vector.addAll(pos, vector1); + flag = vector.addAll(pos, vector1); + flag = vector.addAll(pos, vector1); + flag = vector.addAll(pos, vector1); + flag = vector.addAll(pos, vector1); + flag = vector.addAll(pos, vector1); + flag = vector.addAll(pos, vector1); + } + } + + public void testVectorClone() { + Object obj; + Vector vector = mVector; + for (int i = ITERATIONS - 1; i > 0; i--) { + obj = vector.clone(); + obj = vector.clone(); + obj = vector.clone(); + obj = vector.clone(); + obj = vector.clone(); + obj = vector.clone(); + obj = vector.clone(); + obj = vector.clone(); + obj = vector.clone(); + obj = vector.clone(); + } + } + + public void testVectorCapacity() { + int capacity; + Vector vector = mVector; + for (int i = ITERATIONS - 1; i > 0; i--) { + capacity = vector.capacity(); + capacity = vector.capacity(); + capacity = vector.capacity(); + capacity = vector.capacity(); + capacity = vector.capacity(); + capacity = vector.capacity(); + capacity = vector.capacity(); + capacity = vector.capacity(); + capacity = vector.capacity(); + capacity = vector.capacity(); + } + } + + public void testVectorHashcode() { + int element; + Vector vector = mVector; + for (int i = ITERATIONS - 1; i > 0; i--) { + element = vector.hashCode(); + element = vector.hashCode(); + element = vector.hashCode(); + element = vector.hashCode(); + element = vector.hashCode(); + element = vector.hashCode(); + element = vector.hashCode(); + element = vector.hashCode(); + element = vector.hashCode(); + element = vector.hashCode(); + } + } + + public void testVectorElements() { + Enumeration elements; + Vector vector = mVector; + for (int i = ITERATIONS - 1; i > 0; i--) { + elements = vector.elements(); + elements = vector.elements(); + elements = vector.elements(); + elements = vector.elements(); + elements = vector.elements(); + elements = vector.elements(); + elements = vector.elements(); + elements = vector.elements(); + elements = vector.elements(); + elements = vector.elements(); + } + } + + public void testVectorToString() { + String str; + Vector vector = mVector; + for (int i = ITERATIONS - 1; i > 0; i--) { + str = vector.toString(); + str = vector.toString(); + str = vector.toString(); + str = vector.toString(); + str = vector.toString(); + str = vector.toString(); + str = vector.toString(); + str = vector.toString(); + str = vector.toString(); + str = vector.toString(); + } + } + + public void testVectorElementAt() { + int element; + Vector vector = mVector; + for (int i = ITERATIONS - 1; i > 0; i--) { + element = vector.elementAt(50); + element = vector.elementAt(50); + element = vector.elementAt(50); + element = vector.elementAt(50); + element = vector.elementAt(50); + element = vector.elementAt(50); + element = vector.elementAt(50); + element = vector.elementAt(50); + element = vector.elementAt(50); + element = vector.elementAt(50); + } + } + + public void testVectorAddElement() { + int element; + Vector vector = mStrVector; + for (int i = ITERATIONS - 1; i > 0; i--) { + vector.addElement(mTestString); + vector.addElement(mTestString); + vector.addElement(mTestString); + vector.addElement(mTestString); + vector.addElement(mTestString); + vector.addElement(mTestString); + vector.addElement(mTestString); + vector.addElement(mTestString); + vector.addElement(mTestString); + vector.addElement(mTestString); + } + } + + public void testVectorFirstElement() { + int element; + Vector vector = mVector; + for (int i = ITERATIONS - 1; i > 0; i--) { + element = vector.firstElement(); + element = vector.firstElement(); + element = vector.firstElement(); + element = vector.firstElement(); + element = vector.firstElement(); + element = vector.firstElement(); + element = vector.firstElement(); + element = vector.firstElement(); + element = vector.firstElement(); + element = vector.firstElement(); + } + } + + public void testVectorLastElement() { + int element; + Vector vector = mVector; + for (int i = ITERATIONS - 1; i > 0; i--) { + element = vector.lastElement(); + element = vector.lastElement(); + element = vector.lastElement(); + element = vector.lastElement(); + element = vector.lastElement(); + element = vector.lastElement(); + element = vector.lastElement(); + element = vector.lastElement(); + element = vector.lastElement(); + element = vector.lastElement(); + } + } + + public void testVectorSetElementAt() { + Vector vector = mVector; + int value1 = 500, value2 = 50; + for (int i = ITERATIONS - 1; i > 0; i--) { + vector.setElementAt(value1, value2); + vector.setElementAt(value1, value2); + vector.setElementAt(value1, value2); + vector.setElementAt(value1, value2); + vector.setElementAt(value1, value2); + vector.setElementAt(value1, value2); + vector.setElementAt(value1, value2); + vector.setElementAt(value1, value2); + vector.setElementAt(value1, value2); + vector.setElementAt(value1, value2); + } + } + + public void testVectorIsEmpty() { + boolean flag; + Vector vector = mVector; + for (int i = ITERATIONS - 1; i > 0; i--) { + flag = vector.isEmpty(); + flag = vector.isEmpty(); + flag = vector.isEmpty(); + flag = vector.isEmpty(); + flag = vector.isEmpty(); + flag = vector.isEmpty(); + flag = vector.isEmpty(); + flag = vector.isEmpty(); + flag = vector.isEmpty(); + flag = vector.isEmpty(); + } + } + + public void testVectorCopyInto() { + Integer[] rArray = new Integer[ITERATIONS]; + Vector vector = mVector; + for (int i = ITERATIONS - 1; i > 0; i--) { + vector.copyInto(rArray); + vector.copyInto(rArray); + vector.copyInto(rArray); + vector.copyInto(rArray); + vector.copyInto(rArray); + vector.copyInto(rArray); + vector.copyInto(rArray); + vector.copyInto(rArray); + vector.copyInto(rArray); + vector.copyInto(rArray); + } + } + + public void testVectorInsertElementAt() { + Vector vector = mStrVector; + String string = mTestString; + for (int i = ITERATIONS - 1; i > 0; i--) { + vector.insertElementAt(string, i); + vector.insertElementAt(string, i); + vector.insertElementAt(string, i); + vector.insertElementAt(string, i); + vector.insertElementAt(string, i); + vector.insertElementAt(string, i); + vector.insertElementAt(string, i); + vector.insertElementAt(string, i); + vector.insertElementAt(string, i); + vector.insertElementAt(string, i); + } + } +} diff --git a/tests/AndroidTests/src/com/android/unit_tests/WebkitTest.java b/tests/AndroidTests/src/com/android/unit_tests/WebkitTest.java new file mode 100644 index 0000000000000000000000000000000000000000..4a0519e271e3146fdbec861e53956c06bfbe057d --- /dev/null +++ b/tests/AndroidTests/src/com/android/unit_tests/WebkitTest.java @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2006 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.android.unit_tests; + +import android.test.AndroidTestCase; +import android.text.format.DateFormat; +import android.test.suitebuilder.annotation.MediumTest; +import android.util.Log; +import android.webkit.DateSorter; + +import java.util.Calendar; +import java.util.Date; + +public class WebkitTest extends AndroidTestCase { + + private static final String LOGTAG = WebkitTest.class.getName(); + + @MediumTest + public void testDateSorter() throws Exception { + /** + * Note: check the logging output manually to test + * nothing automated yet, besides object creation + */ + DateSorter dateSorter = new DateSorter(mContext); + Date date = new Date(); + + for (int i = 0; i < DateSorter.DAY_COUNT; i++) { + Log.i(LOGTAG, "Boundary " + i + " " + dateSorter.getBoundary(i)); + Log.i(LOGTAG, "Label " + i + " " + dateSorter.getLabel(i)); + } + + Calendar c = Calendar.getInstance(); + long time = c.getTimeInMillis(); + int index; + Log.i(LOGTAG, "now: " + dateSorter.getIndex(time)); + for (int i = 0; i < 20; i++) { + time -= 8 * 60 * 60 * 1000; // 8 hours + date.setTime(time); + c.setTime(date); + index = dateSorter.getIndex(time); + Log.i(LOGTAG, "time: " + DateFormat.format("yyyy/MM/dd kk:mm:ss", c).toString() + + " " + index + " " + dateSorter.getLabel(index)); + } + } +} diff --git a/tests/AndroidTests/src/com/android/unit_tests/activity/AbortReceiver.java b/tests/AndroidTests/src/com/android/unit_tests/activity/AbortReceiver.java new file mode 100644 index 0000000000000000000000000000000000000000..d9d6101e93ae9e98374a191e4750c7fbfc7052f4 --- /dev/null +++ b/tests/AndroidTests/src/com/android/unit_tests/activity/AbortReceiver.java @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2007 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.android.unit_tests.activity; + +import android.content.Context; +import android.content.Intent; +import android.content.BroadcastReceiver; +import android.os.RemoteException; +import android.os.IBinder; +import android.os.Parcel; +import android.util.Log; + +public class AbortReceiver extends BroadcastReceiver +{ + public AbortReceiver() + { + } + + public void onReceive(Context context, Intent intent) + { + //Log.i("AbortReceiver", "onReceiveIntent!"); + try { + IBinder caller = intent.getIBinderExtra("caller"); + Parcel data = Parcel.obtain(); + data.writeInterfaceToken(LaunchpadActivity.LAUNCH); + data.writeString(LaunchpadActivity.RECEIVER_ABORT); + caller.transact(LaunchpadActivity.GOT_RECEIVE_TRANSACTION, data, null, 0); + data.recycle(); + } catch (RemoteException ex) { + } + + // abort the broadcast!!! + abortBroadcast(); + } +} diff --git a/tests/AndroidTests/src/com/android/unit_tests/activity/ActivityManagerTest.java b/tests/AndroidTests/src/com/android/unit_tests/activity/ActivityManagerTest.java new file mode 100644 index 0000000000000000000000000000000000000000..d7d8c893c78f3a9596369eea517549cf72177e53 --- /dev/null +++ b/tests/AndroidTests/src/com/android/unit_tests/activity/ActivityManagerTest.java @@ -0,0 +1,115 @@ +/* + * 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.android.unit_tests.activity; + +import android.app.ActivityManager; +import android.content.Context; +import android.test.AndroidTestCase; +import android.test.suitebuilder.annotation.SmallTest; +import android.test.suitebuilder.annotation.Suppress; + +import java.util.Iterator; +import java.util.List; + +public class ActivityManagerTest extends AndroidTestCase { + + protected Context mContext; + protected ActivityManager mActivityManager; + + @Override + protected void setUp() throws Exception { + super.setUp(); + mContext = getContext(); + mActivityManager = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE); + } + + // TODO should write a test for getRecentTasks() + // TODO should write a test for getRunningTasks() + // TODO should write a test for getMemoryInfo() + + // TODO: Find a way to re-enable this. It fails if any other app has failed during startup. + // This is probably an OK assumption given the desired system status when we run unit tests, + // but it's not necessarily the right assumption for a unit test. + @Suppress + public void disabledTestErrorTasksEmpty() throws Exception { + + List errList; + + errList = mActivityManager.getProcessesInErrorState(); + + // test: confirm list is empty + assertNull(errList); + } + + // TODO: Force an activity into an error state - then see if we can catch it here? + @SmallTest + public void testErrorTasksWithError() throws Exception { + + List errList; + + // TODO force another process into an error condition. How? + + // test: confirm error list length is at least 1 under varying query lengths +// checkErrorListMax(1,-1); + + errList = mActivityManager.getProcessesInErrorState(); + + // test: the list itself is healthy + checkErrorListSanity(errList); + + // test: confirm our application shows up in the list + } + + // TODO: Force an activity into an ANR state - then see if we can catch it here? + @SmallTest + public void testErrorTasksWithANR() throws Exception { + + List errList; + + // TODO: force an application into an ANR state + + errList = mActivityManager.getProcessesInErrorState(); + + // test: the list itself is healthy + checkErrorListSanity(errList); + + // test: confirm our ANR'ing application shows up in the list + } + + // If any entries in appear in the list, sanity check them against all running applications + private void checkErrorListSanity(List errList) { + if (errList == null) return; + + Iterator iter = errList.iterator(); + while (iter.hasNext()) { + ActivityManager.ProcessErrorStateInfo info = iter.next(); + assertNotNull(info); + // sanity checks + assertTrue((info.condition == ActivityManager.ProcessErrorStateInfo.CRASHED) || + (info.condition == ActivityManager.ProcessErrorStateInfo.NOT_RESPONDING)); + // TODO look at each of these and consider a stronger test + // TODO can we cross-check at the process name via some other API? + // TODO is there a better test for strings, e.g. "assertIsLegalString") + assertNotNull(info.processName); + // reasonableness test for info.pid ? + assertNotNull(info.longMsg); + assertNotNull(info.shortMsg); + // is there any reasonable test for the crashData? Probably not. + } + } +} + diff --git a/tests/AndroidTests/src/com/android/unit_tests/activity/ActivityTests.java b/tests/AndroidTests/src/com/android/unit_tests/activity/ActivityTests.java new file mode 100644 index 0000000000000000000000000000000000000000..cffc60a69505fdfde61cd8c3c2c7347e5af183d5 --- /dev/null +++ b/tests/AndroidTests/src/com/android/unit_tests/activity/ActivityTests.java @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2006 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.android.unit_tests.activity; + +import junit.framework.TestSuite; + +public class ActivityTests { + public static final boolean DEBUG_LIFECYCLE = false; + + public static TestSuite suite() { + TestSuite suite = new TestSuite(ActivityTests.class.getName()); + + suite.addTestSuite(BroadcastTest.class); + suite.addTestSuite(IntentSenderTest.class); + suite.addTestSuite(ActivityManagerTest.class); + suite.addTestSuite(LaunchTest.class); + suite.addTestSuite(LifecycleTest.class); + suite.addTestSuite(ServiceTest.class); + suite.addTestSuite(MetaDataTest.class); + // Remove temporarily until bug 1171309 is fixed. + //suite.addTestSuite(SubActivityTest.class); + suite.addTestSuite(SetTimeZonePermissionsTest.class); + + return suite; + } +} diff --git a/tests/AndroidTests/src/com/android/unit_tests/activity/ActivityTestsBase.java b/tests/AndroidTests/src/com/android/unit_tests/activity/ActivityTestsBase.java new file mode 100644 index 0000000000000000000000000000000000000000..f9609698c7edcd3b6ceb63f6bea689b52db5be0d --- /dev/null +++ b/tests/AndroidTests/src/com/android/unit_tests/activity/ActivityTestsBase.java @@ -0,0 +1,212 @@ +/* + * Copyright (C) 2006 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.android.unit_tests.activity; + +import android.app.Activity; +import android.content.Context; +import android.content.Intent; +import android.test.AndroidTestCase; +import android.test.PerformanceTestCase; + +public class ActivityTestsBase extends AndroidTestCase + implements PerformanceTestCase, LaunchpadActivity.CallingTest { + public static final String PERMISSION_GRANTED = + "com.android.unit_tests.permission.TEST_GRANTED"; + public static final String PERMISSION_DENIED = + "com.android.unit_tests.permission.TEST_DENIED"; + + protected Intent mIntent; + + private PerformanceTestCase.Intermediates mIntermediates; + private String mExpecting; + + // Synchronization of activity result. + private boolean mFinished; + private int mResultCode = 0; + private Intent mData; + private RuntimeException mResultStack = null; + + @Override + protected void setUp() throws Exception { + super.setUp(); + mIntent = new Intent(mContext, LaunchpadActivity.class); + mIntermediates = null; + } + + @Override + protected void tearDown() throws Exception { + mIntermediates = null; + super.tearDown(); + } + + public boolean isPerformanceOnly() { + return false; + } + + public void setInternalIterations(int count) { + } + + public void startTiming(boolean realTime) { + if (mIntermediates != null) { + mIntermediates.startTiming(realTime); + } + } + + public void addIntermediate(String name) { + if (mIntermediates != null) { + mIntermediates.addIntermediate(name); + } + } + + public void addIntermediate(String name, long timeInNS) { + if (mIntermediates != null) { + mIntermediates.addIntermediate(name, timeInNS); + } + } + + public void finishTiming(boolean realTime) { + if (mIntermediates != null) { + mIntermediates.finishTiming(realTime); + } + } + + public void activityFinished(int resultCode, Intent data, RuntimeException where) { + finishWithResult(resultCode, data, where); + } + + public Intent editIntent() { + return mIntent; + } + + public Context getContext() { + return mContext; + } + + public int startPerformance(Intermediates intermediates) { + mIntermediates = intermediates; + return 1; + } + + public void finishGood() { + finishWithResult(Activity.RESULT_OK, null); + } + + public void finishBad(String error) { + finishWithResult(Activity.RESULT_CANCELED, (new Intent()).setAction(error)); + } + + public void finishWithResult(int resultCode, Intent data) { + RuntimeException where = new RuntimeException("Original error was here"); + where.fillInStackTrace(); + finishWithResult(resultCode, data, where); + } + + public void finishWithResult(int resultCode, Intent data, RuntimeException where) { + synchronized (this) { + //System.out.println("*** Activity finished!!"); + mResultCode = resultCode; + mData = data; + mResultStack = where; + mFinished = true; + notifyAll(); + } + } + + public int runLaunchpad(String action) { + LaunchpadActivity.setCallingTest(this); + + synchronized (this) { + mIntent.setAction(action); + mFinished = false; + //System.out.println("*** Starting: " + mIntent); + mIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + mContext.startActivity(mIntent); + } + + return waitForResultOrThrow(60 * 1000); + } + + public int waitForResultOrThrow(int timeoutMs) { + return waitForResultOrThrow(timeoutMs, null); + } + + public int waitForResultOrThrow(int timeoutMs, String expected) { + int res = waitForResult(timeoutMs, expected); + + if (res == Activity.RESULT_CANCELED) { + if (mResultStack != null) { + throw new RuntimeException( + mData != null ? mData.toString() : "Unable to launch", + mResultStack); + } else { + throw new RuntimeException( + mData != null ? mData.toString() : "Unable to launch"); + } + } + return res; + } + + public int waitForResult(int timeoutMs, String expected) { + mExpecting = expected; + + long endTime = System.currentTimeMillis() + timeoutMs; + + boolean timeout = false; + synchronized (this) { + while (!mFinished) { + long delay = endTime - System.currentTimeMillis(); + if (delay < 0) { + timeout = true; + break; + } + + try { + wait(delay); + } catch (java.lang.InterruptedException e) { + // do nothing + } + } + } + + mFinished = false; + + if (timeout) { + mResultCode = Activity.RESULT_CANCELED; + onTimeout(); + } + return mResultCode; + } + + public int getResultCode() { + return mResultCode; + } + + public Intent getResultData() { + return mData; + } + + public RuntimeException getResultStack() { + return mResultStack; + } + + public void onTimeout() { + String msg = mExpecting == null + ? "Timeout" : ("Timeout while expecting " + mExpecting); + finishWithResult(Activity.RESULT_CANCELED, (new Intent()).setAction(msg)); + } +} + diff --git a/tests/AndroidTests/src/com/android/unit_tests/activity/BroadcastTest.java b/tests/AndroidTests/src/com/android/unit_tests/activity/BroadcastTest.java new file mode 100644 index 0000000000000000000000000000000000000000..7f6db3c42498a238ffcfafe195a6a48fd689ca15 --- /dev/null +++ b/tests/AndroidTests/src/com/android/unit_tests/activity/BroadcastTest.java @@ -0,0 +1,536 @@ +/* + * Copyright (C) 2006 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.android.unit_tests.activity; + +import android.app.Activity; +import android.app.ActivityManagerNative; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.os.Binder; +import android.os.Bundle; +import android.os.IBinder; +import android.os.Parcel; +import android.test.FlakyTest; +import android.test.suitebuilder.annotation.Suppress; +import android.util.Log; + +import java.util.Arrays; + +public class BroadcastTest extends ActivityTestsBase { + public static final int BROADCAST_TIMEOUT = 5 * 1000; + + public static final String BROADCAST_REGISTERED = + "com.android.unit_tests.activity.BROADCAST_REGISTERED"; + public static final String BROADCAST_LOCAL = + "com.android.unit_tests.activity.BROADCAST_LOCAL"; + public static final String BROADCAST_LOCAL_GRANTED = + "com.android.unit_tests.activity.BROADCAST_LOCAL_GRANTED"; + public static final String BROADCAST_LOCAL_DENIED = + "com.android.unit_tests.activity.BROADCAST_LOCAL_DENIED"; + public static final String BROADCAST_REMOTE = + "com.android.unit_tests.activity.BROADCAST_REMOTE"; + public static final String BROADCAST_REMOTE_GRANTED = + "com.android.unit_tests.activity.BROADCAST_REMOTE_GRANTED"; + public static final String BROADCAST_REMOTE_DENIED = + "com.android.unit_tests.activity.BROADCAST_REMOTE_DENIED"; + public static final String BROADCAST_ALL = + "com.android.unit_tests.activity.BROADCAST_ALL"; + public static final String BROADCAST_MULTI = + "com.android.unit_tests.activity.BROADCAST_MULTI"; + public static final String BROADCAST_ABORT = + "com.android.unit_tests.activity.BROADCAST_ABORT"; + + public static final String BROADCAST_STICKY1 = + "com.android.unit_tests.activity.BROADCAST_STICKY1"; + public static final String BROADCAST_STICKY2 = + "com.android.unit_tests.activity.BROADCAST_STICKY2"; + + public static final String BROADCAST_FAIL_REGISTER = + "com.android.unit_tests.activity.BROADCAST_FAIL_REGISTER"; + public static final String BROADCAST_FAIL_BIND = + "com.android.unit_tests.activity.BROADCAST_FAIL_BIND"; + + public static final String RECEIVER_REG = "receiver-reg"; + public static final String RECEIVER_LOCAL = "receiver-local"; + public static final String RECEIVER_REMOTE = "receiver-remote"; + public static final String RECEIVER_ABORT = "receiver-abort"; + public static final String RECEIVER_RESULTS = "receiver-results"; + + public static final String DATA_1 = "one"; + public static final String DATA_2 = "two"; + + public static final int GOT_RECEIVE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION; + public static final int ERROR_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 1; + + private String[] mExpectedReceivers = null; + private int mNextReceiver; + + private String[] mExpectedData = null; + private boolean[] mReceivedData = null; + + boolean mReceiverRegistered = false; + + public void setExpectedReceivers(String[] receivers) { + mExpectedReceivers = receivers; + mNextReceiver = 0; + } + + public void setExpectedData(String[] data) { + mExpectedData = data; + mReceivedData = new boolean[data.length]; + } + + public void onTimeout() { + String msg = "Timeout"; + if (mExpectedReceivers != null && mNextReceiver < mExpectedReceivers.length) { + msg = msg + " waiting for " + mExpectedReceivers[mNextReceiver]; + } + finishBad(msg); + } + + public Intent makeBroadcastIntent(String action) { + Intent intent = new Intent(action, null); + intent.putExtra("caller", mCallTarget); + return intent; + } + + public void finishWithResult(int resultCode, Intent data) { + unregisterMyReceiver(); + super.finishWithResult(resultCode, data); + } + + public final void gotReceive(String name, Intent intent) { + synchronized (this) { + + //System.out.println("Got receive: " + name); + //System.out.println(mNextReceiver + " in " + mExpectedReceivers); + //new RuntimeException("stack").printStackTrace(); + + addIntermediate(name); + + if (mExpectedData != null) { + int n = mExpectedData.length; + int i; + boolean prev = false; + for (i = 0; i < n; i++) { + if (mExpectedData[i].equals(intent.getStringExtra("test"))) { + if (mReceivedData[i]) { + prev = true; + continue; + } + mReceivedData[i] = true; + break; + } + } + if (i >= n) { + if (prev) { + finishBad("Receive got data too many times: " + + intent.getStringExtra("test")); + } else { + finishBad("Receive got unexpected data: " + + intent.getStringExtra("test")); + } + new RuntimeException("stack").printStackTrace(); + return; + } + } + + if (mNextReceiver >= mExpectedReceivers.length) { + finishBad("Got too many onReceiveIntent() calls!"); +// System.out.println("Too many intents received: now at " +// + mNextReceiver + ", expect list: " +// + Arrays.toString(mExpectedReceivers)); + fail("Got too many onReceiveIntent() calls!"); + } else if (!mExpectedReceivers[mNextReceiver].equals(name)) { + finishBad("Receive out of order: got " + name + + " but expected " + + mExpectedReceivers[mNextReceiver]); + fail("Receive out of order: got " + name + + " but expected " + + mExpectedReceivers[mNextReceiver]); + } else { + mNextReceiver++; + if (mNextReceiver == mExpectedReceivers.length) { + finishTest(); + } + } + } + } + + public void registerMyReceiver(IntentFilter filter, String permission) { + mReceiverRegistered = true; + //System.out.println("Registering: " + mReceiver); + getContext().registerReceiver(mReceiver, filter, permission, null); + } + + public void unregisterMyReceiver() { + if (mReceiverRegistered) { + unregisterMyReceiverNoCheck(); + } + } + + public void unregisterMyReceiverNoCheck() { + mReceiverRegistered = false; + //System.out.println("Unregistering: " + mReceiver); + getContext().unregisterReceiver(mReceiver); + } + + public void onRegisteredReceiver(Intent intent) { + gotReceive(RECEIVER_REG, intent); + } + + private Binder mCallTarget = new Binder() { + public boolean onTransact(int code, Parcel data, Parcel reply, + int flags) { + data.setDataPosition(0); + data.enforceInterface(LaunchpadActivity.LAUNCH); + if (code == GOT_RECEIVE_TRANSACTION) { + String name = data.readString(); + gotReceive(name, null); + return true; + } else if (code == ERROR_TRANSACTION) { + finishBad(data.readString()); + return true; + } + return false; + } + }; + + private void finishTest() { + if (mReceiverRegistered) { + addIntermediate("before-unregister"); + unregisterMyReceiver(); + } + finishTiming(true); + finishGood(); + } + + private BroadcastReceiver mReceiver = new BroadcastReceiver() { + public void onReceive(Context context, Intent intent) { + //System.out.println("Receive in: " + this + ": " + intent); + onRegisteredReceiver(intent); + } + }; + + // Mark flaky until http://b/issue?id=1191607 is resolved. + @FlakyTest(tolerance=2) + public void testRegistered() throws Exception { + runLaunchpad(LaunchpadActivity.BROADCAST_REGISTERED); + } + + public void testLocal() throws Exception { + runLaunchpad(LaunchpadActivity.BROADCAST_LOCAL); + } + + public void testRemote() throws Exception { + runLaunchpad(LaunchpadActivity.BROADCAST_REMOTE); + } + + public void testAbort() throws Exception { + runLaunchpad(LaunchpadActivity.BROADCAST_ABORT); + } + + @FlakyTest(tolerance=2) + public void testAll() throws Exception { + runLaunchpad(LaunchpadActivity.BROADCAST_ALL); + } + + @FlakyTest(tolerance=2) + public void testMulti() throws Exception { + runLaunchpad(LaunchpadActivity.BROADCAST_MULTI); + } + + private class TestBroadcastReceiver extends BroadcastReceiver { + public boolean mHaveResult = false; + + @Override + public void onReceive(Context context, Intent intent) { + synchronized (BroadcastTest.this) { + mHaveResult = true; + BroadcastTest.this.notifyAll(); + } + } + } + + public void testResult() throws Exception { + TestBroadcastReceiver broadcastReceiver = new TestBroadcastReceiver(); + + synchronized (this) { + Bundle map = new Bundle(); + map.putString("foo", "you"); + map.putString("remove", "me"); + getContext().sendOrderedBroadcast( + new Intent("com.android.unit_tests.activity.BROADCAST_RESULT"), + null, broadcastReceiver, null, 1, "foo", map); + while (!broadcastReceiver.mHaveResult) { + try { + wait(); + } catch (InterruptedException e) { + } + } + + //System.out.println("Code: " + mResultCode + ", data: " + mResultData); + //System.out.println("Extras: " + mResultExtras); + + assertEquals("Incorrect code: " + broadcastReceiver.getResultCode(), + 3, broadcastReceiver.getResultCode()); + + assertEquals("bar", broadcastReceiver.getResultData()); + + Bundle resultExtras = broadcastReceiver.getResultExtras(false); + assertEquals("them", resultExtras.getString("bar")); + assertEquals("you", resultExtras.getString("foo")); + assertNull(resultExtras.getString("remove")); + } + } + + public void testSetSticky() throws Exception { + Intent intent = new Intent(LaunchpadActivity.BROADCAST_STICKY1, null); + intent.putExtra("test", LaunchpadActivity.DATA_1); + ActivityManagerNative.getDefault().unbroadcastIntent(null, intent); + + ActivityManagerNative.broadcastStickyIntent(intent, null); + addIntermediate("finished-broadcast"); + + IntentFilter filter = new IntentFilter(LaunchpadActivity.BROADCAST_STICKY1); + Intent sticky = getContext().registerReceiver(null, filter); + assertNotNull("Sticky not found", sticky); + assertEquals(LaunchpadActivity.DATA_1, sticky.getStringExtra("test")); + } + + public void testClearSticky() throws Exception { + Intent intent = new Intent(LaunchpadActivity.BROADCAST_STICKY1, null); + intent.putExtra("test", LaunchpadActivity.DATA_1); + ActivityManagerNative.broadcastStickyIntent(intent, null); + + ActivityManagerNative.getDefault().unbroadcastIntent( + null, new Intent(LaunchpadActivity.BROADCAST_STICKY1, null)); + addIntermediate("finished-unbroadcast"); + + IntentFilter filter = new IntentFilter(LaunchpadActivity.BROADCAST_STICKY1); + Intent sticky = getContext().registerReceiver(null, filter); + assertNull("Sticky not found", sticky); + } + + public void testReplaceSticky() throws Exception { + Intent intent = new Intent(LaunchpadActivity.BROADCAST_STICKY1, null); + intent.putExtra("test", LaunchpadActivity.DATA_1); + ActivityManagerNative.broadcastStickyIntent(intent, null); + intent.putExtra("test", LaunchpadActivity.DATA_2); + + ActivityManagerNative.broadcastStickyIntent(intent, null); + addIntermediate("finished-broadcast"); + + IntentFilter filter = new IntentFilter(LaunchpadActivity.BROADCAST_STICKY1); + Intent sticky = getContext().registerReceiver(null, filter); + assertNotNull("Sticky not found", sticky); + assertEquals(LaunchpadActivity.DATA_2, sticky.getStringExtra("test")); + } + + // Marking flaky until http://b/issue?id=1191337 is resolved + @FlakyTest(tolerance=2) + public void testReceiveSticky() throws Exception { + Intent intent = new Intent(LaunchpadActivity.BROADCAST_STICKY1, null); + intent.putExtra("test", LaunchpadActivity.DATA_1); + ActivityManagerNative.broadcastStickyIntent(intent, null); + + runLaunchpad(LaunchpadActivity.BROADCAST_STICKY1); + } + + // Marking flaky until http://b/issue?id=1191337 is resolved + @FlakyTest(tolerance=2) + public void testReceive2Sticky() throws Exception { + Intent intent = new Intent(LaunchpadActivity.BROADCAST_STICKY1, null); + intent.putExtra("test", LaunchpadActivity.DATA_1); + ActivityManagerNative.broadcastStickyIntent(intent, null); + intent = new Intent(LaunchpadActivity.BROADCAST_STICKY2, null); + intent.putExtra("test", LaunchpadActivity.DATA_2); + ActivityManagerNative.broadcastStickyIntent(intent, null); + + runLaunchpad(LaunchpadActivity.BROADCAST_STICKY2); + } + + public void testRegisteredReceivePermissionGranted() throws Exception { + setExpectedReceivers(new String[]{RECEIVER_REG}); + registerMyReceiver(new IntentFilter(BROADCAST_REGISTERED), PERMISSION_GRANTED); + addIntermediate("after-register"); + getContext().sendBroadcast(makeBroadcastIntent(BROADCAST_REGISTERED)); + waitForResultOrThrow(BROADCAST_TIMEOUT); + } + + public void testRegisteredReceivePermissionDenied() throws Exception { + setExpectedReceivers(new String[]{RECEIVER_RESULTS}); + registerMyReceiver(new IntentFilter(BROADCAST_REGISTERED), PERMISSION_DENIED); + addIntermediate("after-register"); + + BroadcastReceiver finish = new BroadcastReceiver() { + public void onReceive(Context context, Intent intent) { + gotReceive(RECEIVER_RESULTS, intent); + } + }; + + getContext().sendOrderedBroadcast( + makeBroadcastIntent(BROADCAST_REGISTERED), + null, finish, null, Activity.RESULT_CANCELED, null, null); + waitForResultOrThrow(BROADCAST_TIMEOUT); + } + + public void testRegisteredBroadcastPermissionGranted() throws Exception { + setExpectedReceivers(new String[]{RECEIVER_REG}); + registerMyReceiver(new IntentFilter(BROADCAST_REGISTERED), null); + addIntermediate("after-register"); + getContext().sendBroadcast( + makeBroadcastIntent(BROADCAST_REGISTERED), + PERMISSION_GRANTED); + waitForResultOrThrow(BROADCAST_TIMEOUT); + } + + public void testRegisteredBroadcastPermissionDenied() throws Exception { + setExpectedReceivers(new String[]{RECEIVER_RESULTS}); + registerMyReceiver(new IntentFilter(BROADCAST_REGISTERED), null); + addIntermediate("after-register"); + + BroadcastReceiver finish = new BroadcastReceiver() { + public void onReceive(Context context, Intent intent) { + gotReceive(RECEIVER_RESULTS, intent); + } + }; + + getContext().sendOrderedBroadcast( + makeBroadcastIntent(BROADCAST_REGISTERED), + PERMISSION_DENIED, finish, null, Activity.RESULT_CANCELED, + null, null); + waitForResultOrThrow(BROADCAST_TIMEOUT); + } + + public void testLocalReceivePermissionGranted() throws Exception { + setExpectedReceivers(new String[]{RECEIVER_LOCAL}); + getContext().sendBroadcast(makeBroadcastIntent(BROADCAST_LOCAL_GRANTED)); + waitForResultOrThrow(BROADCAST_TIMEOUT); + } + + public void testLocalReceivePermissionDenied() throws Exception { + setExpectedReceivers(new String[]{RECEIVER_RESULTS}); + + BroadcastReceiver finish = new BroadcastReceiver() { + public void onReceive(Context context, Intent intent) { + gotReceive(RECEIVER_RESULTS, intent); + } + }; + + getContext().sendOrderedBroadcast( + makeBroadcastIntent(BROADCAST_LOCAL_DENIED), + null, finish, null, Activity.RESULT_CANCELED, + null, null); + waitForResultOrThrow(BROADCAST_TIMEOUT); + } + + public void testLocalBroadcastPermissionGranted() throws Exception { + setExpectedReceivers(new String[]{RECEIVER_LOCAL}); + getContext().sendBroadcast( + makeBroadcastIntent(BROADCAST_LOCAL), + PERMISSION_GRANTED); + waitForResultOrThrow(BROADCAST_TIMEOUT); + } + + public void testLocalBroadcastPermissionDenied() throws Exception { + setExpectedReceivers(new String[]{RECEIVER_RESULTS}); + + BroadcastReceiver finish = new BroadcastReceiver() { + public void onReceive(Context context, Intent intent) { + gotReceive(RECEIVER_RESULTS, intent); + } + }; + + getContext().sendOrderedBroadcast( + makeBroadcastIntent(BROADCAST_LOCAL), + PERMISSION_DENIED, finish, null, Activity.RESULT_CANCELED, + null, null); + waitForResultOrThrow(BROADCAST_TIMEOUT); + } + + public void testRemoteReceivePermissionGranted() throws Exception { + setExpectedReceivers(new String[]{RECEIVER_REMOTE}); + getContext().sendBroadcast(makeBroadcastIntent(BROADCAST_REMOTE_GRANTED)); + waitForResultOrThrow(BROADCAST_TIMEOUT); + } + + public void testRemoteReceivePermissionDenied() throws Exception { + setExpectedReceivers(new String[]{RECEIVER_RESULTS}); + + BroadcastReceiver finish = new BroadcastReceiver() { + public void onReceive(Context context, Intent intent) { + gotReceive(RECEIVER_RESULTS, intent); + } + }; + + getContext().sendOrderedBroadcast( + makeBroadcastIntent(BROADCAST_REMOTE_DENIED), + null, finish, null, Activity.RESULT_CANCELED, + null, null); + waitForResultOrThrow(BROADCAST_TIMEOUT); + } + + public void testRemoteBroadcastPermissionGranted() throws Exception { + setExpectedReceivers(new String[]{RECEIVER_REMOTE}); + getContext().sendBroadcast( + makeBroadcastIntent(BROADCAST_REMOTE), + PERMISSION_GRANTED); + waitForResultOrThrow(BROADCAST_TIMEOUT); + } + + public void testRemoteBroadcastPermissionDenied() throws Exception { + setExpectedReceivers(new String[]{RECEIVER_RESULTS}); + + BroadcastReceiver finish = new BroadcastReceiver() { + public void onReceive(Context context, Intent intent) { + gotReceive(RECEIVER_RESULTS, intent); + } + }; + + getContext().sendOrderedBroadcast( + makeBroadcastIntent(BROADCAST_REMOTE), + PERMISSION_DENIED, finish, null, Activity.RESULT_CANCELED, + null, null); + waitForResultOrThrow(BROADCAST_TIMEOUT); + } + + public void testReceiverCanNotRegister() throws Exception { + setExpectedReceivers(new String[]{RECEIVER_LOCAL}); + getContext().sendBroadcast(makeBroadcastIntent(BROADCAST_FAIL_REGISTER)); + waitForResultOrThrow(BROADCAST_TIMEOUT); + } + + public void testReceiverCanNotBind() throws Exception { + setExpectedReceivers(new String[]{RECEIVER_LOCAL}); + getContext().sendBroadcast(makeBroadcastIntent(BROADCAST_FAIL_BIND)); + waitForResultOrThrow(BROADCAST_TIMEOUT); + } + + public void testLocalUnregisterTwice() throws Exception { + registerMyReceiver(new IntentFilter(BROADCAST_REGISTERED), null); + unregisterMyReceiverNoCheck(); + try { + unregisterMyReceiverNoCheck(); + fail("No exception thrown on second unregister"); + } catch (IllegalArgumentException e) { + Log.i("foo", "Unregister exception", e); + } + } +} diff --git a/tests/AndroidTests/src/com/android/unit_tests/activity/ClearTop.java b/tests/AndroidTests/src/com/android/unit_tests/activity/ClearTop.java new file mode 100644 index 0000000000000000000000000000000000000000..dd5274a320021e7a361de73a6b81625b2fd6ffc5 --- /dev/null +++ b/tests/AndroidTests/src/com/android/unit_tests/activity/ClearTop.java @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2006 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.android.unit_tests.activity; + +import android.app.Activity; +import android.content.Intent; +import android.os.Bundle; +import android.util.Log; + +public class ClearTop extends Activity { + public static final String WAIT_CLEAR_TASK = "waitClearTask"; + + public ClearTop() { + } + + @Override + public void onCreate(Bundle icicle) { + super.onCreate(icicle); + //Log.i("foo", "Creating: " + this); + Intent intent = new Intent(getIntent()).setAction(LocalScreen.CLEAR_TASK) + .setClass(this, LocalScreen.class); + startActivity(intent); + } + + @Override + public void onNewIntent(Intent intent) { + //Log.i("foo", "New intent in " + this + ": " + intent); + if (LocalScreen.CLEAR_TASK.equals(intent.getAction())) { + setResult(RESULT_OK); + } else { + setResult(RESULT_CANCELED, new Intent().setAction( + "New intent received " + intent + ", expecting action " + + TestedScreen.CLEAR_TASK)); + } + finish(); + } +} diff --git a/tests/AndroidTests/src/com/android/unit_tests/activity/IntentSenderTest.java b/tests/AndroidTests/src/com/android/unit_tests/activity/IntentSenderTest.java new file mode 100644 index 0000000000000000000000000000000000000000..a30c1cbf7742bb942eab820b1817f8607465f073 --- /dev/null +++ b/tests/AndroidTests/src/com/android/unit_tests/activity/IntentSenderTest.java @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2006 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.android.unit_tests.activity; + +import android.app.Activity; +import android.app.PendingIntent; +import android.content.Intent; +import android.content.IntentFilter; +import android.test.suitebuilder.annotation.Suppress; +import android.os.Bundle; +import android.test.suitebuilder.annotation.Suppress; + +public class IntentSenderTest extends BroadcastTest { + + public void testRegisteredReceivePermissionGranted() throws Exception { + setExpectedReceivers(new String[]{RECEIVER_REG}); + registerMyReceiver(new IntentFilter(BROADCAST_REGISTERED), PERMISSION_GRANTED); + addIntermediate("after-register"); + PendingIntent is = PendingIntent.getBroadcast(getContext(), 0, + makeBroadcastIntent(BROADCAST_REGISTERED), 0); + is.send(); + waitForResultOrThrow(BROADCAST_TIMEOUT); + is.cancel(); + } + + public void testRegisteredReceivePermissionDenied() throws Exception { + final Intent intent = makeBroadcastIntent(BROADCAST_REGISTERED); + + setExpectedReceivers(new String[]{RECEIVER_RESULTS}); + registerMyReceiver(new IntentFilter(BROADCAST_REGISTERED), PERMISSION_DENIED); + addIntermediate("after-register"); + + PendingIntent.OnFinished finish = new PendingIntent.OnFinished() { + public void onSendFinished(PendingIntent pi, Intent intent, + int resultCode, String resultData, Bundle resultExtras) { + gotReceive(RECEIVER_RESULTS, intent); + } + }; + + PendingIntent is = PendingIntent.getBroadcast(getContext(), 0, intent, 0); + is.send(Activity.RESULT_CANCELED, finish, null); + waitForResultOrThrow(BROADCAST_TIMEOUT); + is.cancel(); + } + + public void testLocalReceivePermissionGranted() throws Exception { + setExpectedReceivers(new String[]{RECEIVER_LOCAL}); + PendingIntent is = PendingIntent.getBroadcast(getContext(), 0, + makeBroadcastIntent(BROADCAST_LOCAL_GRANTED), 0); + is.send(); + waitForResultOrThrow(BROADCAST_TIMEOUT); + is.cancel(); + } + + public void testLocalReceivePermissionDenied() throws Exception { + final Intent intent = makeBroadcastIntent(BROADCAST_LOCAL_DENIED); + + setExpectedReceivers(new String[]{RECEIVER_RESULTS}); + + PendingIntent.OnFinished finish = new PendingIntent.OnFinished() { + public void onSendFinished(PendingIntent pi, Intent intent, + int resultCode, String resultData, Bundle resultExtras) { + gotReceive(RECEIVER_RESULTS, intent); + } + }; + + PendingIntent is = PendingIntent.getBroadcast(getContext(), 0, intent, 0); + is.send(Activity.RESULT_CANCELED, finish, null); + waitForResultOrThrow(BROADCAST_TIMEOUT); + is.cancel(); + } +} diff --git a/tests/AndroidTests/src/com/android/unit_tests/activity/LaunchTest.java b/tests/AndroidTests/src/com/android/unit_tests/activity/LaunchTest.java new file mode 100644 index 0000000000000000000000000000000000000000..12b1b5d7d780ba669e08383625321409dfacb780 --- /dev/null +++ b/tests/AndroidTests/src/com/android/unit_tests/activity/LaunchTest.java @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2006 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.android.unit_tests.activity; + +import android.content.ComponentName; +import android.test.suitebuilder.annotation.LargeTest; + +public class LaunchTest extends ActivityTestsBase { + + @LargeTest + public void testColdActivity() throws Exception { + mIntent.putExtra("component", new ComponentName(getContext(), TestedActivity.class)); + runLaunchpad(LaunchpadActivity.LAUNCH); + } + + @LargeTest + public void testLocalActivity() throws Exception { + mIntent.putExtra("component", new ComponentName(getContext(), LocalActivity.class)); + runLaunchpad(LaunchpadActivity.LAUNCH); + } + + @LargeTest + public void testColdScreen() throws Exception { + mIntent.putExtra("component", new ComponentName(getContext(), TestedScreen.class)); + runLaunchpad(LaunchpadActivity.LAUNCH); + } + + @LargeTest + public void testLocalScreen() throws Exception { + mIntent.putExtra("component", new ComponentName(getContext(), LocalScreen.class)); + runLaunchpad(LaunchpadActivity.LAUNCH); + } + + @LargeTest + public void testForwardResult() throws Exception { + runLaunchpad(LaunchpadActivity.FORWARD_RESULT); + } + + // The following is disabled until we can catch and recover from + // application errors. + public void xxtestBadParcelable() throws Exception { + // All we really care about for this test is that the system + // doesn't crash. + runLaunchpad(LaunchpadActivity.BAD_PARCELABLE); + } + + @LargeTest + public void testClearTopInCreate() throws Exception { + mIntent.putExtra("component", new ComponentName(getContext(), ClearTop.class)); + runLaunchpad(LaunchpadActivity.LAUNCH); + } + + @LargeTest + public void testClearTopWhileResumed() throws Exception { + mIntent.putExtra("component", new ComponentName(getContext(), ClearTop.class)); + mIntent.putExtra(ClearTop.WAIT_CLEAR_TASK, true); + runLaunchpad(LaunchpadActivity.LAUNCH); + } +} + + diff --git a/tests/AndroidTests/src/com/android/unit_tests/activity/LaunchpadActivity.java b/tests/AndroidTests/src/com/android/unit_tests/activity/LaunchpadActivity.java new file mode 100644 index 0000000000000000000000000000000000000000..06e7a84758aad9fe5f63cb521af627bfa4c782c2 --- /dev/null +++ b/tests/AndroidTests/src/com/android/unit_tests/activity/LaunchpadActivity.java @@ -0,0 +1,588 @@ +/* + * Copyright (C) 2006 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.android.unit_tests.activity; + +import android.app.Activity; +import android.content.BroadcastReceiver; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.os.Binder; +import android.os.Bundle; +import android.os.Handler; +import android.os.IBinder; +import android.os.Message; +import android.os.Parcel; +import android.os.Parcelable; +import android.test.PerformanceTestCase; +import android.util.Log; + +class MyBadParcelable implements Parcelable { + public MyBadParcelable() { + } + + public void writeToParcel(Parcel out, int flags) { + out.writeString("I am bad"); + } + + public int describeContents() { + return 0; + } + + public static final Parcelable.Creator CREATOR + = new Parcelable.Creator() { + public MyBadParcelable createFromParcel(Parcel in) { + return new MyBadParcelable(in); + } + + public MyBadParcelable[] newArray(int size) { + return new MyBadParcelable[size]; + } + }; + + public MyBadParcelable(Parcel in) { + String nm = in.readString(); + } +} + +public class LaunchpadActivity extends Activity { + public interface CallingTest extends PerformanceTestCase.Intermediates { + public void startTiming(boolean realTime); + public void addIntermediate(String name); + public void addIntermediate(String name, long timeInNS); + public void finishTiming(boolean realTime); + public void activityFinished(int resultCode, Intent data, + RuntimeException where); + } + + // Also used as the Binder interface descriptor string in these tests + public static final String LAUNCH = "com.android.unit_tests.activity.LAUNCH"; + + public static final String FORWARD_RESULT = + "com.android.unit_tests.activity.FORWARD_RESULT"; + public static final String RETURNED_RESULT = + "com.android.unit_tests.activity.RETURNED_RESULT"; + + public static final String BAD_PARCELABLE = + "com.android.unit_tests.activity.BAD_PARCELABLE"; + + public static final int LAUNCHED_RESULT = 1; + public static final int FORWARDED_RESULT = 2; + + public static final String LIFECYCLE_BASIC = + "com.android.unit_tests.activity.LIFECYCLE_BASIC"; + public static final String LIFECYCLE_SCREEN = + "com.android.unit_tests.activity.LIFECYCLE_SCREEN"; + public static final String LIFECYCLE_DIALOG = + "com.android.unit_tests.activity.LIFECYCLE_DIALOG"; + public static final String LIFECYCLE_FINISH_CREATE = + "com.android.unit_tests.activity.LIFECYCLE_FINISH_CREATE"; + public static final String LIFECYCLE_FINISH_START = + "com.android.unit_tests.activity.LIFECYCLE_FINISH_START"; + + public static final String BROADCAST_REGISTERED = + "com.android.unit_tests.activity.BROADCAST_REGISTERED"; + public static final String BROADCAST_LOCAL = + "com.android.unit_tests.activity.BROADCAST_LOCAL"; + public static final String BROADCAST_REMOTE = + "com.android.unit_tests.activity.BROADCAST_REMOTE"; + public static final String BROADCAST_ALL = + "com.android.unit_tests.activity.BROADCAST_ALL"; + public static final String BROADCAST_REPEAT = + "com.android.unit_tests.activity.BROADCAST_REPEAT"; + public static final String BROADCAST_MULTI = + "com.android.unit_tests.activity.BROADCAST_MULTI"; + public static final String BROADCAST_ABORT = + "com.android.unit_tests.activity.BROADCAST_ABORT"; + + public static final String BROADCAST_STICKY1 = + "com.android.unit_tests.activity.BROADCAST_STICKY1"; + public static final String BROADCAST_STICKY2 = + "com.android.unit_tests.activity.BROADCAST_STICKY2"; + + public static final String RECEIVER_REG = "receiver-reg"; + public static final String RECEIVER_LOCAL = "receiver-local"; + public static final String RECEIVER_REMOTE = "receiver-remote"; + public static final String RECEIVER_ABORT = "receiver-abort"; + + public static final String DATA_1 = "one"; + public static final String DATA_2 = "two"; + + public static final String ON_START = "onStart"; + public static final String ON_RESTART = "onRestart"; + public static final String ON_RESUME = "onResume"; + public static final String ON_FREEZE = "onSaveInstanceState"; + public static final String ON_PAUSE = "onPause"; + public static final String ON_STOP = "onStop"; + public static final String ON_DESTROY = "onDestroy"; + + public static final String DO_FINISH = "finish"; + public static final String DO_LOCAL_SCREEN = "local-screen"; + public static final String DO_LOCAL_DIALOG = "local-dialog"; + + private boolean mBadParcelable = false; + + private boolean mStarted = false; + private long mStartTime; + + private int mResultCode = RESULT_CANCELED; + private Intent mData = (new Intent()).setAction("No result received"); + private RuntimeException mResultStack = null; + + private String[] mExpectedLifecycle = null; + private int mNextLifecycle; + + private String[] mExpectedReceivers = null; + private int mNextReceiver; + + private String[] mExpectedData = null; + private boolean[] mReceivedData = null; + + boolean mReceiverRegistered = false; + + private static CallingTest sCallingTest = null; + + public static void setCallingTest(CallingTest ct) { + sCallingTest = ct; + } + + public LaunchpadActivity() { + mStartTime = System.currentTimeMillis(); + } + + @Override + protected void onCreate(Bundle icicle) { + super.onCreate(icicle); + String action = getIntent().getAction(); + if (ActivityTests.DEBUG_LIFECYCLE) Log.v("test", "CREATE lauchpad " + + Integer.toHexString(System.identityHashCode(this)) + ": " + getIntent()); + if (LIFECYCLE_BASIC.equals(action)) { + setExpectedLifecycle(new String[]{ON_START, ON_RESUME, + DO_FINISH, ON_PAUSE, ON_STOP, ON_DESTROY}); + } else if (LIFECYCLE_SCREEN.equals(action)) { + setExpectedLifecycle(new String[]{ON_START, ON_RESUME, + DO_LOCAL_SCREEN, ON_FREEZE, ON_PAUSE, ON_STOP, + ON_RESTART, ON_START, ON_RESUME, + DO_FINISH, ON_PAUSE, ON_STOP, ON_DESTROY}); + } else if (LIFECYCLE_DIALOG.equals(action)) { + setExpectedLifecycle(new String[]{ON_START, ON_RESUME, + DO_LOCAL_DIALOG, ON_FREEZE, ON_PAUSE, ON_RESUME, + DO_FINISH, ON_PAUSE, ON_STOP, ON_DESTROY}); + } else if (LIFECYCLE_FINISH_CREATE.equals(action)) { + // This one behaves a little differently when running in a group. + if (getParent() == null) { + setExpectedLifecycle(new String[]{ON_DESTROY}); + } else { + setExpectedLifecycle(new String[]{ON_START, ON_STOP, ON_DESTROY}); + } + finish(); + } else if (LIFECYCLE_FINISH_START.equals(action)) { + setExpectedLifecycle(new String[]{ON_START, DO_FINISH, + ON_STOP, ON_DESTROY}); + } + } + + @Override + protected void onStart() { + super.onStart(); + if (ActivityTests.DEBUG_LIFECYCLE) Log.v("test", "START lauchpad " + + Integer.toHexString(System.identityHashCode(this)) + ": " + getIntent()); + checkLifecycle(ON_START); + } + + @Override + protected void onRestart() { + super.onStart(); + checkLifecycle(ON_RESTART); + } + + @Override + protected void onResume() { + super.onResume(); + + if (ActivityTests.DEBUG_LIFECYCLE) Log.v("test", "RESUME lauchpad " + + Integer.toHexString(System.identityHashCode(this)) + ": " + getIntent()); + checkLifecycle(ON_RESUME); + + if (!mStarted) { + mStarted = true; + + mHandler.postDelayed(mTimeout, 5 * 1000); + + String action = getIntent().getAction(); + + sCallingTest.startTiming(true); + + if (LAUNCH.equals(action)) { + Intent intent = getIntent(); + intent.setFlags(0); + intent.setComponent((ComponentName) + intent.getParcelableExtra("component")); + //System.out.println("*** Launchpad is starting: comp=" + intent.component); + startActivityForResult(intent, LAUNCHED_RESULT); + } else if (FORWARD_RESULT.equals(action)) { + Intent intent = getIntent(); + intent.setFlags(0); + intent.setClass(this, LocalScreen.class); + startActivityForResult(intent, FORWARDED_RESULT); + } else if (BAD_PARCELABLE.equals(action)) { + mBadParcelable = true; + Intent intent = getIntent(); + intent.setFlags(0); + intent.setClass(this, LocalScreen.class); + startActivityForResult(intent, LAUNCHED_RESULT); + } else if (BROADCAST_REGISTERED.equals(action)) { + setExpectedReceivers(new String[]{RECEIVER_REG}); + registerMyReceiver(new IntentFilter(BROADCAST_REGISTERED)); + sCallingTest.addIntermediate("after-register"); + sendBroadcast(makeBroadcastIntent(BROADCAST_REGISTERED)); + } else if (BROADCAST_LOCAL.equals(action)) { + setExpectedReceivers(new String[]{RECEIVER_LOCAL}); + sendBroadcast(makeBroadcastIntent(BROADCAST_LOCAL)); + } else if (BROADCAST_REMOTE.equals(action)) { + setExpectedReceivers(new String[]{RECEIVER_REMOTE}); + sendBroadcast(makeBroadcastIntent(BROADCAST_REMOTE)); + } else if (BROADCAST_ALL.equals(action)) { + setExpectedReceivers(new String[]{ + RECEIVER_REMOTE, RECEIVER_REG, RECEIVER_LOCAL}); + registerMyReceiver(new IntentFilter(BROADCAST_ALL)); + sCallingTest.addIntermediate("after-register"); + sendOrderedBroadcast(makeBroadcastIntent(BROADCAST_ALL), null); + } else if (BROADCAST_MULTI.equals(action)) { + setExpectedReceivers(new String[]{ + RECEIVER_REMOTE, RECEIVER_REG, RECEIVER_LOCAL, + RECEIVER_REMOTE, RECEIVER_REG, RECEIVER_LOCAL, + RECEIVER_REMOTE, RECEIVER_REG, RECEIVER_LOCAL, + RECEIVER_LOCAL, RECEIVER_REMOTE, + RECEIVER_LOCAL, RECEIVER_REMOTE, + RECEIVER_REMOTE, RECEIVER_REG, RECEIVER_LOCAL, + RECEIVER_REMOTE, RECEIVER_REG, RECEIVER_LOCAL, + RECEIVER_REMOTE, RECEIVER_REG, RECEIVER_LOCAL, + RECEIVER_REMOTE, RECEIVER_LOCAL, + RECEIVER_REMOTE, RECEIVER_LOCAL}); + registerMyReceiver(new IntentFilter(BROADCAST_ALL)); + sCallingTest.addIntermediate("after-register"); + sendOrderedBroadcast(makeBroadcastIntent(BROADCAST_ALL), null); + sendOrderedBroadcast(makeBroadcastIntent(BROADCAST_ALL), null); + sendOrderedBroadcast(makeBroadcastIntent(BROADCAST_ALL), null); + sendOrderedBroadcast(makeBroadcastIntent(BROADCAST_LOCAL), null); + sendOrderedBroadcast(makeBroadcastIntent(BROADCAST_REMOTE), null); + sendOrderedBroadcast(makeBroadcastIntent(BROADCAST_LOCAL), null); + sendOrderedBroadcast(makeBroadcastIntent(BROADCAST_REMOTE), null); + sendOrderedBroadcast(makeBroadcastIntent(BROADCAST_ALL), null); + sendOrderedBroadcast(makeBroadcastIntent(BROADCAST_ALL), null); + sendOrderedBroadcast(makeBroadcastIntent(BROADCAST_ALL), null); + sendOrderedBroadcast(makeBroadcastIntent(BROADCAST_REPEAT), null); + } else if (BROADCAST_ABORT.equals(action)) { + setExpectedReceivers(new String[]{ + RECEIVER_REMOTE, RECEIVER_ABORT}); + registerMyReceiver(new IntentFilter(BROADCAST_ABORT)); + sCallingTest.addIntermediate("after-register"); + sendOrderedBroadcast(makeBroadcastIntent(BROADCAST_ABORT), null); + } else if (BROADCAST_STICKY1.equals(action)) { + setExpectedReceivers(new String[]{RECEIVER_REG}); + setExpectedData(new String[]{DATA_1}); + registerMyReceiver(new IntentFilter(BROADCAST_STICKY1)); + sCallingTest.addIntermediate("after-register"); + } else if (BROADCAST_STICKY2.equals(action)) { + setExpectedReceivers(new String[]{RECEIVER_REG, RECEIVER_REG}); + setExpectedData(new String[]{DATA_1, DATA_2}); + IntentFilter filter = new IntentFilter(BROADCAST_STICKY1); + filter.addAction(BROADCAST_STICKY2); + registerMyReceiver(filter); + sCallingTest.addIntermediate("after-register"); + } + } + } + + @Override + protected void onSaveInstanceState(Bundle icicle) { + super.onSaveInstanceState(icicle); + checkLifecycle(ON_FREEZE); + if (mBadParcelable) { + icicle.putParcelable("baddy", new MyBadParcelable()); + } + } + + @Override + protected void onPause() { + super.onPause(); + if (ActivityTests.DEBUG_LIFECYCLE) Log.v("test", "PAUSE lauchpad " + + Integer.toHexString(System.identityHashCode(this)) + ": " + getIntent()); + checkLifecycle(ON_PAUSE); + } + + @Override + protected void onStop() { + super.onStop(); + if (ActivityTests.DEBUG_LIFECYCLE) Log.v("test", "STOP lauchpad " + + Integer.toHexString(System.identityHashCode(this)) + ": " + getIntent()); + checkLifecycle(ON_STOP); + } + + @Override + protected void onActivityResult(int requestCode, int resultCode, + Intent data) { + switch (requestCode) { + case LAUNCHED_RESULT: + sCallingTest.finishTiming(true); + finishWithResult(resultCode, data); + break; + case FORWARDED_RESULT: + sCallingTest.finishTiming(true); + if (RETURNED_RESULT.equals(data.getAction())) { + finishWithResult(resultCode, data); + } else { + finishWithResult(RESULT_CANCELED, (new Intent()).setAction( + "Bad data returned: " + data)); + } + break; + default: + sCallingTest.finishTiming(true); + finishWithResult(RESULT_CANCELED, (new Intent()).setAction( + "Unexpected request code: " + requestCode)); + break; + } + } + + @Override + protected void onDestroy() { + super.onDestroy(); + if (ActivityTests.DEBUG_LIFECYCLE) Log.v("test", "DESTROY lauchpad " + + Integer.toHexString(System.identityHashCode(this)) + ": " + getIntent()); + checkLifecycle(ON_DESTROY); + sCallingTest.activityFinished(mResultCode, mData, mResultStack); + } + + private void setExpectedLifecycle(String[] lifecycle) { + mExpectedLifecycle = lifecycle; + mNextLifecycle = 0; + } + + private void checkLifecycle(String where) { + if (mExpectedLifecycle == null) return; + + if (mNextLifecycle >= mExpectedLifecycle.length) { + finishBad("Activity lifecycle incorrect: received " + where + + " but don't expect any more calls"); + mExpectedLifecycle = null; + return; + } + if (!mExpectedLifecycle[mNextLifecycle].equals(where)) { + finishBad("Activity lifecycle incorrect: received " + where + + " but expected " + mExpectedLifecycle[mNextLifecycle] + + " at " + mNextLifecycle); + mExpectedLifecycle = null; + return; + } + + mNextLifecycle++; + + if (mNextLifecycle >= mExpectedLifecycle.length) { + setTestResult(RESULT_OK, null); + return; + } + + String next = mExpectedLifecycle[mNextLifecycle]; + if (where.equals(ON_DESTROY)) { + finishBad("Activity lifecycle incorrect: received " + where + + " but expected more actions (next is " + next + ")"); + mExpectedLifecycle = null; + return; + } else if (next.equals(DO_FINISH)) { + mNextLifecycle++; + if (mNextLifecycle >= mExpectedLifecycle.length) { + setTestResult(RESULT_OK, null); + } + if (!isFinishing()) { + finish(); + } + } else if (next.equals(DO_LOCAL_SCREEN)) { + mNextLifecycle++; + Intent intent = new Intent(TestedScreen.WAIT_BEFORE_FINISH); + intent.setClass(this, LocalScreen.class); + startActivity(intent); + } else if (next.equals(DO_LOCAL_DIALOG)) { + mNextLifecycle++; + Intent intent = new Intent(TestedScreen.WAIT_BEFORE_FINISH); + intent.setClass(this, LocalDialog.class); + startActivity(intent); + } + } + + private void setExpectedReceivers(String[] receivers) { + mExpectedReceivers = receivers; + mNextReceiver = 0; + } + + private void setExpectedData(String[] data) { + mExpectedData = data; + mReceivedData = new boolean[data.length]; + } + + private Intent makeBroadcastIntent(String action) { + Intent intent = new Intent(action, null); + intent.putExtra("caller", mCallTarget); + return intent; + } + + private void finishGood() { + finishWithResult(RESULT_OK, null); + } + + private void finishBad(String error) { + finishWithResult(RESULT_CANCELED, (new Intent()).setAction(error)); + } + + private void finishWithResult(int resultCode, Intent data) { + setTestResult(resultCode, data); + finish(); + } + + private void setTestResult(int resultCode, Intent data) { + mHandler.removeCallbacks(mTimeout); + unregisterMyReceiver(); + mResultCode = resultCode; + mData = data; + mResultStack = new RuntimeException("Original error was here"); + mResultStack.fillInStackTrace(); + } + + private void registerMyReceiver(IntentFilter filter) { + mReceiverRegistered = true; + //System.out.println("Registering: " + mReceiver); + registerReceiver(mReceiver, filter); + } + + private void unregisterMyReceiver() { + if (mReceiverRegistered) { + mReceiverRegistered = false; + //System.out.println("Unregistering: " + mReceiver); + unregisterReceiver(mReceiver); + } + } + + private Handler mHandler = new Handler() { + public void handleMessage(Message msg) { + } + }; + + static final int GOT_RECEIVE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION; + static final int ERROR_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 1; + + private Binder mCallTarget = new Binder() { + public boolean onTransact(int code, Parcel data, Parcel reply, int flags) { + data.setDataPosition(0); + data.enforceInterface(LaunchpadActivity.LAUNCH); + if (code == GOT_RECEIVE_TRANSACTION) { + String name = data.readString(); + gotReceive(name, null); + return true; + } else if (code == ERROR_TRANSACTION) { + finishBad(data.readString()); + return true; + } + return false; + } + }; + + private final void gotReceive(String name, Intent intent) { + synchronized (this) { + + //System.out.println("Got receive: " + name); + //System.out.println(mNextReceiver + " in " + mExpectedReceivers); + //new RuntimeException("stack").printStackTrace(); + + sCallingTest.addIntermediate(mNextReceiver + "-" + name); + + if (mExpectedData != null) { + int n = mExpectedData.length; + int i; + boolean prev = false; + for (i = 0; i < n; i++) { + if (mExpectedData[i].equals(intent.getStringExtra("test"))) { + if (mReceivedData[i]) { + prev = true; + continue; + } + mReceivedData[i] = true; + break; + } + } + if (i >= n) { + if (prev) { + finishBad("Receive got data too many times: " + + intent.getStringExtra("test")); + } else { + finishBad("Receive got unexpected data: " + + intent.getStringExtra("test")); + } + return; + } + } + + if (mNextReceiver >= mExpectedReceivers.length) { + finishBad("Got too many onReceiveIntent() calls!"); +// System.out.println("Too many intents received: now at " +// + mNextReceiver + ", expect list: " +// + Arrays.toString(mExpectedReceivers)); + } else if (!mExpectedReceivers[mNextReceiver].equals(name)) { + finishBad("Receive out of order: got " + name + " but expected " + + mExpectedReceivers[mNextReceiver] + " at " + + mNextReceiver); + } else { + mNextReceiver++; + if (mNextReceiver == mExpectedReceivers.length) { + mHandler.post(mUnregister); + } + } + + } + } + + private Runnable mUnregister = new Runnable() { + public void run() { + if (mReceiverRegistered) { + sCallingTest.addIntermediate("before-unregister"); + unregisterMyReceiver(); + } + sCallingTest.finishTiming(true); + finishGood(); + } + }; + + private Runnable mTimeout = new Runnable() { + public void run() { + Log.i("foo", "**** TIMEOUT"); + String msg = "Timeout"; + if (mExpectedReceivers != null + && mNextReceiver < mExpectedReceivers.length) { + msg = msg + " waiting for " + mExpectedReceivers[mNextReceiver]; + } + finishBad(msg); + } + }; + + private BroadcastReceiver mReceiver = new BroadcastReceiver() { + public void onReceive(Context context, Intent intent) { + //System.out.println("Receive in: " + this + ": " + intent); + gotReceive(RECEIVER_REG, intent); + } + }; +} + diff --git a/tests/AndroidTests/src/com/android/unit_tests/activity/LaunchpadTabActivity.java b/tests/AndroidTests/src/com/android/unit_tests/activity/LaunchpadTabActivity.java new file mode 100644 index 0000000000000000000000000000000000000000..1e0e4a62cc9774cb87e6861cd53764d16ae6c1d9 --- /dev/null +++ b/tests/AndroidTests/src/com/android/unit_tests/activity/LaunchpadTabActivity.java @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2006 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.android.unit_tests.activity; + +import android.app.TabActivity; +import android.content.ComponentName; +import android.content.Intent; +import android.os.Bundle; +import android.widget.TabHost; + +public class LaunchpadTabActivity extends TabActivity { + public LaunchpadTabActivity() { + } + + @Override + public void onCreate(Bundle icicle) { + super.onCreate(icicle); + + Intent tabIntent = new Intent(getIntent()); + tabIntent.setComponent((ComponentName)tabIntent.getParcelableExtra("tab")); + + TabHost th = getTabHost(); + TabHost.TabSpec ts = th.newTabSpec("1"); + ts.setIndicator("One"); + ts.setContent(tabIntent); + th.addTab(ts); + } +} + diff --git a/tests/AndroidTests/src/com/android/unit_tests/activity/LifecycleTest.java b/tests/AndroidTests/src/com/android/unit_tests/activity/LifecycleTest.java new file mode 100644 index 0000000000000000000000000000000000000000..fdc12ce727b076dae6eda92e5a259615cdc5592d --- /dev/null +++ b/tests/AndroidTests/src/com/android/unit_tests/activity/LifecycleTest.java @@ -0,0 +1,108 @@ +/* + * Copyright (C) 2006 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.android.unit_tests.activity; + +import android.content.ComponentName; +import android.content.Intent; +import android.test.FlakyTest; +import android.test.suitebuilder.annotation.LargeTest; +import android.test.suitebuilder.annotation.MediumTest; +import android.test.suitebuilder.annotation.SmallTest; +import android.test.suitebuilder.annotation.Suppress; + +public class LifecycleTest extends ActivityTestsBase { + private Intent mTopIntent; + private Intent mTabIntent; + + @Override + protected void setUp() throws Exception { + super.setUp(); + mTopIntent = mIntent; + mTabIntent = new Intent(mContext, LaunchpadTabActivity.class); + mTabIntent.putExtra("tab", new ComponentName(mContext, + LaunchpadActivity.class)); + } + + @LargeTest + public void testBasic() throws Exception { + mIntent = mTopIntent; + runLaunchpad(LaunchpadActivity.LIFECYCLE_BASIC); + } + + //Suppressing until 1285425 is fixed. + @Suppress + public void testTabBasic() throws Exception { + mIntent = mTabIntent; + runLaunchpad(LaunchpadActivity.LIFECYCLE_BASIC); + } + + //Marking flaky until bug 1164344 is fixed. + @FlakyTest(tolerance=2) + @LargeTest + public void testScreen() throws Exception { + mIntent = mTopIntent; + runLaunchpad(LaunchpadActivity.LIFECYCLE_SCREEN); + } + + //Marking flaky until bug 1164344 is fixed. + //@FlakyTest(tolerance=2) + //Suppressing until 1285425 is fixed. + @Suppress + public void testTabScreen() throws Exception { + mIntent = mTabIntent; + runLaunchpad(LaunchpadActivity.LIFECYCLE_SCREEN); + } + + @LargeTest + public void testDialog() throws Exception { + mIntent = mTopIntent; + runLaunchpad(LaunchpadActivity.LIFECYCLE_DIALOG); + } + + //Suppressing until 1285425 is fixed. + @Suppress + public void testTabDialog() throws Exception { + mIntent = mTabIntent; + runLaunchpad(LaunchpadActivity.LIFECYCLE_DIALOG); + } + + @MediumTest + public void testFinishCreate() throws Exception { + mIntent = mTopIntent; + runLaunchpad(LaunchpadActivity.LIFECYCLE_FINISH_CREATE); + } + + //Suppressing until 1285425 is fixed. + @Suppress + public void testTabFinishCreate() throws Exception { + mIntent = mTabIntent; + runLaunchpad(LaunchpadActivity.LIFECYCLE_FINISH_CREATE); + } + + @MediumTest + public void testFinishStart() throws Exception { + mIntent = mTopIntent; + runLaunchpad(LaunchpadActivity.LIFECYCLE_FINISH_START); + } + + //Suppressing until 1285425 is fixed. + @Suppress + public void testTabFinishStart() throws Exception { + mIntent = mTabIntent; + runLaunchpad(LaunchpadActivity.LIFECYCLE_FINISH_START); + } +} diff --git a/tests/AndroidTests/src/com/android/unit_tests/activity/LocalActivity.java b/tests/AndroidTests/src/com/android/unit_tests/activity/LocalActivity.java new file mode 100644 index 0000000000000000000000000000000000000000..3c107be8a9ae5b4b2b411f1db01e493168831bd2 --- /dev/null +++ b/tests/AndroidTests/src/com/android/unit_tests/activity/LocalActivity.java @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2006 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.android.unit_tests.activity; + +import java.util.Map; + +import android.app.Activity; +import android.os.Handler; +import android.os.Looper; +import android.os.Message; +import android.os.MessageQueue; + +public class LocalActivity extends TestedActivity +{ + public LocalActivity() + { + } +} + diff --git a/tests/AndroidTests/src/com/android/unit_tests/activity/LocalDeniedReceiver.java b/tests/AndroidTests/src/com/android/unit_tests/activity/LocalDeniedReceiver.java new file mode 100644 index 0000000000000000000000000000000000000000..ac235c0200d685cc400b62c863bece41138fea0b --- /dev/null +++ b/tests/AndroidTests/src/com/android/unit_tests/activity/LocalDeniedReceiver.java @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2006 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.android.unit_tests.activity; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.os.RemoteException; +import android.os.IBinder; +import android.os.Parcel; + +class LocalDeniedReceiver extends BroadcastReceiver { + public LocalDeniedReceiver() { + } + + public void onReceive(Context context, Intent intent) { + try { + IBinder caller = intent.getIBinderExtra("caller"); + Parcel data = Parcel.obtain(); + data.writeInterfaceToken(LaunchpadActivity.LAUNCH); + data.writeString(BroadcastTest.RECEIVER_LOCAL); + caller.transact(BroadcastTest.GOT_RECEIVE_TRANSACTION, data, null, 0); + data.recycle(); + } catch (RemoteException ex) { + } + } +} + diff --git a/telephony/java/com/android/internal/telephony/gsm/stk/CtlvCommandDetails.java b/tests/AndroidTests/src/com/android/unit_tests/activity/LocalDeniedService.java similarity index 67% rename from telephony/java/com/android/internal/telephony/gsm/stk/CtlvCommandDetails.java rename to tests/AndroidTests/src/com/android/unit_tests/activity/LocalDeniedService.java index 63895372f7f65eed99c0de57bc48a99d8c925796..0473ea9e906d80c375d3f74194e6958dd8c36fea 100644 --- a/telephony/java/com/android/internal/telephony/gsm/stk/CtlvCommandDetails.java +++ b/tests/AndroidTests/src/com/android/unit_tests/activity/LocalDeniedService.java @@ -14,16 +14,9 @@ * limitations under the License. */ -package com.android.internal.telephony.gsm.stk; +package com.android.unit_tests.activity; - -/** - * Class for Command Detailes object of proactive commands from SIM. - * {@hide} - */ -public class CtlvCommandDetails { - public boolean compRequired; - public int commandNumber; - public int typeOfCommand; - public int commandQualifier; +public class LocalDeniedService extends LocalService +{ } + diff --git a/tests/AndroidTests/src/com/android/unit_tests/activity/LocalDialog.java b/tests/AndroidTests/src/com/android/unit_tests/activity/LocalDialog.java new file mode 100644 index 0000000000000000000000000000000000000000..36943752949d6e9c8deff7230ea961007e49200b --- /dev/null +++ b/tests/AndroidTests/src/com/android/unit_tests/activity/LocalDialog.java @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2006 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.android.unit_tests.activity; + +import java.util.Map; + +import android.app.Activity; +import android.os.Handler; +import android.os.Looper; +import android.os.Message; +import android.os.MessageQueue; + +public class LocalDialog extends TestedScreen +{ + public LocalDialog() + { + } +} + diff --git a/tests/AndroidTests/src/com/android/unit_tests/activity/LocalGrantedReceiver.java b/tests/AndroidTests/src/com/android/unit_tests/activity/LocalGrantedReceiver.java new file mode 100644 index 0000000000000000000000000000000000000000..48f5658b1812fb630f18f96f7ed4dfeb79ee102f --- /dev/null +++ b/tests/AndroidTests/src/com/android/unit_tests/activity/LocalGrantedReceiver.java @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2006 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.android.unit_tests.activity; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.os.RemoteException; +import android.os.IBinder; +import android.os.Parcel; + +public class LocalGrantedReceiver extends BroadcastReceiver { + public LocalGrantedReceiver() { + } + + public void onReceive(Context context, Intent intent) { + try { + IBinder caller = intent.getIBinderExtra("caller"); + Parcel data = Parcel.obtain(); + data.writeInterfaceToken(LaunchpadActivity.LAUNCH); + data.writeString(BroadcastTest.RECEIVER_LOCAL); + caller.transact(BroadcastTest.GOT_RECEIVE_TRANSACTION, data, null, 0); + data.recycle(); + } catch (RemoteException ex) { + } + } +} + diff --git a/tests/AndroidTests/src/com/android/unit_tests/activity/LocalGrantedService.java b/tests/AndroidTests/src/com/android/unit_tests/activity/LocalGrantedService.java new file mode 100644 index 0000000000000000000000000000000000000000..0dbcd002f1963c19898d3034521de9c35188a474 --- /dev/null +++ b/tests/AndroidTests/src/com/android/unit_tests/activity/LocalGrantedService.java @@ -0,0 +1,22 @@ +/* + * Copyright (C) 2006 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.android.unit_tests.activity; + +public class LocalGrantedService extends LocalService +{ +} + diff --git a/tests/AndroidTests/src/com/android/unit_tests/activity/LocalProvider.java b/tests/AndroidTests/src/com/android/unit_tests/activity/LocalProvider.java new file mode 100644 index 0000000000000000000000000000000000000000..a3375bdedf3f8e965e22de7bb171eccd75c54753 --- /dev/null +++ b/tests/AndroidTests/src/com/android/unit_tests/activity/LocalProvider.java @@ -0,0 +1,163 @@ +/* + * Copyright (C) 2007 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.android.unit_tests.activity; + +import android.content.UriMatcher; +import android.content.*; +import android.database.Cursor; +import android.database.sqlite.SQLiteDatabase; +import android.database.sqlite.SQLiteOpenHelper; +import android.database.sqlite.SQLiteQueryBuilder; +import android.net.Uri; +import android.util.Config; +import android.util.Log; + +/** Simple test provider that runs in the local process. */ +public class LocalProvider extends ContentProvider { + private static final String TAG = "LocalProvider"; + + private SQLiteOpenHelper mOpenHelper; + + private static final int DATA = 1; + private static final int DATA_ID = 2; + private static final UriMatcher sURLMatcher = new UriMatcher( + UriMatcher.NO_MATCH); + + static { + sURLMatcher.addURI("*", "data", DATA); + sURLMatcher.addURI("*", "data/#", DATA_ID); + } + + private static class DatabaseHelper extends SQLiteOpenHelper { + private static final String DATABASE_NAME = "local.db"; + private static final int DATABASE_VERSION = 1; + + public DatabaseHelper(Context context) { + super(context, DATABASE_NAME, null, DATABASE_VERSION); + } + + @Override + public void onCreate(SQLiteDatabase db) { + db.execSQL("CREATE TABLE data (" + + "_id INTEGER PRIMARY KEY," + + "text TEXT, " + + "integer INTEGER);"); + + // insert alarms + db.execSQL("INSERT INTO data (text, integer) VALUES ('first data', 100);"); + } + + @Override + public void onUpgrade(SQLiteDatabase db, int oldVersion, int currentVersion) { + Log.w(TAG, "Upgrading test database from version " + + oldVersion + " to " + currentVersion + + ", which will destroy all old data"); + db.execSQL("DROP TABLE IF EXISTS data"); + onCreate(db); + } + } + + + public LocalProvider() { + } + + @Override + public boolean onCreate() { + mOpenHelper = new DatabaseHelper(getContext()); + return true; + } + + @Override + public Cursor query(Uri url, String[] projectionIn, String selection, + String[] selectionArgs, String sort) { + SQLiteQueryBuilder qb = new SQLiteQueryBuilder(); + + // Generate the body of the query + int match = sURLMatcher.match(url); + switch (match) { + case DATA: + qb.setTables("data"); + break; + case DATA_ID: + qb.setTables("data"); + qb.appendWhere("_id="); + qb.appendWhere(url.getPathSegments().get(1)); + break; + default: + throw new IllegalArgumentException("Unknown URL " + url); + } + + SQLiteDatabase db = mOpenHelper.getReadableDatabase(); + Cursor ret = qb.query(db, projectionIn, selection, selectionArgs, + null, null, sort); + + if (ret == null) { + if (Config.LOGD) Log.d(TAG, "Alarms.query: failed"); + } else { + ret.setNotificationUri(getContext().getContentResolver(), url); + } + + return ret; + } + + @Override + public String getType(Uri url) { + int match = sURLMatcher.match(url); + switch (match) { + case DATA: + return "vnd.android.cursor.dir/vnd.google.unit_tests.local"; + case DATA_ID: + return "vnd.android.cursor.item/vnd.google.unit_tests.local"; + default: + throw new IllegalArgumentException("Unknown URL"); + } + } + + @Override + public int update(Uri url, ContentValues values, String where, String[] whereArgs) { + int count; + long rowId = 0; + int match = sURLMatcher.match(url); + SQLiteDatabase db = mOpenHelper.getWritableDatabase(); + switch (match) { + case DATA_ID: { + String segment = url.getPathSegments().get(1); + rowId = Long.parseLong(segment); + count = db.update("data", values, "_id=" + rowId, null); + break; + } + default: { + throw new UnsupportedOperationException( + "Cannot update URL: " + url); + } + } + if (Config.LOGD) Log.d(TAG, "*** notifyChange() rowId: " + rowId); + getContext().getContentResolver().notifyChange(url, null); + return count; + } + + + @Override + public Uri insert(Uri url, ContentValues initialValues) { + return null; + } + + @Override + public int delete(Uri url, String where, String[] whereArgs) { + throw new UnsupportedOperationException("delete not supported"); + } +} diff --git a/tests/AndroidTests/src/com/android/unit_tests/activity/LocalReceiver.java b/tests/AndroidTests/src/com/android/unit_tests/activity/LocalReceiver.java new file mode 100644 index 0000000000000000000000000000000000000000..019c5c09e90615dc1a8aa942db3131ce6bbdeaea --- /dev/null +++ b/tests/AndroidTests/src/com/android/unit_tests/activity/LocalReceiver.java @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2006 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.android.unit_tests.activity; + +import android.content.BroadcastReceiver; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.ReceiverCallNotAllowedException; +import android.content.ServiceConnection; +import android.os.RemoteException; +import android.os.IBinder; +import android.os.Parcel; + +public class LocalReceiver extends BroadcastReceiver { + public LocalReceiver() { + } + + public void onReceive(Context context, Intent intent) { + String resultString = LaunchpadActivity.RECEIVER_LOCAL; + if (BroadcastTest.BROADCAST_FAIL_REGISTER.equals(intent.getAction())) { + resultString = "Successfully registered, but expected it to fail"; + try { + context.registerReceiver(this, new IntentFilter("foo.bar")); + context.unregisterReceiver(this); + } catch (ReceiverCallNotAllowedException e) { + //resultString = "This is the correct behavior but not yet implemented"; + resultString = LaunchpadActivity.RECEIVER_LOCAL; + } + } else if (BroadcastTest.BROADCAST_FAIL_BIND.equals(intent.getAction())) { + resultString = "Successfully bound to service, but expected it to fail"; + try { + ServiceConnection sc = new ServiceConnection() { + public void onServiceConnected(ComponentName name, IBinder service) { + } + + public void onServiceDisconnected(ComponentName name) { + } + }; + context.bindService(new Intent(context, LocalService.class), sc, 0); + context.unbindService(sc); + } catch (ReceiverCallNotAllowedException e) { + //resultString = "This is the correct behavior but not yet implemented"; + resultString = LaunchpadActivity.RECEIVER_LOCAL; + } + } else if (LaunchpadActivity.BROADCAST_REPEAT.equals(intent.getAction())) { + Intent newIntent = new Intent(intent); + newIntent.setAction(LaunchpadActivity.BROADCAST_LOCAL); + context.sendOrderedBroadcast(newIntent, null); + } + try { + IBinder caller = intent.getIBinderExtra("caller"); + Parcel data = Parcel.obtain(); + data.writeInterfaceToken(LaunchpadActivity.LAUNCH); + data.writeString(resultString); + caller.transact(LaunchpadActivity.GOT_RECEIVE_TRANSACTION, data, null, 0); + data.recycle(); + } catch (RemoteException ex) { + } + } +} + diff --git a/tests/AndroidTests/src/com/android/unit_tests/activity/LocalScreen.java b/tests/AndroidTests/src/com/android/unit_tests/activity/LocalScreen.java new file mode 100644 index 0000000000000000000000000000000000000000..ad65fcc5d9d595c1f05b700582460646ed444d38 --- /dev/null +++ b/tests/AndroidTests/src/com/android/unit_tests/activity/LocalScreen.java @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2006 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.android.unit_tests.activity; + +import java.util.Map; + +import android.app.Activity; +import android.os.Handler; +import android.os.Looper; +import android.os.Message; +import android.os.MessageQueue; + +public class LocalScreen extends TestedScreen +{ + public LocalScreen() + { + } +} + diff --git a/tests/AndroidTests/src/com/android/unit_tests/activity/LocalService.java b/tests/AndroidTests/src/com/android/unit_tests/activity/LocalService.java new file mode 100644 index 0000000000000000000000000000000000000000..d79205d33fb29df5f7afa0a39ad8765ab729ce63 --- /dev/null +++ b/tests/AndroidTests/src/com/android/unit_tests/activity/LocalService.java @@ -0,0 +1,122 @@ +/* + * Copyright (C) 2006 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.android.unit_tests.activity; + +import android.app.Service; +import android.content.Intent; +import android.os.Binder; +import android.os.Bundle; +import android.os.RemoteException; +import android.os.IBinder; +import android.os.Parcel; +import android.util.Log; + +public class LocalService extends Service { + private final IBinder mBinder = new Binder() { + + @Override + protected boolean onTransact(int code, Parcel data, Parcel reply, + int flags) throws RemoteException { + if (code == ServiceTest.SET_REPORTER_CODE) { + data.enforceInterface(ServiceTest.SERVICE_LOCAL); + mReportObject = data.readStrongBinder(); + return true; + } else { + return super.onTransact(code, data, reply, flags); + } + } + + }; + + private IBinder mReportObject; + private int mStartCount = 1; + + public LocalService() { + } + + @Override + public void onStart(Intent intent, int startId) { + //Log.i("LocalService", "onStart: " + intent); + if (intent.getExtras() != null) { + mReportObject = intent.getExtras().getIBinder(ServiceTest.REPORT_OBJ_NAME); + if (mReportObject != null) { + try { + Parcel data = Parcel.obtain(); + data.writeInterfaceToken(ServiceTest.SERVICE_LOCAL); + data.writeInt(mStartCount); + mStartCount++; + mReportObject.transact( + ServiceTest.STARTED_CODE, data, null, 0); + data.recycle(); + } catch (RemoteException e) { + } + } + } + } + + @Override + public void onDestroy() { + Log.i("LocalService", "onDestroy: mReportObject=" + mReportObject); + if (mReportObject != null) { + try { + Parcel data = Parcel.obtain(); + data.writeInterfaceToken(ServiceTest.SERVICE_LOCAL); + mReportObject.transact( + ServiceTest.DESTROYED_CODE, data, null, 0); + data.recycle(); + } catch (RemoteException e) { + } + } + } + + @Override + public IBinder onBind(Intent intent) { + Log.i("LocalService", "onBind: " + intent); + return mBinder; + } + + @Override + public boolean onUnbind(Intent intent) { + Log.i("LocalService", "onUnbind: " + intent); + if (mReportObject != null) { + try { + Parcel data = Parcel.obtain(); + data.writeInterfaceToken(ServiceTest.SERVICE_LOCAL); + mReportObject.transact( + ServiceTest.UNBIND_CODE, data, null, 0); + data.recycle(); + } catch (RemoteException e) { + } + } + return true; + } + + @Override + public void onRebind(Intent intent) { + Log.i("LocalService", "onUnbind: " + intent); + if (mReportObject != null) { + try { + Parcel data = Parcel.obtain(); + data.writeInterfaceToken(ServiceTest.SERVICE_LOCAL); + mReportObject.transact( + ServiceTest.REBIND_CODE, data, null, 0); + data.recycle(); + } catch (RemoteException e) { + } + } + } +} diff --git a/tests/AndroidTests/src/com/android/unit_tests/activity/MetaDataTest.java b/tests/AndroidTests/src/com/android/unit_tests/activity/MetaDataTest.java new file mode 100644 index 0000000000000000000000000000000000000000..4660e29607dae6c77abc8d17fe66b5885361020d --- /dev/null +++ b/tests/AndroidTests/src/com/android/unit_tests/activity/MetaDataTest.java @@ -0,0 +1,166 @@ +/* + * Copyright (C) 2006 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.android.unit_tests.activity; + +import android.content.ComponentName; +import android.content.pm.ActivityInfo; +import android.content.pm.PackageItemInfo; +import android.content.pm.PackageManager; +import android.content.pm.PermissionInfo; +import android.content.pm.ProviderInfo; +import android.content.pm.ServiceInfo; +import android.content.res.TypedArray; +import android.content.res.XmlResourceParser; +import android.os.Bundle; +import android.test.AndroidTestCase; +import android.test.suitebuilder.annotation.MediumTest; +import android.test.suitebuilder.annotation.SmallTest; +import com.android.unit_tests.R; +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; + +import java.io.IOException; + +/** + * Tests for meta-data associated with application components. + */ +public class MetaDataTest extends AndroidTestCase { + + private void checkMetaData(ComponentName cn, PackageItemInfo ci) + throws IOException, XmlPullParserException { + assertNotNull("Unable to find component " + cn, ci); + + Bundle md = ci.metaData; + assertNotNull("No meta data found", md); + + assertEquals("foo", md.getString("com.android.unit_tests.string")); + assertTrue(md.getBoolean("com.android.unit_tests.boolean")); + assertEquals(100, md.getInt("com.android.unit_tests.integer")); + assertEquals(0xff000000, md.getInt("com.android.unit_tests.color")); + + assertEquals((double) 1001, + Math.floor(md.getFloat("com.android.unit_tests.float") * 10 + .5)); + + assertEquals(R.xml.metadata, md.getInt("com.android.unit_tests.reference")); + + XmlResourceParser xml = ci.loadXmlMetaData(mContext.getPackageManager(), + "com.android.unit_tests.reference"); + assertNotNull(xml); + + int type; + while ((type = xml.next()) != XmlPullParser.START_TAG + && type != XmlPullParser.END_DOCUMENT) { + } + assertEquals(XmlPullParser.START_TAG, type); + assertEquals("thedata", xml.getName()); + + // method 1: direct access + final String rawAttr = xml.getAttributeValue(null, "rawText"); + assertEquals("some raw text", rawAttr); + + // method 2: direct access of typed value + final int rawColorIntAttr = xml.getAttributeIntValue(null, "rawColor", 0); + assertEquals(0xffffff00, rawColorIntAttr); + final String rawColorStrAttr = xml.getAttributeValue(null, "rawColor"); + assertEquals("#ffffff00", rawColorStrAttr); + + // method 2: direct access of resource attribute + final String nameSpace = "http://schemas.android.com/apk/res/android"; + final int colorIntAttr = xml.getAttributeIntValue(nameSpace, "color", 0); + assertEquals(0xffff0000, colorIntAttr); + final String colorStrAttr = xml.getAttributeValue(nameSpace, "color"); + assertEquals("#ffff0000", colorStrAttr); + + // method 3: styled access (borrowing an attr from view system here) + TypedArray a = mContext.obtainStyledAttributes(xml, + android.R.styleable.TextView); + String styledAttr = a.getString(android.R.styleable.TextView_text); + assertEquals("text", styledAttr); + a.recycle(); + + xml.close(); + } + + @SmallTest + public void testActivityWithData() throws Exception { + ComponentName cn = new ComponentName(mContext, LocalActivity.class); + ActivityInfo ai = mContext.getPackageManager().getActivityInfo( + cn, PackageManager.GET_META_DATA); + + checkMetaData(cn, ai); + + ai = mContext.getPackageManager().getActivityInfo(cn, 0); + + assertNull("Meta data returned when not requested", ai.metaData); + } + + @SmallTest + public void testReceiverWithData() throws Exception { + ComponentName cn = new ComponentName(mContext, LocalReceiver.class); + ActivityInfo ai = mContext.getPackageManager().getReceiverInfo( + cn, PackageManager.GET_META_DATA); + + checkMetaData(cn, ai); + + ai = mContext.getPackageManager().getReceiverInfo(cn, 0); + + assertNull("Meta data returned when not requested", ai.metaData); + } + + @SmallTest + public void testServiceWithData() throws Exception { + ComponentName cn = new ComponentName(mContext, LocalService.class); + ServiceInfo si = mContext.getPackageManager().getServiceInfo( + cn, PackageManager.GET_META_DATA); + + checkMetaData(cn, si); + + si = mContext.getPackageManager().getServiceInfo(cn, 0); + + assertNull("Meta data returned when not requested", si.metaData); + } + + @MediumTest + public void testProviderWithData() throws Exception { + ComponentName cn = new ComponentName(mContext, LocalProvider.class); + ProviderInfo pi = mContext.getPackageManager().resolveContentProvider( + "com.android.unit_tests.LocalProvider", + PackageManager.GET_META_DATA); + checkMetaData(cn, pi); + + pi = mContext.getPackageManager().resolveContentProvider( + "com.android.unit_tests.LocalProvider", 0); + + assertNull("Meta data returned when not requested", pi.metaData); + } + + @SmallTest + public void testPermissionWithData() throws Exception { + ComponentName cn = new ComponentName("foo", + "com.android.unit_tests.permission.TEST_GRANTED"); + PermissionInfo pi = mContext.getPackageManager().getPermissionInfo( + cn.getClassName(), PackageManager.GET_META_DATA); + checkMetaData(cn, pi); + + pi = mContext.getPackageManager().getPermissionInfo( + cn.getClassName(), 0); + + assertNull("Meta data returned when not requested", pi.metaData); + } +} + + diff --git a/tests/AndroidTests/src/com/android/unit_tests/activity/RemoteDeniedReceiver.java b/tests/AndroidTests/src/com/android/unit_tests/activity/RemoteDeniedReceiver.java new file mode 100644 index 0000000000000000000000000000000000000000..76565801317bcd4e2075554822af7f67771ada61 --- /dev/null +++ b/tests/AndroidTests/src/com/android/unit_tests/activity/RemoteDeniedReceiver.java @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2006 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.android.unit_tests.activity; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.os.RemoteException; +import android.os.IBinder; +import android.os.Parcel; + +class RemoteDeniedReceiver extends BroadcastReceiver { + public RemoteDeniedReceiver() { + } + + public void onReceive(Context context, Intent intent) { + try { + IBinder caller = intent.getIBinderExtra("caller"); + Parcel data = Parcel.obtain(); + data.writeInterfaceToken(LaunchpadActivity.LAUNCH); + data.writeString(BroadcastTest.RECEIVER_REMOTE); + caller.transact(BroadcastTest.GOT_RECEIVE_TRANSACTION, data, null, 0); + data.recycle(); + } catch (RemoteException ex) { + } + } +} + diff --git a/tests/AndroidTests/src/com/android/unit_tests/activity/RemoteGrantedReceiver.java b/tests/AndroidTests/src/com/android/unit_tests/activity/RemoteGrantedReceiver.java new file mode 100644 index 0000000000000000000000000000000000000000..034aa1df38aa8dc7dcafc2c0d9da8f33b5c8be5f --- /dev/null +++ b/tests/AndroidTests/src/com/android/unit_tests/activity/RemoteGrantedReceiver.java @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2006 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.android.unit_tests.activity; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.os.RemoteException; +import android.os.IBinder; +import android.os.Parcel; + +public class RemoteGrantedReceiver extends BroadcastReceiver { + public RemoteGrantedReceiver() { + } + + public void onReceive(Context context, Intent intent) { + try { + IBinder caller = intent.getIBinderExtra("caller"); + Parcel data = Parcel.obtain(); + data.writeInterfaceToken(LaunchpadActivity.LAUNCH); + data.writeString(BroadcastTest.RECEIVER_REMOTE); + caller.transact(BroadcastTest.GOT_RECEIVE_TRANSACTION, data, null, 0); + data.recycle(); + } catch (RemoteException ex) { + } + } +} + diff --git a/tests/AndroidTests/src/com/android/unit_tests/activity/RemoteReceiver.java b/tests/AndroidTests/src/com/android/unit_tests/activity/RemoteReceiver.java new file mode 100644 index 0000000000000000000000000000000000000000..818bffe62507b05d385bc403b0265cc5d17f1486 --- /dev/null +++ b/tests/AndroidTests/src/com/android/unit_tests/activity/RemoteReceiver.java @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2006 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.android.unit_tests.activity; + +import android.content.Context; +import android.content.Intent; +import android.content.BroadcastReceiver; +import android.os.RemoteException; +import android.os.IBinder; +import android.os.Parcel; + +public class RemoteReceiver extends BroadcastReceiver +{ + public RemoteReceiver() + { + } + + public void onReceive(Context context, Intent intent) + { + if (LaunchpadActivity.BROADCAST_REPEAT.equals(intent.getAction())) { + Intent newIntent = new Intent(intent); + newIntent.setAction(LaunchpadActivity.BROADCAST_REMOTE); + context.sendOrderedBroadcast(newIntent, null); + } + try { + IBinder caller = intent.getIBinderExtra("caller"); + Parcel data = Parcel.obtain(); + data.writeInterfaceToken(LaunchpadActivity.LAUNCH); + data.writeString(LaunchpadActivity.RECEIVER_REMOTE); + caller.transact(LaunchpadActivity.GOT_RECEIVE_TRANSACTION, data, null, 0); + data.recycle(); + } catch (RemoteException ex) { + } + } +} + diff --git a/tests/AndroidTests/src/com/android/unit_tests/activity/RemoteSubActivityScreen.java b/tests/AndroidTests/src/com/android/unit_tests/activity/RemoteSubActivityScreen.java new file mode 100644 index 0000000000000000000000000000000000000000..e750ed6e753e4aeeda2241b8bdf501a03e18e2b9 --- /dev/null +++ b/tests/AndroidTests/src/com/android/unit_tests/activity/RemoteSubActivityScreen.java @@ -0,0 +1,59 @@ +/* //device/apps/AndroidTests/src/com.android.unit_tests/activity/TestedScreen.java +** +** Copyright 2006, 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.android.unit_tests.activity; + +import android.content.Intent; +import android.os.Bundle; +import android.os.Handler; +import android.os.Process; +import android.util.Log; + +public class RemoteSubActivityScreen extends SubActivityScreen { + Handler mHandler = new Handler(); + boolean mFirst = false; + + public RemoteSubActivityScreen() { + } + + @Override + public void onCreate(Bundle icicle) { + // We are running in a remote process, so want to have the sub-activity + // sending the result back in the original process. + Intent intent = getIntent(); + intent.setClass(this, SubActivityScreen.class); + + super.onCreate(icicle); + + boolean kill = intent.getBooleanExtra("kill", false); + //Log.i("foo", "RemoteSubActivityScreen pid=" + Process.myPid() + // + " kill=" + kill); + + if (kill) { + // After finishing initialization, kill the process! But only if + // this is the first time... + if (icicle == null) { + mHandler.post(new Runnable() { + public void run() { + handleBeforeStopping(); + Process.killProcess(Process.myPid()); + } + }); + } + } + } +} diff --git a/tests/AndroidTests/src/com/android/unit_tests/activity/ResultReceiver.java b/tests/AndroidTests/src/com/android/unit_tests/activity/ResultReceiver.java new file mode 100644 index 0000000000000000000000000000000000000000..4b5d46808825fff8bd444e130846c869f68dbcc7 --- /dev/null +++ b/tests/AndroidTests/src/com/android/unit_tests/activity/ResultReceiver.java @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2006 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.android.unit_tests.activity; + +import android.content.Context; +import android.content.Intent; +import android.content.BroadcastReceiver; +import android.os.IBinder; +import android.os.Parcel; +import android.os.Bundle; + +import java.util.Map; + +public class ResultReceiver extends BroadcastReceiver +{ + public ResultReceiver() + { + } + + public void onReceive(Context context, Intent intent) + { + setResultCode(3); + setResultData("bar"); + Bundle map = getResultExtras(false); + map.remove("remove"); + map.putString("bar", "them"); + } +} + diff --git a/tests/AndroidTests/src/com/android/unit_tests/activity/ServiceTest.java b/tests/AndroidTests/src/com/android/unit_tests/activity/ServiceTest.java new file mode 100644 index 0000000000000000000000000000000000000000..db523dc4d50692a5083fbc2056a479c669d856fb --- /dev/null +++ b/tests/AndroidTests/src/com/android/unit_tests/activity/ServiceTest.java @@ -0,0 +1,465 @@ +/* + * Copyright (C) 2006 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.android.unit_tests.activity; + +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.ServiceConnection; +import android.os.Binder; +import android.os.Bundle; +import android.os.RemoteException; +import android.os.IBinder; +import android.os.Parcel; +import android.test.suitebuilder.annotation.MediumTest; +import android.test.suitebuilder.annotation.SmallTest; +import android.util.Log; + +// These test binders purport to support an interface whose canonical +// interface name is ServiceTest.SERVICE_LOCAL +public class ServiceTest extends ActivityTestsBase { + + public static final String SERVICE_LOCAL = + "com.android.unit_tests.activity.SERVICE_LOCAL"; + public static final String SERVICE_LOCAL_GRANTED = + "com.android.unit_tests.activity.SERVICE_LOCAL_GRANTED"; + public static final String SERVICE_LOCAL_DENIED = + "com.android.unit_tests.activity.SERVICE_LOCAL_DENIED"; + + public static final String REPORT_OBJ_NAME = "report"; + + public static final int STARTED_CODE = 1; + public static final int DESTROYED_CODE = 2; + public static final int SET_REPORTER_CODE = 3; + public static final int UNBIND_CODE = 4; + public static final int REBIND_CODE = 5; + + public static final int STATE_START_1 = 0; + public static final int STATE_START_2 = 1; + public static final int STATE_UNBIND = 2; + public static final int STATE_DESTROY = 3; + public static final int STATE_REBIND = 4; + public static final int STATE_UNBIND_ONLY = 5; + public int mStartState; + + public IBinder mStartReceiver = new Binder() { + @Override + protected boolean onTransact(int code, Parcel data, Parcel reply, + int flags) throws RemoteException { + //Log.i("ServiceTest", "Received code " + code + " in state " + mStartState); + if (code == STARTED_CODE) { + data.enforceInterface(SERVICE_LOCAL); + int count = data.readInt(); + if (mStartState == STATE_START_1) { + if (count == 1) { + finishGood(); + } else { + finishBad("onStart() again on an object when it should have been the first time"); + } + } else if (mStartState == STATE_START_2) { + if (count == 2) { + finishGood(); + } else { + finishBad("onStart() the first time on an object when it should have been the second time"); + } + } else { + finishBad("onStart() was called when not expected (state="+mStartState+")"); + } + return true; + } else if (code == DESTROYED_CODE) { + data.enforceInterface(SERVICE_LOCAL); + if (mStartState == STATE_DESTROY) { + finishGood(); + } else { + finishBad("onDestroy() was called when not expected (state="+mStartState+")"); + } + return true; + } else if (code == UNBIND_CODE) { + data.enforceInterface(SERVICE_LOCAL); + if (mStartState == STATE_UNBIND) { + mStartState = STATE_DESTROY; + } else if (mStartState == STATE_UNBIND_ONLY) { + finishGood(); + } else { + finishBad("onUnbind() was called when not expected (state="+mStartState+")"); + } + return true; + } else if (code == REBIND_CODE) { + data.enforceInterface(SERVICE_LOCAL); + if (mStartState == STATE_REBIND) { + finishGood(); + } else { + finishBad("onRebind() was called when not expected (state="+mStartState+")"); + } + return true; + } else { + return super.onTransact(code, data, reply, flags); + } + } + }; + + public class EmptyConnection implements ServiceConnection { + public void onServiceConnected(ComponentName name, IBinder service) { + } + + public void onServiceDisconnected(ComponentName name) { + } + } + + public class TestConnection implements ServiceConnection { + private final boolean mExpectDisconnect; + private final boolean mSetReporter; + private boolean mMonitor; + private int mCount; + + public TestConnection(boolean expectDisconnect, boolean setReporter) { + mExpectDisconnect = expectDisconnect; + mSetReporter = setReporter; + mMonitor = !setReporter; + } + + void setMonitor(boolean v) { + mMonitor = v; + } + + public void onServiceConnected(ComponentName name, IBinder service) { + if (mSetReporter) { + Parcel data = Parcel.obtain(); + data.writeInterfaceToken(SERVICE_LOCAL); + data.writeStrongBinder(mStartReceiver); + try { + service.transact(SET_REPORTER_CODE, data, null, 0); + } catch (RemoteException e) { + finishBad("DeadObjectException when sending reporting object"); + } + data.recycle(); + } + + if (mMonitor) { + mCount++; + if (mStartState == STATE_START_1) { + if (mCount == 1) { + finishGood(); + } else { + finishBad("onServiceConnected() again on an object when it should have been the first time"); + } + } else if (mStartState == STATE_START_2) { + if (mCount == 2) { + finishGood(); + } else { + finishBad("onServiceConnected() the first time on an object when it should have been the second time"); + } + } else { + finishBad("onServiceConnected() called unexpectedly"); + } + } + } + + public void onServiceDisconnected(ComponentName name) { + if (mMonitor) { + if (mStartState == STATE_DESTROY) { + if (mExpectDisconnect) { + finishGood(); + } else { + finishBad("onServiceDisconnected() when it shouldn't have been"); + } + } else { + finishBad("onServiceDisconnected() called unexpectedly"); + } + } + } + } + + void startExpectResult(Intent service) { + startExpectResult(service, new Bundle()); + } + + void startExpectResult(Intent service, Bundle bundle) { + bundle.putIBinder(REPORT_OBJ_NAME, mStartReceiver); + boolean success = false; + try { + //Log.i("foo", "STATE_START_1"); + mStartState = STATE_START_1; + getContext().startService(new Intent(service).putExtras(bundle)); + waitForResultOrThrow(5 * 1000, "service to start first time"); + //Log.i("foo", "STATE_START_2"); + mStartState = STATE_START_2; + getContext().startService(new Intent(service).putExtras(bundle)); + waitForResultOrThrow(5 * 1000, "service to start second time"); + success = true; + } finally { + if (!success) { + try { + getContext().stopService(service); + } catch (Exception e) { + // eat + } + } + } + //Log.i("foo", "STATE_DESTROY"); + mStartState = STATE_DESTROY; + getContext().stopService(service); + waitForResultOrThrow(5 * 1000, "service to be destroyed"); + } + + void startExpectNoPermission(Intent service) { + try { + getContext().startService(service); + fail("Expected security exception when starting " + service); + } catch (SecurityException e) { + // expected + } + } + + void bindExpectResult(Intent service) { + TestConnection conn = new TestConnection(true, false); + TestConnection conn2 = new TestConnection(false, false); + boolean success = false; + try { + // Expect to see the TestConnection connected. + mStartState = STATE_START_1; + getContext().bindService(service, conn, 0); + getContext().startService(service); + waitForResultOrThrow(5 * 1000, "existing connection to receive service"); + + // Expect to see the second TestConnection connected. + getContext().bindService(service, conn2, 0); + waitForResultOrThrow(5 * 1000, "new connection to receive service"); + + getContext().unbindService(conn2); + success = true; + } finally { + if (!success) { + try { + getContext().stopService(service); + getContext().unbindService(conn); + getContext().unbindService(conn2); + } catch (Exception e) { + // eat + } + } + } + + // Expect to see the TestConnection disconnected. + mStartState = STATE_DESTROY; + getContext().stopService(service); + waitForResultOrThrow(5 * 1000, "existing connection to lose service"); + + getContext().unbindService(conn); + + conn = new TestConnection(true, true); + success = false; + try { + // Expect to see the TestConnection connected. + conn.setMonitor(true); + mStartState = STATE_START_1; + getContext().bindService(service, conn, 0); + getContext().startService(service); + waitForResultOrThrow(5 * 1000, "existing connection to receive service"); + + success = true; + } finally { + if (!success) { + try { + getContext().stopService(service); + getContext().unbindService(conn); + } catch (Exception e) { + // eat + } + } + } + + // Expect to see the service unbind and then destroyed. + conn.setMonitor(false); + mStartState = STATE_UNBIND; + getContext().stopService(service); + waitForResultOrThrow(5 * 1000, "existing connection to lose service"); + + getContext().unbindService(conn); + + conn = new TestConnection(true, true); + success = false; + try { + // Expect to see the TestConnection connected. + conn.setMonitor(true); + mStartState = STATE_START_1; + getContext().bindService(service, conn, 0); + getContext().startService(service); + waitForResultOrThrow(5 * 1000, "existing connection to receive service"); + + success = true; + } finally { + if (!success) { + try { + getContext().stopService(service); + getContext().unbindService(conn); + } catch (Exception e) { + // eat + } + } + } + + // Expect to see the service unbind but not destroyed. + conn.setMonitor(false); + mStartState = STATE_UNBIND_ONLY; + getContext().unbindService(conn); + waitForResultOrThrow(5 * 1000, "existing connection to unbind service"); + + // Expect to see the service rebound. + mStartState = STATE_REBIND; + getContext().bindService(service, conn, 0); + waitForResultOrThrow(5 * 1000, "existing connection to rebind service"); + + // Expect to see the service unbind and then destroyed. + mStartState = STATE_UNBIND; + getContext().stopService(service); + waitForResultOrThrow(5 * 1000, "existing connection to lose service"); + + getContext().unbindService(conn); + } + + void bindAutoExpectResult(Intent service) { + TestConnection conn = new TestConnection(false, true); + boolean success = false; + try { + conn.setMonitor(true); + mStartState = STATE_START_1; + getContext().bindService( + service, conn, Context.BIND_AUTO_CREATE); + waitForResultOrThrow(5 * 1000, "connection to start and receive service"); + success = true; + } finally { + if (!success) { + try { + getContext().unbindService(conn); + } catch (Exception e) { + // eat + } + } + } + mStartState = STATE_UNBIND; + getContext().unbindService(conn); + waitForResultOrThrow(5 * 1000, "disconnecting from service"); + } + + void bindExpectNoPermission(Intent service) { + TestConnection conn = new TestConnection(false, false); + try { + getContext().bindService(service, conn, Context.BIND_AUTO_CREATE); + fail("Expected security exception when binding " + service); + } catch (SecurityException e) { + // expected + } finally { + getContext().unbindService(conn); + } + } + + + @MediumTest + public void testLocalStartClass() throws Exception { + startExpectResult(new Intent(getContext(), LocalService.class)); + } + + @MediumTest + public void testLocalStartAction() throws Exception { + startExpectResult(new Intent(SERVICE_LOCAL)); + } + + @MediumTest + public void testLocalBindClass() throws Exception { + bindExpectResult(new Intent(getContext(), LocalService.class)); + } + + @MediumTest + public void testLocalBindAction() throws Exception { + bindExpectResult(new Intent(SERVICE_LOCAL)); + } + + @MediumTest + public void testLocalBindAutoClass() throws Exception { + bindAutoExpectResult(new Intent(getContext(), LocalService.class)); + } + + @MediumTest + public void testLocalBindAutoAction() throws Exception { + bindAutoExpectResult(new Intent(SERVICE_LOCAL)); + } + + @MediumTest + public void testLocalStartClassPermissionGranted() throws Exception { + startExpectResult(new Intent(getContext(), LocalGrantedService.class)); + } + + @MediumTest + public void testLocalStartActionPermissionGranted() throws Exception { + startExpectResult(new Intent(SERVICE_LOCAL_GRANTED)); + } + + @MediumTest + public void testLocalBindClassPermissionGranted() throws Exception { + bindExpectResult(new Intent(getContext(), LocalGrantedService.class)); + } + + @MediumTest + public void testLocalBindActionPermissionGranted() throws Exception { + bindExpectResult(new Intent(SERVICE_LOCAL_GRANTED)); + } + + @MediumTest + public void testLocalBindAutoClassPermissionGranted() throws Exception { + bindAutoExpectResult(new Intent(getContext(), LocalGrantedService.class)); + } + + @MediumTest + public void testLocalBindAutoActionPermissionGranted() throws Exception { + bindAutoExpectResult(new Intent(SERVICE_LOCAL_GRANTED)); + } + + @MediumTest + public void testLocalStartClassPermissionDenied() throws Exception { + startExpectNoPermission(new Intent(getContext(), LocalDeniedService.class)); + } + + @MediumTest + public void testLocalStartActionPermissionDenied() throws Exception { + startExpectNoPermission(new Intent(SERVICE_LOCAL_DENIED)); + } + + @MediumTest + public void testLocalBindClassPermissionDenied() throws Exception { + bindExpectNoPermission(new Intent(getContext(), LocalDeniedService.class)); + } + + @MediumTest + public void testLocalBindActionPermissionDenied() throws Exception { + bindExpectNoPermission(new Intent(SERVICE_LOCAL_DENIED)); + } + + @MediumTest + public void testLocalUnbindTwice() throws Exception { + EmptyConnection conn = new EmptyConnection(); + getContext().bindService( + new Intent(SERVICE_LOCAL_GRANTED), conn, 0); + getContext().unbindService(conn); + try { + getContext().unbindService(conn); + fail("No exception thrown on second unbind"); + } catch (IllegalArgumentException e) { + //Log.i("foo", "Unbind exception", e); + } + } +} diff --git a/tests/AndroidTests/src/com/android/unit_tests/activity/SetTimeZonePermissionsTest.java b/tests/AndroidTests/src/com/android/unit_tests/activity/SetTimeZonePermissionsTest.java new file mode 100644 index 0000000000000000000000000000000000000000..1fa7579fc61476d85895ecc500d48004b82b68fb --- /dev/null +++ b/tests/AndroidTests/src/com/android/unit_tests/activity/SetTimeZonePermissionsTest.java @@ -0,0 +1,70 @@ +/* + * 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.android.unit_tests.activity; + +import android.app.AlarmManager; +import android.content.Context; +import android.test.AndroidTestCase; +import android.test.suitebuilder.annotation.LargeTest; + +import java.util.TimeZone; + +public class SetTimeZonePermissionsTest extends AndroidTestCase { + + private String[] mZones; + private String mCurrentZone; + private AlarmManager mAlarm; + + @Override + protected void setUp() throws Exception { + super.setUp(); + + mZones = TimeZone.getAvailableIDs(); + mCurrentZone = TimeZone.getDefault().getID(); + mAlarm = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE); + } + + /** + * Verify that non-system processes cannot set the time zone. + */ + @LargeTest + public void testSetTimeZonePermissions() { + /** + * Attempt to set several predefined time zones, verifying that the system + * system default time zone has not actually changed from its prior state + * after each attempt. + */ + int max = (mZones.length > 10) ? mZones.length : 10; + assertTrue("No system-defined time zones - test invalid", max > 0); + + for (int i = 0; i < max; i++) { + String tz = mZones[i]; + try { + mAlarm.setTimeZone(tz); + } catch (SecurityException se) { + // Expected failure; no need to handle specially since we're + // about to assert that the test invariant holds: no change + // to the system time zone. + } + + String newZone = TimeZone.getDefault().getID(); + assertEquals("AlarmManager.setTimeZone() succeeded despite lack of permission", + mCurrentZone, + newZone); + } + } +} diff --git a/tests/AndroidTests/src/com/android/unit_tests/activity/SubActivityScreen.java b/tests/AndroidTests/src/com/android/unit_tests/activity/SubActivityScreen.java new file mode 100644 index 0000000000000000000000000000000000000000..914b909fd3cbcb4c9aec317c9eb604b7a0a1720c --- /dev/null +++ b/tests/AndroidTests/src/com/android/unit_tests/activity/SubActivityScreen.java @@ -0,0 +1,168 @@ +/* + * Copyright (C) 2006 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.android.unit_tests.activity; + +import android.app.Activity; +import android.app.PendingIntent; +import android.content.Intent; +import android.os.Bundle; + +public class SubActivityScreen extends Activity { + static final int NO_RESULT_MODE = 0; + static final int RESULT_MODE = 1; + static final int PENDING_RESULT_MODE = 2; + static final int FINISH_SUB_MODE = 3; + + static final int CHILD_OFFSET = 1000; + + int mMode; + + public SubActivityScreen() { + } + + @Override + public void onCreate(Bundle icicle) { + super.onCreate(icicle); + mMode = getIntent().getIntExtra("mode", mMode); + //Log.i("foo", "SubActivityScreen pid=" + Process.myPid() + // + " mode=" + mMode); + + // Move on to the next thing that will generate a result... but only + // if we are being launched for the first time. + if (icicle == null) { + if (mMode == PENDING_RESULT_MODE) { + PendingIntent apr = createPendingResult(1, null, + Intent.FILL_IN_ACTION); + Intent res = new Intent(); + res.putExtra("tkey", "tval"); + res.setAction("test"); + try { + apr.send(this, RESULT_OK, res); + } catch (PendingIntent.CanceledException e) { + } + } else if (mMode < CHILD_OFFSET) { + Intent intent = new Intent(); + intent.setClass(this, SubActivityScreen.class); + intent.putExtra("mode", CHILD_OFFSET+mMode); + //System.out.println("*** Starting from onStart: " + intent); + startActivityForResult(intent, 1); + return; + } + } + } + + @Override + protected void onRestoreInstanceState(Bundle state) { + super.onRestoreInstanceState(state); + } + + @Override + protected void onResume() { + super.onResume(); + + //Log.i("foo", "SubActivityScreen pid=" + Process.myPid() + " onResume"); + + if (mMode >= CHILD_OFFSET) { + // Wait a little bit, to give our parent time to kill itself + // if that is something it is into. + try { + Thread.sleep(500); + } catch (InterruptedException e) { + setResult(RESULT_CANCELED, (new Intent()).setAction("Interrupted!")); + finish(); + return; + } + //System.out.println("Resuming sub-activity: mode=" + mMode); + switch (mMode-CHILD_OFFSET) { + case NO_RESULT_MODE: + finish(); + break; + case RESULT_MODE: + Intent res = new Intent(); + res.putExtra("tkey", "tval"); + res.setAction("test"); + setResult(RESULT_OK, res); + finish(); + break; + case FINISH_SUB_MODE: + break; + } + } + } + + @Override + protected void onActivityResult(int requestCode, int resultCode, + Intent data) { + //Log.i("foo", "SubActivityScreen pid=" + Process.myPid() + // + " onActivityResult: req=" + requestCode + // + " res=" + resultCode); + + // Assume success. + setResult(RESULT_OK); + + if (requestCode == 1) { + switch (mMode) { + case NO_RESULT_MODE: + case FINISH_SUB_MODE: + if (resultCode != RESULT_CANCELED) { + setResult(RESULT_CANCELED, (new Intent()).setAction( + "Incorrect result code returned: " + resultCode)); + } + break; + case RESULT_MODE: + case PENDING_RESULT_MODE: + if (resultCode != RESULT_OK) { + setResult(RESULT_CANCELED, (new Intent()).setAction( + "Incorrect result code returned: " + resultCode)); + } else if (data == null) { + setResult(RESULT_CANCELED, (new Intent()).setAction( + "null data returned")); + } else if (!("test".equals(data.getAction()))) { + setResult(RESULT_CANCELED, (new Intent()).setAction( + "Incorrect action returned: " + data)); + } else if (!("tval".equals(data.getStringExtra("tkey")))) { + setResult(RESULT_CANCELED, (new Intent()).setAction( + "Incorrect extras returned: " + data.getExtras())); + } + break; + } + } else { + setResult(RESULT_CANCELED, (new Intent()).setAction( + "Incorrect request code returned: " + requestCode)); + } + + finish(); + } + + @Override + protected void onSaveInstanceState(Bundle outState) { + super.onSaveInstanceState(outState); + } + + @Override + protected void onStop() { + super.onStop(); + handleBeforeStopping(); + } + + public void handleBeforeStopping() { + if (mMode == FINISH_SUB_MODE) { + finishActivity(1); + } + } +} + diff --git a/tests/AndroidTests/src/com/android/unit_tests/activity/SubActivityTest.java b/tests/AndroidTests/src/com/android/unit_tests/activity/SubActivityTest.java new file mode 100644 index 0000000000000000000000000000000000000000..ee02c98b4de2e0dff35e1809d7425ef778a8e6a6 --- /dev/null +++ b/tests/AndroidTests/src/com/android/unit_tests/activity/SubActivityTest.java @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2006 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.android.unit_tests.activity; + +import android.test.suitebuilder.annotation.Suppress; +import android.content.ComponentName; + +@Suppress +public class SubActivityTest extends ActivityTestsBase { + + public void testPendingResult() throws Exception { + mIntent.putExtra("component", new ComponentName(getContext(), SubActivityScreen.class)); + mIntent.putExtra("mode", SubActivityScreen.PENDING_RESULT_MODE); + runLaunchpad(LaunchpadActivity.LAUNCH); + } + + public void testNoResult() throws Exception { + mIntent.putExtra("component", new ComponentName(getContext(), SubActivityScreen.class)); + mIntent.putExtra("mode", SubActivityScreen.NO_RESULT_MODE); + runLaunchpad(LaunchpadActivity.LAUNCH); + } + + public void testResult() throws Exception { + mIntent.putExtra("component", new ComponentName(getContext(), SubActivityScreen.class)); + mIntent.putExtra("mode", SubActivityScreen.RESULT_MODE); + runLaunchpad(LaunchpadActivity.LAUNCH); + } + + public void testFinishSub() throws Exception { + mIntent.putExtra("component", + new ComponentName(getContext(), RemoteSubActivityScreen.class)); + mIntent.putExtra("mode", SubActivityScreen.FINISH_SUB_MODE); + runLaunchpad(LaunchpadActivity.LAUNCH); + } + + public void testRemoteNoResult() throws Exception { + mIntent.putExtra("component", + new ComponentName(getContext(), RemoteSubActivityScreen.class)); + mIntent.putExtra("mode", SubActivityScreen.NO_RESULT_MODE); + runLaunchpad(LaunchpadActivity.LAUNCH); + } + + public void testRemoteResult() throws Exception { + mIntent.putExtra("component", + new ComponentName(getContext(), RemoteSubActivityScreen.class)); + mIntent.putExtra("mode", SubActivityScreen.RESULT_MODE); + runLaunchpad(LaunchpadActivity.LAUNCH); + } + + public void testRemoteFinishSub() throws Exception { + mIntent.putExtra("component", new ComponentName(getContext(), SubActivityScreen.class)); + mIntent.putExtra("mode", SubActivityScreen.FINISH_SUB_MODE); + runLaunchpad(LaunchpadActivity.LAUNCH); + } + + public void testRemoteRestartNoResult() throws Exception { + mIntent.putExtra("component", + new ComponentName(getContext(), RemoteSubActivityScreen.class)); + mIntent.putExtra("mode", SubActivityScreen.NO_RESULT_MODE); + mIntent.putExtra("kill", true); + runLaunchpad(LaunchpadActivity.LAUNCH); + } + + public void testRemoteRestartResult() throws Exception { + mIntent.putExtra("component", + new ComponentName(getContext(), RemoteSubActivityScreen.class)); + mIntent.putExtra("mode", SubActivityScreen.RESULT_MODE); + mIntent.putExtra("kill", true); + runLaunchpad(LaunchpadActivity.LAUNCH); + } + + public void testRemoteRestartFinishSub() throws Exception { + mIntent.putExtra("component", new ComponentName(getContext(), SubActivityScreen.class)); + mIntent.putExtra("mode", SubActivityScreen.FINISH_SUB_MODE); + mIntent.putExtra("kill", true); + runLaunchpad(LaunchpadActivity.LAUNCH); + } +} diff --git a/tests/AndroidTests/src/com/android/unit_tests/activity/TestedActivity.java b/tests/AndroidTests/src/com/android/unit_tests/activity/TestedActivity.java new file mode 100644 index 0000000000000000000000000000000000000000..ec407a9b96550796be53e719edb02d215abe248b --- /dev/null +++ b/tests/AndroidTests/src/com/android/unit_tests/activity/TestedActivity.java @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2006 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.android.unit_tests.activity; + +import android.app.Activity; +import android.os.Handler; +import android.os.Looper; +import android.os.Message; +import android.os.MessageQueue; +import android.os.Bundle; + +public class TestedActivity extends Activity +{ + public TestedActivity() + { + } + + public void onCreate(Bundle icicle) + { + super.onCreate(icicle); + } + + protected void onRestoreInstanceState(Bundle state) + { + super.onRestoreInstanceState(state); + } + + protected void onResume() + { + super.onResume(); + Looper.myLooper().myQueue().addIdleHandler(new Idler()); + } + + protected void onSaveInstanceState(Bundle outState) + { + super.onSaveInstanceState(outState); + } + + protected void onStop() + { + super.onStop(); + } + + private Handler mHandler = new Handler() { + public void handleMessage(Message msg) { + setResult(RESULT_OK); + finish(); + } + }; + + private class Idler implements MessageQueue.IdleHandler + { + public final boolean queueIdle() + { + //Message m = Message.obtain(); + //mHandler.sendMessageAtTime(m, SystemClock.uptimeMillis()+1000); + setResult(RESULT_OK); + finish(); + return false; + } + } +} + diff --git a/tests/AndroidTests/src/com/android/unit_tests/activity/TestedScreen.java b/tests/AndroidTests/src/com/android/unit_tests/activity/TestedScreen.java new file mode 100644 index 0000000000000000000000000000000000000000..4085aa95c2b50417571daf3bde7ff7552476cbe0 --- /dev/null +++ b/tests/AndroidTests/src/com/android/unit_tests/activity/TestedScreen.java @@ -0,0 +1,128 @@ +/* + * Copyright (C) 2006 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.android.unit_tests.activity; + +import android.app.Activity; +import android.content.Intent; +import android.os.Handler; +import android.os.Looper; +import android.os.Message; +import android.os.MessageQueue; +import android.os.SystemClock; +import android.os.Bundle; +import android.util.Log; + +public class TestedScreen extends Activity +{ + public static final String WAIT_BEFORE_FINISH = "TestedScreen.WAIT_BEFORE_FINISH"; + public static final String DELIVER_RESULT = "TestedScreen.DELIVER_RESULT"; + public static final String CLEAR_TASK = "TestedScreen.CLEAR_TASK"; + + public TestedScreen() { + } + + public void onCreate(Bundle icicle) { + super.onCreate(icicle); + if (ActivityTests.DEBUG_LIFECYCLE) Log.v("test", "CREATE tested " + + Integer.toHexString(System.identityHashCode(this)) + ": " + getIntent()); + if (LaunchpadActivity.FORWARD_RESULT.equals(getIntent().getAction())) { + Intent intent = new Intent(getIntent()); + intent.setAction(DELIVER_RESULT); + intent.setFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT); + startActivity(intent); + if (ActivityTests.DEBUG_LIFECYCLE) Log.v("test", "Finishing tested " + + Integer.toHexString(System.identityHashCode(this)) + ": " + getIntent()); + finish(); + } else if (DELIVER_RESULT.equals(getIntent().getAction())) { + setResult(RESULT_OK, (new Intent()).setAction( + LaunchpadActivity.RETURNED_RESULT)); + if (ActivityTests.DEBUG_LIFECYCLE) Log.v("test", "Finishing tested " + + Integer.toHexString(System.identityHashCode(this)) + ": " + getIntent()); + finish(); + } else if (CLEAR_TASK.equals(getIntent().getAction())) { + if (!getIntent().getBooleanExtra(ClearTop.WAIT_CLEAR_TASK, false)) { + launchClearTask(); + } + } + } + + protected void onRestoreInstanceState(Bundle state) { + super.onRestoreInstanceState(state); + } + + protected void onResume() { + super.onResume(); + if (ActivityTests.DEBUG_LIFECYCLE) Log.v("test", "RESUME tested " + + Integer.toHexString(System.identityHashCode(this)) + ": " + getIntent()); + if (CLEAR_TASK.equals(getIntent().getAction())) { + if (getIntent().getBooleanExtra(ClearTop.WAIT_CLEAR_TASK, false)) { + Looper.myLooper().myQueue().addIdleHandler(new Idler()); + } + } else { + Looper.myLooper().myQueue().addIdleHandler(new Idler()); + } + } + + protected void onSaveInstanceState(Bundle outState) { + super.onSaveInstanceState(outState); + } + + protected void onStop() { + super.onStop(); + if (ActivityTests.DEBUG_LIFECYCLE) Log.v("test", "STOP tested " + + Integer.toHexString(System.identityHashCode(this)) + ": " + getIntent()); + } + + private void launchClearTask() { + Intent intent = new Intent(getIntent()). + addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP). + setClass(this, ClearTop.class); + startActivity(intent); + } + + private Handler mHandler = new Handler() { + public void handleMessage(Message msg) { + if (CLEAR_TASK.equals(getIntent().getAction())) { + launchClearTask(); + } else { + if (ActivityTests.DEBUG_LIFECYCLE) Log.v("test", "Finishing tested " + + Integer.toHexString(System.identityHashCode(this)) + ": " + getIntent()); + setResult(RESULT_OK); + finish(); + } + } + }; + + private class Idler implements MessageQueue.IdleHandler { + public final boolean queueIdle() { + if (WAIT_BEFORE_FINISH.equals(getIntent().getAction())) { + Message m = Message.obtain(); + mHandler.sendMessageAtTime(m, SystemClock.uptimeMillis()+1000); + } else if (CLEAR_TASK.equals(getIntent().getAction())) { + Message m = Message.obtain(); + mHandler.sendMessageAtTime(m, SystemClock.uptimeMillis()+1000); + } else { + if (ActivityTests.DEBUG_LIFECYCLE) Log.v("test", "Finishing tested " + + Integer.toHexString(System.identityHashCode(this)) + ": " + getIntent()); + setResult(RESULT_OK); + finish(); + } + return false; + } + } +} + diff --git a/tests/AndroidTests/src/com/android/unit_tests/content/ArrayTest.java b/tests/AndroidTests/src/com/android/unit_tests/content/ArrayTest.java new file mode 100644 index 0000000000000000000000000000000000000000..4d5b5e778041262d9ba612bffc6431e203a89f4d --- /dev/null +++ b/tests/AndroidTests/src/com/android/unit_tests/content/ArrayTest.java @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2007 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.android.unit_tests.content; + +import android.content.res.Resources; +import android.test.AndroidTestCase; +import android.test.suitebuilder.annotation.SmallTest; +import android.util.TypedValue; +import com.android.unit_tests.R; + +public class ArrayTest extends AndroidTestCase { + private Resources mResources; + + @Override + protected void setUp() throws Exception { + super.setUp(); + mResources = mContext.getResources(); + } + + private void checkEntry(int resid, int index, Object res, Object expected) { + assertEquals("in resource 0x" + Integer.toHexString(resid) + + " at index " + index, expected, res); + } + + private void checkStringArray(int resid, String[] expected) { + String[] res = mResources.getStringArray(resid); + assertEquals(res.length, expected.length); + for (int i=0; i 0) { + for (int i = 0; i < readCount; i++) { + assertEquals("At index " + curIndex + + " expected " + expectedString.charAt(curIndex) + + " but found " + ((char) buffer[i]), + buffer[i], expectedString.charAt(curIndex)); + curIndex++; + } + } + + readCount = is.read(buffer, 0, buffer.length); + assertEquals("Reading end of buffer: expected readCount=-1 but got " + readCount, + -1, readCount); + + readCount = is.read(buffer, buffer.length, 0); + assertEquals("Reading end of buffer length 0: expected readCount=0 but got " + readCount, + 0, readCount); + + is.close(); + } + + @SmallTest + public void testReadToEnd() throws Exception { + InputStream is = mAssets.open("text.txt"); + verifyTextAsset(is); + } + + // XXX failing + public void xxtestListDir() throws Exception { + String[] files = mAssets.list(""); + assertEquals(1, files.length); + assertEquals("test.txt", files[0]); + } +} diff --git a/tests/AndroidTests/src/com/android/unit_tests/content/ConfigTest.java b/tests/AndroidTests/src/com/android/unit_tests/content/ConfigTest.java new file mode 100644 index 0000000000000000000000000000000000000000..a63885ded19dafdb0b7c20072fcbca178c1a3065 --- /dev/null +++ b/tests/AndroidTests/src/com/android/unit_tests/content/ConfigTest.java @@ -0,0 +1,326 @@ +/* + * Copyright (C) 2007 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.android.unit_tests.content; + +import android.content.Context; +import android.content.res.AssetManager; +import android.content.res.Configuration; +import android.content.res.Resources; +import android.content.res.TypedArray; +import android.test.AndroidTestCase; +import android.test.suitebuilder.annotation.MediumTest; +import android.test.suitebuilder.annotation.SmallTest; +import android.util.DisplayMetrics; +import android.view.Display; +import android.view.WindowManager; +import com.android.unit_tests.R; + +import java.util.Locale; + +public class ConfigTest extends AndroidTestCase { + + private static void checkValue(Resources res, int resId, String expectedValue) { + try { + String actual = res.getString(resId); + assertNotNull("Returned wrong configuration-based simple value: expected , got '" + + actual + "' from resource 0x" + + Integer.toHexString(resId), + expectedValue); + assertEquals("Returned wrong configuration-based simple value: expected " + + expectedValue + ", got '" + actual + "' from resource 0x" + + Integer.toHexString(resId), + expectedValue, actual); + } catch (Resources.NotFoundException e) { + assertNull("Resource not found for configuration-based simple value: expecting \"" + + expectedValue + "\"", + expectedValue); + } + } + + private static void checkValue(Resources res, int resId, + int[] styleable, String[] expectedValues) { + Resources.Theme theme = res.newTheme(); + TypedArray sa = theme.obtainStyledAttributes(resId, styleable); + for (int i = 0; i < styleable.length; i++) { + String actual = sa.getString(i); + assertEquals("Returned wrong configuration-based style value: expected " + + expectedValues[i] + ", got '" + actual + "' from attr " + + i + " of resource 0x" + Integer.toHexString(resId), + actual, expectedValues[i]); + } + sa.recycle(); + } + + public Resources getResources(Configuration config, + int mcc, int mnc, int touchscreen, int keyboard, int keysHidden, + int navigation, int width, int height) { + AssetManager assmgr = new AssetManager(); + assmgr.addAssetPath(mContext.getPackageResourcePath()); + DisplayMetrics metrics = new DisplayMetrics(); + WindowManager wm = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE); + Display d = wm.getDefaultDisplay(); + d.getMetrics(metrics); + config.mcc = mcc; + config.mnc = mnc; + config.touchscreen = touchscreen; + config.keyboard = keyboard; + config.keyboardHidden = keysHidden; + config.navigation = navigation; + metrics.widthPixels = width; + metrics.heightPixels = height; + return new Resources(assmgr, metrics, config); + } + + private static void checkPair(Resources res, int[] notResIds, + int simpleRes, String simpleString, + int bagRes, String bagString) { + boolean willHave = true; + if (notResIds != null) { + for (int i : notResIds) { + if (i == simpleRes) { + willHave = false; + break; + } + } + } + checkValue(res, simpleRes, willHave ? simpleString : null); + checkValue(res, bagRes, R.styleable.TestConfig, + new String[]{willHave ? bagString : null}); + } + + private static void checkAllExcept(Resources res, int[] notResIds) { + checkPair(res, notResIds, + R.configVarying.simple_default, "only simple default", + R.configVarying.bag_default, "only bag default"); + checkPair(res, notResIds, + R.configVarying.simple_mcc111, "only simple mcc111", + R.configVarying.bag_mcc111, "only bag mcc111"); + checkPair(res, notResIds, + R.configVarying.simple_mnc222, "only simple mnc222", + R.configVarying.bag_mnc222, "only bag mnc222"); + checkPair(res, notResIds, + R.configVarying.simple_xx, "only simple xx", + R.configVarying.bag_xx, "only bag xx"); + checkPair(res, notResIds, + R.configVarying.simple_xx_rYY, "only simple xx_rYY", + R.configVarying.bag_xx_rYY, "only bag xx_rYY"); + checkPair(res, notResIds, + R.configVarying.simple_notouch, "only simple notouch", + R.configVarying.bag_notouch, "only bag notouch"); + checkPair(res, notResIds, + R.configVarying.simple_finger, "only simple finger", + R.configVarying.bag_finger, "only bag finger"); + checkPair(res, notResIds, + R.configVarying.simple_stylus, "only simple stylus", + R.configVarying.bag_stylus, "only bag stylus"); + checkPair(res, notResIds, + R.configVarying.simple_12key, "only simple 12key", + R.configVarying.bag_12key, "only bag 12key"); + checkPair(res, notResIds, + R.configVarying.simple_320x200, "only simple 320x200", + R.configVarying.bag_320x200, "only bag 320x200"); + checkPair(res, notResIds, + R.configVarying.simple_480x320, "only simple 480x320", + R.configVarying.bag_480x320, "only bag 480x320"); + } + + @SmallTest + public void testDefaultNavigationMethod() throws Exception { + assertEquals(mContext.getResources().getConfiguration().navigation, + Configuration.NAVIGATION_TRACKBALL); + } + + @SmallTest + public void testAllConfigs() throws Exception { + /** + * Test a resource that contains a value for each possible single + * configuration value. + */ + Configuration config = new Configuration(); + Resources res = getResources(config, 0, 0, 0, 0, 0, 0, 0, 0); + checkValue(res, R.configVarying.simple, "simple default"); + checkValue(res, R.configVarying.bag, + R.styleable.TestConfig, new String[]{"bag default"}); + + config.locale = new Locale("xx"); + res = getResources(config, 0, 0, 0, 0, 0, 0, 0, 0); + checkValue(res, R.configVarying.simple, "simple xx"); + checkValue(res, R.configVarying.bag, + R.styleable.TestConfig, new String[]{"bag xx"}); + + config.locale = new Locale("xx", "YY"); + res = getResources(config, 0, 0, 0, 0, 0, 0, 0, 0); + checkValue(res, R.configVarying.simple, "simple xx-rYY"); + checkValue(res, R.configVarying.bag, + R.styleable.TestConfig, new String[]{"bag xx-rYY"}); + + config = new Configuration(); + res = getResources(config, 111, 0, 0, 0, 0, 0, 0, 0); + checkValue(res, R.configVarying.simple, "simple mcc111"); + checkValue(res, R.configVarying.bag, + R.styleable.TestConfig, new String[]{"bag mcc111"}); + + res = getResources(config, 0, 222, 0, 0, 0, 0, 0, 0); + checkValue(res, R.configVarying.simple, "simple mnc222"); + checkValue(res, R.configVarying.bag, + R.styleable.TestConfig, new String[]{"bag mnc222"}); + + res = getResources(config, 0, 0, Configuration.TOUCHSCREEN_NOTOUCH, 0, 0, 0, 0, 0); + checkValue(res, R.configVarying.simple, "simple notouch"); + checkValue(res, R.configVarying.bag, + R.styleable.TestConfig, new String[]{"bag notouch"}); + + res = getResources(config, 0, 0, Configuration.TOUCHSCREEN_FINGER, 0, 0, 0, 0, 0); + checkValue(res, R.configVarying.simple, "simple finger"); + checkValue(res, R.configVarying.bag, + R.styleable.TestConfig, new String[]{"bag finger"}); + + res = getResources(config, 0, 0, Configuration.TOUCHSCREEN_STYLUS, 0, 0, 0, 0, 0); + checkValue(res, R.configVarying.simple, "simple stylus"); + checkValue(res, R.configVarying.bag, + R.styleable.TestConfig, new String[]{"bag stylus"}); + + res = getResources(config, 0, 0, 0, Configuration.KEYBOARD_NOKEYS, 0, 0, 0, 0); + checkValue(res, R.configVarying.simple, "simple nokeys"); + checkValue(res, R.configVarying.bag, + R.styleable.TestConfig, new String[]{"bag nokeys"}); + + res = getResources(config, 0, 0, 0, Configuration.KEYBOARD_QWERTY, 0, 0, 0, 0); + checkValue(res, R.configVarying.simple, "simple qwerty"); + checkValue(res, R.configVarying.bag, + R.styleable.TestConfig, new String[]{"bag qwerty"}); + + res = getResources(config, 0, 0, 0, Configuration.KEYBOARD_12KEY, 0, 0, 0, 0); + checkValue(res, R.configVarying.simple, "simple 12key"); + checkValue(res, R.configVarying.bag, + R.styleable.TestConfig, new String[]{"bag 12key"}); + + res = getResources(config, 0, 0, 0, 0, Configuration.KEYBOARDHIDDEN_YES, 0, 0, 0); + checkValue(res, R.configVarying.simple, "simple keyshidden"); + checkValue(res, R.configVarying.bag, + R.styleable.TestConfig, new String[]{"bag keyshidden"}); + + res = getResources(config, 0, 0, 0, 0, Configuration.KEYBOARDHIDDEN_NO, 0, 0, 0); + checkValue(res, R.configVarying.simple, "simple keysexposed"); + checkValue(res, R.configVarying.bag, + R.styleable.TestConfig, new String[]{"bag keysexposed"}); + + res = getResources(config, 0, 0, 0, 0, 0, Configuration.NAVIGATION_NONAV, 0, 0); + checkValue(res, R.configVarying.simple, "simple nonav"); + checkValue(res, R.configVarying.bag, + R.styleable.TestConfig, new String[]{"bag nonav"}); + + res = getResources(config, 0, 0, 0, 0, 0, Configuration.NAVIGATION_DPAD, 0, 0); + checkValue(res, R.configVarying.simple, "simple dpad"); + checkValue(res, R.configVarying.bag, + R.styleable.TestConfig, new String[]{"bag dpad"}); + + res = getResources(config, 0, 0, 0, 0, 0, Configuration.NAVIGATION_TRACKBALL, 0, 0); + checkValue(res, R.configVarying.simple, "simple trackball"); + checkValue(res, R.configVarying.bag, + R.styleable.TestConfig, new String[]{"bag trackball"}); + + res = getResources(config, 0, 0, 0, 0, 0, Configuration.NAVIGATION_WHEEL, 0, 0); + checkValue(res, R.configVarying.simple, "simple wheel"); + checkValue(res, R.configVarying.bag, + R.styleable.TestConfig, new String[]{"bag wheel"}); + + res = getResources(config, 0, 0, 0, 0, 0, 0, 320, 200); + checkValue(res, R.configVarying.simple, "simple 320x200"); + checkValue(res, R.configVarying.bag, + R.styleable.TestConfig, new String[]{"bag 320x200"}); + + res = getResources(config, 0, 0, 0, 0, 0, 0, 480, 320); + checkValue(res, R.configVarying.simple, "simple 480x320"); + checkValue(res, R.configVarying.bag, + R.styleable.TestConfig, new String[]{"bag 480x320"}); + } + + @MediumTest + public void testSingleConfig() throws Exception { + /** + * Test resources that contain a value for only one possible configuration + * value. XXX This is not yet complete. + */ + Configuration config = new Configuration(); + Resources res = getResources(config, 0, 0, 0, 0, 0, 0, 0, 0); + checkAllExcept(res, new int[]{ + R.configVarying.simple_xx, + R.configVarying.simple_xx_rYY}); + + config.locale = new Locale("xx"); + res = getResources(config, 0, 0, 0, 0, 0, 0, 0, 0); + checkAllExcept(res, null); + + config.locale = new Locale("xx", "YY"); + res = getResources(config, 0, 0, 0, 0, 0, 0, 0, 0); + checkAllExcept(res, null); + + config.locale = new Locale("xx", "ZZ"); + res = getResources(config, 0, 0, 0, 0, 0, 0, 0, 0); + checkAllExcept(res, new int[]{R.configVarying.simple_xx_rYY}); + + config = new Configuration(); + res = getResources(config, 111, 0, 0, 0, 0, 0, 0, 0); + checkAllExcept(res, new int[]{ + R.configVarying.simple_xx, + R.configVarying.simple_xx_rYY}); + + res = getResources(config, 0, 222, 0, 0, 0, 0, 0, 0); + checkAllExcept(res, new int[]{ + R.configVarying.simple_xx, + R.configVarying.simple_xx_rYY}); + + res = getResources(config, 0, 0, Configuration.TOUCHSCREEN_NOTOUCH, 0, 0, 0, 0, 0); + checkAllExcept(res, new int[]{ + R.configVarying.simple_xx, + R.configVarying.simple_xx_rYY, + R.configVarying.simple_finger, + R.configVarying.simple_stylus}); + + res = getResources(config, 0, 0, Configuration.TOUCHSCREEN_FINGER, 0, 0, 0, 0, 0); + checkAllExcept(res, new int[]{ + R.configVarying.simple_xx, + R.configVarying.simple_xx_rYY, + R.configVarying.simple_notouch, + R.configVarying.simple_stylus}); + + res = getResources(config, 0, 0, Configuration.TOUCHSCREEN_STYLUS, 0, 0, 0, 0, 0); + checkAllExcept(res, new int[]{ + R.configVarying.simple_xx, + R.configVarying.simple_xx_rYY, + R.configVarying.simple_notouch, + R.configVarying.simple_finger}); + + res = getResources(config, 0, 0, 0, Configuration.KEYBOARD_12KEY, 0, 0, 0, 0); + checkAllExcept(res, new int[]{ + R.configVarying.simple_xx, + R.configVarying.simple_xx_rYY}); + + res = getResources(config, 0, 0, 0, 0, 0, 0, 320, 200); + checkAllExcept(res, new int[]{ + R.configVarying.simple_xx, + R.configVarying.simple_xx_rYY, + R.configVarying.simple_480x320}); + + res = getResources(config, 0, 0, 0, 0, 0, 0, 480, 320); + checkAllExcept(res, new int[]{ + R.configVarying.simple_xx, + R.configVarying.simple_xx_rYY, + R.configVarying.simple_320x200}); + } +} diff --git a/tests/AndroidTests/src/com/android/unit_tests/content/ContentTests.java b/tests/AndroidTests/src/com/android/unit_tests/content/ContentTests.java new file mode 100644 index 0000000000000000000000000000000000000000..80318dcc6772cc1b360a002c9ae52aab176cd58b --- /dev/null +++ b/tests/AndroidTests/src/com/android/unit_tests/content/ContentTests.java @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2006 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.android.unit_tests.content; + +import junit.framework.TestSuite; + +public class ContentTests { + public static TestSuite suite() { + TestSuite suite = new TestSuite(ContentTests.class.getName()); + + suite.addTestSuite(AssetTest.class); + suite.addTestSuite(IntentFilterTest.class); + suite.addTest(ResourceTests.suite()); + suite.addTestSuite(PluralResourcesTest.class); + suite.addTestSuite(ConfigTest.class); + return suite; + } +} diff --git a/tests/AndroidTests/src/com/android/unit_tests/content/FractionTest.java b/tests/AndroidTests/src/com/android/unit_tests/content/FractionTest.java new file mode 100644 index 0000000000000000000000000000000000000000..74a6b8de3d5b3460aba900b5d5b401c9bebb8f53 --- /dev/null +++ b/tests/AndroidTests/src/com/android/unit_tests/content/FractionTest.java @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2007 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.android.unit_tests.content; + +import android.content.res.Resources; +import android.test.AndroidTestCase; +import android.test.suitebuilder.annotation.SmallTest; +import android.util.TypedValue; +import com.android.unit_tests.R; + +public class FractionTest extends AndroidTestCase { + + private Resources mResources; + private final TypedValue mValue = new TypedValue(); + + @Override + protected void setUp() throws Exception { + super.setUp(); + mResources = mContext.getResources(); + } + + @SmallTest + public void testFractions() throws Exception { + tryFraction(R.dimen.frac100perc, 1, 1, 1); + tryFraction(R.dimen.frac1perc, 1, 1, .01f); + tryFraction(R.dimen.fracp1perc, 1, 1, .001f); + tryFraction(R.dimen.fracp01perc, 1, 1, .0001f); + tryFraction(R.dimen.frac0perc, 1, 1, 0); + tryFraction(R.dimen.frac1p1perc, 1, 1, .011f); + tryFraction(R.dimen.frac100p1perc, 1, 1, 1.001f); + tryFraction(R.dimen.frac25510perc, 1, 1, 255.1f); + tryFraction(R.dimen.frac25610perc, 1, 1, 256.1f); + tryFraction(R.dimen.frac6553510perc, 1, 1, 65535.1f); + tryFraction(R.dimen.frac6553610perc, 1, 1, 65536.1f); + + tryFraction(R.dimen.frac100perc, 100, 1, 100); + tryFraction(R.dimen.frac1perc, 100, 1, .01f * 100); + tryFraction(R.dimen.fracp1perc, 100, 1, .001f * 100); + tryFraction(R.dimen.fracp01perc, 100, 1, .0001f * 100); + tryFraction(R.dimen.frac0perc, 100, 1, 0); + tryFraction(R.dimen.frac1p1perc, 100, 1, .011f * 100); + tryFraction(R.dimen.frac100p1perc, 100, 1, 1.001f * 100); + tryFraction(R.dimen.frac25510perc, 100, 1, 255.1f * 100); + tryFraction(R.dimen.frac25610perc, 100, 1, 256.1f * 100); + tryFraction(R.dimen.frac6553510perc, 100, 1, 65535.1f * 100); + tryFraction(R.dimen.frac6553610perc, 100, 1, 65536.1f * 100); + + tryFraction(R.dimen.frac100pperc, 100, 2, 2); + tryFraction(R.dimen.frac1pperc, 100, 2, .01f * 2); + tryFraction(R.dimen.fracp1pperc, 100, 2, .001f * 2); + tryFraction(R.dimen.fracp01pperc, 100, 2, .0001f * 2); + tryFraction(R.dimen.frac0pperc, 100, 2, 0); + tryFraction(R.dimen.frac1p1pperc, 100, 2, .011f * 2); + tryFraction(R.dimen.frac100p1pperc, 100, 2, 1.001f * 2); + tryFraction(R.dimen.frac25510pperc, 100, 2, 255.1f * 2); + tryFraction(R.dimen.frac25610pperc, 100, 2, 256.1f * 2); + tryFraction(R.dimen.frac6553510pperc, 100, 2, 65535.1f * 2); + tryFraction(R.dimen.frac6553610pperc, 100, 2, 65536.1f * 2); + } + + private void tryFraction(int resid, float base, float pbase, float expected) { + mResources.getValue(resid, mValue, true); + float res = mValue.getFraction(base, pbase); + float diff = Math.abs(expected - res); + float prec = expected * 1e-4f; + if (prec < 1e-5f) { + prec = 1e-5f; + } + //System.out.println( + // "Res 0x" + Integer.toHexString(resid) + ": got=" + res + // + ", expected=" + expected + ", diff=" + diff); + assertFalse("Expecting value " + expected + " got " + res + + ": in resource 0x" + Integer.toHexString(resid) + + " " + mValue, + diff > prec); + } +} + diff --git a/tests/AndroidTests/src/com/android/unit_tests/content/IntentFilterTest.java b/tests/AndroidTests/src/com/android/unit_tests/content/IntentFilterTest.java new file mode 100644 index 0000000000000000000000000000000000000000..0335b9d38798747e7ae41ef7f0d0b138df8faafa --- /dev/null +++ b/tests/AndroidTests/src/com/android/unit_tests/content/IntentFilterTest.java @@ -0,0 +1,570 @@ +/* + * Copyright (C) 2007 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.android.unit_tests.content; + +import android.content.IntentFilter; +import android.test.suitebuilder.annotation.SmallTest; +import static android.os.PatternMatcher.PATTERN_LITERAL; +import static android.os.PatternMatcher.PATTERN_PREFIX; +import static android.os.PatternMatcher.PATTERN_SIMPLE_GLOB; +import android.net.Uri; +import android.util.StringBuilderPrinter; +import junit.framework.TestCase; + +import java.util.HashSet; + +public class IntentFilterTest extends TestCase { + + public static class Match extends IntentFilter { + Match(String[] actions, String[] categories, String[] mimeTypes, + String[] schemes, String[] authorities, String[] ports) { + if (actions != null) { + for (int i = 0; i < actions.length; i++) { + addAction(actions[i]); + } + } + if (categories != null) { + for (int i = 0; i < categories.length; i++) { + addCategory(categories[i]); + } + } + if (mimeTypes != null) { + for (int i = 0; i < mimeTypes.length; i++) { + try { + addDataType(mimeTypes[i]); + } catch (IntentFilter.MalformedMimeTypeException e) { + throw new RuntimeException("Bad mime type", e); + } + } + } + if (schemes != null) { + for (int i = 0; i < schemes.length; i++) { + addDataScheme(schemes[i]); + } + } + if (authorities != null) { + for (int i = 0; i < authorities.length; i++) { + addDataAuthority(authorities[i], + ports != null ? ports[i] : null); + } + } + } + + Match(String[] actions, String[] categories, String[] mimeTypes, + String[] schemes, String[] authorities, String[] ports, + String[] paths, int[] pathTypes) { + this(actions, categories, mimeTypes, schemes, authorities, ports); + if (paths != null) { + for (int i = 0; i < paths.length; i++) { + addDataPath(paths[i], pathTypes[i]); + } + } + } + } + + public static class MatchCondition { + public final int result; + public final String action; + public final String mimeType; + public final Uri data; + public final String[] categories; + + public MatchCondition(int _result, String _action, String[] _categories, + String _mimeType, String _data) { + result = _result; + action = _action; + mimeType = _mimeType; + data = _data != null ? Uri.parse(_data) : null; + categories = _categories; + } + } + + public static void checkMatches(IntentFilter filter, + MatchCondition[] results) { + for (int i = 0; i < results.length; i++) { + MatchCondition mc = results[i]; + HashSet categories = null; + if (mc.categories != null) { + for (int j = 0; j < mc.categories.length; j++) { + if (categories == null) { + categories = new HashSet(); + } + categories.add(mc.categories[j]); + } + } + int result = filter.match(mc.action, mc.mimeType, + mc.data != null ? mc.data.getScheme() : null, mc.data, + categories, "test"); + if ( (result & IntentFilter.MATCH_CATEGORY_MASK) + != (mc.result & IntentFilter.MATCH_CATEGORY_MASK) ) { + StringBuilder msg = new StringBuilder(); + msg.append("Error matching against IntentFilter:\n"); + filter.dump(new StringBuilderPrinter(msg), " "); + msg.append("Match action: "); + msg.append(mc.action); + msg.append("\nMatch mimeType: "); + msg.append(mc.mimeType); + msg.append("\nMatch data: "); + msg.append(mc.data); + msg.append("\nMatch categories: "); + if (mc.categories != null) { + for (int j = 0; j < mc.categories.length; j++) { + if (j > 0) msg.append(", "); + msg.append(mc.categories[j]); + } + } + msg.append("\nExpected result: 0x"); + msg.append(Integer.toHexString(mc.result)); + msg.append(", got result: 0x"); + msg.append(Integer.toHexString(result)); + throw new RuntimeException(msg.toString()); + } + } + } + + @SmallTest + public void testActions() throws Exception { + IntentFilter filter = new Match( + new String[]{"action1"}, null, null, null, null, null); + checkMatches(filter, new MatchCondition[]{ + new MatchCondition(IntentFilter.MATCH_CATEGORY_EMPTY, null, + null, null, null), + new MatchCondition(IntentFilter.MATCH_CATEGORY_EMPTY, "action1", + null, null, null), + new MatchCondition(IntentFilter.NO_MATCH_ACTION, "action2", + null, null, null), + }); + + filter = new Match( + new String[]{"action1", "action2"}, + null, null, null, null, null); + checkMatches(filter, new MatchCondition[]{ + new MatchCondition(IntentFilter.MATCH_CATEGORY_EMPTY, null, + null, null, null), + new MatchCondition(IntentFilter.MATCH_CATEGORY_EMPTY, "action1", + null, null, null), + new MatchCondition(IntentFilter.MATCH_CATEGORY_EMPTY, "action2", + null, null, null), + new MatchCondition(IntentFilter.NO_MATCH_ACTION, "action3", + null, null, null), + }); + } + + @SmallTest + public void testCategories() throws Exception { + IntentFilter filter = new Match( + null, new String[]{"category1"}, null, null, null, null); + checkMatches(filter, new MatchCondition[]{ + new MatchCondition(IntentFilter.MATCH_CATEGORY_EMPTY, null, + null, null, null), + new MatchCondition(IntentFilter.MATCH_CATEGORY_EMPTY, null, + new String[]{"category1"}, null, null), + new MatchCondition(IntentFilter.NO_MATCH_CATEGORY, null, + new String[]{"category2"}, null, null), + new MatchCondition(IntentFilter.NO_MATCH_CATEGORY, null, + new String[]{"category1", "category2"}, null, null), + }); + + filter = new Match( + null, new String[]{"category1", "category2"}, null, null, + null, null); + checkMatches(filter, new MatchCondition[]{ + new MatchCondition(IntentFilter.MATCH_CATEGORY_EMPTY, null, + null, null, null), + new MatchCondition(IntentFilter.MATCH_CATEGORY_EMPTY, null, + new String[]{"category1"}, null, null), + new MatchCondition(IntentFilter.MATCH_CATEGORY_EMPTY, null, + new String[]{"category2"}, null, null), + new MatchCondition(IntentFilter.MATCH_CATEGORY_EMPTY, null, + new String[]{"category1", "category2"}, null, null), + new MatchCondition(IntentFilter.NO_MATCH_CATEGORY, null, + new String[]{"category3"}, null, null), + new MatchCondition(IntentFilter.NO_MATCH_CATEGORY, null, + new String[]{"category1", "category2", "category3"}, + null, null), + }); + } + + @SmallTest + public void testMimeTypes() throws Exception { + IntentFilter filter = new Match( + null, null, new String[]{"which1/what1"}, null, null, null); + checkMatches(filter, new MatchCondition[]{ + new MatchCondition(IntentFilter.NO_MATCH_TYPE, null, + null, null, null), + new MatchCondition(IntentFilter.MATCH_CATEGORY_TYPE, null, null, + "which1/what1", null), + new MatchCondition(IntentFilter.MATCH_CATEGORY_TYPE, null, null, + "which1/*", null), + new MatchCondition(IntentFilter.MATCH_CATEGORY_TYPE, null, null, + "*/*", null), + new MatchCondition(IntentFilter.NO_MATCH_TYPE, null, null, + "which2/what2", null), + new MatchCondition(IntentFilter.NO_MATCH_TYPE, null, null, + "which2/*", null), + new MatchCondition(IntentFilter.NO_MATCH_TYPE, null, null, + "which1/what2", null), + }); + + filter = new Match(null, null, + new String[]{"which1/what1", "which2/what2"}, null, null, + null); + checkMatches(filter, new MatchCondition[]{ + new MatchCondition(IntentFilter.NO_MATCH_TYPE, null, + null, null, null), + new MatchCondition(IntentFilter.MATCH_CATEGORY_TYPE, null, null, + "which1/what1", null), + new MatchCondition(IntentFilter.MATCH_CATEGORY_TYPE, null, null, + "which1/*", null), + new MatchCondition(IntentFilter.MATCH_CATEGORY_TYPE, null, null, + "*/*", null), + new MatchCondition(IntentFilter.MATCH_CATEGORY_TYPE, null, null, + "which2/what2", null), + new MatchCondition(IntentFilter.MATCH_CATEGORY_TYPE, null, null, + "which2/*", null), + new MatchCondition(IntentFilter.NO_MATCH_TYPE, null, null, + "which1/what2", null), + new MatchCondition(IntentFilter.NO_MATCH_TYPE, null, null, + "which3/what3", null), + }); + + filter = new Match(null, null, + new String[]{"which1/*"}, null, null, null); + checkMatches(filter, new MatchCondition[]{ + new MatchCondition(IntentFilter.NO_MATCH_TYPE, null, + null, null, null), + new MatchCondition(IntentFilter.MATCH_CATEGORY_TYPE, null, null, + "which1/what1", null), + new MatchCondition(IntentFilter.MATCH_CATEGORY_TYPE, null, null, + "which1/*", null), + new MatchCondition(IntentFilter.MATCH_CATEGORY_TYPE, null, null, + "*/*", null), + new MatchCondition(IntentFilter.NO_MATCH_TYPE, null, null, + "which2/what2", null), + new MatchCondition(IntentFilter.NO_MATCH_TYPE, null, null, + "which2/*", null), + new MatchCondition(IntentFilter.MATCH_CATEGORY_TYPE, null, null, + "which1/what2", null), + new MatchCondition(IntentFilter.NO_MATCH_TYPE, null, null, + "which3/what3", null), + }); + + filter = new Match(null, null, + new String[]{"*/*"}, null, null, null); + checkMatches(filter, new MatchCondition[]{ + new MatchCondition(IntentFilter.NO_MATCH_TYPE, null, + null, null, null), + new MatchCondition(IntentFilter.MATCH_CATEGORY_TYPE, null, null, + "which1/what1", null), + new MatchCondition(IntentFilter.MATCH_CATEGORY_TYPE, null, null, + "which1/*", null), + new MatchCondition(IntentFilter.MATCH_CATEGORY_TYPE, null, null, + "*/*", null), + new MatchCondition(IntentFilter.MATCH_CATEGORY_TYPE, null, null, + "which2/what2", null), + new MatchCondition(IntentFilter.MATCH_CATEGORY_TYPE, null, null, + "which2/*", null), + new MatchCondition(IntentFilter.MATCH_CATEGORY_TYPE, null, null, + "which1/what2", null), + new MatchCondition(IntentFilter.MATCH_CATEGORY_TYPE, null, null, + "which3/what3", null), + }); + } + + @SmallTest + public void testSchemes() throws Exception { + IntentFilter filter = new Match(null, null, null, + new String[]{"scheme1"}, null, null); + checkMatches(filter, new MatchCondition[]{ + new MatchCondition(IntentFilter.NO_MATCH_DATA, null, + null, null, null), + new MatchCondition(IntentFilter.MATCH_CATEGORY_SCHEME, null, + null, null, "scheme1:foo"), + new MatchCondition(IntentFilter.NO_MATCH_DATA, null, + null, null, "scheme2:foo"), + }); + + filter = new Match(null, null, null, + new String[]{"scheme1", "scheme2"}, null, null); + checkMatches(filter, new MatchCondition[]{ + new MatchCondition(IntentFilter.NO_MATCH_DATA, null, + null, null, null), + new MatchCondition(IntentFilter.MATCH_CATEGORY_SCHEME, null, + null, null, "scheme1:foo"), + new MatchCondition(IntentFilter.MATCH_CATEGORY_SCHEME, null, + null, null, "scheme2:foo"), + new MatchCondition(IntentFilter.NO_MATCH_DATA, null, + null, null, "scheme3:foo"), + }); + } + + @SmallTest + public void testAuthorities() throws Exception { + IntentFilter filter = new Match(null, null, null, + new String[]{"scheme1"}, + new String[]{"authority1"}, new String[]{null}); + checkMatches(filter, new MatchCondition[]{ + new MatchCondition(IntentFilter.NO_MATCH_DATA, null, + null, null, null), + new MatchCondition(IntentFilter.NO_MATCH_DATA, null, + null, null, "scheme1:foo"), + new MatchCondition(IntentFilter.MATCH_CATEGORY_HOST, null, + null, null, "scheme1://authority1/"), + new MatchCondition(IntentFilter.NO_MATCH_DATA, null, + null, null, "scheme1://authority2/"), + new MatchCondition(IntentFilter.MATCH_CATEGORY_HOST, null, + null, null, "scheme1://authority1:100/"), + }); + + filter = new Match(null, null, null, new String[]{"scheme1"}, + new String[]{"authority1"}, new String[]{"100"}); + checkMatches(filter, new MatchCondition[]{ + new MatchCondition(IntentFilter.NO_MATCH_DATA, null, + null, null, null), + new MatchCondition(IntentFilter.NO_MATCH_DATA, null, + null, null, "scheme1:foo"), + new MatchCondition(IntentFilter.NO_MATCH_DATA, null, + null, null, "scheme1://authority1/"), + new MatchCondition(IntentFilter.NO_MATCH_DATA, null, + null, null, "scheme1://authority2/"), + new MatchCondition(IntentFilter.MATCH_CATEGORY_PORT, null, + null, null, "scheme1://authority1:100/"), + new MatchCondition(IntentFilter.NO_MATCH_DATA, null, + null, null, "scheme1://authority1:200/"), + }); + + filter = new Match(null, null, null, new String[]{"scheme1"}, + new String[]{"authority1", "authority2"}, + new String[]{"100", null}); + checkMatches(filter, new MatchCondition[]{ + new MatchCondition(IntentFilter.NO_MATCH_DATA, null, + null, null, null), + new MatchCondition(IntentFilter.NO_MATCH_DATA, null, + null, null, "scheme1:foo"), + new MatchCondition(IntentFilter.NO_MATCH_DATA, null, + null, null, "scheme1://authority1/"), + new MatchCondition(IntentFilter.MATCH_CATEGORY_HOST, null, + null, null, "scheme1://authority2/"), + new MatchCondition(IntentFilter.MATCH_CATEGORY_PORT, null, + null, null, "scheme1://authority1:100/"), + new MatchCondition(IntentFilter.NO_MATCH_DATA, null, + null, null, "scheme1://authority1:200/"), + }); + } + + @SmallTest + public void testPaths() throws Exception { + IntentFilter filter = new Match(null, null, null, + new String[]{"scheme"}, new String[]{"authority"}, null, + new String[]{"/literal1", "/2literal"}, + new int[]{PATTERN_LITERAL, PATTERN_LITERAL}); + checkMatches(filter, new MatchCondition[]{ + new MatchCondition(IntentFilter.NO_MATCH_DATA, null, + null, null, null), + new MatchCondition(IntentFilter.MATCH_CATEGORY_PATH, null, + null, null, "scheme://authority/literal1"), + new MatchCondition(IntentFilter.MATCH_CATEGORY_PATH, null, + null, null, "scheme://authority/2literal"), + new MatchCondition(IntentFilter.NO_MATCH_DATA, null, + null, null, "scheme://authority/literal"), + new MatchCondition(IntentFilter.NO_MATCH_DATA, null, + null, null, "scheme://authority/literal12"), + }); + filter = new Match(null, null, null, + new String[]{"scheme"}, new String[]{"authority"}, null, + new String[]{"/literal1", "/2literal"}, + new int[]{PATTERN_PREFIX, PATTERN_PREFIX}); + checkMatches(filter, new MatchCondition[]{ + new MatchCondition(IntentFilter.NO_MATCH_DATA, null, + null, null, null), + new MatchCondition(IntentFilter.MATCH_CATEGORY_PATH, null, + null, null, "scheme://authority/literal1"), + new MatchCondition(IntentFilter.MATCH_CATEGORY_PATH, null, + null, null, "scheme://authority/2literal"), + new MatchCondition(IntentFilter.NO_MATCH_DATA, null, + null, null, "scheme://authority/literal"), + new MatchCondition(IntentFilter.MATCH_CATEGORY_PATH, null, + null, null, "scheme://authority/literal12"), + }); + filter = new Match(null, null, null, + new String[]{"scheme"}, new String[]{"authority"}, null, + new String[]{"/.*"}, + new int[]{PATTERN_SIMPLE_GLOB}); + checkMatches(filter, new MatchCondition[]{ + new MatchCondition(IntentFilter.NO_MATCH_DATA, null, + null, null, null), + new MatchCondition(IntentFilter.MATCH_CATEGORY_PATH, null, + null, null, "scheme://authority/literal1"), + new MatchCondition(IntentFilter.MATCH_CATEGORY_PATH, null, + null, null, "scheme://authority/"), + new MatchCondition(IntentFilter.NO_MATCH_DATA, null, + null, null, "scheme://authority"), + }); + filter = new Match(null, null, null, + new String[]{"scheme"}, new String[]{"authority"}, null, + new String[]{".*"}, + new int[]{PATTERN_SIMPLE_GLOB}); + checkMatches(filter, new MatchCondition[]{ + new MatchCondition(IntentFilter.NO_MATCH_DATA, null, + null, null, null), + new MatchCondition(IntentFilter.MATCH_CATEGORY_PATH, null, + null, null, "scheme://authority/literal1"), + new MatchCondition(IntentFilter.MATCH_CATEGORY_PATH, null, + null, null, "scheme://authority/"), + new MatchCondition(IntentFilter.MATCH_CATEGORY_PATH, null, + null, null, "scheme://authority"), + }); + filter = new Match(null, null, null, + new String[]{"scheme"}, new String[]{"authority"}, null, + new String[]{"/a1*b"}, + new int[]{PATTERN_SIMPLE_GLOB}); + checkMatches(filter, new MatchCondition[]{ + new MatchCondition(IntentFilter.NO_MATCH_DATA, null, + null, null, null), + new MatchCondition(IntentFilter.MATCH_CATEGORY_PATH, null, + null, null, "scheme://authority/ab"), + new MatchCondition(IntentFilter.MATCH_CATEGORY_PATH, null, + null, null, "scheme://authority/a1b"), + new MatchCondition(IntentFilter.MATCH_CATEGORY_PATH, null, + null, null, "scheme://authority/a11b"), + new MatchCondition(IntentFilter.NO_MATCH_DATA, null, + null, null, "scheme://authority/a2b"), + new MatchCondition(IntentFilter.NO_MATCH_DATA, null, + null, null, "scheme://authority/a1bc"), + new MatchCondition(IntentFilter.NO_MATCH_DATA, null, + null, null, "scheme://authority/"), + }); + filter = new Match(null, null, null, + new String[]{"scheme"}, new String[]{"authority"}, null, + new String[]{"/a1*"}, + new int[]{PATTERN_SIMPLE_GLOB}); + checkMatches(filter, new MatchCondition[]{ + new MatchCondition(IntentFilter.NO_MATCH_DATA, null, + null, null, null), + new MatchCondition(IntentFilter.MATCH_CATEGORY_PATH, null, + null, null, "scheme://authority/a1"), + new MatchCondition(IntentFilter.NO_MATCH_DATA, null, + null, null, "scheme://authority/ab"), + new MatchCondition(IntentFilter.MATCH_CATEGORY_PATH, null, + null, null, "scheme://authority/a11"), + new MatchCondition(IntentFilter.NO_MATCH_DATA, null, + null, null, "scheme://authority/a1b"), + new MatchCondition(IntentFilter.MATCH_CATEGORY_PATH, null, + null, null, "scheme://authority/a11"), + new MatchCondition(IntentFilter.NO_MATCH_DATA, null, + null, null, "scheme://authority/a2"), + }); + filter = new Match(null, null, null, + new String[]{"scheme"}, new String[]{"authority"}, null, + new String[]{"/a\\.*b"}, + new int[]{PATTERN_SIMPLE_GLOB}); + checkMatches(filter, new MatchCondition[]{ + new MatchCondition(IntentFilter.NO_MATCH_DATA, null, + null, null, null), + new MatchCondition(IntentFilter.MATCH_CATEGORY_PATH, null, + null, null, "scheme://authority/ab"), + new MatchCondition(IntentFilter.MATCH_CATEGORY_PATH, null, + null, null, "scheme://authority/a.b"), + new MatchCondition(IntentFilter.MATCH_CATEGORY_PATH, null, + null, null, "scheme://authority/a..b"), + new MatchCondition(IntentFilter.NO_MATCH_DATA, null, + null, null, "scheme://authority/a2b"), + new MatchCondition(IntentFilter.NO_MATCH_DATA, null, + null, null, "scheme://authority/a.bc"), + new MatchCondition(IntentFilter.NO_MATCH_DATA, null, + null, null, "scheme://authority/"), + }); + filter = new Match(null, null, null, + new String[]{"scheme"}, new String[]{"authority"}, null, + new String[]{"/a.*b"}, + new int[]{PATTERN_SIMPLE_GLOB}); + checkMatches(filter, new MatchCondition[]{ + new MatchCondition(IntentFilter.NO_MATCH_DATA, null, + null, null, null), + new MatchCondition(IntentFilter.MATCH_CATEGORY_PATH, null, + null, null, "scheme://authority/ab"), + new MatchCondition(IntentFilter.MATCH_CATEGORY_PATH, null, + null, null, "scheme://authority/a.b"), + new MatchCondition(IntentFilter.MATCH_CATEGORY_PATH, null, + null, null, "scheme://authority/a.1b"), + new MatchCondition(IntentFilter.MATCH_CATEGORY_PATH, null, + null, null, "scheme://authority/a2b"), + new MatchCondition(IntentFilter.NO_MATCH_DATA, null, + null, null, "scheme://authority/a.bc"), + new MatchCondition(IntentFilter.NO_MATCH_DATA, null, + null, null, "scheme://authority/"), + }); + filter = new Match(null, null, null, + new String[]{"scheme"}, new String[]{"authority"}, null, + new String[]{"/a.*"}, + new int[]{PATTERN_SIMPLE_GLOB}); + checkMatches(filter, new MatchCondition[]{ + new MatchCondition(IntentFilter.NO_MATCH_DATA, null, + null, null, null), + new MatchCondition(IntentFilter.MATCH_CATEGORY_PATH, null, + null, null, "scheme://authority/ab"), + new MatchCondition(IntentFilter.MATCH_CATEGORY_PATH, null, + null, null, "scheme://authority/a.b"), + new MatchCondition(IntentFilter.MATCH_CATEGORY_PATH, null, + null, null, "scheme://authority/a.1b"), + new MatchCondition(IntentFilter.MATCH_CATEGORY_PATH, null, + null, null, "scheme://authority/a2b"), + new MatchCondition(IntentFilter.MATCH_CATEGORY_PATH, null, + null, null, "scheme://authority/a.bc"), + new MatchCondition(IntentFilter.NO_MATCH_DATA, null, + null, null, "scheme://authority/"), + }); + filter = new Match(null, null, null, + new String[]{"scheme"}, new String[]{"authority"}, null, + new String[]{"/a.\\*b"}, + new int[]{PATTERN_SIMPLE_GLOB}); + checkMatches(filter, new MatchCondition[]{ + new MatchCondition(IntentFilter.NO_MATCH_DATA, null, + null, null, null), + new MatchCondition(IntentFilter.NO_MATCH_DATA, null, + null, null, "scheme://authority/ab"), + new MatchCondition(IntentFilter.MATCH_CATEGORY_PATH, null, + null, null, "scheme://authority/a.*b"), + new MatchCondition(IntentFilter.MATCH_CATEGORY_PATH, null, + null, null, "scheme://authority/a1*b"), + new MatchCondition(IntentFilter.NO_MATCH_DATA, null, + null, null, "scheme://authority/a2b"), + new MatchCondition(IntentFilter.NO_MATCH_DATA, null, + null, null, "scheme://authority/a.bc"), + new MatchCondition(IntentFilter.NO_MATCH_DATA, null, + null, null, "scheme://authority/"), + }); + filter = new Match(null, null, null, + new String[]{"scheme"}, new String[]{"authority"}, null, + new String[]{"/a.\\*"}, + new int[]{PATTERN_SIMPLE_GLOB}); + checkMatches(filter, new MatchCondition[]{ + new MatchCondition(IntentFilter.NO_MATCH_DATA, null, + null, null, null), + new MatchCondition(IntentFilter.NO_MATCH_DATA, null, + null, null, "scheme://authority/ab"), + new MatchCondition(IntentFilter.MATCH_CATEGORY_PATH, null, + null, null, "scheme://authority/a.*"), + new MatchCondition(IntentFilter.MATCH_CATEGORY_PATH, null, + null, null, "scheme://authority/a1*"), + new MatchCondition(IntentFilter.NO_MATCH_DATA, null, + null, null, "scheme://authority/a1b"), + }); + } + +} + diff --git a/tests/AndroidTests/src/com/android/unit_tests/content/PluralResourcesTest.java b/tests/AndroidTests/src/com/android/unit_tests/content/PluralResourcesTest.java new file mode 100644 index 0000000000000000000000000000000000000000..c3d1478e8f63920e6423c35aa2b596b41c064e20 --- /dev/null +++ b/tests/AndroidTests/src/com/android/unit_tests/content/PluralResourcesTest.java @@ -0,0 +1,97 @@ +/* + * Copyright (C) 2007 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.android.unit_tests.content; + +import android.content.res.AssetManager; +import android.content.res.Configuration; +import android.content.res.Resources; +import android.content.res.TypedArray; +import android.test.AndroidTestCase; +import android.test.suitebuilder.annotation.SmallTest; +import android.util.TypedValue; +import android.util.Log; +import com.android.unit_tests.R; + +import junit.framework.Assert; + +import java.util.Locale; + +public class PluralResourcesTest extends AndroidTestCase { + private static final String TAG = "PluralResourcesTest"; + + private Resources mResources; + + @Override + protected void setUp() throws Exception { + super.setUp(); + mResources = mContext.getResources(); + } + + Resources resourcesForLanguage(String lang) { + Configuration config = new Configuration(); + config.updateFrom(mResources.getConfiguration()); + config.locale = new Locale(lang); + return new Resources(mResources.getAssets(), mResources.getDisplayMetrics(), config); + } + + @SmallTest + public void testPlurals() throws Exception { + CharSequence cs; + Resources res = resourcesForLanguage("en"); + + cs = res.getQuantityText(R.plurals.plurals_test, 0); + Log.d(TAG, "english 0 cs=" + cs); + Assert.assertEquals(cs.toString(), "Some dogs"); + + cs = res.getQuantityText(R.plurals.plurals_test, 1); + Log.d(TAG, "english 1 cs=" + cs); + Assert.assertEquals(cs.toString(), "A dog"); + + cs = res.getQuantityText(R.plurals.plurals_test, 2); + Assert.assertEquals(cs.toString(), "Some dogs"); + + cs = res.getQuantityText(R.plurals.plurals_test, 5); + Assert.assertEquals(cs.toString(), "Some dogs"); + + cs = res.getQuantityText(R.plurals.plurals_test, 500); + Assert.assertEquals(cs.toString(), "Some dogs"); + } + + @SmallTest + public void testCzech() throws Exception { + CharSequence cs; + Resources res = resourcesForLanguage("cs"); + + cs = res.getQuantityText(R.plurals.plurals_test, 0); + Log.d(TAG, "czech 0 cs=" + cs); + Assert.assertEquals(cs.toString(), "Some Czech dogs"); + + cs = res.getQuantityText(R.plurals.plurals_test, 1); + Log.d(TAG, "czech 1 cs=" + cs); + Assert.assertEquals(cs.toString(), "A Czech dog"); + + cs = res.getQuantityText(R.plurals.plurals_test, 2); + Log.d(TAG, "czech 2 cs=" + cs); + Assert.assertEquals(cs.toString(), "Few Czech dogs"); + + cs = res.getQuantityText(R.plurals.plurals_test, 5); + Assert.assertEquals(cs.toString(), "Some Czech dogs"); + + cs = res.getQuantityText(R.plurals.plurals_test, 500); + Assert.assertEquals(cs.toString(), "Some Czech dogs"); + } +} diff --git a/tests/AndroidTests/src/com/android/unit_tests/content/PrimitiveTest.java b/tests/AndroidTests/src/com/android/unit_tests/content/PrimitiveTest.java new file mode 100644 index 0000000000000000000000000000000000000000..44098cc5edcbc9a6f72ce655c25f065179eca536 --- /dev/null +++ b/tests/AndroidTests/src/com/android/unit_tests/content/PrimitiveTest.java @@ -0,0 +1,141 @@ +/* + * Copyright (C) 2007 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.android.unit_tests.content; + +import android.content.res.Resources; +import android.content.res.TypedArray; +import android.test.AndroidTestCase; +import android.test.suitebuilder.annotation.SmallTest; +import android.util.TypedValue; +import com.android.unit_tests.R; + +public class PrimitiveTest extends AndroidTestCase { + private Resources mResources; + + @Override + protected void setUp() throws Exception { + super.setUp(); + mResources = mContext.getResources(); + } + + private void tryEnum(int resid, int expected) { + TypedArray sa = + mContext.obtainStyledAttributes(resid, R.styleable.EnumStyle); + int value = sa.getInt(R.styleable.EnumStyle_testEnum, -1); + sa.recycle(); + + assertEquals("Expecting value " + expected + " got " + value + + ": in resource 0x" + Integer.toHexString(resid), + expected, value); + } + + @SmallTest + public void testEnum() throws Exception { + tryEnum(R.style.TestEnum1, 1); + tryEnum(R.style.TestEnum2, 2); + tryEnum(R.style.TestEnum10, 10); + tryEnum(R.style.TestEnum1_EmptyInherit, 1); + } + + private void tryFlag(int resid, int expected) { + TypedArray sa = + mContext.obtainStyledAttributes(resid, R.styleable.FlagStyle); + int value = sa.getInt(R.styleable.FlagStyle_testFlags, -1); + sa.recycle(); + + assertEquals("Expecting value " + expected + " got " + value + + ": in resource 0x" + Integer.toHexString(resid), + expected, value); + } + + @SmallTest + public void testFlags() throws Exception { + tryFlag(R.style.TestFlag1, 0x1); + tryFlag(R.style.TestFlag2, 0x2); + tryFlag(R.style.TestFlag31, 0x40000000); + tryFlag(R.style.TestFlag1And2, 0x3); + tryFlag(R.style.TestFlag1And2And31, 0x40000003); + } + + private void tryBoolean(int resid, boolean expected) { + TypedValue v = new TypedValue(); + mContext.getResources().getValue(resid, v, true); + assertEquals(TypedValue.TYPE_INT_BOOLEAN, v.type); + assertEquals("Expecting boolean value " + expected + " got " + v + + " from TypedValue: in resource 0x" + Integer.toHexString(resid), + expected, v.data != 0); + assertEquals("Expecting boolean value " + expected + " got " + v + + " from getBoolean(): in resource 0x" + Integer.toHexString(resid), + expected, mContext.getResources().getBoolean(resid)); + } + + @SmallTest + public void testBoolean() throws Exception { + tryBoolean(R.bool.trueRes, true); + tryBoolean(R.bool.falseRes, false); + } + + private void tryString(int resid, String expected) { + TypedValue v = new TypedValue(); + mContext.getResources().getValue(resid, v, true); + assertEquals(TypedValue.TYPE_STRING, v.type); + assertEquals("Expecting string value " + expected + " got " + v + + ": in resource 0x" + Integer.toHexString(resid), + expected, v.string); + } + + @SmallTest + public void testStringCoerce() throws Exception { + tryString(R.string.coerceIntegerToString, "100"); + tryString(R.string.coerceBooleanToString, "true"); + tryString(R.string.coerceColorToString, "#fff"); + tryString(R.string.coerceFloatToString, "100.0"); + tryString(R.string.coerceDimensionToString, "100px"); + tryString(R.string.coerceFractionToString, "100%"); + } + + private static void checkString(int resid, String actual, String expected) { + assertEquals("Expecting string value \"" + expected + "\" got \"" + + actual + "\" in resources 0x" + Integer.toHexString(resid), + expected, actual); + } + + @SmallTest + public void testFormattedString() throws Exception { + // Make sure the regular one doesn't format anything + checkString(R.string.formattedStringNone, + mResources.getString(R.string.formattedStringNone), + "Format[]"); + checkString(R.string.formattedStringOne, + mResources.getString(R.string.formattedStringOne), + "Format[%d]"); + checkString(R.string.formattedStringTwo, + mResources.getString(R.string.formattedStringTwo), + "Format[%3$d,%2$s]"); + // Make sure the formatted one works + checkString(R.string.formattedStringNone, + mResources.getString(R.string.formattedStringNone), + "Format[]"); + checkString(R.string.formattedStringOne, + mResources.getString(R.string.formattedStringOne, 42), + "Format[42]"); + checkString(R.string.formattedStringTwo, + mResources.getString(R.string.formattedStringTwo, "unused", "hi", 43), + "Format[43,hi]"); + } +} + diff --git a/tests/AndroidTests/src/com/android/unit_tests/content/RawResourceTest.java b/tests/AndroidTests/src/com/android/unit_tests/content/RawResourceTest.java new file mode 100644 index 0000000000000000000000000000000000000000..1786dc46b89f9bb496bbd580bfd5f0831f69fa90 --- /dev/null +++ b/tests/AndroidTests/src/com/android/unit_tests/content/RawResourceTest.java @@ -0,0 +1,40 @@ +/* + * 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.android.unit_tests.content; + +import android.content.res.Resources; +import android.test.AndroidTestCase; +import android.test.suitebuilder.annotation.SmallTest; +import com.android.unit_tests.R; + +import java.io.InputStream; + +public class RawResourceTest extends AndroidTestCase { + private Resources mResources; + + @Override + protected void setUp() throws Exception { + super.setUp(); + mResources = mContext.getResources(); + } + + @SmallTest + public void testReadToEnd() throws Exception { + InputStream is = mResources.openRawResource(R.raw.text); + AssetTest.verifyTextAsset(is); + } +} diff --git a/tests/AndroidTests/src/com/android/unit_tests/content/ResourceNameTest.java b/tests/AndroidTests/src/com/android/unit_tests/content/ResourceNameTest.java new file mode 100644 index 0000000000000000000000000000000000000000..2a56243cfb0ebdbf55aa8101a05558620b134615 --- /dev/null +++ b/tests/AndroidTests/src/com/android/unit_tests/content/ResourceNameTest.java @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2007 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.android.unit_tests.content; + +import android.content.res.Resources; +import android.test.AndroidTestCase; +import android.test.suitebuilder.annotation.SmallTest; + +import com.android.unit_tests.R; + +public class ResourceNameTest extends AndroidTestCase { + + @SmallTest + public void testGetResourceName() { + Resources res = mContext.getResources(); + + String fullName = res.getResourceName(R.configVarying.simple); + assertEquals("com.android.unit_tests:configVarying/simple", fullName); + + String packageName = res.getResourcePackageName(R.configVarying.simple); + assertEquals("com.android.unit_tests", packageName); + + String typeName = res.getResourceTypeName(R.configVarying.simple); + assertEquals("configVarying", typeName); + + String entryName = res.getResourceEntryName(R.configVarying.simple); + assertEquals("simple", entryName); + } + + @SmallTest + public void testGetResourceIdentifier() { + Resources res = mContext.getResources(); + int resid = res.getIdentifier( + "com.android.unit_tests:configVarying/simple", + null, null); + assertEquals(R.configVarying.simple, resid); + + resid = res.getIdentifier("configVarying/simple", null, + "com.android.unit_tests"); + assertEquals(R.configVarying.simple, resid); + + resid = res.getIdentifier("simple", "configVarying", + "com.android.unit_tests"); + assertEquals(R.configVarying.simple, resid); + } +} + diff --git a/tests/AndroidTests/src/com/android/unit_tests/content/ResourceTests.java b/tests/AndroidTests/src/com/android/unit_tests/content/ResourceTests.java new file mode 100644 index 0000000000000000000000000000000000000000..943941e517a421e0df2ce23d30d5223885e10e23 --- /dev/null +++ b/tests/AndroidTests/src/com/android/unit_tests/content/ResourceTests.java @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2006 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.android.unit_tests.content; + +import junit.framework.TestSuite; + +public class ResourceTests { + public static TestSuite suite() { + TestSuite suite = new TestSuite(ResourceTests.class.getName()); + + suite.addTestSuite(FractionTest.class); + suite.addTestSuite(PrimitiveTest.class); + suite.addTestSuite(ArrayTest.class); + suite.addTestSuite(ConfigTest.class); + suite.addTestSuite(RawResourceTest.class); + suite.addTestSuite(ResourceNameTest.class); + return suite; + } +} diff --git a/tests/AndroidTests/src/com/android/unit_tests/graphics/BitmapTest.java b/tests/AndroidTests/src/com/android/unit_tests/graphics/BitmapTest.java new file mode 100644 index 0000000000000000000000000000000000000000..e8001e34c0868d77818e12f209e633b9ae56e9e4 --- /dev/null +++ b/tests/AndroidTests/src/com/android/unit_tests/graphics/BitmapTest.java @@ -0,0 +1,232 @@ +/* + * Copyright (C) 2006 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.android.unit_tests.graphics; + +import android.graphics.Bitmap; +import android.graphics.Color; +import android.test.suitebuilder.annotation.SmallTest; +import junit.framework.TestCase; + + +public class BitmapTest extends TestCase { + + @SmallTest + public void testBasic() throws Exception { + Bitmap bm1 = Bitmap.createBitmap(100, 200, Bitmap.Config.ARGB_8888); + Bitmap bm2 = Bitmap.createBitmap(100, 200, Bitmap.Config.RGB_565); + Bitmap bm3 = Bitmap.createBitmap(100, 200, Bitmap.Config.ARGB_4444); + + assertTrue("mutability", bm1.isMutable()); + assertTrue("mutability", bm2.isMutable()); + assertTrue("mutability", bm3.isMutable()); + + assertEquals("width", 100, bm1.getWidth()); + assertEquals("width", 100, bm2.getWidth()); + assertEquals("width", 100, bm3.getWidth()); + + assertEquals("rowbytes", 400, bm1.getRowBytes()); + assertEquals("rowbytes", 200, bm2.getRowBytes()); + assertEquals("rowbytes", 200, bm3.getRowBytes()); + + assertEquals("height", 200, bm1.getHeight()); + assertEquals("height", 200, bm2.getHeight()); + assertEquals("height", 200, bm3.getHeight()); + + assertTrue("hasAlpha", bm1.hasAlpha()); + assertFalse("hasAlpha", bm2.hasAlpha()); + assertTrue("hasAlpha", bm3.hasAlpha()); + + assertTrue("getConfig", bm1.getConfig() == Bitmap.Config.ARGB_8888); + assertTrue("getConfig", bm2.getConfig() == Bitmap.Config.RGB_565); + assertTrue("getConfig", bm3.getConfig() == Bitmap.Config.ARGB_4444); + } + + @SmallTest + public void testMutability() throws Exception { + Bitmap bm1 = Bitmap.createBitmap(100, 200, Bitmap.Config.ARGB_8888); + Bitmap bm2 = Bitmap.createBitmap(new int[100 * 200], 100, 200, + Bitmap.Config.ARGB_8888); + + assertTrue("mutability", bm1.isMutable()); + assertFalse("mutability", bm2.isMutable()); + + bm1.eraseColor(0); + + try { + bm2.eraseColor(0); + fail("eraseColor should throw exception"); + } catch (IllegalStateException ex) { + // safe to catch and ignore this + } + } + + @SmallTest + public void testGetPixelsWithAlpha() throws Exception { + int[] colors = new int[100]; + for (int i = 0; i < 100; i++) { + colors[i] = (0xFF << 24) | (i << 16) | (i << 8) | i; + } + + Bitmap bm = Bitmap.createBitmap(colors, 10, 10, + Bitmap.Config.ARGB_8888); + + int[] pixels = new int[100]; + bm.getPixels(pixels, 0, 10, 0, 0, 10, 10); + for (int i = 0; i < 100; i++) { + int p = bm.getPixel(i % 10, i / 10); + assertEquals("getPixels", p, pixels[i]); + } + + for (int i = 0; i < 100; i++) { + int p = bm.getPixel(i % 10, i / 10); + assertEquals("getPixel", p, colors[i]); + assertEquals("pixel value", p, + ((0xFF << 24) | (i << 16) | (i << 8) | i)); + } + + } + + @SmallTest + public void testGetPixelsWithoutAlpha() throws Exception { + int[] colors = new int[100]; + for (int i = 0; i < 100; i++) { + colors[i] = (0xFF << 24) | (i << 16) | (i << 8) | i; + } + + Bitmap bm = Bitmap.createBitmap(colors, 10, 10, Bitmap.Config.RGB_565); + + int[] pixels = new int[100]; + bm.getPixels(pixels, 0, 10, 0, 0, 10, 10); + for (int i = 0; i < 100; i++) { + int p = bm.getPixel(i % 10, i / 10); + assertEquals("getPixels", p, pixels[i]); + } + } + + @SmallTest + public void testSetPixelsWithAlpha() throws Exception { + int[] colors = new int[100]; + for (int i = 0; i < 100; i++) { + colors[i] = (0xFF << 24) | (i << 16) | (i << 8) | i; + } + + Bitmap.Config config = Bitmap.Config.ARGB_8888; + Bitmap bm1 = Bitmap.createBitmap(colors, 10, 10, config); + Bitmap bm2 = Bitmap.createBitmap(10, 10, config); + + for (int i = 0; i < 100; i++) { + bm2.setPixel(i % 10, i / 10, colors[i]); + } + + for (int i = 0; i < 100; i++) { + assertEquals("setPixel", + bm1.getPixel(i % 10, i / 10), bm2.getPixel(i % 10, i / 10)); + } + + for (int i = 0; i < 100; i++) { + assertEquals("setPixel value", + bm1.getPixel(i % 10, i / 10), colors[i]); + } + } + + @SmallTest + public void testSetPixelsWithoutAlpha() throws Exception { + int[] colors = new int[100]; + for (int i = 0; i < 100; i++) { + colors[i] = (0xFF << 24) | (i << 16) | (i << 8) | i; + } + + Bitmap.Config config = Bitmap.Config.RGB_565; + Bitmap bm1 = Bitmap.createBitmap(colors, 10, 10, config); + Bitmap bm2 = Bitmap.createBitmap(10, 10, config); + + for (int i = 0; i < 100; i++) { + bm2.setPixel(i % 10, i / 10, colors[i]); + } + + for (int i = 0; i < 100; i++) { + assertEquals("setPixel", bm1.getPixel(i % 10, i / 10), + bm2.getPixel(i % 10, i / 10)); + } + } + + private static int computePrePostMul(int alpha, int comp) { + if (alpha == 0) { + return 0; + } + int premul = Math.round(alpha * comp / 255.f); + int unpre = Math.round(255.0f * premul / alpha); + return unpre; + } + + @SmallTest + public void testSetPixelsWithNonOpaqueAlpha() throws Exception { + int[] colors = new int[256]; + for (int i = 0; i < 256; i++) { + colors[i] = (i << 24) | (0xFF << 16) | (0x80 << 8) | 0; + } + + Bitmap.Config config = Bitmap.Config.ARGB_8888; + + // create a bitmap with the color array specified + Bitmap bm1 = Bitmap.createBitmap(colors, 16, 16, config); + + // create a bitmap with no colors, but then call setPixels + Bitmap bm2 = Bitmap.createBitmap(16, 16, config); + bm2.setPixels(colors, 0, 16, 0, 0, 16, 16); + + // now check that we did a good job returning the unpremultiplied alpha + final int tolerance = 1; + for (int i = 0; i < 256; i++) { + int c0 = colors[i]; + int c1 = bm1.getPixel(i % 16, i / 16); + int c2 = bm2.getPixel(i % 16, i / 16); + + // these two should always be identical + assertEquals("getPixel", c1, c2); + + // comparing the original (c0) with the returned color is tricky, + // since it gets premultiplied during the set(), and unpremultiplied + // by the get(). + int a0 = Color.alpha(c0); + int a1 = Color.alpha(c1); + assertEquals("alpha", a0, a1); + + int r0 = Color.red(c0); + int r1 = Color.red(c1); + int rr = computePrePostMul(a0, r0); + assertTrue("red", Math.abs(rr - r1) <= tolerance); + + int g0 = Color.green(c0); + int g1 = Color.green(c1); + int gg = computePrePostMul(a0, g0); + assertTrue("green", Math.abs(gg - g1) <= tolerance); + + int b0 = Color.blue(c0); + int b1 = Color.blue(c1); + int bb = computePrePostMul(a0, b0); + assertTrue("blue", Math.abs(bb - b1) <= tolerance); + + if (false) { + int cc = Color.argb(a0, rr, gg, bb); + android.util.Log.d("skia", "original " + Integer.toHexString(c0) + + " set+get " + Integer.toHexString(c1) + + " local " + Integer.toHexString(cc)); + } + } + } +} diff --git a/tests/AndroidTests/src/com/android/unit_tests/graphics/GraphicsTests.java b/tests/AndroidTests/src/com/android/unit_tests/graphics/GraphicsTests.java new file mode 100644 index 0000000000000000000000000000000000000000..a8b6b9ab2cbd792ef2ff0289314a506c44cdb123 --- /dev/null +++ b/tests/AndroidTests/src/com/android/unit_tests/graphics/GraphicsTests.java @@ -0,0 +1,29 @@ +/* + * 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.android.unit_tests.graphics; + +import junit.framework.TestSuite; + +public class GraphicsTests { + public static TestSuite suite() { + TestSuite suite = new TestSuite(GraphicsTests.class.getName()); + + suite.addTestSuite(BitmapTest.class); + suite.addTestSuite(TypefaceTest.class); + return suite; + } +} diff --git a/tests/AndroidTests/src/com/android/unit_tests/graphics/TypefaceTest.java b/tests/AndroidTests/src/com/android/unit_tests/graphics/TypefaceTest.java new file mode 100644 index 0000000000000000000000000000000000000000..5c40e6f91c9402383ea121709aad88f771fef276 --- /dev/null +++ b/tests/AndroidTests/src/com/android/unit_tests/graphics/TypefaceTest.java @@ -0,0 +1,91 @@ +/* + * 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.android.unit_tests.graphics; + +import android.graphics.Paint; +import android.graphics.Typeface; +import android.test.suitebuilder.annotation.MediumTest; +import android.test.suitebuilder.annotation.SmallTest; +import junit.framework.TestCase; + + +public class TypefaceTest extends TestCase { + + // create array of all std faces + private final Typeface[] mFaces = new Typeface[] { + Typeface.create(Typeface.SANS_SERIF, 0), + Typeface.create(Typeface.SANS_SERIF, 1), + Typeface.create(Typeface.SERIF, 0), + Typeface.create(Typeface.SERIF, 1), + Typeface.create(Typeface.SERIF, 2), + Typeface.create(Typeface.SERIF, 3), + Typeface.create(Typeface.MONOSPACE, 0) + }; + + @SmallTest + public void testBasic() throws Exception { + assertTrue("basic", Typeface.DEFAULT != null); + assertTrue("basic", Typeface.DEFAULT_BOLD != null); + assertTrue("basic", Typeface.SANS_SERIF != null); + assertTrue("basic", Typeface.SERIF != null); + assertTrue("basic", Typeface.MONOSPACE != null); + } + + @SmallTest + public void testUnique() throws Exception { + final int n = mFaces.length; + for (int i = 0; i < n; i++) { + for (int j = i + 1; j < n; j++) { + assertTrue("unique", mFaces[i] != mFaces[j]); + } + } + } + + @SmallTest + public void testStyles() throws Exception { + assertTrue("style", mFaces[0].getStyle() == Typeface.NORMAL); + assertTrue("style", mFaces[1].getStyle() == Typeface.BOLD); + assertTrue("style", mFaces[2].getStyle() == Typeface.NORMAL); + assertTrue("style", mFaces[3].getStyle() == Typeface.BOLD); + assertTrue("style", mFaces[4].getStyle() == Typeface.ITALIC); + assertTrue("style", mFaces[5].getStyle() == Typeface.BOLD_ITALIC); + assertTrue("style", mFaces[6].getStyle() == Typeface.NORMAL); + } + + @MediumTest + public void testUniformY() throws Exception { + Paint p = new Paint(); + final int n = mFaces.length; + for (int i = 1; i <= 36; i++) { + p.setTextSize(i); + float ascent = 0; + float descent = 0; + for (int j = 0; j < n; j++) { + p.setTypeface(mFaces[j]); + Paint.FontMetrics fm = p.getFontMetrics(); + if (j == 0) { + ascent = fm.ascent; + descent = fm.descent; + } else { + assertTrue("fontMetrics", fm.ascent == ascent); + assertTrue("fontMetrics", fm.descent == descent); + } + } + } + } + +} diff --git a/tests/AndroidTests/src/com/android/unit_tests/os/AidlTest.aidl b/tests/AndroidTests/src/com/android/unit_tests/os/AidlTest.aidl new file mode 100644 index 0000000000000000000000000000000000000000..62c75a514a860e26a06ebfd92ea60af1e74edf68 --- /dev/null +++ b/tests/AndroidTests/src/com/android/unit_tests/os/AidlTest.aidl @@ -0,0 +1,20 @@ +/* //device/apps/AndroidTests/src/com.android.unit_tests/AidlTest.aidl +** +** Copyright 2007, 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.android.unit_tests.os; + +parcelable AidlTest.TestParcelable; diff --git a/tests/AndroidTests/src/com/android/unit_tests/os/AidlTest.java b/tests/AndroidTests/src/com/android/unit_tests/os/AidlTest.java new file mode 100644 index 0000000000000000000000000000000000000000..52e666d84e2506b00bc02c40e3eb871ef0c4f10c --- /dev/null +++ b/tests/AndroidTests/src/com/android/unit_tests/os/AidlTest.java @@ -0,0 +1,422 @@ +/* + * Copyright (C) 2007 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.android.unit_tests.os; + +import android.os.IInterface; +import android.os.Parcel; +import android.os.Parcelable; +import android.test.suitebuilder.annotation.SmallTest; +import com.google.android.collect.Lists; +import junit.framework.TestCase; + +import java.util.List; + +public class AidlTest extends TestCase { + + private IAidlTest mRemote; + + @Override + protected void setUp() throws Exception { + super.setUp(); + AidlObject mLocal = new AidlObject(); + mRemote = IAidlTest.Stub.asInterface(mLocal); + } + + private static boolean check(TestParcelable p, int n, String s) { + return p.mAnInt == n && + ((s == null && p.mAString == null) || s.equals(p.mAString)); + } + + public static class TestParcelable implements Parcelable { + public int mAnInt; + public String mAString; + + public TestParcelable() { + } + + public TestParcelable(int i, String s) { + mAnInt = i; + mAString = s; + } + + public int describeContents() { + return 0; + } + + public void writeToParcel(Parcel parcel, int flags) { + parcel.writeInt(mAnInt); + parcel.writeString(mAString); + } + + public void readFromParcel(Parcel parcel) { + mAnInt = parcel.readInt(); + mAString = parcel.readString(); + } + + public static final Parcelable.Creator CREATOR + = new Parcelable.Creator() { + public TestParcelable createFromParcel(Parcel parcel) { + return new TestParcelable(parcel.readInt(), + parcel.readString()); + } + + public TestParcelable[] newArray(int size) { + return new TestParcelable[size]; + } + }; + + public String toString() { + return super.toString() + " {" + mAnInt + "/" + mAString + "}"; + } + } + + private static class AidlObject extends IAidlTest.Stub { + public IInterface queryLocalInterface(String descriptor) { + // overriding this to return null makes asInterface always + // generate a proxy + return null; + } + + public int intMethod(int a) { + return a; + } + + public TestParcelable parcelableIn(TestParcelable p) { + p.mAnInt++; + return p; + } + + public TestParcelable parcelableOut(TestParcelable p) { + p.mAnInt = 44; + return p; + } + + public TestParcelable parcelableInOut(TestParcelable p) { + p.mAnInt++; + return p; + } + + public TestParcelable listParcelableLonger(List list, int index) { + list.add(list.get(index)); + return list.get(index); + } + + public int listParcelableShorter(List list, int index) { + list.remove(index); + return list.size(); + } + + public boolean[] booleanArray(boolean[] a0, boolean[] a1, boolean[] a2) { + for (int i = 0; i < a0.length && i < a2.length; i++) { + a2[i] = a0[i]; + } + for (int i = 0; i < a0.length && i < a1.length; i++) { + a1[i] = a0[i]; + } + return a0; + } + + public char[] charArray(char[] a0, char[] a1, char[] a2) { + for (int i = 0; i < a0.length && i < a2.length; i++) { + a2[i] = a0[i]; + } + for (int i = 0; i < a0.length && i < a1.length; i++) { + a1[i] = a0[i]; + } + return a0; + } + + public int[] intArray(int[] a0, int[] a1, int[] a2) { + for (int i = 0; i < a0.length && i < a2.length; i++) { + a2[i] = a0[i]; + } + for (int i = 0; i < a0.length && i < a1.length; i++) { + a1[i] = a0[i]; + } + return a0; + } + + public long[] longArray(long[] a0, long[] a1, long[] a2) { + for (int i = 0; i < a0.length && i < a2.length; i++) { + a2[i] = a0[i]; + } + for (int i = 0; i < a0.length && i < a1.length; i++) { + a1[i] = a0[i]; + } + return a0; + } + + public float[] floatArray(float[] a0, float[] a1, float[] a2) { + for (int i = 0; i < a0.length && i < a2.length; i++) { + a2[i] = a0[i]; + } + for (int i = 0; i < a0.length && i < a1.length; i++) { + a1[i] = a0[i]; + } + return a0; + } + + public double[] doubleArray(double[] a0, double[] a1, double[] a2) { + for (int i = 0; i < a0.length && i < a2.length; i++) { + a2[i] = a0[i]; + } + for (int i = 0; i < a0.length && i < a1.length; i++) { + a1[i] = a0[i]; + } + return a0; + } + + public String[] stringArray(String[] a0, String[] a1, String[] a2) { + for (int i = 0; i < a0.length && i < a2.length; i++) { + a2[i] = a0[i]; + } + for (int i = 0; i < a0.length && i < a1.length; i++) { + a1[i] = a0[i]; + } + return a0; + } + + public TestParcelable[] parcelableArray(TestParcelable[] a0, + TestParcelable[] a1, TestParcelable[] a2) { + return null; + } + + public void voidSecurityException() { + throw new SecurityException("gotcha!"); + } + + public int intSecurityException() { + throw new SecurityException("gotcha!"); + } + } + + @SmallTest + public void testInt() throws Exception { + int result = mRemote.intMethod(42); + assertEquals(42, result); + } + + @SmallTest + public void testParcelableIn() throws Exception { + TestParcelable arg = new TestParcelable(43, "hi"); + TestParcelable result = mRemote.parcelableIn(arg); + assertNotSame(arg, result); + + assertEquals(43, arg.mAnInt); + assertEquals(44, result.mAnInt); + } + + @SmallTest + public void testParcelableOut() throws Exception { + TestParcelable arg = new TestParcelable(43, "hi"); + TestParcelable result = mRemote.parcelableOut(arg); + assertNotSame(arg, result); + assertEquals(44, arg.mAnInt); + } + + @SmallTest + public void testParcelableInOut() throws Exception { + TestParcelable arg = new TestParcelable(43, "hi"); + TestParcelable result = mRemote.parcelableInOut(arg); + assertNotSame(arg, result); + assertEquals(44, arg.mAnInt); + } + + @SmallTest + public void testListParcelableLonger() throws Exception { + List list = Lists.newArrayList(); + list.add(new TestParcelable(33, "asdf")); + list.add(new TestParcelable(34, "jkl;")); + + TestParcelable result = mRemote.listParcelableLonger(list, 1); + +// System.out.println("result=" + result); +// for (TestParcelable p : list) { +// System.out.println("longer: " + p); +// } + + assertEquals("jkl;", result.mAString); + assertEquals(34, result.mAnInt); + + assertEquals(3, list.size()); + assertTrue("out parameter 0: " + list.get(0), check(list.get(0), 33, "asdf")); + assertTrue("out parameter 1: " + list.get(1), check(list.get(1), 34, "jkl;")); + assertTrue("out parameter 2: " + list.get(2), check(list.get(2), 34, "jkl;")); + + assertNotSame(list.get(1), list.get(2)); + } + + @SmallTest + public void testListParcelableShorter() throws Exception { + List list = Lists.newArrayList(); + list.add(new TestParcelable(33, "asdf")); + list.add(new TestParcelable(34, "jkl;")); + list.add(new TestParcelable(35, "qwerty")); + + int result = mRemote.listParcelableShorter(list, 2); + +// System.out.println("result=" + result); +// for (TestParcelable p : list) { +// System.out.println("shorter: " + p); +// } + + assertEquals(2, result); + assertEquals(2, list.size()); + assertTrue("out parameter 0: " + list.get(0), check(list.get(0), 33, "asdf")); + assertTrue("out parameter 1: " + list.get(1), check(list.get(1), 34, "jkl;")); + + assertNotSame(list.get(0), list.get(1)); + } + + @SmallTest + public void testArrays() throws Exception { + // boolean + boolean[] b0 = new boolean[]{true}; + boolean[] b1 = new boolean[]{false, true}; + boolean[] b2 = new boolean[]{true, false, true}; + boolean[] br = mRemote.booleanArray(b0, b1, b2); + + assertEquals(1, br.length); + assertTrue(br[0]); + + assertTrue(b1[0]); + assertFalse(b1[1]); + + assertTrue(b2[0]); + assertFalse(b2[1]); + assertTrue(b2[2]); + + // char + char[] c0 = new char[]{'a'}; + char[] c1 = new char[]{'b', 'c'}; + char[] c2 = new char[]{'d', 'e', 'f'}; + char[] cr = mRemote.charArray(c0, c1, c2); + + assertEquals(1, cr.length); + assertEquals('a', cr[0]); + + assertEquals('a', c1[0]); + assertEquals('\0', c1[1]); + + assertEquals('a', c2[0]); + assertEquals('e', c2[1]); + assertEquals('f', c2[2]); + + // int + int[] i0 = new int[]{34}; + int[] i1 = new int[]{38, 39}; + int[] i2 = new int[]{42, 43, 44}; + int[] ir = mRemote.intArray(i0, i1, i2); + + assertEquals(1, ir.length); + assertEquals(34, ir[0]); + + assertEquals(34, i1[0]); + assertEquals(0, i1[1]); + + assertEquals(34, i2[0]); + assertEquals(43, i2[1]); + assertEquals(44, i2[2]); + + // long + long[] l0 = new long[]{50}; + long[] l1 = new long[]{51, 52}; + long[] l2 = new long[]{53, 54, 55}; + long[] lr = mRemote.longArray(l0, l1, l2); + + assertEquals(1, lr.length); + assertEquals(50, lr[0]); + + assertEquals(50, l1[0]); + assertEquals(0, l1[1]); + + assertEquals(50, l2[0]); + assertEquals(54, l2[1]); + assertEquals(55, l2[2]); + + // float + float[] f0 = new float[]{90.1f}; + float[] f1 = new float[]{90.2f, 90.3f}; + float[] f2 = new float[]{90.4f, 90.5f, 90.6f}; + float[] fr = mRemote.floatArray(f0, f1, f2); + + assertEquals(1, fr.length); + assertEquals(90.1f, fr[0]); + + assertEquals(90.1f, f1[0]); + assertEquals(0f, f1[1], 0.0f); + + assertEquals(90.1f, f2[0]); + assertEquals(90.5f, f2[1]); + assertEquals(90.6f, f2[2]); + + // double + double[] d0 = new double[]{100.1}; + double[] d1 = new double[]{100.2, 100.3}; + double[] d2 = new double[]{100.4, 100.5, 100.6}; + double[] dr = mRemote.doubleArray(d0, d1, d2); + + assertEquals(1, dr.length); + assertEquals(100.1, dr[0]); + + assertEquals(100.1, d1[0]); + assertEquals(0, d1[1], 0.0); + + assertEquals(100.1, d2[0]); + assertEquals(100.5, d2[1]); + assertEquals(100.6, d2[2]); + + // String + String[] s0 = new String[]{"s0[0]"}; + String[] s1 = new String[]{"s1[0]", "s1[1]"}; + String[] s2 = new String[]{"s2[0]", "s2[1]", "s2[2]"}; + String[] sr = mRemote.stringArray(s0, s1, s2); + + assertEquals(1, sr.length); + assertEquals("s0[0]", sr[0]); + + assertEquals("s0[0]", s1[0]); + assertNull(s1[1]); + + assertEquals("s0[0]", s2[0]); + assertEquals("s2[1]", s2[1]); + assertEquals("s2[2]", s2[2]); + } + + @SmallTest + public void testVoidSecurityException() throws Exception { + boolean good = false; + try { + mRemote.voidSecurityException(); + } catch (SecurityException e) { + good = true; + } + assertEquals(good, true); + } + + @SmallTest + public void testIntSecurityException() throws Exception { + boolean good = false; + try { + mRemote.intSecurityException(); + } catch (SecurityException e) { + good = true; + } + assertEquals(good, true); + } +} + diff --git a/tests/AndroidTests/src/com/android/unit_tests/os/BroadcasterTest.java b/tests/AndroidTests/src/com/android/unit_tests/os/BroadcasterTest.java new file mode 100644 index 0000000000000000000000000000000000000000..0df1653a46f164b70176369d5d76fee86d886bd2 --- /dev/null +++ b/tests/AndroidTests/src/com/android/unit_tests/os/BroadcasterTest.java @@ -0,0 +1,232 @@ +/* + * Copyright (C) 2007 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.android.unit_tests.os; + +import android.os.Broadcaster; +import android.os.Handler; +import android.os.Message; +import android.test.suitebuilder.annotation.MediumTest; +import android.test.suitebuilder.annotation.SmallTest; +import junit.framework.TestCase; + +public class BroadcasterTest extends TestCase { + private static final int MESSAGE_A = 23234; + private static final int MESSAGE_B = 3; + private static final int MESSAGE_C = 14; + private static final int MESSAGE_D = 95; + + @MediumTest + public void test1() throws Exception { + /* + * One handler requestes one message, with a translation + */ + HandlerTester tester = new HandlerTester() { + Handler h; + + public void go() { + Broadcaster b = new Broadcaster(); + h = new H(); + + b.request(MESSAGE_A, h, MESSAGE_B); + + Message msg = new Message(); + msg.what = MESSAGE_A; + + b.broadcast(msg); + } + + public void handleMessage(Message msg) { + if (msg.what == MESSAGE_B) { + success(); + } else { + failure(); + } + } + }; + tester.doTest(1000); + } + + private static class Tests2and3 extends HandlerTester { + Tests2and3(int n) { + N = n; + } + + int N; + Handler mHandlers[]; + boolean mSuccess[]; + + public void go() { + Broadcaster b = new Broadcaster(); + mHandlers = new Handler[N]; + mSuccess = new boolean[N]; + for (int i = 0; i < N; i++) { + mHandlers[i] = new H(); + mSuccess[i] = false; + b.request(MESSAGE_A, mHandlers[i], MESSAGE_B + i); + } + + Message msg = new Message(); + msg.what = MESSAGE_A; + + b.broadcast(msg); + } + + public void handleMessage(Message msg) { + int index = msg.what - MESSAGE_B; + if (index < 0 || index >= N) { + failure(); + } else { + if (msg.getTarget() == mHandlers[index]) { + mSuccess[index] = true; + } + } + boolean winner = true; + for (int i = 0; i < N; i++) { + if (!mSuccess[i]) { + winner = false; + } + } + if (winner) { + success(); + } + } + } + + @MediumTest + public void test2() throws Exception { + /* + * 2 handlers request the same message, with different translations + */ + HandlerTester tester = new Tests2and3(2); + tester.doTest(1000); + } + + @MediumTest + public void test3() throws Exception { + /* + * 1000 handlers request the same message, with different translations + */ + HandlerTester tester = new Tests2and3(10); + tester.doTest(1000); + } + + @MediumTest + public void test4() throws Exception { + /* + * Two handlers request different messages, with translations, sending + * only one. The other one should never get sent. + */ + HandlerTester tester = new HandlerTester() { + Handler h1; + Handler h2; + + public void go() { + Broadcaster b = new Broadcaster(); + h1 = new H(); + h2 = new H(); + + b.request(MESSAGE_A, h1, MESSAGE_C); + b.request(MESSAGE_B, h2, MESSAGE_D); + + Message msg = new Message(); + msg.what = MESSAGE_A; + + b.broadcast(msg); + } + + public void handleMessage(Message msg) { + if (msg.what == MESSAGE_C && msg.getTarget() == h1) { + success(); + } else { + failure(); + } + } + }; + tester.doTest(1000); + } + + @MediumTest + public void test5() throws Exception { + /* + * Two handlers request different messages, with translations, sending + * only one. The other one should never get sent. + */ + HandlerTester tester = new HandlerTester() { + Handler h1; + Handler h2; + + public void go() { + Broadcaster b = new Broadcaster(); + h1 = new H(); + h2 = new H(); + + b.request(MESSAGE_A, h1, MESSAGE_C); + b.request(MESSAGE_B, h2, MESSAGE_D); + + Message msg = new Message(); + msg.what = MESSAGE_B; + + b.broadcast(msg); + } + + public void handleMessage(Message msg) { + if (msg.what == MESSAGE_D && msg.getTarget() == h2) { + success(); + } else { + failure(); + } + } + }; + tester.doTest(1000); + } + + @MediumTest + public void test6() throws Exception { + /* + * Two handlers request same message. Cancel the request for the + * 2nd handler, make sure the first still works. + */ + HandlerTester tester = new HandlerTester() { + Handler h1; + Handler h2; + + public void go() { + Broadcaster b = new Broadcaster(); + h1 = new H(); + h2 = new H(); + + b.request(MESSAGE_A, h1, MESSAGE_C); + b.request(MESSAGE_A, h2, MESSAGE_D); + b.cancelRequest(MESSAGE_A, h2, MESSAGE_D); + + Message msg = new Message(); + msg.what = MESSAGE_A; + + b.broadcast(msg); + } + + public void handleMessage(Message msg) { + if (msg.what == MESSAGE_C && msg.getTarget() == h1) { + success(); + } else { + failure(); + } + } + }; + tester.doTest(1000); + } +} diff --git a/tests/AndroidTests/src/com/android/unit_tests/os/FileObserverTest.java b/tests/AndroidTests/src/com/android/unit_tests/os/FileObserverTest.java new file mode 100644 index 0000000000000000000000000000000000000000..a504cd3b384b7057eca9c349a2bafc2fdbe4d8a1 --- /dev/null +++ b/tests/AndroidTests/src/com/android/unit_tests/os/FileObserverTest.java @@ -0,0 +1,120 @@ +/* + * Copyright (C) 2006 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.android.unit_tests.os; + +import com.google.android.collect.Lists; +import com.google.android.collect.Maps; + +import android.os.FileObserver; +import android.test.AndroidTestCase; +import android.test.suitebuilder.annotation.LargeTest; +import android.util.Log; + +import java.io.File; +import java.io.FileOutputStream; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +public class FileObserverTest extends AndroidTestCase { + private Observer mObserver; + private File mTestFile; + + private static class Observer extends FileObserver { + public List events = Lists.newArrayList(); + public int totalEvents = 0; + + public Observer(String path) { + super(path); + } + + public void onEvent(int event, String path) { + synchronized (this) { + totalEvents++; + Map map = Maps.newHashMap(); + + map.put("event", event); + map.put("path", path); + + events.add(map); + + this.notifyAll(); + } + } + } + + @Override + protected void setUp() throws Exception { + mTestFile = File.createTempFile(".file_observer_test", ".txt"); + } + + @Override + protected void tearDown() throws Exception { + if (mTestFile != null && mTestFile.exists()) { + mTestFile.delete(); + } + } + + @LargeTest + public void testRun() throws Exception { + // make file changes and wait for them + assertTrue(mTestFile.exists()); + assertNotNull(mTestFile.getParent()); + + mObserver = new Observer(mTestFile.getParent()); + mObserver.startWatching(); + + FileOutputStream out = new FileOutputStream(mTestFile); + try { + out.write(0x20); + waitForEvent(); // open + waitForEvent(); // modify + + mTestFile.delete(); + waitForEvent(); // delete + + mObserver.stopWatching(); + + // Ensure that we have seen at least 3 events. + assertTrue(mObserver.totalEvents > 3); + } finally { + out.close(); + } + } + + private void waitForEvent() { + synchronized (mObserver) { + boolean done = false; + while (!done) { + try { + mObserver.wait(2000); + done = true; + } catch (InterruptedException e) { + } + } + + Iterator it = mObserver.events.iterator(); + + while (it.hasNext()) { + Map map = it.next(); + Log.i("FileObserverTest", "event: " + map.get("event").toString() + " path: " + map.get("path")); + } + + mObserver.events.clear(); + } + } +} diff --git a/tests/AndroidTests/src/com/android/unit_tests/os/FileUtilsTest.java b/tests/AndroidTests/src/com/android/unit_tests/os/FileUtilsTest.java new file mode 100644 index 0000000000000000000000000000000000000000..f2c92932f8a1337d86136c0fd02638f373f5ac0f --- /dev/null +++ b/tests/AndroidTests/src/com/android/unit_tests/os/FileUtilsTest.java @@ -0,0 +1,171 @@ +/* + * 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.android.unit_tests.os; + +import android.content.Context; +import android.os.FileUtils; +import android.os.FileUtils.FileStatus; +import android.test.AndroidTestCase; +import android.test.suitebuilder.annotation.LargeTest; +import android.test.suitebuilder.annotation.MediumTest; +import android.test.suitebuilder.annotation.SmallTest; + +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.FileWriter; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; + +import junit.framework.Assert; + +public class FileUtilsTest extends AndroidTestCase { + private static final String TEST_DATA = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; + + private File mTestFile; + private File mCopyFile; + + @Override + protected void setUp() throws Exception { + super.setUp(); + File testDir = getContext().getDir("testing", Context.MODE_PRIVATE); + mTestFile = new File(testDir, "test.file"); + mCopyFile = new File(testDir, "copy.file"); + FileWriter writer = new FileWriter(mTestFile); + try { + writer.write(TEST_DATA, 0, TEST_DATA.length()); + } finally { + writer.close(); + } + } + + @Override + protected void tearDown() throws Exception { + if (mTestFile.exists()) mTestFile.delete(); + if (mCopyFile.exists()) mCopyFile.delete(); + } + + @LargeTest + public void testGetFileStatus() { + final byte[] MAGIC = { 0xB, 0xE, 0x0, 0x5 }; + + try { + // truncate test file and write MAGIC (4 bytes) to it. + FileOutputStream os = new FileOutputStream(mTestFile, false); + os.write(MAGIC, 0, 4); + os.flush(); + os.close(); + } catch (FileNotFoundException e) { + Assert.fail("File was removed durning test" + e); + } catch (IOException e) { + Assert.fail("Unexpected IOException: " + e); + } + + Assert.assertTrue(mTestFile.exists()); + Assert.assertTrue(FileUtils.getFileStatus(mTestFile.getPath(), null)); + + FileStatus status1 = new FileStatus(); + FileUtils.getFileStatus(mTestFile.getPath(), status1); + + Assert.assertEquals(4, status1.size); + + // Sleep for at least one second so that the modification time will be different. + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + } + + try { + // append so we don't change the creation time. + FileOutputStream os = new FileOutputStream(mTestFile, true); + os.write(MAGIC, 0, 4); + os.flush(); + os.close(); + } catch (FileNotFoundException e) { + Assert.fail("File was removed durning test" + e); + } catch (IOException e) { + Assert.fail("Unexpected IOException: " + e); + } + + FileStatus status2 = new FileStatus(); + FileUtils.getFileStatus(mTestFile.getPath(), status2); + + Assert.assertEquals(8, status2.size); + Assert.assertTrue(status2.mtime > status1.mtime); + + mTestFile.delete(); + + Assert.assertFalse(mTestFile.exists()); + Assert.assertFalse(FileUtils.getFileStatus(mTestFile.getPath(), null)); + } + + // TODO: test setPermissions(), getPermissions() + + @MediumTest + public void testCopyFile() throws Exception { + assertFalse(mCopyFile.exists()); + FileUtils.copyFile(mTestFile, mCopyFile); + assertTrue(mCopyFile.exists()); + assertEquals(TEST_DATA, FileUtils.readTextFile(mCopyFile, 0, null)); + } + + @MediumTest + public void testCopyToFile() throws Exception { + final String s = "Foo Bar"; + assertFalse(mCopyFile.exists()); + FileUtils.copyToFile(new ByteArrayInputStream(s.getBytes()), mCopyFile); assertTrue(mCopyFile.exists()); + assertEquals(s, FileUtils.readTextFile(mCopyFile, 0, null)); + } + + @MediumTest + public void testIsFilenameSafe() throws Exception { + assertTrue(FileUtils.isFilenameSafe(new File("foobar"))); + assertTrue(FileUtils.isFilenameSafe(new File("a_b-c=d.e/0,1+23"))); + assertFalse(FileUtils.isFilenameSafe(new File("foo*bar"))); + assertFalse(FileUtils.isFilenameSafe(new File("foo\nbar"))); + } + + @MediumTest + public void testReadTextFile() throws Exception { + assertEquals(TEST_DATA, FileUtils.readTextFile(mTestFile, 0, null)); + + assertEquals("ABCDE", FileUtils.readTextFile(mTestFile, 5, null)); + assertEquals("ABCDE<>", FileUtils.readTextFile(mTestFile, 5, "<>")); + assertEquals(TEST_DATA.substring(0, 51) + "<>", + FileUtils.readTextFile(mTestFile, 51, "<>")); + assertEquals(TEST_DATA, FileUtils.readTextFile(mTestFile, 52, "<>")); + assertEquals(TEST_DATA, FileUtils.readTextFile(mTestFile, 100, "<>")); + + assertEquals("vwxyz", FileUtils.readTextFile(mTestFile, -5, null)); + assertEquals("<>vwxyz", FileUtils.readTextFile(mTestFile, -5, "<>")); + assertEquals("<>" + TEST_DATA.substring(1, 52), + FileUtils.readTextFile(mTestFile, -51, "<>")); + assertEquals(TEST_DATA, FileUtils.readTextFile(mTestFile, -52, "<>")); + assertEquals(TEST_DATA, FileUtils.readTextFile(mTestFile, -100, "<>")); + } + + @MediumTest + public void testReadTextFileWithZeroLengthFile() throws Exception { + new FileOutputStream(mTestFile).close(); // Zero out the file + assertEquals("", FileUtils.readTextFile(mTestFile, 0, null)); + assertEquals("", FileUtils.readTextFile(mTestFile, 1, "<>")); + assertEquals("", FileUtils.readTextFile(mTestFile, 10, "<>")); + assertEquals("", FileUtils.readTextFile(mTestFile, -1, "<>")); + assertEquals("", FileUtils.readTextFile(mTestFile, -10, "<>")); + } +} diff --git a/tests/AndroidTests/src/com/android/unit_tests/os/HandlerTester.java b/tests/AndroidTests/src/com/android/unit_tests/os/HandlerTester.java new file mode 100644 index 0000000000000000000000000000000000000000..303245f59ff81841c64b3963800a9ee1b8657643 --- /dev/null +++ b/tests/AndroidTests/src/com/android/unit_tests/os/HandlerTester.java @@ -0,0 +1,89 @@ +/* + * Copyright (C) 2007 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.android.unit_tests.os; + +import android.os.Handler; +import android.os.Looper; +import android.os.Message; + +public abstract class HandlerTester extends Thread { + public abstract void go(); + public abstract void handleMessage(Message msg); + + public HandlerTester() { + } + + public void doTest(long timeout) { + start(); + + synchronized (this) { + try { + wait(timeout); + quit(); + } + catch (InterruptedException e) { + } + } + + if (!mDone) { + throw new RuntimeException("test timed out"); + } + if (!mSuccess) { + throw new RuntimeException("test failed"); + } + } + + public void success() { + mDone = true; + mSuccess = true; + } + + public void failure() { + mDone = true; + mSuccess = false; + } + + public void run() { + Looper.prepare(); + mLooper = Looper.myLooper(); + go(); + Looper.loop(); + } + + protected class H extends Handler { + public void handleMessage(Message msg) { + synchronized (HandlerTester.this) { + // Call into them with our monitor locked, so they don't have + // to deal with other races. + HandlerTester.this.handleMessage(msg); + if (mDone) { + HandlerTester.this.notify(); + quit(); + } + } + } + } + + private void quit() { + mLooper.quit(); + } + + private boolean mDone = false; + private boolean mSuccess = false; + private Looper mLooper; +} + diff --git a/tests/AndroidTests/src/com/android/unit_tests/os/HandlerThreadTest.java b/tests/AndroidTests/src/com/android/unit_tests/os/HandlerThreadTest.java new file mode 100644 index 0000000000000000000000000000000000000000..c62f94f4fcf917e42828afbbb11a7ac83e011264 --- /dev/null +++ b/tests/AndroidTests/src/com/android/unit_tests/os/HandlerThreadTest.java @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2006 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.android.unit_tests.os; + +import junit.framework.TestCase; +import android.os.Handler; +import android.os.HandlerThread; +import android.os.Message; +import android.os.Process; +import android.test.suitebuilder.annotation.MediumTest; +import android.test.suitebuilder.annotation.SmallTest; + +public class HandlerThreadTest extends TestCase { + private static final int TEST_WHAT = 1; + + private boolean mGotMessage = false; + private int mGotMessageWhat = -1; + private volatile boolean mDidSetup = false; + private volatile int mLooperTid = -1; + + @MediumTest + public void testHandlerThread() throws Exception { + HandlerThread th1 = new HandlerThread("HandlerThreadTest") { + protected void onLooperPrepared() { + mDidSetup = true; + mLooperTid = Process.myTid(); + } + }; + + assertFalse(th1.isAlive()); + assertNull(th1.getLooper()); + + th1.start(); + + assertTrue(th1.isAlive()); + assertNotNull(th1.getLooper()); + + /* + * Since getLooper() will block until the HandlerThread is setup, we are guaranteed + * that mDidSetup and mLooperTid will have been initalized. If they have not, then + * this test should fail + */ + // Make sure that the onLooperPrepared() was called on a different thread. + assertNotSame(Process.myTid(), mLooperTid); + assertTrue(mDidSetup); + + final Handler h1 = new Handler(th1.getLooper()) { + public void handleMessage(Message msg) { + assertEquals(TEST_WHAT, msg.what); + // Ensure that we are running on the same thread in which the looper was setup on. + assertEquals(mLooperTid, Process.myTid()); + + mGotMessageWhat = msg.what; + mGotMessage = true; + synchronized(this) { + notifyAll(); + } + } + }; + + Message msg = h1.obtainMessage(TEST_WHAT); + + synchronized (h1) { + // wait until we have the lock before sending the message. + h1.sendMessage(msg); + try { + // wait for the message to be handled + h1.wait(); + } catch (InterruptedException e) { + } + } + + assertTrue(mGotMessage); + assertEquals(TEST_WHAT, mGotMessageWhat); + } +} diff --git a/tests/AndroidTests/src/com/android/unit_tests/os/IAidlTest.aidl b/tests/AndroidTests/src/com/android/unit_tests/os/IAidlTest.aidl new file mode 100644 index 0000000000000000000000000000000000000000..94c39ff74e101aea3d548c56044b4d490643fb24 --- /dev/null +++ b/tests/AndroidTests/src/com/android/unit_tests/os/IAidlTest.aidl @@ -0,0 +1,47 @@ +/* //device/apps/AndroidTests/src/com.android.unit_tests/IAidlTest.aidl +** +** Copyright 2007, 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.android.unit_tests.os; + +import com.android.unit_tests.os.AidlTest; + +interface IAidlTest { + int intMethod(int a); + + AidlTest.TestParcelable parcelableIn(in AidlTest.TestParcelable p); + AidlTest.TestParcelable parcelableOut(out AidlTest.TestParcelable p); + AidlTest.TestParcelable parcelableInOut(inout AidlTest.TestParcelable p); + + AidlTest.TestParcelable listParcelableLonger( + inout List list, int index); + int listParcelableShorter( + inout List list, int index); + + boolean[] booleanArray(in boolean[] a0, out boolean[] a1, inout boolean[] a2); + char[] charArray(in char[] a0, out char[] a1, inout char[] a2); + int[] intArray(in int[] a0, out int[] a1, inout int[] a2); + long[] longArray(in long[] a0, out long[] a1, inout long[] a2); + float[] floatArray(in float[] a0, out float[] a1, inout float[] a2); + double[] doubleArray(in double[] a0, out double[] a1, inout double[] a2); + String[] stringArray(in String[] a0, out String[] a1, inout String[] a2); + AidlTest.TestParcelable[] parcelableArray(in AidlTest.TestParcelable[] a0, + out AidlTest.TestParcelable[] a1, + inout AidlTest.TestParcelable[] a2); + + void voidSecurityException(); + int intSecurityException(); +} diff --git a/tests/AndroidTests/src/com/android/unit_tests/os/IdleHandlerTest.java b/tests/AndroidTests/src/com/android/unit_tests/os/IdleHandlerTest.java new file mode 100644 index 0000000000000000000000000000000000000000..fc3b00745d4feda991ac02b0287a9ce0c5cdbe76 --- /dev/null +++ b/tests/AndroidTests/src/com/android/unit_tests/os/IdleHandlerTest.java @@ -0,0 +1,199 @@ +/* + * Copyright (C) 2007 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.android.unit_tests.os; + +import android.os.Handler; +import android.os.Looper; +import android.os.Message; +import android.os.MessageQueue.IdleHandler; +import android.test.suitebuilder.annotation.MediumTest; +import junit.framework.TestCase; + +public class IdleHandlerTest extends TestCase { + + private static class BaseTestHandler extends TestHandlerThread { + Handler mHandler; + + public BaseTestHandler() { + } + + public void go() { + mHandler = new Handler() { + public void handleMessage(Message msg) { + BaseTestHandler.this.handleMessage(msg); + } + }; + } + + public void addIdleHandler() { + Looper.myQueue().addIdleHandler(new IdleHandler() { + public boolean queueIdle() { + return BaseTestHandler.this.queueIdle(); + } + }); + } + + public void handleMessage(Message msg) { + } + + public boolean queueIdle() { + return false; + } + } + + @MediumTest + public void testOneShotFirst() throws Exception { + TestHandlerThread tester = new BaseTestHandler() { + int mCount; + + public void go() { + super.go(); + mCount = 0; + mHandler.sendMessageDelayed(mHandler.obtainMessage(0), 100); + addIdleHandler(); + } + + public void handleMessage(Message msg) { + if (msg.what == 0) { + mHandler.sendMessageDelayed(mHandler.obtainMessage(1), 100); + } else if (msg.what == 1) { + if (mCount == 1) { + success(); + } else { + failure(new RuntimeException( + "Idle handler called " + mCount + " times")); + } + } + } + + public boolean queueIdle() { + mCount++; + return false; + } + }; + + tester.doTest(1000); + } + + @MediumTest + public void testOneShotLater() throws Exception { + TestHandlerThread tester = new BaseTestHandler() { + int mCount; + + public void go() { + super.go(); + mCount = 0; + mHandler.sendMessage(mHandler.obtainMessage(0)); + } + + public void handleMessage(Message msg) { + if (msg.what == 0) { + addIdleHandler(); + mHandler.sendMessageDelayed(mHandler.obtainMessage(1), 100); + } else if (msg.what == 1) { + mHandler.sendMessageDelayed(mHandler.obtainMessage(2), 100); + } else if (msg.what == 2) { + if (mCount == 1) { + success(); + } else { + failure(new RuntimeException( + "Idle handler called " + mCount + " times")); + } + } + } + + public boolean queueIdle() { + mCount++; + return false; + } + }; + + tester.doTest(1000); + } + + + @MediumTest + public void testRepeatedFirst() throws Exception { + TestHandlerThread tester = new BaseTestHandler() { + int mCount; + + public void go() { + super.go(); + mCount = 0; + mHandler.sendMessageDelayed(mHandler.obtainMessage(0), 100); + addIdleHandler(); + } + + public void handleMessage(Message msg) { + if (msg.what == 0) { + mHandler.sendMessageDelayed(mHandler.obtainMessage(1), 100); + } else if (msg.what == 1) { + if (mCount == 2) { + success(); + } else { + failure(new RuntimeException( + "Idle handler called " + mCount + " times")); + } + } + } + + public boolean queueIdle() { + mCount++; + return true; + } + }; + + tester.doTest(1000); + } + + @MediumTest + public void testRepeatedLater() throws Exception { + TestHandlerThread tester = new BaseTestHandler() { + int mCount; + + public void go() { + super.go(); + mCount = 0; + mHandler.sendMessage(mHandler.obtainMessage(0)); + } + + public void handleMessage(Message msg) { + if (msg.what == 0) { + addIdleHandler(); + mHandler.sendMessageDelayed(mHandler.obtainMessage(1), 100); + } else if (msg.what == 1) { + mHandler.sendMessageDelayed(mHandler.obtainMessage(2), 100); + } else if (msg.what == 2) { + if (mCount == 2) { + success(); + } else { + failure(new RuntimeException( + "Idle handler called " + mCount + " times")); + } + } + } + + public boolean queueIdle() { + mCount++; + return true; + } + }; + + tester.doTest(1000); + } +} + diff --git a/tests/AndroidTests/src/com/android/unit_tests/os/MemoryFileTest.java b/tests/AndroidTests/src/com/android/unit_tests/os/MemoryFileTest.java new file mode 100644 index 0000000000000000000000000000000000000000..508afcf411b81d60e74402a8e41afbd6cd6ed79a --- /dev/null +++ b/tests/AndroidTests/src/com/android/unit_tests/os/MemoryFileTest.java @@ -0,0 +1,243 @@ +/* + * 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.android.unit_tests.os; + +import android.os.MemoryFile; +import android.test.suitebuilder.annotation.MediumTest; +import android.test.suitebuilder.annotation.SmallTest; +import junit.framework.TestCase; + +import java.io.InputStream; +import java.io.OutputStream; +import java.io.IOException; + +import java.util.List; +import java.util.ArrayList; + +public class MemoryFileTest extends TestCase { + + private void compareBuffers(byte[] buffer1, byte[] buffer2, int length) throws Exception { + for (int i = 0; i < length; i++) { + if (buffer1[i] != buffer2[i]) { + throw new Exception("readBytes did not read back what writeBytes wrote"); + } + } + } + + /** + * Keep allocating new files till the system purges them. + */ + @MediumTest + public void testPurge() throws Exception { + List files = new ArrayList(); + while (true) { + MemoryFile newFile = new MemoryFile("MemoryFileTest", 1000000); + newFile.allowPurging(true); + newFile.writeBytes(testString, 0, 0, testString.length); + files.add(newFile); + for (MemoryFile file : files) { + try { + file.readBytes(testString, 0, 0, testString.length); + } catch (IOException e) { + // Expected + for (MemoryFile fileToClose : files) { + fileToClose.close(); + } + return; + } + } + } + } + + @SmallTest + public void testRun() throws Exception { + MemoryFile file = new MemoryFile("MemoryFileTest", 1000000); + + byte[] buffer = new byte[testString.length]; + + // check low level accessors + file.writeBytes(testString, 0, 2000, testString.length); + file.readBytes(buffer, 2000, 0, testString.length); + compareBuffers(testString, buffer, testString.length); + + // check streams + buffer = new byte[testString.length]; + + OutputStream os = file.getOutputStream(); + os.write(testString); + + InputStream is = file.getInputStream(); + is.mark(testString.length); + is.read(buffer); + compareBuffers(testString, buffer, testString.length); + + // test mark/reset + buffer = new byte[testString.length]; + is.reset(); + is.read(buffer); + compareBuffers(testString, buffer, testString.length); + + file.close(); + } + + private static final byte[] testString = new byte[] { + 3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5, 8, 9, 7, 9, 3, 2, 3, 8, 4, 6, 2, 6, 4, 3, 3, 8, 3, 2, 7, 9, 5, 0, 2, 8, 8, 4, 1, 9, 7, 1, 6, 9, 3, 9, 9, 3, 7, 5, 1, 0, 5, 8, 2, 0, 9, 7, 4, 9, 4, 4, 5, 9, 2, 3, 0, 7, 8, 1, 6, 4, + 0, 6, 2, 8, 6, 2, 0, 8, 9, 9, 8, 6, 2, 8, 0, 3, 4, 8, 2, 5, 3, 4, 2, 1, 1, 7, 0, 6, 7, 9, 8, 2, 1, 4, 8, 0, 8, 6, 5, 1, 3, 2, 8, 2, 3, 0, 6, 6, 4, 7, 0, 9, 3, 8, 4, 4, 6, 0, 9, 5, 5, 0, 5, 8, 2, 2, 3, 1, 7, 2, + 5, 3, 5, 9, 4, 0, 8, 1, 2, 8, 4, 8, 1, 1, 1, 7, 4, 5, 0, 2, 8, 4, 1, 0, 2, 7, 0, 1, 9, 3, 8, 5, 2, 1, 1, 0, 5, 5, 5, 9, 6, 4, 4, 6, 2, 2, 9, 4, 8, 9, 5, 4, 9, 3, 0, 3, 8, 1, 9, 6, 4, 4, 2, 8, 8, 1, 0, 9, 7, 5, + 6, 6, 5, 9, 3, 3, 4, 4, 6, 1, 2, 8, 4, 7, 5, 6, 4, 8, 2, 3, 3, 7, 8, 6, 7, 8, 3, 1, 6, 5, 2, 7, 1, 2, 0, 1, 9, 0, 9, 1, 4, 5, 6, 4, 8, 5, 6, 6, 9, 2, 3, 4, 6, 0, 3, 4, 8, 6, 1, 0, 4, 5, 4, 3, 2, 6, 6, 4, 8, 2, + 1, 3, 3, 9, 3, 6, 0, 7, 2, 6, 0, 2, 4, 9, 1, 4, 1, 2, 7, 3, 7, 2, 4, 5, 8, 7, 0, 0, 6, 6, 0, 6, 3, 1, 5, 5, 8, 8, 1, 7, 4, 8, 8, 1, 5, 2, 0, 9, 2, 0, 9, 6, 2, 8, 2, 9, 2, 5, 4, 0, 9, 1, 7, 1, 5, 3, 6, 4, 3, 6, + 7, 8, 9, 2, 5, 9, 0, 3, 6, 0, 0, 1, 1, 3, 3, 0, 5, 3, 0, 5, 4, 8, 8, 2, 0, 4, 6, 6, 5, 2, 1, 3, 8, 4, 1, 4, 6, 9, 5, 1, 9, 4, 1, 5, 1, 1, 6, 0, 9, 4, 3, 3, 0, 5, 7, 2, 7, 0, 3, 6, 5, 7, 5, 9, 5, 9, 1, 9, 5, 3, + 0, 9, 2, 1, 8, 6, 1, 1, 7, 3, 8, 1, 9, 3, 2, 6, 1, 1, 7, 9, 3, 1, 0, 5, 1, 1, 8, 5, 4, 8, 0, 7, 4, 4, 6, 2, 3, 7, 9, 9, 6, 2, 7, 4, 9, 5, 6, 7, 3, 5, 1, 8, 8, 5, 7, 5, 2, 7, 2, 4, 8, 9, 1, 2, 2, 7, 9, 3, 8, 1, + 8, 3, 0, 1, 1, 9, 4, 9, 1, 2, 9, 8, 3, 3, 6, 7, 3, 3, 6, 2, 4, 4, 0, 6, 5, 6, 6, 4, 3, 0, 8, 6, 0, 2, 1, 3, 9, 4, 9, 4, 6, 3, 9, 5, 2, 2, 4, 7, 3, 7, 1, 9, 0, 7, 0, 2, 1, 7, 9, 8, 6, 0, 9, 4, 3, 7, 0, 2, 7, 7, + 0, 5, 3, 9, 2, 1, 7, 1, 7, 6, 2, 9, 3, 1, 7, 6, 7, 5, 2, 3, 8, 4, 6, 7, 4, 8, 1, 8, 4, 6, 7, 6, 6, 9, 4, 0, 5, 1, 3, 2, 0, 0, 0, 5, 6, 8, 1, 2, 7, 1, 4, 5, 2, 6, 3, 5, 6, 0, 8, 2, 7, 7, 8, 5, 7, 7, 1, 3, 4, 2, + 7, 5, 7, 7, 8, 9, 6, 0, 9, 1, 7, 3, 6, 3, 7, 1, 7, 8, 7, 2, 1, 4, 6, 8, 4, 4, 0, 9, 0, 1, 2, 2, 4, 9, 5, 3, 4, 3, 0, 1, 4, 6, 5, 4, 9, 5, 8, 5, 3, 7, 1, 0, 5, 0, 7, 9, 2, 2, 7, 9, 6, 8, 9, 2, 5, 8, 9, 2, 3, 5, + 4, 2, 0, 1, 9, 9, 5, 6, 1, 1, 2, 1, 2, 9, 0, 2, 1, 9, 6, 0, 8, 6, 4, 0, 3, 4, 4, 1, 8, 1, 5, 9, 8, 1, 3, 6, 2, 9, 7, 7, 4, 7, 7, 1, 3, 0, 9, 9, 6, 0, 5, 1, 8, 7, 0, 7, 2, 1, 1, 3, 4, 9, 9, 9, 9, 9, 9, 8, 3, 7, + 2, 9, 7, 8, 0, 4, 9, 9, 5, 1, 0, 5, 9, 7, 3, 1, 7, 3, 2, 8, 1, 6, 0, 9, 6, 3, 1, 8, 5, 9, 5, 0, 2, 4, 4, 5, 9, 4, 5, 5, 3, 4, 6, 9, 0, 8, 3, 0, 2, 6, 4, 2, 5, 2, 2, 3, 0, 8, 2, 5, 3, 3, 4, 4, 6, 8, 5, 0, 3, 5, + 2, 6, 1, 9, 3, 1, 1, 8, 8, 1, 7, 1, 0, 1, 0, 0, 0, 3, 1, 3, 7, 8, 3, 8, 7, 5, 2, 8, 8, 6, 5, 8, 7, 5, 3, 3, 2, 0, 8, 3, 8, 1, 4, 2, 0, 6, 1, 7, 1, 7, 7, 6, 6, 9, 1, 4, 7, 3, 0, 3, 5, 9, 8, 2, 5, 3, 4, 9, 0, 4, + 2, 8, 7, 5, 5, 4, 6, 8, 7, 3, 1, 1, 5, 9, 5, 6, 2, 8, 6, 3, 8, 8, 2, 3, 5, 3, 7, 8, 7, 5, 9, 3, 7, 5, 1, 9, 5, 7, 7, 8, 1, 8, 5, 7, 7, 8, 0, 5, 3, 2, 1, 7, 1, 2, 2, 6, 8, 0, 6, 6, 1, 3, 0, 0, 1, 9, 2, 7, 8, 7, + 6, 6, 1, 1, 1, 9, 5, 9, 0, 9, 2, 1, 6, 4, 2, 0, 1, 9, 8, 9, 3, 8, 0, 9, 5, 2, 5, 7, 2, 0, 1, 0, 6, 5, 4, 8, 5, 8, 6, 3, 2, 7, 8, 8, 6, 5, 9, 3, 6, 1, 5, 3, 3, 8, 1, 8, 2, 7, 9, 6, 8, 2, 3, 0, 3, 0, 1, 9, 5, 2, + 0, 3, 5, 3, 0, 1, 8, 5, 2, 9, 6, 8, 9, 9, 5, 7, 7, 3, 6, 2, 2, 5, 9, 9, 4, 1, 3, 8, 9, 1, 2, 4, 9, 7, 2, 1, 7, 7, 5, 2, 8, 3, 4, 7, 9, 1, 3, 1, 5, 1, 5, 5, 7, 4, 8, 5, 7, 2, 4, 2, 4, 5, 4, 1, 5, 0, 6, 9, 5, 9, + 5, 0, 8, 2, 9, 5, 3, 3, 1, 1, 6, 8, 6, 1, 7, 2, 7, 8, 5, 5, 8, 8, 9, 0, 7, 5, 0, 9, 8, 3, 8, 1, 7, 5, 4, 6, 3, 7, 4, 6, 4, 9, 3, 9, 3, 1, 9, 2, 5, 5, 0, 6, 0, 4, 0, 0, 9, 2, 7, 7, 0, 1, 6, 7, 1, 1, 3, 9, 0, 0, + 9, 8, 4, 8, 8, 2, 4, 0, 1, 2, 8, 5, 8, 3, 6, 1, 6, 0, 3, 5, 6, 3, 7, 0, 7, 6, 6, 0, 1, 0, 4, 7, 1, 0, 1, 8, 1, 9, 4, 2, 9, 5, 5, 5, 9, 6, 1, 9, 8, 9, 4, 6, 7, 6, 7, 8, 3, 7, 4, 4, 9, 4, 4, 8, 2, 5, 5, 3, 7, 9, + 7, 7, 4, 7, 2, 6, 8, 4, 7, 1, 0, 4, 0, 4, 7, 5, 3, 4, 6, 4, 6, 2, 0, 8, 0, 4, 6, 6, 8, 4, 2, 5, 9, 0, 6, 9, 4, 9, 1, 2, 9, 3, 3, 1, 3, 6, 7, 7, 0, 2, 8, 9, 8, 9, 1, 5, 2, 1, 0, 4, 7, 5, 2, 1, 6, 2, 0, 5, 6, 9, + 6, 6, 0, 2, 4, 0, 5, 8, 0, 3, 8, 1, 5, 0, 1, 9, 3, 5, 1, 1, 2, 5, 3, 3, 8, 2, 4, 3, 0, 0, 3, 5, 5, 8, 7, 6, 4, 0, 2, 4, 7, 4, 9, 6, 4, 7, 3, 2, 6, 3, 9, 1, 4, 1, 9, 9, 2, 7, 2, 6, 0, 4, 2, 6, 9, 9, 2, 2, 7, 9, + 6, 7, 8, 2, 3, 5, 4, 7, 8, 1, 6, 3, 6, 0, 0, 9, 3, 4, 1, 7, 2, 1, 6, 4, 1, 2, 1, 9, 9, 2, 4, 5, 8, 6, 3, 1, 5, 0, 3, 0, 2, 8, 6, 1, 8, 2, 9, 7, 4, 5, 5, 5, 7, 0, 6, 7, 4, 9, 8, 3, 8, 5, 0, 5, 4, 9, 4, 5, 8, 8, + 5, 8, 6, 9, 2, 6, 9, 9, 5, 6, 9, 0, 9, 2, 7, 2, 1, 0, 7, 9, 7, 5, 0, 9, 3, 0, 2, 9, 5, 5, 3, 2, 1, 1, 6, 5, 3, 4, 4, 9, 8, 7, 2, 0, 2, 7, 5, 5, 9, 6, 0, 2, 3, 6, 4, 8, 0, 6, 6, 5, 4, 9, 9, 1, 1, 9, 8, 8, 1, 8, + 3, 4, 7, 9, 7, 7, 5, 3, 5, 6, 6, 3, 6, 9, 8, 0, 7, 4, 2, 6, 5, 4, 2, 5, 2, 7, 8, 6, 2, 5, 5, 1, 8, 1, 8, 4, 1, 7, 5, 7, 4, 6, 7, 2, 8, 9, 0, 9, 7, 7, 7, 7, 2, 7, 9, 3, 8, 0, 0, 0, 8, 1, 6, 4, 7, 0, 6, 0, 0, 1, + 6, 1, 4, 5, 2, 4, 9, 1, 9, 2, 1, 7, 3, 2, 1, 7, 2, 1, 4, 7, 7, 2, 3, 5, 0, 1, 4, 1, 4, 4, 1, 9, 7, 3, 5, 6, 8, 5, 4, 8, 1, 6, 1, 3, 6, 1, 1, 5, 7, 3, 5, 2, 5, 5, 2, 1, 3, 3, 4, 7, 5, 7, 4, 1, 8, 4, 9, 4, 6, 8, + 4, 3, 8, 5, 2, 3, 3, 2, 3, 9, 0, 7, 3, 9, 4, 1, 4, 3, 3, 3, 4, 5, 4, 7, 7, 6, 2, 4, 1, 6, 8, 6, 2, 5, 1, 8, 9, 8, 3, 5, 6, 9, 4, 8, 5, 5, 6, 2, 0, 9, 9, 2, 1, 9, 2, 2, 2, 1, 8, 4, 2, 7, 2, 5, 5, 0, 2, 5, 4, 2, + 5, 6, 8, 8, 7, 6, 7, 1, 7, 9, 0, 4, 9, 4, 6, 0, 1, 6, 5, 3, 4, 6, 6, 8, 0, 4, 9, 8, 8, 6, 2, 7, 2, 3, 2, 7, 9, 1, 7, 8, 6, 0, 8, 5, 7, 8, 4, 3, 8, 3, 8, 2, 7, 9, 6, 7, 9, 7, 6, 6, 8, 1, 4, 5, 4, 1, 0, 0, 9, 5, + 3, 8, 8, 3, 7, 8, 6, 3, 6, 0, 9, 5, 0, 6, 8, 0, 0, 6, 4, 2, 2, 5, 1, 2, 5, 2, 0, 5, 1, 1, 7, 3, 9, 2, 9, 8, 4, 8, 9, 6, 0, 8, 4, 1, 2, 8, 4, 8, 8, 6, 2, 6, 9, 4, 5, 6, 0, 4, 2, 4, 1, 9, 6, 5, 2, 8, 5, 0, 2, 2, + 2, 1, 0, 6, 6, 1, 1, 8, 6, 3, 0, 6, 7, 4, 4, 2, 7, 8, 6, 2, 2, 0, 3, 9, 1, 9, 4, 9, 4, 5, 0, 4, 7, 1, 2, 3, 7, 1, 3, 7, 8, 6, 9, 6, 0, 9, 5, 6, 3, 6, 4, 3, 7, 1, 9, 1, 7, 2, 8, 7, 4, 6, 7, 7, 6, 4, 6, 5, 7, 5, + 7, 3, 9, 6, 2, 4, 1, 3, 8, 9, 0, 8, 6, 5, 8, 3, 2, 6, 4, 5, 9, 9, 5, 8, 1, 3, 3, 9, 0, 4, 7, 8, 0, 2, 7, 5, 9, 0, 0, 9, 9, 4, 6, 5, 7, 6, 4, 0, 7, 8, 9, 5, 1, 2, 6, 9, 4, 6, 8, 3, 9, 8, 3, 5, 2, 5, 9, 5, 7, 0, + 9, 8, 2, 5, 8, 2, 2, 6, 2, 0, 5, 2, 2, 4, 8, 9, 4, 0, 7, 7, 2, 6, 7, 1, 9, 4, 7, 8, 2, 6, 8, 4, 8, 2, 6, 0, 1, 4, 7, 6, 9, 9, 0, 9, 0, 2, 6, 4, 0, 1, 3, 6, 3, 9, 4, 4, 3, 7, 4, 5, 5, 3, 0, 5, 0, 6, 8, 2, 0, 3, + 4, 9, 6, 2, 5, 2, 4, 5, 1, 7, 4, 9, 3, 9, 9, 6, 5, 1, 4, 3, 1, 4, 2, 9, 8, 0, 9, 1, 9, 0, 6, 5, 9, 2, 5, 0, 9, 3, 7, 2, 2, 1, 6, 9, 6, 4, 6, 1, 5, 1, 5, 7, 0, 9, 8, 5, 8, 3, 8, 7, 4, 1, 0, 5, 9, 7, 8, 8, 5, 9, + 5, 9, 7, 7, 2, 9, 7, 5, 4, 9, 8, 9, 3, 0, 1, 6, 1, 7, 5, 3, 9, 2, 8, 4, 6, 8, 1, 3, 8, 2, 6, 8, 6, 8, 3, 8, 6, 8, 9, 4, 2, 7, 7, 4, 1, 5, 5, 9, 9, 1, 8, 5, 5, 9, 2, 5, 2, 4, 5, 9, 5, 3, 9, 5, 9, 4, 3, 1, 0, 4, + 9, 9, 7, 2, 5, 2, 4, 6, 8, 0, 8, 4, 5, 9, 8, 7, 2, 7, 3, 6, 4, 4, 6, 9, 5, 8, 4, 8, 6, 5, 3, 8, 3, 6, 7, 3, 6, 2, 2, 2, 6, 2, 6, 0, 9, 9, 1, 2, 4, 6, 0, 8, 0, 5, 1, 2, 4, 3, 8, 8, 4, 3, 9, 0, 4, 5, 1, 2, 4, 4, + 1, 3, 6, 5, 4, 9, 7, 6, 2, 7, 8, 0, 7, 9, 7, 7, 1, 5, 6, 9, 1, 4, 3, 5, 9, 9, 7, 7, 0, 0, 1, 2, 9, 6, 1, 6, 0, 8, 9, 4, 4, 1, 6, 9, 4, 8, 6, 8, 5, 5, 5, 8, 4, 8, 4, 0, 6, 3, 5, 3, 4, 2, 2, 0, 7, 2, 2, 2, 5, 8, + 2, 8, 4, 8, 8, 6, 4, 8, 1, 5, 8, 4, 5, 6, 0, 2, 8, 5, 0, 6, 0, 1, 6, 8, 4, 2, 7, 3, 9, 4, 5, 2, 2, 6, 7, 4, 6, 7, 6, 7, 8, 8, 9, 5, 2, 5, 2, 1, 3, 8, 5, 2, 2, 5, 4, 9, 9, 5, 4, 6, 6, 6, 7, 2, 7, 8, 2, 3, 9, 8, + 6, 4, 5, 6, 5, 9, 6, 1, 1, 6, 3, 5, 4, 8, 8, 6, 2, 3, 0, 5, 7, 7, 4, 5, 6, 4, 9, 8, 0, 3, 5, 5, 9, 3, 6, 3, 4, 5, 6, 8, 1, 7, 4, 3, 2, 4, 1, 1, 2, 5, 1, 5, 0, 7, 6, 0, 6, 9, 4, 7, 9, 4, 5, 1, 0, 9, 6, 5, 9, 6, + 0, 9, 4, 0, 2, 5, 2, 2, 8, 8, 7, 9, 7, 1, 0, 8, 9, 3, 1, 4, 5, 6, 6, 9, 1, 3, 6, 8, 6, 7, 2, 2, 8, 7, 4, 8, 9, 4, 0, 5, 6, 0, 1, 0, 1, 5, 0, 3, 3, 0, 8, 6, 1, 7, 9, 2, 8, 6, 8, 0, 9, 2, 0, 8, 7, 4, 7, 6, 0, 9, + 1, 7, 8, 2, 4, 9, 3, 8, 5, 8, 9, 0, 0, 9, 7, 1, 4, 9, 0, 9, 6, 7, 5, 9, 8, 5, 2, 6, 1, 3, 6, 5, 5, 4, 9, 7, 8, 1, 8, 9, 3, 1, 2, 9, 7, 8, 4, 8, 2, 1, 6, 8, 2, 9, 9, 8, 9, 4, 8, 7, 2, 2, 6, 5, 8, 8, 0, 4, 8, 5, + 7, 5, 6, 4, 0, 1, 4, 2, 7, 0, 4, 7, 7, 5, 5, 5, 1, 3, 2, 3, 7, 9, 6, 4, 1, 4, 5, 1, 5, 2, 3, 7, 4, 6, 2, 3, 4, 3, 6, 4, 5, 4, 2, 8, 5, 8, 4, 4, 4, 7, 9, 5, 2, 6, 5, 8, 6, 7, 8, 2, 1, 0, 5, 1, 1, 4, 1, 3, 5, 4, + 7, 3, 5, 7, 3, 9, 5, 2, 3, 1, 1, 3, 4, 2, 7, 1, 6, 6, 1, 0, 2, 1, 3, 5, 9, 6, 9, 5, 3, 6, 2, 3, 1, 4, 4, 2, 9, 5, 2, 4, 8, 4, 9, 3, 7, 1, 8, 7, 1, 1, 0, 1, 4, 5, 7, 6, 5, 4, 0, 3, 5, 9, 0, 2, 7, 9, 9, 3, 4, 4, + 0, 3, 7, 4, 2, 0, 0, 7, 3, 1, 0, 5, 7, 8, 5, 3, 9, 0, 6, 2, 1, 9, 8, 3, 8, 7, 4, 4, 7, 8, 0, 8, 4, 7, 8, 4, 8, 9, 6, 8, 3, 3, 2, 1, 4, 4, 5, 7, 1, 3, 8, 6, 8, 7, 5, 1, 9, 4, 3, 5, 0, 6, 4, 3, 0, 2, 1, 8, 4, 5, + 3, 1, 9, 1, 0, 4, 8, 4, 8, 1, 0, 0, 5, 3, 7, 0, 6, 1, 4, 6, 8, 0, 6, 7, 4, 9, 1, 9, 2, 7, 8, 1, 9, 1, 1, 9, 7, 9, 3, 9, 9, 5, 2, 0, 6, 1, 4, 1, 9, 6, 6, 3, 4, 2, 8, 7, 5, 4, 4, 4, 0, 6, 4, 3, 7, 4, 5, 1, 2, 3, + 7, 1, 8, 1, 9, 2, 1, 7, 9, 9, 9, 8, 3, 9, 1, 0, 1, 5, 9, 1, 9, 5, 6, 1, 8, 1, 4, 6, 7, 5, 1, 4, 2, 6, 9, 1, 2, 3, 9, 7, 4, 8, 9, 4, 0, 9, 0, 7, 1, 8, 6, 4, 9, 4, 2, 3, 1, 9, 6, 1, 5, 6, 7, 9, 4, 5, 2, 0, 8, 0, + 9, 5, 1, 4, 6, 5, 5, 0, 2, 2, 5, 2, 3, 1, 6, 0, 3, 8, 8, 1, 9, 3, 0, 1, 4, 2, 0, 9, 3, 7, 6, 2, 1, 3, 7, 8, 5, 5, 9, 5, 6, 6, 3, 8, 9, 3, 7, 7, 8, 7, 0, 8, 3, 0, 3, 9, 0, 6, 9, 7, 9, 2, 0, 7, 7, 3, 4, 6, 7, 2, + 2, 1, 8, 2, 5, 6, 2, 5, 9, 9, 6, 6, 1, 5, 0, 1, 4, 2, 1, 5, 0, 3, 0, 6, 8, 0, 3, 8, 4, 4, 7, 7, 3, 4, 5, 4, 9, 2, 0, 2, 6, 0, 5, 4, 1, 4, 6, 6, 5, 9, 2, 5, 2, 0, 1, 4, 9, 7, 4, 4, 2, 8, 5, 0, 7, 3, 2, 5, 1, 8, + 6, 6, 6, 0, 0, 2, 1, 3, 2, 4, 3, 4, 0, 8, 8, 1, 9, 0, 7, 1, 0, 4, 8, 6, 3, 3, 1, 7, 3, 4, 6, 4, 9, 6, 5, 1, 4, 5, 3, 9, 0, 5, 7, 9, 6, 2, 6, 8, 5, 6, 1, 0, 0, 5, 5, 0, 8, 1, 0, 6, 6, 5, 8, 7, 9, 6, 9, 9, 8, 1, + 6, 3, 5, 7, 4, 7, 3, 6, 3, 8, 4, 0, 5, 2, 5, 7, 1, 4, 5, 9, 1, 0, 2, 8, 9, 7, 0, 6, 4, 1, 4, 0, 1, 1, 0, 9, 7, 1, 2, 0, 6, 2, 8, 0, 4, 3, 9, 0, 3, 9, 7, 5, 9, 5, 1, 5, 6, 7, 7, 1, 5, 7, 7, 0, 0, 4, 2, 0, 3, 3, + 7, 8, 6, 9, 9, 3, 6, 0, 0, 7, 2, 3, 0, 5, 5, 8, 7, 6, 3, 1, 7, 6, 3, 5, 9, 4, 2, 1, 8, 7, 3, 1, 2, 5, 1, 4, 7, 1, 2, 0, 5, 3, 2, 9, 2, 8, 1, 9, 1, 8, 2, 6, 1, 8, 6, 1, 2, 5, 8, 6, 7, 3, 2, 1, 5, 7, 9, 1, 9, 8, + 4, 1, 4, 8, 4, 8, 8, 2, 9, 1, 6, 4, 4, 7, 0, 6, 0, 9, 5, 7, 5, 2, 7, 0, 6, 9, 5, 7, 2, 2, 0, 9, 1, 7, 5, 6, 7, 1, 1, 6, 7, 2, 2, 9, 1, 0, 9, 8, 1, 6, 9, 0, 9, 1, 5, 2, 8, 0, 1, 7, 3, 5, 0, 6, 7, 1, 2, 7, 4, 8, + 5, 8, 3, 2, 2, 2, 8, 7, 1, 8, 3, 5, 2, 0, 9, 3, 5, 3, 9, 6, 5, 7, 2, 5, 1, 2, 1, 0, 8, 3, 5, 7, 9, 1, 5, 1, 3, 6, 9, 8, 8, 2, 0, 9, 1, 4, 4, 4, 2, 1, 0, 0, 6, 7, 5, 1, 0, 3, 3, 4, 6, 7, 1, 1, 0, 3, 1, 4, 1, 2, + 6, 7, 1, 1, 1, 3, 6, 9, 9, 0, 8, 6, 5, 8, 5, 1, 6, 3, 9, 8, 3, 1, 5, 0, 1, 9, 7, 0, 1, 6, 5, 1, 5, 1, 1, 6, 8, 5, 1, 7, 1, 4, 3, 7, 6, 5, 7, 6, 1, 8, 3, 5, 1, 5, 5, 6, 5, 0, 8, 8, 4, 9, 0, 9, 9, 8, 9, 8, 5, 9, + 9, 8, 2, 3, 8, 7, 3, 4, 5, 5, 2, 8, 3, 3, 1, 6, 3, 5, 5, 0, 7, 6, 4, 7, 9, 1, 8, 5, 3, 5, 8, 9, 3, 2, 2, 6, 1, 8, 5, 4, 8, 9, 6, 3, 2, 1, 3, 2, 9, 3, 3, 0, 8, 9, 8, 5, 7, 0, 6, 4, 2, 0, 4, 6, 7, 5, 2, 5, 9, 0, + 7, 0, 9, 1, 5, 4, 8, 1, 4, 1, 6, 5, 4, 9, 8, 5, 9, 4, 6, 1, 6, 3, 7, 1, 8, 0, 2, 7, 0, 9, 8, 1, 9, 9, 4, 3, 0, 9, 9, 2, 4, 4, 8, 8, 9, 5, 7, 5, 7, 1, 2, 8, 2, 8, 9, 0, 5, 9, 2, 3, 2, 3, 3, 2, 6, 0, 9, 7, 2, 9, + 9, 7, 1, 2, 0, 8, 4, 4, 3, 3, 5, 7, 3, 2, 6, 5, 4, 8, 9, 3, 8, 2, 3, 9, 1, 1, 9, 3, 2, 5, 9, 7, 4, 6, 3, 6, 6, 7, 3, 0, 5, 8, 3, 6, 0, 4, 1, 4, 2, 8, 1, 3, 8, 8, 3, 0, 3, 2, 0, 3, 8, 2, 4, 9, 0, 3, 7, 5, 8, 9, + 8, 5, 2, 4, 3, 7, 4, 4, 1, 7, 0, 2, 9, 1, 3, 2, 7, 6, 5, 6, 1, 8, 0, 9, 3, 7, 7, 3, 4, 4, 4, 0, 3, 0, 7, 0, 7, 4, 6, 9, 2, 1, 1, 2, 0, 1, 9, 1, 3, 0, 2, 0, 3, 3, 0, 3, 8, 0, 1, 9, 7, 6, 2, 1, 1, 0, 1, 1, 0, 0, + 4, 4, 9, 2, 9, 3, 2, 1, 5, 1, 6, 0, 8, 4, 2, 4, 4, 4, 8, 5, 9, 6, 3, 7, 6, 6, 9, 8, 3, 8, 9, 5, 2, 2, 8, 6, 8, 4, 7, 8, 3, 1, 2, 3, 5, 5, 2, 6, 5, 8, 2, 1, 3, 1, 4, 4, 9, 5, 7, 6, 8, 5, 7, 2, 6, 2, 4, 3, 3, 4, + 4, 1, 8, 9, 3, 0, 3, 9, 6, 8, 6, 4, 2, 6, 2, 4, 3, 4, 1, 0, 7, 7, 3, 2, 2, 6, 9, 7, 8, 0, 2, 8, 0, 7, 3, 1, 8, 9, 1, 5, 4, 4, 1, 1, 0, 1, 0, 4, 4, 6, 8, 2, 3, 2, 5, 2, 7, 1, 6, 2, 0, 1, 0, 5, 2, 6, 5, 2, 2, 7, + 2, 1, 1, 1, 6, 6, 0, 3, 9, 6, 6, 6, 5, 5, 7, 3, 0, 9, 2, 5, 4, 7, 1, 1, 0, 5, 5, 7, 8, 5, 3, 7, 6, 3, 4, 6, 6, 8, 2, 0, 6, 5, 3, 1, 0, 9, 8, 9, 6, 5, 2, 6, 9, 1, 8, 6, 2, 0, 5, 6, 4, 7, 6, 9, 3, 1, 2, 5, 7, 0, + 5, 8, 6, 3, 5, 6, 6, 2, 0, 1, 8, 5, 5, 8, 1, 0, 0, 7, 2, 9, 3, 6, 0, 6, 5, 9, 8, 7, 6, 4, 8, 6, 1, 1, 7, 9, 1, 0, 4, 5, 3, 3, 4, 8, 8, 5, 0, 3, 4, 6, 1, 1, 3, 6, 5, 7, 6, 8, 6, 7, 5, 3, 2, 4, 9, 4, 4, 1, 6, 6, + 8, 0, 3, 9, 6, 2, 6, 5, 7, 9, 7, 8, 7, 7, 1, 8, 5, 5, 6, 0, 8, 4, 5, 5, 2, 9, 6, 5, 4, 1, 2, 6, 6, 5, 4, 0, 8, 5, 3, 0, 6, 1, 4, 3, 4, 4, 4, 3, 1, 8, 5, 8, 6, 7, 6, 9, 7, 5, 1, 4, 5, 6, 6, 1, 4, 0, 6, 8, 0, 0, + 7, 0, 0, 2, 3, 7, 8, 7, 7, 6, 5, 9, 1, 3, 4, 4, 0, 1, 7, 1, 2, 7, 4, 9, 4, 7, 0, 4, 2, 0, 5, 6, 2, 2, 3, 0, 5, 3, 8, 9, 9, 4, 5, 6, 1, 3, 1, 4, 0, 7, 1, 1, 2, 7, 0, 0, 0, 4, 0, 7, 8, 5, 4, 7, 3, 3, 2, 6, 9, 9, + 3, 9, 0, 8, 1, 4, 5, 4, 6, 6, 4, 6, 4, 5, 8, 8, 0, 7, 9, 7, 2, 7, 0, 8, 2, 6, 6, 8, 3, 0, 6, 3, 4, 3, 2, 8, 5, 8, 7, 8, 5, 6, 9, 8, 3, 0, 5, 2, 3, 5, 8, 0, 8, 9, 3, 3, 0, 6, 5, 7, 5, 7, 4, 0, 6, 7, 9, 5, 4, 5, + 7, 1, 6, 3, 7, 7, 5, 2, 5, 4, 2, 0, 2, 1, 1, 4, 9, 5, 5, 7, 6, 1, 5, 8, 1, 4, 0, 0, 2, 5, 0, 1, 2, 6, 2, 2, 8, 5, 9, 4, 1, 3, 0, 2, 1, 6, 4, 7, 1, 5, 5, 0, 9, 7, 9, 2, 5, 9, 2, 3, 0, 9, 9, 0, 7, 9, 6, 5, 4, 7, + 3, 7, 6, 1, 2, 5, 5, 1, 7, 6, 5, 6, 7, 5, 1, 3, 5, 7, 5, 1, 7, 8, 2, 9, 6, 6, 6, 4, 5, 4, 7, 7, 9, 1, 7, 4, 5, 0, 1, 1, 2, 9, 9, 6, 1, 4, 8, 9, 0, 3, 0, 4, 6, 3, 9, 9, 4, 7, 1, 3, 2, 9, 6, 2, 1, 0, 7, 3, 4, 0, + 4, 3, 7, 5, 1, 8, 9, 5, 7, 3, 5, 9, 6, 1, 4, 5, 8, 9, 0, 1, 9, 3, 8, 9, 7, 1, 3, 1, 1, 1, 7, 9, 0, 4, 2, 9, 7, 8, 2, 8, 5, 6, 4, 7, 5, 0, 3, 2, 0, 3, 1, 9, 8, 6, 9, 1, 5, 1, 4, 0, 2, 8, 7, 0, 8, 0, 8, 5, 9, 9, + 0, 4, 8, 0, 1, 0, 9, 4, 1, 2, 1, 4, 7, 2, 2, 1, 3, 1, 7, 9, 4, 7, 6, 4, 7, 7, 7, 2, 6, 2, 2, 4, 1, 4, 2, 5, 4, 8, 5, 4, 5, 4, 0, 3, 3, 2, 1, 5, 7, 1, 8, 5, 3, 0, 6, 1, 4, 2, 2, 8, 8, 1, 3, 7, 5, 8, 5, 0, 4, 3, + 0, 6, 3, 3, 2, 1, 7, 5, 1, 8, 2, 9, 7, 9, 8, 6, 6, 2, 2, 3, 7, 1, 7, 2, 1, 5, 9, 1, 6, 0, 7, 7, 1, 6, 6, 9, 2, 5, 4, 7, 4, 8, 7, 3, 8, 9, 8, 6, 6, 5, 4, 9, 4, 9, 4, 5, 0, 1, 1, 4, 6, 5, 4, 0, 6, 2, 8, 4, 3, 3, + 6, 6, 3, 9, 3, 7, 9, 0, 0, 3, 9, 7, 6, 9, 2, 6, 5, 6, 7, 2, 1, 4, 6, 3, 8, 5, 3, 0, 6, 7, 3, 6, 0, 9, 6, 5, 7, 1, 2, 0, 9, 1, 8, 0, 7, 6, 3, 8, 3, 2, 7, 1, 6, 6, 4, 1, 6, 2, 7, 4, 8, 8, 8, 8, 0, 0, 7, 8, 6, 9, + 2, 5, 6, 0, 2, 9, 0, 2, 2, 8, 4, 7, 2, 1, 0, 4, 0, 3, 1, 7, 2, 1, 1, 8, 6, 0, 8, 2, 0, 4, 1, 9, 0, 0, 0, 4, 2, 2, 9, 6, 6, 1, 7, 1, 1, 9, 6, 3, 7, 7, 9, 2, 1, 3, 3, 7, 5, 7, 5, 1, 1, 4, 9, 5, 9, 5, 0, 1, 5, 6, + 6, 0, 4, 9, 6, 3, 1, 8, 6, 2, 9, 4, 7, 2, 6, 5, 4, 7, 3, 6, 4, 2, 5, 2, 3, 0, 8, 1, 7, 7, 0, 3, 6, 7, 5, 1, 5, 9, 0, 6, 7, 3, 5, 0, 2, 3, 5, 0, 7, 2, 8, 3, 5, 4, 0, 5, 6, 7, 0, 4, 0, 3, 8, 6, 7, 4, 3, 5, 1, 3, + 6, 2, 2, 2, 2, 4, 7, 7, 1, 5, 8, 9, 1, 5, 0, 4, 9, 5, 3, 0, 9, 8, 4, 4, 4, 8, 9, 3, 3, 3, 0, 9, 6, 3, 4, 0, 8, 7, 8, 0, 7, 6, 9, 3, 2, 5, 9, 9, 3, 9, 7, 8, 0, 5, 4, 1, 9, 3, 4, 1, 4, 4, 7, 3, 7, 7, 4, 4, 1, 8, + 4, 2, 6, 3, 1, 2, 9, 8, 6, 0, 8, 0, 9, 9, 8, 8, 8, 6, 8, 7, 4, 1, 3, 2, 6, 0, 4, 7, 2, 1, 5, 6, 9, 5, 1, 6, 2, 3, 9, 6, 5, 8, 6, 4, 5, 7, 3, 0, 2, 1, 6, 3, 1, 5, 9, 8, 1, 9, 3, 1, 9, 5, 1, 6, 7, 3, 5, 3, 8, 1, + 2, 9, 7, 4, 1, 6, 7, 7, 2, 9, 4, 7, 8, 6, 7, 2, 4, 2, 2, 9, 2, 4, 6, 5, 4, 3, 6, 6, 8, 0, 0, 9, 8, 0, 6, 7, 6, 9, 2, 8, 2, 3, 8, 2, 8, 0, 6, 8, 9, 9, 6, 4, 0, 0, 4, 8, 2, 4, 3, 5, 4, 0, 3, 7, 0, 1, 4, 1, 6, 3, + 1, 4, 9, 6, 5, 8, 9, 7, 9, 4, 0, 9, 2, 4, 3, 2, 3, 7, 8, 9, 6, 9, 0, 7, 0, 6, 9, 7, 7, 9, 4, 2, 2, 3, 6, 2, 5, 0, 8, 2, 2, 1, 6, 8, 8, 9, 5, 7, 3, 8, 3, 7, 9, 8, 6, 2, 3, 0, 0, 1, 5, 9, 3, 7, 7, 6, 4, 7, 1, 6, + 5, 1, 2, 2, 8, 9, 3, 5, 7, 8, 6, 0, 1, 5, 8, 8, 1, 6, 1, 7, 5, 5, 7, 8, 2, 9, 7, 3, 5, 2, 3, 3, 4, 4, 6, 0, 4, 2, 8, 1, 5, 1, 2, 6, 2, 7, 2, 0, 3, 7, 3, 4, 3, 1, 4, 6, 5, 3, 1, 9, 7, 7, 7, 7, 4, 1, 6, 0, 3, 1, + 9, 9, 0, 6, 6, 5, 5, 4, 1, 8, 7, 6, 3, 9, 7, 9, 2, 9, 3, 3, 4, 4, 1, 9, 5, 2, 1, 5, 4, 1, 3, 4, 1, 8, 9, 9, 4, 8, 5, 4, 4, 4, 7, 3, 4, 5, 6, 7, 3, 8, 3, 1, 6, 2, 4, 9, 9, 3, 4, 1, 9, 1, 3, 1, 8, 1, 4, 8, 0, 9, + 2, 7, 7, 7, 7, 1, 0, 3, 8, 6, 3, 8, 7, 7, 3, 4, 3, 1, 7, 7, 2, 0, 7, 5, 4, 5, 6, 5, 4, 5, 3, 2, 2, 0, 7, 7, 7, 0, 9, 2, 1, 2, 0, 1, 9, 0, 5, 1, 6, 6, 0, 9, 6, 2, 8, 0, 4, 9, 0, 9, 2, 6, 3, 6, 0, 1, 9, 7, 5, 9, + 8, 8, 2, 8, 1, 6, 1, 3, 3, 2, 3, 1, 6, 6, 6, 3, 6, 5, 2, 8, 6, 1, 9, 3, 2, 6, 6, 8, 6, 3, 3, 6, 0, 6, 2, 7, 3, 5, 6, 7, 6, 3, 0, 3, 5, 4, 4, 7, 7, 6, 2, 8, 0, 3, 5, 0, 4, 5, 0, 7, 7, 7, 2, 3, 5, 5, 4, 7, 1, 0, + 5, 8, 5, 9, 5, 4, 8, 7, 0, 2, 7, 9, 0, 8, 1, 4, 3, 5, 6, 2, 4, 0, 1, 4, 5, 1, 7, 1, 8, 0, 6, 2, 4, 6, 4, 3, 6, 2, 6, 7, 9, 4, 5, 6, 1, 2, 7, 5, 3, 1, 8, 1, 3, 4, 0, 7, 8, 3, 3, 0, 3, 3, 6, 2, 5, 4, 2, 3, 2, 7, + 8, 3, 9, 4, 4, 9, 7, 5, 3, 8, 2, 4, 3, 7, 2, 0, 5, 8, 3, 5, 3, 1, 1, 4, 7, 7, 1, 1, 9, 9, 2, 6, 0, 6, 3, 8, 1, 3, 3, 4, 6, 7, 7, 6, 8, 7, 9, 6, 9, 5, 9, 7, 0, 3, 0, 9, 8, 3, 3, 9, 1, 3, 0, 7, 7, 1, 0, 9, 8, 7, + 0, 4, 0, 8, 5, 9, 1, 3, 3, 7, 4, 6, 4, 1, 4, 4, 2, 8, 2, 2, 7, 7, 2, 6, 3, 4, 6, 5, 9, 4, 7, 0, 4, 7, 4, 5, 8, 7, 8, 4, 7, 7, 8, 7, 2, 0, 1, 9, 2, 7, 7, 1, 5, 2, 8, 0, 7, 3, 1, 7, 6, 7, 9, 0, 7, 7, 0, 7, 1, 5, + 7, 2, 1, 3, 4, 4, 4, 7, 3, 0, 6, 0, 5, 7, 0, 0, 7, 3, 3, 4, 9, 2, 4, 3, 6, 9, 3, 1, 1, 3, 8, 3, 5, 0, 4, 9, 3, 1, 6, 3, 1, 2, 8, 4, 0, 4, 2, 5, 1, 2, 1, 9, 2, 5, 6, 5, 1, 7, 9, 8, 0, 6, 9, 4, 1, 1, 3, 5, 2, 8, + 0, 1, 3, 1, 4, 7, 0, 1, 3, 0, 4, 7, 8, 1, 6, 4, 3, 7, 8, 8, 5, 1, 8, 5, 2, 9, 0, 9, 2, 8, 5, 4, 5, 2, 0, 1, 1, 6, 5, 8, 3, 9, 3, 4, 1, 9, 6, 5, 6, 2, 1, 3, 4, 9, 1, 4, 3, 4, 1, 5, 9, 5, 6, 2, 5, 8, 6, 5, 8, 6, + 5, 5, 7, 0, 5, 5, 2, 6, 9, 0, 4, 9, 6, 5, 2, 0, 9, 8, 5, 8, 0, 3, 3, 8, 5, 0, 7, 2, 2, 4, 2, 6, 4, 8, 2, 9, 3, 9, 7, 2, 8, 5, 8, 4, 7, 8, 3, 1, 6, 3, 0, 5, 7, 7, 7, 7, 5, 6, 0, 6, 8, 8, 8, 7, 6, 4, 4, 6, 2, 4, + 8, 2, 4, 6, 8, 5, 7, 9, 2, 6, 0, 3, 9, 5, 3, 5, 2, 7, 7, 3, 4, 8, 0, 3, 0, 4, 8, 0, 2, 9, 0, 0, 5, 8, 7, 6, 0, 7, 5, 8, 2, 5, 1, 0, 4, 7, 4, 7, 0, 9, 1, 6, 4, 3, 9, 6, 1, 3, 6, 2, 6, 7, 6, 0, 4, 4, 9, 2, 5, 6, + 2, 7, 4, 2, 0, 4, 2, 0, 8, 3, 2, 0, 8, 5, 6, 6, 1, 1, 9, 0, 6, 2, 5, 4, 5, 4, 3, 3, 7, 2, 1, 3, 1, 5, 3, 5, 9, 5, 8, 4, 5, 0, 6, 8, 7, 7, 2, 4, 6, 0, 2, 9, 0, 1, 6, 1, 8, 7, 6, 6, 7, 9, 5, 2, 4, 0, 6, 1, 6, 3, + 4, 2, 5, 2, 2, 5, 7, 7, 1, 9, 5, 4, 2, 9, 1, 6, 2, 9, 9, 1, 9, 3, 0, 6, 4, 5, 5, 3, 7, 7, 9, 9, 1, 4, 0, 3, 7, 3, 4, 0, 4, 3, 2, 8, 7, 5, 2, 6, 2, 8, 8, 8, 9, 6, 3, 9, 9, 5, 8, 7, 9, 4, 7, 5, 7, 2, 9, 1, 7, 4, + 6, 4, 2, 6, 3, 5, 7, 4, 5, 5, 2, 5, 4, 0, 7, 9, 0, 9, 1, 4, 5, 1, 3, 5, 7, 1, 1, 1, 3, 6, 9, 4, 1, 0, 9, 1, 1, 9, 3, 9, 3, 2, 5, 1, 9, 1, 0, 7, 6, 0, 2, 0, 8, 2, 5, 2, 0, 2, 6, 1, 8, 7, 9, 8, 5, 3, 1, 8, 8, 7, + 7, 0, 5, 8, 4, 2, 9, 7, 2, 5, 9, 1, 6, 7, 7, 8, 1, 3, 1, 4, 9, 6, 9, 9, 0, 0, 9, 0, 1, 9, 2, 1, 1, 6, 9, 7, 1, 7, 3, 7, 2, 7, 8, 4, 7, 6, 8, 4, 7, 2, 6, 8, 6, 0, 8, 4, 9, 0, 0, 3, 3, 7, 7, 0, 2, 4, 2, 4, 2, 9, + 1, 6, 5, 1, 3, 0, 0, 5, 0, 0, 5, 1, 6, 8, 3, 2, 3, 3, 6, 4, 3, 5, 0, 3, 8, 9, 5, 1, 7, 0, 2, 9, 8, 9, 3, 9, 2, 2, 3, 3, 4, 5, 1, 7, 2, 2, 0, 1, 3, 8, 1, 2, 8, 0, 6, 9, 6, 5, 0, 1, 1, 7, 8, 4, 4, 0, 8, 7, 4, 5, + 1, 9, 6, 0, 1, 2, 1, 2, 2, 8, 5, 9, 9, 3, 7, 1, 6, 2, 3, 1, 3, 0, 1, 7, 1, 1, 4, 4, 4, 8, 4, 6, 4, 0, 9, 0, 3, 8, 9, 0, 6, 4, 4, 9, 5, 4, 4, 4, 0, 0, 6, 1, 9, 8, 6, 9, 0, 7, 5, 4, 8, 5, 1, 6, 0, 2, 6, 3, 2, 7, + 5, 0, 5, 2, 9, 8, 3, 4, 9, 1, 8, 7, 4, 0, 7, 8, 6, 6, 8, 0, 8, 8, 1, 8, 3, 3, 8, 5, 1, 0, 2, 2, 8, 3, 3, 4, 5, 0, 8, 5, 0, 4, 8, 6, 0, 8, 2, 5, 0, 3, 9, 3, 0, 2, 1, 3, 3, 2, 1, 9, 7, 1, 5, 5, 1, 8, 4, 3, 0, 6, + 3, 5, 4, 5, 5, 0, 0, 7, 6, 6, 8, 2, 8, 2, 9, 4, 9, 3, 0, 4, 1, 3, 7, 7, 6, 5, 5, 2, 7, 9, 3, 9, 7, 5, 1, 7, 5, 4, 6, 1, 3, 9, 5, 3, 9, 8, 4, 6, 8, 3, 3, 9, 3, 6, 3, 8, 3, 0, 4, 7, 4, 6, 1, 1, 9, 9, 6, 6, 5, 3, + 8, 5, 8, 1, 5, 3, 8, 4, 2, 0, 5, 6, 8, 5, 3, 3, 8, 6, 2, 1, 8, 6, 7, 2, 5, 2, 3, 3, 4, 0, 2, 8, 3, 0, 8, 7, 1, 1, 2, 3, 2, 8, 2, 7, 8, 9, 2, 1, 2, 5, 0, 7, 7, 1, 2, 6, 2, 9, 4, 6, 3, 2, 2, 9, 5, 6, 3, 9, 8, 9, + 8, 9, 8, 9, 3, 5, 8, 2, 1, 1, 6, 7, 4, 5, 6, 2, 7, 0, 1, 0, 2, 1, 8, 3, 5, 6, 4, 6, 2, 2, 0, 1, 3, 4, 9, 6, 7, 1, 5, 1, 8, 8, 1, 9, 0, 9, 7, 3, 0, 3, 8, 1, 1, 9, 8, 0, 0, 4, 9, 7, 3, 4, 0, 7, 2, 3, 9, 6, 1, 0, + 3, 6, 8, 5, 4, 0, 6, 6, 4, 3, 1, 9, 3, 9, 5, 0, 9, 7, 9, 0, 1, 9, 0, 6, 9, 9, 6, 3, 9, 5, 5, 2, 4, 5, 3, 0, 0, 5, 4, 5, 0, 5, 8, 0, 6, 8, 5, 5, 0, 1, 9, 5, 6, 7, 3, 0, 2, 2, 9, 2, 1, 9, 1, 3, 9, 3, 3, 9, 1, 8, + 5, 6, 8, 0, 3, 4, 4, 9, 0, 3, 9, 8, 2, 0, 5, 9, 5, 5, 1, 0, 0, 2, 2, 6, 3, 5, 3, 5, 3, 6, 1, 9, 2, 0, 4, 1, 9, 9, 4, 7, 4, 5, 5, 3, 8, 5, 9, 3, 8, 1, 0, 2, 3, 4, 3, 9, 5, 5, 4, 4, 9, 5, 9, 7, 7, 8, 3, 7, 7, 9, + 0, 2, 3, 7, 4, 2, 1, 6, 1, 7, 2, 7, 1, 1, 1, 7, 2, 3, 6, 4, 3, 4, 3, 5, 4, 3, 9, 4, 7, 8, 2, 2, 1, 8, 1, 8, 5, 2, 8, 6, 2, 4, 0, 8, 5, 1, 4, 0, 0, 6, 6, 6, 0, 4, 4, 3, 3, 2, 5, 8, 8, 8, 5, 6, 9, 8, 6, 7, 0, 5, + 4, 3, 1, 5, 4, 7, 0, 6, 9, 6, 5, 7, 4, 7, 4, 5, 8, 5, 5, 0, 3, 3, 2, 3, 2, 3, 3, 4, 2, 1, 0, 7, 3, 0, 1, 5, 4, 5, 9, 4, 0, 5, 1, 6, 5, 5, 3, 7, 9, 0, 6, 8, 6, 6, 2, 7, 3, 3, 3, 7, 9, 9, 5, 8, 5, 1, 1, 5, 6, 2, + 5, 7, 8, 4, 3, 2, 2, 9, 8, 8, 2, 7, 3, 7, 2, 3, 1, 9, 8, 9, 8, 7, 5, 7, 1, 4, 1, 5, 9, 5, 7, 8, 1, 1, 1, 9, 6, 3, 5, 8, 3, 3, 0, 0, 5, 9, 4, 0, 8, 7, 3, 0, 6, 8, 1, 2, 1, 6, 0, 2, 8, 7, 6, 4, 9, 6, 2, 8, 6, 7, + 4, 4, 6, 0, 4, 7, 7, 4, 6, 4, 9, 1, 5, 9, 9, 5, 0, 5, 4, 9, 7, 3, 7, 4, 2, 5, 6, 2, 6, 9, 0, 1, 0, 4, 9, 0, 3, 7, 7, 8, 1, 9, 8, 6, 8, 3, 5, 9, 3, 8, 1, 4, 6, 5, 7, 4, 1, 2, 6, 8, 0, 4, 9, 2, 5, 6, 4, 8, 7, 9, + 8, 5, 5, 6, 1, 4, 5, 3, 7, 2, 3, 4, 7, 8, 6, 7, 3, 3, 0, 3, 9, 0, 4, 6, 8, 8, 3, 8, 3, 4, 3, 6, 3, 4, 6, 5, 5, 3, 7, 9, 4, 9, 8, 6, 4, 1, 9, 2, 7, 0, 5, 6, 3, 8, 7, 2, 9, 3, 1, 7, 4, 8, 7, 2, 3, 3, 2, 0, 8, 3, + 7, 6, 0, 1, 1, 2, 3, 0, 2, 9, 9, 1, 1, 3, 6, 7, 9, 3, 8, 6, 2, 7, 0, 8, 9, 4, 3, 8, 7, 9, 9, 3, 6, 2, 0, 1, 6, 2, 9, 5, 1, 5, 4, 1, 3, 3, 7, 1, 4, 2, 4, 8, 9, 2, 8, 3, 0, 7, 2, 2, 0, 1, 2, 6, 9, 0, 1, 4, 7, 5, + 4, 6, 6, 8, 4, 7, 6, 5, 3, 5, 7, 6, 1, 6, 4, 7, 7, 3, 7, 9, 4, 6, 7, 5, 2, 0, 0, 4, 9, 0, 7, 5, 7, 1, 5, 5, 5, 2, 7, 8, 1, 9, 6, 5, 3, 6, 2, 1, 3, 2, 3, 9, 2, 6, 4, 0, 6, 1, 6, 0, 1, 3, 6, 3, 5, 8, 1, 5, 5, 9, + 0, 7, 4, 2, 2, 0, 2, 0, 2, 0, 3, 1, 8, 7, 2, 7, 7, 6, 0, 5, 2, 7, 7, 2, 1, 9, 0, 0, 5, 5, 6, 1, 4, 8, 4, 2, 5, 5, 5, 1, 8, 7, 9, 2, 5, 3, 0, 3, 4, 3, 5, 1, 3, 9, 8, 4, 4, 2, 5, 3, 2, 2, 3, 4, 1, 5, 7, 6, 2, 3, + 3, 6, 1, 0, 6, 4, 2, 5, 0, 6, 3, 9, 0, 4, 9, 7, 5, 0, 0, 8, 6, 5, 6, 2, 7, 1, 0, 9, 5, 3, 5, 9, 1, 9, 4, 6, 5, 8, 9, 7, 5, 1, 4, 1, 3, 1, 0, 3, 4, 8, 2, 2, 7, 6, 9, 3, 0, 6, 2, 4, 7, 4, 3, 5, 3, 6, 3, 2, 5, 6, + 9, 1, 6, 0, 7, 8, 1, 5, 4, 7, 8, 1, 8, 1, 1, 5, 2, 8, 4, 3, 6, 6, 7, 9, 5, 7, 0, 6, 1, 1, 0, 8, 6, 1, 5, 3, 3, 1, 5, 0, 4, 4, 5, 2, 1, 2, 7, 4, 7, 3, 9, 2, 4, 5, 4, 4, 9, 4, 5, 4, 2, 3, 6, 8, 2, 8, 8, 6, 0, 6, + 1, 3, 4, 0, 8, 4, 1, 4, 8, 6, 3, 7, 7, 6, 7, 0, 0, 9, 6, 1, 2, 0, 7, 1, 5, 1, 2, 4, 9, 1, 4, 0, 4, 3, 0, 2, 7, 2, 5, 3, 8, 6, 0, 7, 6, 4, 8, 2, 3, 6, 3, 4, 1, 4, 3, 3, 4, 6, 2, 3, 5, 1, 8, 9, 7, 5, 7, 6, 6, 4, + 5, 2, 1, 6, 4, 1, 3, 7, 6, 7, 9, 6, 9, 0, 3, 1, 4, 9, 5, 0, 1, 9, 1, 0, 8, 5, 7, 5, 9, 8, 4, 4, 2, 3, 9, 1, 9, 8, 6, 2, 9, 1, 6, 4, 2, 1, 9, 3, 9, 9, 4, 9, 0, 7, 2, 3, 6, 2, 3, 4, 6, 4, 6, 8, 4, 4, 1, 1, 7, 3, + 9, 4, 0, 3, 2, 6, 5, 9, 1, 8, 4, 0, 4, 4, 3, 7, 8, 0, 5, 1, 3, 3, 3, 8, 9, 4, 5, 2, 5, 7, 4, 2, 3, 9, 9, 5, 0, 8, 2, 9, 6, 5, 9, 1, 2, 2, 8, 5, 0, 8, 5, 5, 5, 8, 2, 1, 5, 7, 2, 5, 0, 3, 1, 0, 7, 1, 2, 5, 7, 0, + 1, 2, 6, 6, 8, 3, 0, 2, 4, 0, 2, 9, 2, 9, 5, 2, 5, 2, 2, 0, 1, 1, 8, 7, 2, 6, 7, 6, 7, 5, 6, 2, 2, 0, 4, 1, 5, 4, 2, 0, 5, 1, 6, 1, 8, 4, 1, 6, 3, 4, 8, 4, 7, 5, 6, 5, 1, 6, 9, 9, 9, 8, 1, 1, 6, 1, 4, 1, 0, 1, + 0, 0, 2, 9, 9, 6, 0, 7, 8, 3, 8, 6, 9, 0, 9, 2, 9, 1, 6, 0, 3, 0, 2, 8, 8, 4, 0, 0, 2, 6, 9, 1, 0, 4, 1, 4, 0, 7, 9, 2, 8, 8, 6, 2, 1, 5, 0, 7, 8, 4, 2, 4, 5, 1, 6, 7, 0, 9, 0, 8, 7, 0, 0, 0, 6, 9, 9, 2, 8, 2, + 1, 2, 0, 6, 6, 0, 4, 1, 8, 3, 7, 1, 8, 0, 6, 5, 3, 5, 5, 6, 7, 2, 5, 2, 5, 3, 2, 5, 6, 7, 5, 3, 2, 8, 6, 1, 2, 9, 1, 0, 4, 2, 4, 8, 7, 7, 6, 1, 8, 2, 5, 8, 2, 9, 7, 6, 5, 1, 5, 7, 9, 5, 9, 8, 4, 7, 0, 3, 5, 6, + 2, 2, 2, 6, 2, 9, 3, 4, 8, 6, 0, 0, 3, 4, 1, 5, 8, 7, 2, 2, 9, 8, 0, 5, 3, 4, 9, 8, 9, 6, 5, 0, 2, 2, 6, 2, 9, 1, 7, 4, 8, 7, 8, 8, 2, 0, 2, 7, 3, 4, 2, 0, 9, 2, 2, 2, 2, 4, 5, 3, 3, 9, 8, 5, 6, 2, 6, 4, 7, 6, + 6, 9, 1, 4, 9, 0, 5, 5, 6, 2, 8, 4, 2, 5, 0, 3, 9, 1, 2, 7, 5, 7, 7, 1, 0, 2, 8, 4, 0, 2, 7, 9, 9, 8, 0, 6, 6, 3, 6, 5, 8, 2, 5, 4, 8, 8, 9, 2, 6, 4, 8, 8, 0, 2, 5, 4, 5, 6, 6, 1, 0, 1, 7, 2, 9, 6, 7, 0, 2, 6, + 6, 4, 0, 7, 6, 5, 5, 9, 0, 4, 2, 9, 0, 9, 9, 4, 5, 6, 8, 1, 5, 0, 6, 5, 2, 6, 5, 3, 0, 5, 3, 7, 1, 8, 2, 9, 4, 1, 2, 7, 0, 3, 3, 6, 9, 3, 1, 3, 7, 8, 5, 1, 7, 8, 6, 0, 9, 0, 4, 0, 7, 0, 8, 6, 6, 7, 1, 1, 4, 9, + 6, 5, 5, 8, 3, 4, 3, 4, 3, 4, 7, 6, 9, 3, 3, 8, 5, 7, 8, 1, 7, 1, 1, 3, 8, 6, 4, 5, 5, 8, 7, 3, 6, 7, 8, 1, 2, 3, 0, 1, 4, 5, 8, 7, 6, 8, 7, 1, 2, 6, 6, 0, 3, 4, 8, 9, 1, 3, 9, 0, 9, 5, 6, 2, 0, 0, 9, 9, 3, 9, + 3, 6, 1, 0, 3, 1, 0, 2, 9, 1, 6, 1, 6, 1, 5, 2, 8, 8, 1, 3, 8, 4, 3, 7, 9, 0, 9, 9, 0, 4, 2, 3, 1, 7, 4, 7, 3, 3, 6, 3, 9, 4, 8, 0, 4, 5, 7, 5, 9, 3, 1, 4, 9, 3, 1, 4, 0, 5, 2, 9, 7, 6, 3, 4, 7, 5, 7, 4, 8, 1, + 1, 9, 3, 5, 6, 7, 0, 9, 1, 1, 0, 1, 3, 7, 7, 5, 1, 7, 2, 1, 0, 0, 8, 0, 3, 1, 5, 5, 9, 0, 2, 4, 8, 5, 3, 0, 9, 0, 6, 6, 9, 2, 0, 3, 7, 6, 7, 1, 9, 2, 2, 0, 3, 3, 2, 2, 9, 0, 9, 4, 3, 3, 4, 6, 7, 6, 8, 5, 1, 4, + 2, 2, 1, 4, 4, 7, 7, 3, 7, 9, 3, 9, 3, 7, 5, 1, 7, 0, 3, 4, 4, 3, 6, 6, 1, 9, 9, 1, 0, 4, 0, 3, 3, 7, 5, 1, 1, 1, 7, 3, 5, 4, 7, 1, 9, 1, 8, 5, 5, 0, 4, 6, 4, 4, 9, 0, 2, 6, 3, 6, 5, 5, 1, 2, 8, 1, 6, 2, 2, 8, + 8, 2, 4, 4, 6, 2, 5, 7, 5, 9, 1, 6, 3, 3, 3, 0, 3, 9, 1, 0, 7, 2, 2, 5, 3, 8, 3, 7, 4, 2, 1, 8, 2, 1, 4, 0, 8, 8, 3, 5, 0, 8, 6, 5, 7, 3, 9, 1, 7, 7, 1, 5, 0, 9, 6, 8, 2, 8, 8, 7, 4, 7, 8, 2, 6, 5, 6, 9, 9, 5, + 9, 9, 5, 7, 4, 4, 9, 0, 6, 6, 1, 7, 5, 8, 3, 4, 4, 1, 3, 7, 5, 2, 2, 3, 9, 7, 0, 9, 6, 8, 3, 4, 0, 8, 0, 0, 5, 3, 5, 5, 9, 8, 4, 9, 1, 7, 5, 4, 1, 7, 3, 8, 1, 8, 8, 3, 9, 9, 9, 4, 4, 6, 9, 7, 4, 8, 6, 7, 6, 2, + 6, 5, 5, 1, 6, 5, 8, 2, 7, 6, 5, 8, 4, 8, 3, 5, 8, 8, 4, 5, 3, 1, 4, 2, 7, 7, 5, 6, 8, 7, 9, 0, 0, 2, 9, 0, 9, 5, 1, 7, 0, 2, 8, 3, 5, 2, 9, 7, 1, 6, 3, 4, 4, 5, 6, 2, 1, 2, 9, 6, 4, 0, 4, 3, 5, 2, 3, 1, 1, 7, + 6, 0, 0, 6, 6, 5, 1, 0, 1, 2, 4, 1, 2, 0, 0, 6, 5, 9, 7, 5, 5, 8, 5, 1, 2, 7, 6, 1, 7, 8, 5, 8, 3, 8, 2, 9, 2, 0, 4, 1, 9, 7, 4, 8, 4, 4, 2, 3, 6, 0, 8, 0, 0, 7, 1, 9, 3, 0, 4, 5, 7, 6, 1, 8, 9, 3, 2, 3, 4, 9, + 2, 2, 9, 2, 7, 9, 6, 5, 0, 1, 9, 8, 7, 5, 1, 8, 7, 2, 1, 2, 7, 2, 6, 7, 5, 0, 7, 9, 8, 1, 2, 5, 5, 4, 7, 0, 9, 5, 8, 9, 0, 4, 5, 5, 6, 3, 5, 7, 9, 2, 1, 2, 2, 1, 0, 3, 3, 3, 4, 6, 6, 9, 7, 4, 9, 9, 2, 3, 5, 6, + 3, 0, 2, 5, 4, 9, 4, 7, 8, 0, 2, 4, 9, 0, 1, 1, 4, 1, 9, 5, 2, 1, 2, 3, 8, 2, 8, 1, 5, 3, 0, 9, 1, 1, 4, 0, 7, 9, 0, 7, 3, 8, 6, 0, 2, 5, 1, 5, 2, 2, 7, 4, 2, 9, 9, 5, 8, 1, 8, 0, 7, 2, 4, 7, 1, 6, 2, 5, 9, 1, + 6, 6, 8, 5, 4, 5, 1, 3, 3, 3, 1, 2, 3, 9, 4, 8, 0, 4, 9, 4, 7, 0, 7, 9, 1, 1, 9, 1, 5, 3, 2, 6, 7, 3, 4, 3, 0, 2, 8, 2, 4, 4, 1, 8, 6, 0, 4, 1, 4, 2, 6, 3, 6, 3, 9, 5, 4, 8, 0, 0, 0, 4, 4, 8, 0, 0, 2, 6, 7, 0, + 4, 9, 6, 2, 4, 8, 2, 0, 1, 7, 9, 2, 8, 9, 6, 4, 7, 6, 6, 9, 7, 5, 8, 3, 1, 8, 3, 2, 7, 1, 3, 1, 4, 2, 5, 1, 7, 0, 2, 9, 6, 9, 2, 3, 4, 8, 8, 9, 6, 2, 7, 6, 6, 8, 4, 4, 0, 3, 2, 3, 2, 6, 0, 9, 2, 7, 5, 2, 4, 9, + 6, 0, 3, 5, 7, 9, 9, 6, 4, 6, 9, 2, 5, 6, 5, 0, 4, 9, 3, 6, 8, 1, 8, 3, 6, 0, 9, 0, 0, 3, 2, 3, 8, 0, 9, 2, 9, 3, 4, 5, + 9, 5, 8, 8, 9, 7, 0, 6, 9, 5, 3, 6, 5, 3, 4, 9, 4, 0, 6, 0, 3, 4, 0, 2, 1, 6, 6, 5, 4, 4, 3, 7, 5, 5, 8, 9, 0, 0, 4, 5, 6, 3, 2, 8, 8, 2, 2, 5, 0, 5, 4, 5, 2, 5, 5, 6, 4, 0, 5, 6, 4, 4, 8, 2, 4, 6, 5, 1, 5, 1, + 8, 7, 5, 4, 7, 1, 1, 9, 6, 2, 1, 8, 4, 4, 3, 9, 6, 5, 8, 2, 5, 3, 3, 7, 5, 4, 3, 8, 8, 5, 6, 9, 0, 9, 4, 1, 1, 3, 0, 3, 1, 5, 0, 9, 5, 2, 6, 1, 7, 9, 3, 7, 8, 0, 0, 2, 9, 7, 4, 1, 2, 0, 7, 6, 6, 5, 1, 4, 7, 9, + 3, 9, 4, 2, 5, 9, 0, 2, 9, 8, 9, 6, 9, 5, 9, 4, 6, 9, 9, 5, 5, 6, 5, 7, 6, 1, 2, 1, 8, 6, 5, 6, 1, 9, 6, 7, 3, 3, 7, 8, 6, 2, 3, 6, 2, 5, 6, 1, 2, 5, 2, 1, 6, 3, 2, 0, 8, 6, 2, 8, 6, 9, 2, 2, 2, 1, 0, 3, 2, 7, + 4, 8, 8, 9, 2, 1, 8, 6, 5, 4, 3, 6, 4, 8, 0, 2, 2, 9, 6, 7, 8, 0, 7, 0, 5, 7, 6, 5, 6, 1, 5, 1, 4, 4, 6, 3, 2, 0, 4, 6, 9, 2, 7, 9, 0, 6, 8, 2, 1, 2, 0, 7, 3, 8, 8, 3, 7, 7, 8, 1, 4, 2, 3, 3, 5, 6, 2, 8, 2, 3, + 6, 0, 8, 9, 6, 3, 2, 0, 8, 0, 6, 8, 2, 2, 2, 4, 6, 8, 0, 1, 2, 2, 4, 8, 2, 6, 1, 1, 7, 7, 1, 8, 5, 8, 9, 6, 3, 8, 1, 4, 0, 9, 1, 8, 3, 9, 0, 3, 6, 7, 3, 6, 7, 2, 2, 2, 0, 8, 8, 8, 3, 2, 1, 5, 1, 3, 7, 5, 5, 6, + 0, 0, 3, 7, 2, 7, 9, 8, 3, 9, 4, 0, 0, 4, 1, 5, 2, 9, 7, 0, 0, 2, 8, 7, 8, 3, 0, 7, 6, 6, 7, 0, 9, 4, 4, 4, 7, 4, 5, 6, 0, 1, 3, 4, 5, 5, 6, 4, 1, 7, 2, 5, 4, 3, 7, 0, 9, 0, 6, 9, 7, 9, 3, 9, 6, 1, 2, 2, 5, 7, + 1, 4, 2, 9, 8, 9, 4, 6, 7, 1, 5, 4, 3, 5, 7, 8, 4, 6, 8, 7, 8, 8, 6, 1, 4, 4, 4, 5, 8, 1, 2, 3, 1, 4, 5, 9, 3, 5, 7, 1, 9, 8, 4, 9, 2, 2, 5, 2, 8, 4, 7, 1, 6, 0, 5, 0, 4, 9, 2, 2, 1, 2, 4, 2, 4, 7, 0, 1, 4, 1, + 2, 1, 4, 7, 8, 0, 5, 7, 3, 4, 5, 5, 1, 0, 5, 0, 0, 8, 0, 1, 9, 0, 8, 6, 9, 9, 6, 0, 3, 3, 0, 2, 7, 6, 3, 4, 7, 8, 7, 0, 8, 1, 0, 8, 1, 7, 5, 4, 5, 0, 1, 1, 9, 3, 0, 7, 1, 4, 1, 2, 2, 3, 3, 9, 0, 8, 6, 6, 3, 9, + 3, 8, 3, 3, 9, 5, 2, 9, 4, 2, 5, 7, 8, 6, 9, 0, 5, 0, 7, 6, 4, 3, 1, 0, 0, 6, 3, 8, 3, 5, 1, 9, 8, 3, 4, 3, 8, 9, 3, 4, 1, 5, 9, 6, 1, 3, 1, 8, 5, 4, 3, 4, 7, 5, 4, 6, 4, 9, 5, 5, 6, 9, 7, 8, 1, 0, 3, 8, 2, 9, + 3, 0, 9, 7, 1, 6, 4, 6, 5, 1, 4, 3, 8, 4, 0, 7, 0, 0, 7, 0, 7, 3, 6, 0, 4, 1, 1, 2, 3, 7, 3, 5, 9, 9, 8, 4, 3, 4, 5, 2, 2, 5, 1, 6, 1, 0, 5, 0, 7, 0, 2, 7, 0, 5, 6, 2, 3, 5, 2, 6, 6, 0, 1, 2, 7, 6, 4, 8, 4, 8, + 3, 0, 8, 4, 0, 7, 6, 1, 1, 8, 3, 0, 1, 3, 0, 5, 2, 7, 9, 3, 2, 0, 5, 4, 2, 7, 4, 6, 2, 8, 6, 5, 4, 0, 3, 6, 0, 3, 6, 7, 4, 5, 3, 2, 8, 6, 5, 1, 0, 5, 7, 0, 6, 5, 8, 7, 4, 8, 8, 2, 2, 5, 6, 9, 8, 1, 5, 7, 9, 3, + 6, 7, 8, 9, 7, 6, 6, 9, 7, 4, 2, 2, 0, 5, 7, 5, 0, 5, 9, 6, 8, 3, 4, 4, 0, 8, 6, 9, 7, 3, 5, 0, 2, 0, 1, 4, 1, 0, 2, 0, 6, 7, 2, 3, 5, 8, 5, 0, 2, 0, 0, 7, 2, 4, 5, 2, 2, 5, 6, 3, 2, 6, 5, 1, 3, 4, 1, 0, 5, 5, + 9, 2, 4, 0, 1, 9, 0, 2, 7, 4, 2, 1, 6, 2, 4, 8, 4, 3, 9, 1, 4, 0, 3, 5, 9, 9, 8, 9, 5, 3, 5, 3, 9, 4, 5, 9, 0, 9, 4, 4, 0, 7, 0, 4, 6, 9, 1, 2, 0, 9, 1, 4, 0, 9, 3, 8, 7, 0, 0, 1, 2, 6, 4, 5, 6, 0, 0, 1, 6, 2, + 3, 7, 4, 2, 8, 8, 0, 2, 1, 0, 9, 2, 7, 6, 4, 5, 7, 9, 3, 1, 0, 6, 5, 7, 9, 2, 2, 9, 5, 5, 2, 4, 9, 8, 8, 7, 2, 7, 5, 8, 4, 6, 1, 0, 1, 2, 6, 4, 8, 3, 6, 9, 9, 9, 8, 9, 2, 2, 5, 6, 9, 5, 9, 6, 8, 8, 1, 5, 9, 2, + 0, 5, 6, 0, 0, 1, 0, 1, 6, 5, 5, 2, 5, 6, 3, 7, 5, 6, 7, 8 + }; +} diff --git a/tests/AndroidTests/src/com/android/unit_tests/os/MessageQueueTest.java b/tests/AndroidTests/src/com/android/unit_tests/os/MessageQueueTest.java new file mode 100644 index 0000000000000000000000000000000000000000..155a2471b22e812cc45be3cf97e2e76468dd9895 --- /dev/null +++ b/tests/AndroidTests/src/com/android/unit_tests/os/MessageQueueTest.java @@ -0,0 +1,103 @@ +/* + * Copyright (C) 2007 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.android.unit_tests.os; + +import android.os.Handler; +import android.os.Message; +import android.os.SystemClock; +import android.test.suitebuilder.annotation.MediumTest; +import junit.framework.TestCase; + +public class MessageQueueTest extends TestCase { + + private static class BaseTestHandler extends TestHandlerThread { + Handler mHandler; + int mLastMessage; + int mCount; + + public BaseTestHandler() { + } + + public void go() { + mHandler = new Handler() { + public void handleMessage(Message msg) { + BaseTestHandler.this.handleMessage(msg); + } + }; + } + + public void handleMessage(Message msg) { + if (mCount <= mLastMessage) { + if (msg.what != mCount) { + failure(new RuntimeException( + "Expected message #" + mCount + + ", received #" + msg.what)); + } else if (mCount == mLastMessage) { + success(); + } + mCount++; + } else { + failure(new RuntimeException( + "Message received after done, #" + msg.what)); + } + } + } + + @MediumTest + public void testMessageOrder() throws Exception { + TestHandlerThread tester = new BaseTestHandler() { + public void go() { + super.go(); + long now = SystemClock.uptimeMillis() + 200; + mLastMessage = 4; + mCount = 0; + mHandler.sendMessageAtTime(mHandler.obtainMessage(2), now + 1); + mHandler.sendMessageAtTime(mHandler.obtainMessage(3), now + 2); + mHandler.sendMessageAtTime(mHandler.obtainMessage(4), now + 2); + mHandler.sendMessageAtTime(mHandler.obtainMessage(0), now + 0); + mHandler.sendMessageAtTime(mHandler.obtainMessage(1), now + 0); + } + }; + + tester.doTest(1000); + } + + @MediumTest + public void testAtFrontOfQueue() throws Exception { + TestHandlerThread tester = new BaseTestHandler() { + public void go() { + super.go(); + long now = SystemClock.uptimeMillis() + 200; + mLastMessage = 3; + mCount = 0; + mHandler.sendMessageAtTime(mHandler.obtainMessage(3), now); + mHandler.sendMessageAtFrontOfQueue(mHandler.obtainMessage(2)); + mHandler.sendMessageAtFrontOfQueue(mHandler.obtainMessage(0)); + } + + public void handleMessage(Message msg) { + super.handleMessage(msg); + if (msg.what == 0) { + mHandler.sendMessageAtFrontOfQueue(mHandler.obtainMessage(1)); + } + } + }; + + tester.doTest(1000); + } +} + diff --git a/tests/AndroidTests/src/com/android/unit_tests/os/MessengerService.java b/tests/AndroidTests/src/com/android/unit_tests/os/MessengerService.java new file mode 100644 index 0000000000000000000000000000000000000000..9228a43fb7b7d885a46bd8b1a730d067bb3fa93e --- /dev/null +++ b/tests/AndroidTests/src/com/android/unit_tests/os/MessengerService.java @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2006 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.android.unit_tests.os; + +import android.app.Service; +import android.content.Intent; +import android.os.RemoteException; +import android.os.IBinder; +import android.os.Handler; +import android.os.Message; +import android.os.Messenger; + +public class MessengerService extends Service { + private final Handler mHandler = new Handler() { + @Override + public void handleMessage(Message msg) { + Message reply = Message.obtain(); + reply.copyFrom(msg); + try { + msg.replyTo.send(reply); + } catch (RemoteException e) { + } + } + }; + + private final Messenger mMessenger = new Messenger(mHandler); + + public MessengerService() { + } + + @Override + public IBinder onBind(Intent intent) { + return mMessenger.getBinder(); + } +} + diff --git a/tests/AndroidTests/src/com/android/unit_tests/os/MessengerTest.java b/tests/AndroidTests/src/com/android/unit_tests/os/MessengerTest.java new file mode 100644 index 0000000000000000000000000000000000000000..2a3e204df41b6abb436c0b4d3bebe811c0acdf0f --- /dev/null +++ b/tests/AndroidTests/src/com/android/unit_tests/os/MessengerTest.java @@ -0,0 +1,119 @@ +/* + * Copyright (C) 2007 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.android.unit_tests.os; + +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.ServiceConnection; +import android.os.RemoteException; +import android.os.Handler; +import android.os.IBinder; +import android.os.Message; +import android.os.Messenger; +import android.test.AndroidTestCase; +import android.test.suitebuilder.annotation.MediumTest; + +public class MessengerTest extends AndroidTestCase { + private Messenger mServiceMessenger; + + private ServiceConnection mConnection = new ServiceConnection() { + public void onServiceConnected(ComponentName name, IBinder service) { + synchronized (MessengerTest.this) { + mServiceMessenger = new Messenger(service); + MessengerTest.this.notifyAll(); + } + } + public void onServiceDisconnected(ComponentName name) { + mServiceMessenger = null; + } + }; + + private class TestThread extends TestHandlerThread { + private Handler mTestHandler; + private Messenger mTestMessenger; + + public void go() { + synchronized (MessengerTest.this) { + mTestHandler = new Handler() { + public void handleMessage(Message msg) { + TestThread.this.handleMessage(msg); + } + }; + mTestMessenger = new Messenger(mTestHandler); + TestThread.this.executeTest(); + } + } + + public void executeTest() { + Message msg = Message.obtain(); + msg.arg1 = 100; + msg.arg2 = 1000; + msg.replyTo = mTestMessenger; + try { + mServiceMessenger.send(msg); + } catch (RemoteException e) { + } + } + + public void handleMessage(Message msg) { + if (msg.arg1 != 100) { + failure(new RuntimeException( + "Message.arg1 is not 100: " + msg.arg1)); + return; + } + if (msg.arg2 != 1000) { + failure(new RuntimeException( + "Message.arg2 is not 1000: " + msg.arg2)); + return; + } + if (!mTestMessenger.equals(msg.replyTo)) { + failure(new RuntimeException( + "Message.replyTo is not me: " + msg.replyTo)); + return; + } + success(); + } + }; + + @Override + protected void setUp() throws Exception { + super.setUp(); + getContext().bindService(new Intent(mContext, MessengerService.class), + mConnection, Context.BIND_AUTO_CREATE); + synchronized (this) { + while (mServiceMessenger == null) { + try { + wait(); + } catch (InterruptedException e) { + } + } + } + } + + @Override + protected void tearDown() throws Exception { + super.tearDown(); + getContext().unbindService(mConnection); + } + + @MediumTest + public void testSend() { + (new TestThread()).doTest(1000); + + } +} diff --git a/tests/AndroidTests/src/com/android/unit_tests/os/OsTests.java b/tests/AndroidTests/src/com/android/unit_tests/os/OsTests.java new file mode 100644 index 0000000000000000000000000000000000000000..bf02509ed35fe39ed86a9efa3b43eeb4711fba4e --- /dev/null +++ b/tests/AndroidTests/src/com/android/unit_tests/os/OsTests.java @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2006 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.android.unit_tests.os; + +import com.google.android.collect.Lists; +import junit.framework.TestSuite; + +import java.util.Enumeration; +import java.util.List; + +public class OsTests { + public static TestSuite suite() { + TestSuite suite = new TestSuite(OsTests.class.getName()); + + suite.addTestSuite(AidlTest.class); + suite.addTestSuite(BroadcasterTest.class); + suite.addTestSuite(FileObserverTest.class); + suite.addTestSuite(IdleHandlerTest.class); + suite.addTestSuite(MemoryFileTest.class); + suite.addTestSuite(MessageQueueTest.class); + suite.addTestSuite(MessengerTest.class); + suite.addTestSuite(PowerManagerTest.class); + suite.addTestSuite(SystemPropertiesTest.class); + + return suite; + } +} diff --git a/tests/AndroidTests/src/com/android/unit_tests/os/PowerManagerTest.java b/tests/AndroidTests/src/com/android/unit_tests/os/PowerManagerTest.java new file mode 100644 index 0000000000000000000000000000000000000000..bd5c955eac16734cda02d6dfc831461820eef78d --- /dev/null +++ b/tests/AndroidTests/src/com/android/unit_tests/os/PowerManagerTest.java @@ -0,0 +1,125 @@ +/* + * 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.android.unit_tests.os; + +import android.content.Context; +import android.os.PowerManager; +import android.test.AndroidTestCase; +import android.test.suitebuilder.annotation.MediumTest; + +public class PowerManagerTest extends AndroidTestCase { + + private PowerManager mPm; + + /** + * Setup any common data for the upcoming tests. + */ + @Override + public void setUp() throws Exception { + super.setUp(); + mPm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE); + } + + /** + * Confirm that the setup is good. + * + * @throws Exception + */ + @MediumTest + public void testPreconditions() throws Exception { + assertNotNull(mPm); + } + + /** + * Confirm that we can create functional wakelocks. + * + * @throws Exception + */ + @MediumTest + public void testNewWakeLock() throws Exception { + PowerManager.WakeLock wl = mPm.newWakeLock(PowerManager.FULL_WAKE_LOCK, "FULL_WAKE_LOCK"); + doTestWakeLock(wl); + + wl = mPm.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK, "SCREEN_BRIGHT_WAKE_LOCK"); + doTestWakeLock(wl); + + wl = mPm.newWakeLock(PowerManager.SCREEN_DIM_WAKE_LOCK, "SCREEN_DIM_WAKE_LOCK"); + doTestWakeLock(wl); + + wl = mPm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "PARTIAL_WAKE_LOCK"); + doTestWakeLock(wl); + + // TODO: Some sort of functional test (maybe not in the unit test here?) + // that confirms that things are really happening e.g. screen power, keyboard power. +} + + /** + * Confirm that we can't create dysfunctional wakelocks. + * + * @throws Exception + */ + @MediumTest + public void testBadNewWakeLock() throws Exception { + + final int badFlags = PowerManager.SCREEN_BRIGHT_WAKE_LOCK + | PowerManager.SCREEN_DIM_WAKE_LOCK; + // wrap in try because we want the error here + try { + PowerManager.WakeLock wl = mPm.newWakeLock(badFlags, "foo"); + } catch (IllegalArgumentException e) { + return; + } + fail("Bad WakeLock flag was not caught."); + } + + /** + * Apply a few tests to a wakelock to make sure it's healthy. + * + * @param wl The wakelock to be tested. + */ + private void doTestWakeLock(PowerManager.WakeLock wl) { + // First try simple acquire/release + wl.acquire(); + assertTrue(wl.isHeld()); + wl.release(); + assertFalse(wl.isHeld()); + + // Try ref-counted acquire/release + wl.setReferenceCounted(true); + wl.acquire(); + assertTrue(wl.isHeld()); + wl.acquire(); + assertTrue(wl.isHeld()); + wl.release(); + assertTrue(wl.isHeld()); + wl.release(); + assertFalse(wl.isHeld()); + + // Try non-ref-counted + wl.setReferenceCounted(false); + wl.acquire(); + assertTrue(wl.isHeld()); + wl.acquire(); + assertTrue(wl.isHeld()); + wl.release(); + assertFalse(wl.isHeld()); + + // TODO: Threaded test (needs handler) to make sure timed wakelocks work too + } + + +} diff --git a/tests/AndroidTests/src/com/android/unit_tests/os/SystemPropertiesTest.java b/tests/AndroidTests/src/com/android/unit_tests/os/SystemPropertiesTest.java new file mode 100644 index 0000000000000000000000000000000000000000..df08bb9293ae90e113413fba690e00812f5249e2 --- /dev/null +++ b/tests/AndroidTests/src/com/android/unit_tests/os/SystemPropertiesTest.java @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2006 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.android.unit_tests.os; + +import static junit.framework.Assert.assertEquals; +import junit.framework.TestCase; + +import android.os.SystemProperties; +import android.test.suitebuilder.annotation.SmallTest; + +public class SystemPropertiesTest extends TestCase { + private static final String KEY = "com.android.unit_tests"; + @SmallTest + public void testProperties() throws Exception { + if (false) { + String value; + + SystemProperties.set(KEY, ""); + value = SystemProperties.get(KEY, "default"); + assertEquals("default", value); + + SystemProperties.set(KEY, "AAA"); + value = SystemProperties.get(KEY, "default"); + assertEquals("AAA", value); + + value = SystemProperties.get(KEY); + assertEquals("AAA", value); + + SystemProperties.set(KEY, ""); + value = SystemProperties.get(KEY, "default"); + assertEquals("default", value); + + value = SystemProperties.get(KEY); + assertEquals("", value); + } + } +} diff --git a/tests/AndroidTests/src/com/android/unit_tests/os/TestHandlerThread.java b/tests/AndroidTests/src/com/android/unit_tests/os/TestHandlerThread.java new file mode 100644 index 0000000000000000000000000000000000000000..dba8dde9ed17800d61f11f2738e68fa1336e03f4 --- /dev/null +++ b/tests/AndroidTests/src/com/android/unit_tests/os/TestHandlerThread.java @@ -0,0 +1,104 @@ +/* + * Copyright (C) 2007 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.android.unit_tests.os; + +import android.os.Handler; +import android.os.Looper; +import android.os.Message; +import android.os.MessageQueue.IdleHandler; + +abstract class TestHandlerThread { + private boolean mDone = false; + private boolean mSuccess = false; + private RuntimeException mFailure = null; + private Looper mLooper; + + public abstract void go(); + + public TestHandlerThread() { + } + + public void doTest(long timeout) { + (new LooperThread()).start(); + + synchronized (this) { + long now = System.currentTimeMillis(); + long endTime = now + timeout; + while (!mDone && now < endTime) { + try { + wait(endTime-now); + } + catch (InterruptedException e) { + } + now = System.currentTimeMillis(); + } + } + + mLooper.quit(); + + if (!mDone) { + throw new RuntimeException("test timed out"); + } + if (!mSuccess) { + throw mFailure; + } + } + + public Looper getLooper() { + return mLooper; + } + + public void success() { + synchronized (this) { + mSuccess = true; + quit(); + } + } + + public void failure(RuntimeException failure) { + synchronized (this) { + mSuccess = false; + mFailure = failure; + quit(); + } + } + + class LooperThread extends Thread { + public void run() { + Looper.prepare(); + mLooper = Looper.myLooper(); + go(); + Looper.loop(); + + synchronized (TestHandlerThread.this) { + mDone = true; + if (!mSuccess && mFailure == null) { + mFailure = new RuntimeException("no failure exception set"); + } + TestHandlerThread.this.notifyAll(); + } + } + + } + + private void quit() { + synchronized (this) { + mDone = true; + notifyAll(); + } + } +} diff --git a/tests/CoreTests/Android.mk b/tests/CoreTests/Android.mk new file mode 100644 index 0000000000000000000000000000000000000000..833843220098b51c2fdbf09b2c03aa088b180461 --- /dev/null +++ b/tests/CoreTests/Android.mk @@ -0,0 +1,2 @@ +include $(call all-subdir-makefiles) + diff --git a/tests/CoreTests/MODULE_LICENSE_APACHE2 b/tests/CoreTests/MODULE_LICENSE_APACHE2 new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/tests/CoreTests/android/Android.mk b/tests/CoreTests/android/Android.mk new file mode 100644 index 0000000000000000000000000000000000000000..3b80228d75abb21bf8295b4d6f9085f596270e49 --- /dev/null +++ b/tests/CoreTests/android/Android.mk @@ -0,0 +1,15 @@ +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_MODULE_TAGS := eng tests + +LOCAL_SRC_FILES := \ + $(call all-subdir-java-files) +LOCAL_SRC_FILES += \ + $(call all-java-files-under, ../com) + +LOCAL_JAVA_LIBRARIES := android.test.runner + +LOCAL_PACKAGE_NAME := CoreTests + +include $(BUILD_PACKAGE) diff --git a/tests/CoreTests/android/AndroidManifest.xml b/tests/CoreTests/android/AndroidManifest.xml new file mode 100644 index 0000000000000000000000000000000000000000..8eb5ca0ea27af152bd0da88a388bfc0b60ab84fc --- /dev/null +++ b/tests/CoreTests/android/AndroidManifest.xml @@ -0,0 +1,53 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/CoreTests/android/content/ObserverNodeTest.java b/tests/CoreTests/android/content/ObserverNodeTest.java new file mode 100644 index 0000000000000000000000000000000000000000..68cc75b7b2ad861636915b1cc0bc6f90dfd1f671 --- /dev/null +++ b/tests/CoreTests/android/content/ObserverNodeTest.java @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2007 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 android.content; + +import java.util.ArrayList; + +import android.content.ContentService.ObserverCall; +import android.content.ContentService.ObserverNode; +import android.database.ContentObserver; +import android.net.Uri; +import android.os.Handler; +import android.test.AndroidTestCase; +import android.util.Log; + +public class ObserverNodeTest extends AndroidTestCase { + static class TestObserver extends ContentObserver { + public TestObserver() { + super(new Handler()); + } + } + + public void testUri() { + ObserverNode root = new ObserverNode(""); + Uri[] uris = new Uri[] { + Uri.parse("content://c/a/"), + Uri.parse("content://c/"), + Uri.parse("content://x/"), + Uri.parse("content://c/b/"), + Uri.parse("content://c/a/a1/1/"), + Uri.parse("content://c/a/a1/2/"), + Uri.parse("content://c/b/1/"), + Uri.parse("content://c/b/2/"), + }; + + int[] nums = new int[] {4, 7, 1, 4, 2, 2, 3, 3}; + + // special case + root.addObserver(uris[0], new TestObserver().getContentObserver(), false); + for(int i = 1; i < uris.length; i++) { + root.addObserver(uris[i], new TestObserver().getContentObserver(), true); + } + + ArrayList calls = new ArrayList(); + + for (int i = nums.length - 1; i >=0; --i) { + root.collectObservers(uris[i], 0, null, false, calls); + assertEquals(nums[i], calls.size()); + calls.clear(); + } + } + + public void testUriNotNotify() { + ObserverNode root = new ObserverNode(""); + Uri[] uris = new Uri[] { + Uri.parse("content://c/"), + Uri.parse("content://x/"), + Uri.parse("content://c/a/"), + Uri.parse("content://c/b/"), + Uri.parse("content://c/a/1/"), + Uri.parse("content://c/a/2/"), + Uri.parse("content://c/b/1/"), + Uri.parse("content://c/b/2/"), + }; + int[] nums = new int[] {7, 1, 3, 3, 1, 1, 1, 1}; + + for(int i = 0; i < uris.length; i++) { + root.addObserver(uris[i], new TestObserver().getContentObserver(), false); + } + + ArrayList calls = new ArrayList(); + + for (int i = uris.length - 1; i >=0; --i) { + root.collectObservers(uris[i], 0, null, false, calls); + assertEquals(nums[i], calls.size()); + calls.clear(); + } + } +} diff --git a/tests/CoreTests/android/content/SyncStorageEngineTest.java b/tests/CoreTests/android/content/SyncStorageEngineTest.java new file mode 100644 index 0000000000000000000000000000000000000000..36805b15e864c852c3702ff11bc7deddc921a9b6 --- /dev/null +++ b/tests/CoreTests/android/content/SyncStorageEngineTest.java @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2007 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 android.content; + +import android.test.AndroidTestCase; +import android.test.RenamingDelegatingContext; +import android.test.mock.MockContext; +import android.test.mock.MockContentResolver; +import android.provider.Sync; + +public class SyncStorageEngineTest extends AndroidTestCase { + + /** + * Test that we handle the case of a history row being old enough to purge before the + * correcponding sync is finished. This can happen if the clock changes while we are syncing. + */ + public void testPurgeActiveSync() throws Exception { + final String account = "a@example.com"; + final String authority = "testprovider"; + + MockContentResolver mockResolver = new MockContentResolver(); + + SyncStorageEngine engine = SyncStorageEngine.newTestInstance( + new TestContext(mockResolver, getContext())); + + long time0 = 1000; + long historyId = engine.insertStartSyncEvent( + account, authority, time0, Sync.History.SOURCE_LOCAL); + long time1 = time0 + SyncStorageEngine.MILLIS_IN_4WEEKS * 2; + engine.stopSyncEvent(historyId, time1 - time0, "yay", 0, 0); + } +} + +class TestContext extends ContextWrapper { + + ContentResolver mResolver; + + public TestContext(ContentResolver resolver, Context realContext) { + super(new RenamingDelegatingContext(new MockContext(), realContext, "test.")); + mResolver = resolver; + } + + @Override + public void enforceCallingOrSelfPermission(String permission, String message) { + } + + + @Override + public ContentResolver getContentResolver() { + return mResolver; + } +} diff --git a/tests/CoreTests/android/core/AbstractJDBCDriverTest.java b/tests/CoreTests/android/core/AbstractJDBCDriverTest.java new file mode 100644 index 0000000000000000000000000000000000000000..e381a5ef557aaba0bcf25f32b1c0a44323c7dfc7 --- /dev/null +++ b/tests/CoreTests/android/core/AbstractJDBCDriverTest.java @@ -0,0 +1,211 @@ +/* + * 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 android.core; + +import java.io.File; +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; + +import junit.framework.TestCase; +import android.test.suitebuilder.annotation.MediumTest; + +/** + * Tests for the most commonly used methods of sql like creating a connection, + * inserting, selecting, updating. + */ +public abstract class AbstractJDBCDriverTest extends TestCase { + + @MediumTest + public void testJDBCDriver() throws Exception { + Connection firstConnection = null; + Connection secondConnection = null; + File dbFile = getDbFile(); + String connectionURL = getConnectionURL(); + Statement firstStmt = null; + Statement secondStmt = null; + try { + Class.forName(getJDBCDriverClassName()); + firstConnection = DriverManager.getConnection(connectionURL); + secondConnection = DriverManager.getConnection(connectionURL); + + String[] ones = {"hello!", "goodbye"}; + short[] twos = {10, 20}; + String[] onesUpdated = new String[ones.length]; + for (int i = 0; i < ones.length; i++) { + onesUpdated[i] = ones[i] + twos[i]; + } + firstStmt = firstConnection.createStatement(); + firstStmt.execute("create table tbl1(one varchar(10), two smallint)"); + secondStmt = secondConnection.createStatement(); + + autoCommitInsertSelectTest(firstStmt, ones, twos); + updateSelectCommitSelectTest(firstStmt, secondStmt, ones, onesUpdated, twos); + updateSelectRollbackSelectTest(firstStmt, secondStmt, onesUpdated, ones, twos); + } finally { + closeConnections(firstConnection, secondConnection, dbFile, firstStmt, secondStmt); + } + } + + protected abstract String getJDBCDriverClassName(); + protected abstract String getConnectionURL(); + protected abstract File getDbFile(); + + private void closeConnections(Connection firstConnection, Connection secondConnection, + File dbFile, Statement firstStmt, Statement secondStmt) { + String failText = null; + try { + if (firstStmt != null) { + firstStmt.execute("drop table tbl1"); + } + } catch (SQLException e) { + failText = e.getLocalizedMessage(); + } + try { + if (firstStmt != null) { + firstStmt.close(); + } + } catch (SQLException e) { + failText = e.getLocalizedMessage(); + } + try { + if (firstConnection != null) { + firstConnection.close(); + } + } catch (SQLException e) { + failText = e.getLocalizedMessage(); + } + try { + if (secondStmt != null) { + secondStmt.close(); + } + } catch (SQLException e) { + failText = e.getLocalizedMessage(); + } + try { + if (secondConnection != null) { + secondConnection.close(); + } + } catch (SQLException e) { + failText = e.getLocalizedMessage(); + } + dbFile.delete(); + assertNull(failText, failText); + } + + /** + * Inserts the values from 'ones' with the values from 'twos' into 'tbl1' + * @param stmt the statement to use for the inserts. + * @param ones the string values to insert into tbl1. + * @param twos the corresponding numerical values to insert into tbl1. + * @throws SQLException in case of a problem during insert. + */ + private void autoCommitInsertSelectTest(Statement stmt, String[] ones, + short[] twos) throws SQLException { + for (int i = 0; i < ones.length; i++) { + stmt.execute("insert into tbl1 values('" + ones[i] + "'," + twos[i] + + ")"); + } + assertAllFromTbl1(stmt, ones, twos); + } + + /** + * Asserts that all values that where added to tbl1 are actually in tbl1. + * @param stmt the statement to use for the select. + * @param ones the string values that where added. + * @param twos the numerical values that where added. + * @throws SQLException in case of a problem during select. + */ + private void assertAllFromTbl1(Statement stmt, String[] ones, short[] twos) + throws SQLException { + ResultSet rs = stmt.executeQuery("select * from tbl1"); + int i = 0; + for (; rs.next(); i++) { + assertTrue(i < ones.length); + assertEquals(ones[i], rs.getString("one")); + assertEquals(twos[i], rs.getShort("two")); + } + assertEquals(i, ones.length); + } + + /** + * Tests the results of an update followed bz a select on a diffrent statement. + * After that the first statement commits its update. and now the second + * statement should also be able to see the changed values in a select. + * @param firstStmt the statement to use for the update and commit. + * @param secondStmt the statement that should be used to check if the commit works + * @param ones the original string values. + * @param onesUpdated the updated string values. + * @param twos the numerical values. + * @throws SQLException in case of a problem during any of the executed commands. + */ + private void updateSelectCommitSelectTest(Statement firstStmt, + Statement secondStmt, String[] ones, String[] onesUpdated, + short[] twos) throws SQLException { + firstStmt.getConnection().setAutoCommit(false); + try { + updateOnes(firstStmt, onesUpdated, twos); + assertAllFromTbl1(secondStmt, ones, twos); + firstStmt.getConnection().commit(); + assertAllFromTbl1(secondStmt, onesUpdated, twos); + } finally { + firstStmt.getConnection().setAutoCommit(true); + } + } + + /** + * Tests if an update followed by a select works. After that a rollback will + * be made and again a select should show that the rollback worked. + * @param firstStmt the statement to use for the update and the rollback + * @param secondStmt the statement to use for checking if the rollback worked as intended. + * @param ones the original string values. + * @param onesUpdated the updated string values. + * @param twos the nomerical values. + * @throws SQLException in case of a problem during any command. + */ + private void updateSelectRollbackSelectTest(Statement firstStmt, + Statement secondStmt, String[] ones, String[] onesUpdated, + short[] twos) throws SQLException { + firstStmt.getConnection().setAutoCommit(false); + try { + updateOnes(firstStmt, onesUpdated, twos); + assertAllFromTbl1(secondStmt, ones, twos); + firstStmt.getConnection().rollback(); + assertAllFromTbl1(secondStmt, ones, twos); + } finally { + firstStmt.getConnection().setAutoCommit(true); + } + } + + /** + * updates the sring values. the original values are stored in 'ones' + * and the updated values in 'ones_updated' + * @param stmt the statement to use for the update. + * @param onesUpdated the new string values. + * @param twos the numerical values. + * @throws SQLException in case of a problem during update. + */ + private void updateOnes(Statement stmt, String[] onesUpdated, short[] twos) + throws SQLException { + for (int i = 0; i < onesUpdated.length; i++) { + stmt.execute("UPDATE tbl1 SET one = '" + onesUpdated[i] + + "' WHERE two = " + twos[i]); + } + } +} diff --git a/tests/CoreTests/android/core/ArrayListTest.java b/tests/CoreTests/android/core/ArrayListTest.java new file mode 100644 index 0000000000000000000000000000000000000000..763bf9947835d5516d2a140a674ce0cd64d628f7 --- /dev/null +++ b/tests/CoreTests/android/core/ArrayListTest.java @@ -0,0 +1,94 @@ +/* + * 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 android.core; + +import junit.framework.TestCase; + +import java.util.ArrayList; +import android.test.suitebuilder.annotation.SmallTest; + +/** + * This test case tests several often used functionality of ArrayLists. + */ +public class ArrayListTest extends TestCase { + + @SuppressWarnings("unchecked") + @SmallTest + public void testArrayList() throws Exception { + ArrayList array = new ArrayList(); + assertEquals(0, array.size()); + assertTrue(array.isEmpty()); + + array.add(new Integer(0)); + array.add(0, new Integer(1)); + array.add(1, new Integer(2)); + array.add(new Integer(3)); + array.add(new Integer(1)); + + assertEquals(5, array.size()); + assertFalse(array.isEmpty()); + + assertEquals(1, ((Integer) array.get(0)).intValue()); + assertEquals(2, ((Integer) array.get(1)).intValue()); + assertEquals(0, ((Integer) array.get(2)).intValue()); + assertEquals(3, ((Integer) array.get(3)).intValue()); + assertEquals(1, ((Integer) array.get(4)).intValue()); + + assertFalse(array.contains(null)); + assertTrue(array.contains(new Integer(2))); + assertEquals(0, array.indexOf(new Integer(1))); + assertEquals(4, array.lastIndexOf(new Integer(1))); + assertTrue(array.indexOf(new Integer(5)) < 0); + assertTrue(array.lastIndexOf(new Integer(5)) < 0); + + + array.remove(1); + array.remove(1); + + assertEquals(3, array.size()); + assertFalse(array.isEmpty()); + assertEquals(1, ((Integer) array.get(0)).intValue()); + assertEquals(3, ((Integer) array.get(1)).intValue()); + assertEquals(1, ((Integer) array.get(2)).intValue()); + + assertFalse(array.contains(null)); + assertFalse(array.contains(new Integer(2))); + assertEquals(0, array.indexOf(new Integer(1))); + assertEquals(2, array.lastIndexOf(new Integer(1))); + assertTrue(array.indexOf(new Integer(5)) < 0); + assertTrue(array.lastIndexOf(new Integer(5)) < 0); + + array.clear(); + + assertEquals(0, array.size()); + assertTrue(array.isEmpty()); + assertTrue(array.indexOf(new Integer(5)) < 0); + assertTrue(array.lastIndexOf(new Integer(5)) < 0); + + ArrayList al = new ArrayList(); + + assertFalse(al.remove(null)); + assertFalse(al.remove("string")); + + al.add("string"); + al.add(null); + + assertTrue(al.remove(null)); + assertTrue(al.remove("string")); + } +} + diff --git a/tests/CoreTests/android/core/AtParserTest.java b/tests/CoreTests/android/core/AtParserTest.java new file mode 100644 index 0000000000000000000000000000000000000000..09cb6e97d24ef3b610476a680b0aab603625227d --- /dev/null +++ b/tests/CoreTests/android/core/AtParserTest.java @@ -0,0 +1,348 @@ +/* + * Copyright (C) 2007 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 android.core; + +import android.bluetooth.AtCommandHandler; +import android.bluetooth.AtCommandResult; +import android.bluetooth.AtParser; + +import java.util.*; +import junit.framework.*; + +public class AtParserTest extends TestCase { + + /* An AtCommandHandler instrumented for testing purposes + */ + private class HandlerTest extends AtCommandHandler { + boolean mBasicCalled, mActionCalled, mReadCalled, mTestCalled, + mSetCalled; + int mBasicReturn, mActionReturn, mReadReturn, mTestReturn, mSetReturn; + Object[] mSetArgs; + String mBasicArgs; + + HandlerTest() { + this(AtCommandResult.ERROR, AtCommandResult.ERROR, + AtCommandResult.ERROR, AtCommandResult.ERROR, + AtCommandResult.ERROR); + } + + HandlerTest(int a, int b, int c, int d, int e) { + mBasicReturn = a; + mActionReturn = b; + mReadReturn = c; + mSetReturn = d; + mTestReturn = e; + reset(); + } + public void reset() { + mBasicCalled = false; + mActionCalled = false; + mReadCalled = false; + mSetCalled = false; + mTestCalled = false; + mSetArgs = null; + mBasicArgs = null; + } + public boolean wasCalled() { // helper + return mBasicCalled || mActionCalled || mReadCalled || + mTestCalled || mSetCalled; + } + @Override + public AtCommandResult handleBasicCommand(String args) { + mBasicCalled = true; + mBasicArgs = args; + return new AtCommandResult(mBasicReturn); + } + @Override + public AtCommandResult handleActionCommand() { + mActionCalled = true; + return new AtCommandResult(mActionReturn); + } + @Override + public AtCommandResult handleReadCommand() { + mReadCalled = true; + return new AtCommandResult(mReadReturn); + } + @Override + public AtCommandResult handleSetCommand(Object[] args) { + mSetCalled = true; + mSetArgs = args; + return new AtCommandResult(mSetReturn); + } + @Override + public AtCommandResult handleTestCommand() { + mTestCalled = true; + return new AtCommandResult(mTestReturn); + } + } + + private AtParser mParser; + + @Override + protected void setUp() throws Exception { + super.setUp(); + mParser = new AtParser(); + } + + @Override + protected void tearDown() throws Exception { + super.tearDown(); + } + + + /* Test that the right method is being called + */ +/* public void testBasic1() throws Exception { + HandlerTest D = new HandlerTest(0, 1, 1, 1, 1); + HandlerTest A = new HandlerTest(0, 1, 1, 1, 1); + mParser.register('D', D); + mParser.register('A', A); + + assertTrue(Arrays.equals( + new String[]{"OK"}, + mParser.process(" A T D = ? T 1 2 3 4 ").toStrings())); + assertTrue(D.mBasicCalled); + assertFalse(D.mActionCalled); + assertFalse(D.mTestCalled); + assertFalse(D.mSetCalled); + assertFalse(D.mReadCalled); + assertFalse(A.wasCalled()); + assertEquals("=?T1234", D.mBasicArgs); + } +*/ + /* Test some crazy strings + *//* + public void testBasic2() throws Exception { + HandlerTest A = new HandlerTest(0, 1, 1, 1, 1); + mParser.register('A', A); + + assertTrue(Arrays.equals( + new String[]{}, + mParser.process(" ").toStrings())); + + assertTrue(Arrays.equals( + new String[]{"OK"}, + mParser.process(" a T a t \"\" 1 2 3 a 4 ") + .toStrings())); + assertEquals("T\"\"123A4", A.mBasicArgs); + + assertTrue(Arrays.equals( + new String[]{"OK"}, + mParser.process(" a T a t \"foo BaR12Z\" 1 2 3 a 4 ") + .toStrings())); + assertEquals("T\"foo BaR12Z\"123A4", A.mBasicArgs); + + assertTrue(Arrays.equals( + new String[]{"OK"}, + mParser.process("ATA\"").toStrings())); + assertEquals("\"\"", A.mBasicArgs); + + assertTrue(Arrays.equals( + new String[]{"OK"}, + mParser.process("ATA\"a").toStrings())); + assertEquals("\"a\"", A.mBasicArgs); + + assertTrue(Arrays.equals( + new String[]{"OK"}, + mParser.process("ATa\" ").toStrings())); + assertEquals("\" \"", A.mBasicArgs); + + assertTrue(Arrays.equals( + new String[]{"OK"}, + mParser.process("ATA \"one \" two \"t hr ee ") + .toStrings())); + assertEquals("\"one \"TWO\"t hr ee \"", A.mBasicArgs); + }*/ + + /* Simple extended commands + *//* + public void testExt1() throws Exception { + HandlerTest A = new HandlerTest(1, 0, 0, 0, 0); + mParser.register("+A", A); + + assertTrue(Arrays.equals( + new String[]{"ERROR"}, + mParser.process("AT+B").toStrings())); + assertFalse(A.wasCalled()); + + assertTrue(Arrays.equals( + new String[]{"OK"}, + mParser.process("AT+A").toStrings())); + assertTrue(A.mActionCalled); + A.mActionCalled = false; + assertFalse(A.wasCalled()); + A.reset(); + + assertTrue(Arrays.equals( + new String[]{"OK"}, + mParser.process("AT+A=").toStrings())); + assertTrue(A.mSetCalled); + A.mSetCalled = false; + assertFalse(A.wasCalled()); + assertEquals(1, A.mSetArgs.length); + A.reset(); + + assertTrue(Arrays.equals( + new String[]{"OK"}, + mParser.process("AT+A=?").toStrings())); + assertTrue(A.mTestCalled); + A.mTestCalled = false; + assertFalse(A.wasCalled()); + A.reset(); + + assertTrue(Arrays.equals( + new String[]{"OK"}, + mParser.process("AT+A?").toStrings())); + assertTrue(A.mReadCalled); + A.mReadCalled = false; + assertFalse(A.wasCalled()); + A.reset(); + } +*/ + + + /* Test chained commands + *//* + public void testChain1() throws Exception { + HandlerTest A = new HandlerTest(0, 1, 1, 1, 1); + HandlerTest B = new HandlerTest(1, 0, 0, 0, 0); + HandlerTest C = new HandlerTest(1, 1, 1, 1, 1); + mParser.register('A', A); + mParser.register("+B", B); + mParser.register("+C", C); + + assertTrue(Arrays.equals( + new String[]{"ERROR"}, + mParser.process("AT+B;+C").toStrings())); + assertTrue(B.mActionCalled); + assertTrue(C.mActionCalled); + B.reset(); + C.reset(); + + assertTrue(Arrays.equals( + new String[]{"ERROR"}, + mParser.process("AT+C;+B").toStrings())); + assertFalse(B.wasCalled()); + assertTrue(C.mActionCalled); + B.reset(); + C.reset(); + }*/ + + /* Test Set command + *//* + public void testSet1() throws Exception { + HandlerTest A = new HandlerTest(1, 1, 1, 0, 1); + mParser.register("+AAAA", A); + Object[] expectedResult; + + assertTrue(Arrays.equals( + new String[]{"OK"}, + mParser.process("AT+AAAA=1").toStrings())); + expectedResult = new Object[]{(Integer)1}; + assertTrue(Arrays.equals(expectedResult, A.mSetArgs)); + A.reset(); + + assertTrue(Arrays.equals( + new String[]{"OK"}, + mParser.process("AT+AAAA=1,2,3").toStrings())); + expectedResult = new Object[]{(Integer)1, (Integer)2, (Integer)3}; + assertTrue(Arrays.equals(expectedResult, A.mSetArgs)); + A.reset(); + + assertTrue(Arrays.equals( + new String[]{"OK"}, + mParser.process("AT+AAAA=3,0,0,1").toStrings())); + expectedResult = new Object[]{(Integer)3, (Integer)0, (Integer)0, + (Integer)1}; + assertTrue(Arrays.equals(expectedResult, A.mSetArgs)); + A.reset(); + + assertTrue(Arrays.equals( + new String[]{"OK"}, + mParser.process("AT+AAAA=\"foo\",1,\"b,ar").toStrings())); + expectedResult = new Object[]{"\"foo\"", 1, "\"b,ar\""}; + assertTrue(Arrays.equals(expectedResult, A.mSetArgs)); + A.reset(); + + assertTrue(Arrays.equals( + new String[]{"OK"}, + mParser.process("AT+AAAA=").toStrings())); + expectedResult = new Object[]{""}; + assertTrue(Arrays.equals(expectedResult, A.mSetArgs)); + A.reset(); + + assertTrue(Arrays.equals( + new String[]{"OK"}, + mParser.process("AT+AAAA=,").toStrings())); + expectedResult = new Object[]{"", ""}; + assertTrue(Arrays.equals(expectedResult, A.mSetArgs)); + A.reset(); + + assertTrue(Arrays.equals( + new String[]{"OK"}, + mParser.process("AT+AAAA=,,,").toStrings())); + expectedResult = new Object[]{"", "", "", ""}; + assertTrue(Arrays.equals(expectedResult, A.mSetArgs)); + A.reset(); + + assertTrue(Arrays.equals( + new String[]{"OK"}, + mParser.process("AT+AAAA=,1,,\"foo\",").toStrings())); + expectedResult = new Object[]{"", 1, "", "\"foo\"", ""}; + assertEquals(5, A.mSetArgs.length); + assertTrue(Arrays.equals(expectedResult, A.mSetArgs)); + A.reset(); + }*/ + + /* Test repeat command "A/" + *//* + public void testRepeat() throws Exception { + HandlerTest A = new HandlerTest(0, 0, 0, 0, 0); + mParser.register('A', A); + + // Try repeated command on fresh parser + assertTrue(Arrays.equals( + new String[]{}, + mParser.process("A/").toStrings())); + assertFalse(A.wasCalled()); + A.reset(); + + assertTrue(Arrays.equals( + new String[]{"OK"}, + mParser.process("ATA").toStrings())); + assertTrue(A.mBasicCalled); + assertEquals("", A.mBasicArgs); + A.reset(); + + // Now repeat the command + assertTrue(Arrays.equals( + new String[]{"OK"}, + mParser.process("A/").toStrings())); + assertTrue(A.mBasicCalled); + assertEquals("", A.mBasicArgs); + A.reset(); + + // Multiple repeats + assertTrue(Arrays.equals( + new String[]{"OK"}, + mParser.process("A/").toStrings())); + assertTrue(A.mBasicCalled); + assertEquals("", A.mBasicArgs); + A.reset(); + + }*/ +} diff --git a/tests/CoreTests/android/core/BooleanTest.java b/tests/CoreTests/android/core/BooleanTest.java new file mode 100644 index 0000000000000000000000000000000000000000..211947ec923986b2f70f57937321b091e8f3f79e --- /dev/null +++ b/tests/CoreTests/android/core/BooleanTest.java @@ -0,0 +1,46 @@ +/* + * 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 android.core; + +import junit.framework.TestCase; +import android.test.suitebuilder.annotation.SmallTest; + +/** + * Tests some basic functionality of Booleans. + */ +public class BooleanTest extends TestCase { + + @SmallTest + public void testBoolean() throws Exception { + Boolean a = new Boolean(true); + Boolean b = new Boolean("True"); + Boolean c = new Boolean(false); + Boolean d = new Boolean("Yes"); + + assertEquals(a, b); + assertEquals(c, d); + assertTrue(a.booleanValue()); + assertFalse(c.booleanValue()); + assertEquals("true", a.toString()); + assertEquals("false", c.toString()); + assertEquals(Boolean.TRUE, a); + assertEquals(Boolean.FALSE, c); + assertSame(Boolean.valueOf(true), Boolean.TRUE); + assertSame(Boolean.valueOf(false), Boolean.FALSE); + } +} + diff --git a/tests/CoreTests/android/core/BufferedInputStreamTest.java b/tests/CoreTests/android/core/BufferedInputStreamTest.java new file mode 100644 index 0000000000000000000000000000000000000000..1ad95a14083743258fc22dca78560a4ac18ab49e --- /dev/null +++ b/tests/CoreTests/android/core/BufferedInputStreamTest.java @@ -0,0 +1,81 @@ +/* + * 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 android.core; + +import junit.framework.TestCase; + +import java.io.BufferedInputStream; +import java.io.ByteArrayInputStream; +import android.test.suitebuilder.annotation.SmallTest; + +/** + * Tests to verify that simple functionality works for BufferedInputStreams. + */ +public class BufferedInputStreamTest extends TestCase { + + @SmallTest + public void testBufferedInputStream() throws Exception { + String str = "AbCdEfGhIjKlM\nOpQrStUvWxYz"; + ByteArrayInputStream aa = new ByteArrayInputStream(str.getBytes()); + ByteArrayInputStream ba = new ByteArrayInputStream(str.getBytes()); + ByteArrayInputStream ca = new ByteArrayInputStream(str.getBytes()); + ByteArrayInputStream da = new ByteArrayInputStream(str.getBytes()); + ByteArrayInputStream ea = new ByteArrayInputStream(str.getBytes()); + + BufferedInputStream a = new BufferedInputStream(aa, 6); + try { + assertEquals(str, IOUtil.read(a)); + } finally { + a.close(); + } + + BufferedInputStream b = new BufferedInputStream(ba, 7); + try { + assertEquals("AbCdEfGhIj", IOUtil.read(b, 10)); + } finally { + b.close(); + } + + BufferedInputStream c = new BufferedInputStream(ca, 9); + try { + assertEquals("bdfhjl\nprtvxz", IOUtil.skipRead(c)); + } finally { + c.close(); + } + + BufferedInputStream d = new BufferedInputStream(da, 9); + try { + assertEquals('A', d.read()); + d.mark(15); + assertEquals('b', d.read()); + assertEquals('C', d.read()); + d.reset(); + assertEquals('b', d.read()); + } finally { + d.close(); + } + + BufferedInputStream e = new BufferedInputStream(ea, 11); + try { + // test that we can ask for more than is present, and that we'll get + // back only what is there. + assertEquals(str, IOUtil.read(e, 10000)); + } finally { + e.close(); + } + } +} diff --git a/tests/CoreTests/android/core/BufferedOutputStreamTest.java b/tests/CoreTests/android/core/BufferedOutputStreamTest.java new file mode 100644 index 0000000000000000000000000000000000000000..cd8ec08629dcf0407819f39e6aaccb4a34b3de00 --- /dev/null +++ b/tests/CoreTests/android/core/BufferedOutputStreamTest.java @@ -0,0 +1,50 @@ +/* + * 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 android.core; + +import junit.framework.TestCase; + +import java.io.BufferedOutputStream; +import java.io.ByteArrayOutputStream; +import android.test.suitebuilder.annotation.SmallTest; + +/** + * Tests to verify that simple functionality works for BufferedOutputStreams. + */ +public class BufferedOutputStreamTest extends TestCase { + + @SmallTest + public void testBufferedOutputStream() throws Exception { + String str = "AbCdEfGhIjKlMnOpQrStUvWxYz"; + ByteArrayOutputStream aa = new ByteArrayOutputStream(); + BufferedOutputStream a = new BufferedOutputStream(aa, 15); + try { + a.write(str.getBytes(), 0, 26); + a.write('A'); + + assertEquals(26, aa.size()); + assertEquals(aa.toString(), str); + + a.flush(); + + assertEquals(27, aa.size()); + assertEquals("AbCdEfGhIjKlMnOpQrStUvWxYzA", aa.toString()); + } finally { + a.close(); + } + } +} diff --git a/tests/CoreTests/android/core/BufferedReaderTest.java b/tests/CoreTests/android/core/BufferedReaderTest.java new file mode 100644 index 0000000000000000000000000000000000000000..a94ca0204e376cb01f4d2c4b3f41ce23e6e5c067 --- /dev/null +++ b/tests/CoreTests/android/core/BufferedReaderTest.java @@ -0,0 +1,66 @@ +/* + * 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 android.core; + +import junit.framework.TestCase; + +import java.io.BufferedReader; +import java.io.StringReader; +import android.test.suitebuilder.annotation.MediumTest; + +/** + * Tests to verify that simple functionality works for BufferedReaders. + */ +public class BufferedReaderTest extends TestCase { + + @MediumTest + public void testBufferedReader() throws Exception { + String str = "AbCdEfGhIjKlMnOpQrStUvWxYz"; + StringReader aa = new StringReader(str); + StringReader ba = new StringReader(str); + StringReader ca = new StringReader(str); + StringReader da = new StringReader(str); + + BufferedReader a = new BufferedReader(aa, 5); + try { + assertEquals(str, IOUtil.read(a)); + } finally { + a.close(); + } + + BufferedReader b = new BufferedReader(ba, 15); + try { + assertEquals("AbCdEfGhIj", IOUtil.read(b, 10)); + } finally { + b.close(); + } + + BufferedReader c = new BufferedReader(ca); + try { + assertEquals("bdfhjlnprtvxz", IOUtil.skipRead(c)); + } finally { + c.close(); + } + + BufferedReader d = new BufferedReader(da); + try { + assertEquals("AbCdEfGdEfGhIjKlMnOpQrStUvWxYz", IOUtil.markRead(d, 3, 4)); + } finally { + d.close(); + } + } +} diff --git a/tests/CoreTests/android/core/BufferedWriterTest.java b/tests/CoreTests/android/core/BufferedWriterTest.java new file mode 100644 index 0000000000000000000000000000000000000000..12dfcef2753d948edaba2beb5d6afc6a888acf62 --- /dev/null +++ b/tests/CoreTests/android/core/BufferedWriterTest.java @@ -0,0 +1,53 @@ +/* + * 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 android.core; + +import junit.framework.TestCase; + +import java.io.BufferedWriter; +import java.io.StringWriter; +import android.test.suitebuilder.annotation.SmallTest; + +/** + * Some basic tests for BufferedWriter. + */ +public class BufferedWriterTest extends TestCase { + + @SmallTest + public void testBufferedWriter() throws Exception { + String str = "AbCdEfGhIjKlMnOpQrStUvWxYz"; + StringWriter aa = new StringWriter(); + + BufferedWriter a = new BufferedWriter(aa, 20); + try { + a.write(str.toCharArray(), 0, 26); + a.write('X'); + a.flush(); + assertEquals("AbCdEfGhIjKlMnOpQrStUvWxYzX", aa.toString()); + + a.write("alphabravodelta", 5, 5); + a.flush(); + assertEquals("AbCdEfGhIjKlMnOpQrStUvWxYzXbravo", aa.toString()); + a.newLine(); + a.write("I'm on a new line."); + a.flush(); + assertEquals("AbCdEfGhIjKlMnOpQrStUvWxYzXbravo\nI\'m on a new line.", aa.toString()); + } finally { + a.close(); + } + } +} diff --git a/tests/CoreTests/android/core/ByteArrayInputStreamTest.java b/tests/CoreTests/android/core/ByteArrayInputStreamTest.java new file mode 100644 index 0000000000000000000000000000000000000000..d964102048e21c294dbf86df9bcd379a6863f98f --- /dev/null +++ b/tests/CoreTests/android/core/ByteArrayInputStreamTest.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 android.core; + +import junit.framework.TestCase; + +import java.io.ByteArrayInputStream; +import android.test.suitebuilder.annotation.SmallTest; + +/** + * Tests to verify that simple functionality works for ByteArrayInputStreams. + */ +public class ByteArrayInputStreamTest extends TestCase { + + @SmallTest + public void testByteArrayInputStream() throws Exception { + String str = "AbCdEfGhIjKlMnOpQrStUvWxYz"; + + ByteArrayInputStream a = new ByteArrayInputStream(str.getBytes()); + ByteArrayInputStream b = new ByteArrayInputStream(str.getBytes()); + ByteArrayInputStream c = new ByteArrayInputStream(str.getBytes()); + ByteArrayInputStream d = new ByteArrayInputStream(str.getBytes()); + + assertEquals(str, IOUtil.read(a)); + assertEquals("AbCdEfGhIj", IOUtil.read(b, 10)); + assertEquals("bdfhjlnprtvxz", IOUtil.skipRead(c)); + assertEquals("AbCdEfGdEfGhIjKlMnOpQrStUvWxYz", IOUtil.markRead(d, 3, 4)); + } +} diff --git a/tests/CoreTests/android/core/ByteArrayOutputStreamTest.java b/tests/CoreTests/android/core/ByteArrayOutputStreamTest.java new file mode 100644 index 0000000000000000000000000000000000000000..e605214cc9385d7283db38979048283cfae779f4 --- /dev/null +++ b/tests/CoreTests/android/core/ByteArrayOutputStreamTest.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 android.core; + +import junit.framework.TestCase; + +import java.io.ByteArrayOutputStream; +import android.test.suitebuilder.annotation.SmallTest; + +/** + * A basic test for ByteArrayOutputStraem. + */ +public class ByteArrayOutputStreamTest extends TestCase { + + @SmallTest + public void testByteArrayOutputStream() throws Exception { + String str = "AbCdEfGhIjKlMnOpQrStUvWxYz"; + ByteArrayOutputStream a = new ByteArrayOutputStream(); + ByteArrayOutputStream b = new ByteArrayOutputStream(10); + + a.write(str.getBytes(), 0, 26); + a.write('X'); + a.writeTo(b); + + assertEquals(27, a.size()); + assertEquals("AbCdEfGhIjKlMnOpQrStUvWxYzX", a.toString()); + assertEquals("AbCdEfGhIjKlMnOpQrStUvWxYzX", b.toString()); + } +} diff --git a/tests/CoreTests/android/core/CharArrayReaderTest.java b/tests/CoreTests/android/core/CharArrayReaderTest.java new file mode 100644 index 0000000000000000000000000000000000000000..50a217a1599a817f4652dcb06c1a98fa6b5e4499 --- /dev/null +++ b/tests/CoreTests/android/core/CharArrayReaderTest.java @@ -0,0 +1,42 @@ +/* + * 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 android.core; + +import junit.framework.TestCase; + +import java.io.CharArrayReader; +import android.test.suitebuilder.annotation.SmallTest; + +/** + * Basic tests for CharArrayReader. + */ +public class CharArrayReaderTest extends TestCase { + + @SmallTest + public void testCharArrayReader() throws Exception { + String str = "AbCdEfGhIjKlMnOpQrStUvWxYz"; + CharArrayReader a = new CharArrayReader(str.toCharArray()); + CharArrayReader b = new CharArrayReader(str.toCharArray()); + CharArrayReader c = new CharArrayReader(str.toCharArray()); + CharArrayReader d = new CharArrayReader(str.toCharArray()); + + assertEquals(str, IOUtil.read(a)); + assertEquals("AbCdEfGhIj", IOUtil.read(b, 10)); + assertEquals("bdfhjlnprtvxz", IOUtil.skipRead(c)); + assertEquals("AbCdEfGdEfGhIjKlMnOpQrStUvWxYz", IOUtil.markRead(d, 3, 4)); + } +} diff --git a/tests/CoreTests/android/core/CharArrayWriterTest.java b/tests/CoreTests/android/core/CharArrayWriterTest.java new file mode 100644 index 0000000000000000000000000000000000000000..0aae1e46d777772fde634ad32fa21a1a714e5992 --- /dev/null +++ b/tests/CoreTests/android/core/CharArrayWriterTest.java @@ -0,0 +1,48 @@ +/* + * 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 android.core; + +import junit.framework.TestCase; + +import java.io.CharArrayWriter; +import android.test.suitebuilder.annotation.SmallTest; + +/** + * Basic tests for CharArrayWriter. + */ +public class CharArrayWriterTest extends TestCase { + + @SmallTest + public void testCharArrayWriter() throws Exception { + String str = "AbCdEfGhIjKlMnOpQrStUvWxYz"; + CharArrayWriter a = new CharArrayWriter(); + CharArrayWriter b = new CharArrayWriter(); + + a.write(str, 0, 26); + a.write('X'); + a.writeTo(b); + + assertEquals(27, a.size()); + assertEquals("AbCdEfGhIjKlMnOpQrStUvWxYzX", a.toString()); + + b.write("alphabravodelta", 5, 5); + b.append('X'); + assertEquals("AbCdEfGhIjKlMnOpQrStUvWxYzXbravoX", b.toString()); + b.append("omega"); + assertEquals("AbCdEfGhIjKlMnOpQrStUvWxYzXbravoXomega", b.toString()); + } +} diff --git a/tests/CoreTests/android/core/ChecksumTest.java b/tests/CoreTests/android/core/ChecksumTest.java new file mode 100644 index 0000000000000000000000000000000000000000..24fb739e1a3f3328a1ce00a2a9e9626e9452d357 --- /dev/null +++ b/tests/CoreTests/android/core/ChecksumTest.java @@ -0,0 +1,97 @@ +/* + * 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 android.core; + +import junit.framework.TestCase; + +import java.util.zip.Adler32; +import java.util.zip.CRC32; +import android.test.suitebuilder.annotation.SmallTest; + +/** + * tests for CRC32 and Adler32 checksum algorithms. + */ +public class ChecksumTest extends TestCase { + + @SmallTest + public void testChecksum() throws Exception { + /* + * Values computed experimentally, using C interfaces. + */ + adler32Test(mTestString, 0x9de210dbL); + cRC32Test(mTestString, 0x939f04afL); + + // Test for issue 1016037 + wrongChecksumWithAdler32Test(); + } + + private void adler32Test(byte[] values, long expected) { + Adler32 adler = new Adler32(); + + // try it all at once + adler.update(values); + assertEquals(adler.getValue(), expected); + + // try resetting and computing one byte at a time + adler.reset(); + for (int i = 0; i < values.length; i++) { + adler.update(values[i]); + } + assertEquals(adler.getValue(), expected); + } + + private void cRC32Test(byte[] values, long expected) { + CRC32 crc = new CRC32(); + + // try it all at once + crc.update(values); + assertEquals(crc.getValue(), expected); + + // try resetting and computing one byte at a time + crc.reset(); + for (int i = 0; i < values.length; i++) { + crc.update(values[i]); + } + assertEquals(crc.getValue(), expected); + } + + // "The quick brown fox jumped over the lazy dogs\n" + private static byte[] mTestString = { + 0x54, 0x68, 0x65, 0x20, 0x71, 0x75, 0x69, 0x63, + 0x6b, 0x20, 0x62, 0x72, 0x6f, 0x77, 0x6e, 0x20, + 0x66, 0x6f, 0x78, 0x20, 0x6a, 0x75, 0x6d, 0x70, + 0x65, 0x64, 0x20, 0x6f, 0x76, 0x65, 0x72, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x6c, 0x61, 0x7a, 0x79, + 0x20, 0x64, 0x6f, 0x67, 0x73, 0x2e, 0x0a + }; + + + // Test for issue 1016037 + private void wrongChecksumWithAdler32Test() { + byte[] bytes = {1, 0, 5, 0, 15, 0, 1, 11, 0, 1}; + Adler32 adler = new Adler32(); + adler.update(bytes); + long arrayChecksum = adler.getValue(); + adler.reset(); + for (int i = 0; i < bytes.length; i++) { + adler.update(bytes[i]); + } + assertEquals("Checksums not equal: expected: " + arrayChecksum + + " actual: " + adler.getValue(), arrayChecksum, adler.getValue()); + } +} + diff --git a/tests/CoreTests/android/core/ClassLoaderTest.java b/tests/CoreTests/android/core/ClassLoaderTest.java new file mode 100644 index 0000000000000000000000000000000000000000..5e7f5a48c6235fb0b9a1e1e6c62b1557360217c2 --- /dev/null +++ b/tests/CoreTests/android/core/ClassLoaderTest.java @@ -0,0 +1,243 @@ +/* + * 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 android.core; + +import junit.framework.TestCase; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +import android.test.suitebuilder.annotation.Suppress; + +/** + * Test for basic ClassLoader functionality. + */ +@Suppress +public class ClassLoaderTest extends TestCase { + /* + package my.pkg; + public class CLTest { + public CLTest() {} + + public String test() { return "This is test 1"; } + } + */ + static private byte[] test1class = { + (byte) 0xca, (byte) 0xfe, (byte) 0xba, (byte) 0xbe, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x31, + (byte) 0x00, (byte) 0x11, (byte) 0x0a, (byte) 0x00, + (byte) 0x04, (byte) 0x00, (byte) 0x0d, (byte) 0x08, + (byte) 0x00, (byte) 0x0e, (byte) 0x07, (byte) 0x00, + (byte) 0x0f, (byte) 0x07, (byte) 0x00, (byte) 0x10, + (byte) 0x01, (byte) 0x00, (byte) 0x06, (byte) 0x3c, + (byte) 0x69, (byte) 0x6e, (byte) 0x69, (byte) 0x74, + (byte) 0x3e, (byte) 0x01, (byte) 0x00, (byte) 0x03, + (byte) 0x28, (byte) 0x29, (byte) 0x56, (byte) 0x01, + (byte) 0x00, (byte) 0x04, (byte) 0x43, (byte) 0x6f, + (byte) 0x64, (byte) 0x65, (byte) 0x01, (byte) 0x00, + (byte) 0x0f, (byte) 0x4c, (byte) 0x69, (byte) 0x6e, + (byte) 0x65, (byte) 0x4e, (byte) 0x75, (byte) 0x6d, + (byte) 0x62, (byte) 0x65, (byte) 0x72, (byte) 0x54, + (byte) 0x61, (byte) 0x62, (byte) 0x6c, (byte) 0x65, + (byte) 0x01, (byte) 0x00, (byte) 0x04, (byte) 0x74, + (byte) 0x65, (byte) 0x73, (byte) 0x74, (byte) 0x01, + (byte) 0x00, (byte) 0x14, (byte) 0x28, (byte) 0x29, + (byte) 0x4c, (byte) 0x6a, (byte) 0x61, (byte) 0x76, + (byte) 0x61, (byte) 0x2f, (byte) 0x6c, (byte) 0x61, + (byte) 0x6e, (byte) 0x67, (byte) 0x2f, (byte) 0x53, + (byte) 0x74, (byte) 0x72, (byte) 0x69, (byte) 0x6e, + (byte) 0x67, (byte) 0x3b, (byte) 0x01, (byte) 0x00, + (byte) 0x0a, (byte) 0x53, (byte) 0x6f, (byte) 0x75, + (byte) 0x72, (byte) 0x63, (byte) 0x65, (byte) 0x46, + (byte) 0x69, (byte) 0x6c, (byte) 0x65, (byte) 0x01, + (byte) 0x00, (byte) 0x0b, (byte) 0x43, (byte) 0x4c, + (byte) 0x54, (byte) 0x65, (byte) 0x73, (byte) 0x74, + (byte) 0x2e, (byte) 0x6a, (byte) 0x61, (byte) 0x76, + (byte) 0x61, (byte) 0x0c, (byte) 0x00, (byte) 0x05, + (byte) 0x00, (byte) 0x06, (byte) 0x01, (byte) 0x00, + (byte) 0x0e, (byte) 0x54, (byte) 0x68, (byte) 0x69, + (byte) 0x73, (byte) 0x20, (byte) 0x69, (byte) 0x73, + (byte) 0x20, (byte) 0x74, (byte) 0x65, (byte) 0x73, + (byte) 0x74, (byte) 0x20, (byte) 0x31, (byte) 0x01, + (byte) 0x00, (byte) 0x0d, (byte) 0x6d, (byte) 0x79, + (byte) 0x2f, (byte) 0x70, (byte) 0x6b, (byte) 0x67, + (byte) 0x2f, (byte) 0x43, (byte) 0x4c, (byte) 0x54, + (byte) 0x65, (byte) 0x73, (byte) 0x74, (byte) 0x01, + (byte) 0x00, (byte) 0x10, (byte) 0x6a, (byte) 0x61, + (byte) 0x76, (byte) 0x61, (byte) 0x2f, (byte) 0x6c, + (byte) 0x61, (byte) 0x6e, (byte) 0x67, (byte) 0x2f, + (byte) 0x4f, (byte) 0x62, (byte) 0x6a, (byte) 0x65, + (byte) 0x63, (byte) 0x74, (byte) 0x00, (byte) 0x21, + (byte) 0x00, (byte) 0x03, (byte) 0x00, (byte) 0x04, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x02, (byte) 0x00, (byte) 0x01, + (byte) 0x00, (byte) 0x05, (byte) 0x00, (byte) 0x06, + (byte) 0x00, (byte) 0x01, (byte) 0x00, (byte) 0x07, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x1d, + (byte) 0x00, (byte) 0x01, (byte) 0x00, (byte) 0x01, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x05, + (byte) 0x2a, (byte) 0xb7, (byte) 0x00, (byte) 0x01, + (byte) 0xb1, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x01, (byte) 0x00, (byte) 0x08, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x06, (byte) 0x00, + (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x04, (byte) 0x00, (byte) 0x01, (byte) 0x00, + (byte) 0x09, (byte) 0x00, (byte) 0x0a, (byte) 0x00, + (byte) 0x01, (byte) 0x00, (byte) 0x07, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x1b, (byte) 0x00, + (byte) 0x01, (byte) 0x00, (byte) 0x01, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x03, (byte) 0x12, + (byte) 0x02, (byte) 0xb0, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x01, (byte) 0x00, (byte) 0x08, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x06, + (byte) 0x00, (byte) 0x01, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x06, (byte) 0x00, (byte) 0x01, + (byte) 0x00, (byte) 0x0b, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x02, (byte) 0x00, (byte) 0x0c + }; + + /* + package my.pkg; + public class CLTest { + public CLTest() {} + + public String test() { return "This is test 2"; } + } + */ + static private byte[] test2class = { + (byte) 0xca, (byte) 0xfe, (byte) 0xba, (byte) 0xbe, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x31, + (byte) 0x00, (byte) 0x11, (byte) 0x0a, (byte) 0x00, + (byte) 0x04, (byte) 0x00, (byte) 0x0d, (byte) 0x08, + (byte) 0x00, (byte) 0x0e, (byte) 0x07, (byte) 0x00, + (byte) 0x0f, (byte) 0x07, (byte) 0x00, (byte) 0x10, + (byte) 0x01, (byte) 0x00, (byte) 0x06, (byte) 0x3c, + (byte) 0x69, (byte) 0x6e, (byte) 0x69, (byte) 0x74, + (byte) 0x3e, (byte) 0x01, (byte) 0x00, (byte) 0x03, + (byte) 0x28, (byte) 0x29, (byte) 0x56, (byte) 0x01, + (byte) 0x00, (byte) 0x04, (byte) 0x43, (byte) 0x6f, + (byte) 0x64, (byte) 0x65, (byte) 0x01, (byte) 0x00, + (byte) 0x0f, (byte) 0x4c, (byte) 0x69, (byte) 0x6e, + (byte) 0x65, (byte) 0x4e, (byte) 0x75, (byte) 0x6d, + (byte) 0x62, (byte) 0x65, (byte) 0x72, (byte) 0x54, + (byte) 0x61, (byte) 0x62, (byte) 0x6c, (byte) 0x65, + (byte) 0x01, (byte) 0x00, (byte) 0x04, (byte) 0x74, + (byte) 0x65, (byte) 0x73, (byte) 0x74, (byte) 0x01, + (byte) 0x00, (byte) 0x14, (byte) 0x28, (byte) 0x29, + (byte) 0x4c, (byte) 0x6a, (byte) 0x61, (byte) 0x76, + (byte) 0x61, (byte) 0x2f, (byte) 0x6c, (byte) 0x61, + (byte) 0x6e, (byte) 0x67, (byte) 0x2f, (byte) 0x53, + (byte) 0x74, (byte) 0x72, (byte) 0x69, (byte) 0x6e, + (byte) 0x67, (byte) 0x3b, (byte) 0x01, (byte) 0x00, + (byte) 0x0a, (byte) 0x53, (byte) 0x6f, (byte) 0x75, + (byte) 0x72, (byte) 0x63, (byte) 0x65, (byte) 0x46, + (byte) 0x69, (byte) 0x6c, (byte) 0x65, (byte) 0x01, + (byte) 0x00, (byte) 0x0b, (byte) 0x43, (byte) 0x4c, + (byte) 0x54, (byte) 0x65, (byte) 0x73, (byte) 0x74, + (byte) 0x2e, (byte) 0x6a, (byte) 0x61, (byte) 0x76, + (byte) 0x61, (byte) 0x0c, (byte) 0x00, (byte) 0x05, + (byte) 0x00, (byte) 0x06, (byte) 0x01, (byte) 0x00, + (byte) 0x0e, (byte) 0x54, (byte) 0x68, (byte) 0x69, + (byte) 0x73, (byte) 0x20, (byte) 0x69, (byte) 0x73, + (byte) 0x20, (byte) 0x74, (byte) 0x65, (byte) 0x73, + (byte) 0x74, (byte) 0x20, (byte) 0x32, (byte) 0x01, + (byte) 0x00, (byte) 0x0d, (byte) 0x6d, (byte) 0x79, + (byte) 0x2f, (byte) 0x70, (byte) 0x6b, (byte) 0x67, + (byte) 0x2f, (byte) 0x43, (byte) 0x4c, (byte) 0x54, + (byte) 0x65, (byte) 0x73, (byte) 0x74, (byte) 0x01, + (byte) 0x00, (byte) 0x10, (byte) 0x6a, (byte) 0x61, + (byte) 0x76, (byte) 0x61, (byte) 0x2f, (byte) 0x6c, + (byte) 0x61, (byte) 0x6e, (byte) 0x67, (byte) 0x2f, + (byte) 0x4f, (byte) 0x62, (byte) 0x6a, (byte) 0x65, + (byte) 0x63, (byte) 0x74, (byte) 0x00, (byte) 0x21, + (byte) 0x00, (byte) 0x03, (byte) 0x00, (byte) 0x04, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x02, (byte) 0x00, (byte) 0x01, + (byte) 0x00, (byte) 0x05, (byte) 0x00, (byte) 0x06, + (byte) 0x00, (byte) 0x01, (byte) 0x00, (byte) 0x07, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x1d, + (byte) 0x00, (byte) 0x01, (byte) 0x00, (byte) 0x01, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x05, + (byte) 0x2a, (byte) 0xb7, (byte) 0x00, (byte) 0x01, + (byte) 0xb1, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x01, (byte) 0x00, (byte) 0x08, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x06, (byte) 0x00, + (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x04, (byte) 0x00, (byte) 0x01, (byte) 0x00, + (byte) 0x09, (byte) 0x00, (byte) 0x0a, (byte) 0x00, + (byte) 0x01, (byte) 0x00, (byte) 0x07, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x1b, (byte) 0x00, + (byte) 0x01, (byte) 0x00, (byte) 0x01, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x03, (byte) 0x12, + (byte) 0x02, (byte) 0xb0, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x01, (byte) 0x00, (byte) 0x08, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x06, + (byte) 0x00, (byte) 0x01, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x06, (byte) 0x00, (byte) 0x01, + (byte) 0x00, (byte) 0x0b, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x02, (byte) 0x00, (byte) 0x0c + }; + + /* + * Custom class loader. + */ + private class MyLoader extends ClassLoader { + public MyLoader(byte[] data) { + super(); + mData = data; + } + + protected Class findClass(String name) throws ClassNotFoundException { + assertEquals("my.pkg.CLTest", name); + return defineClass(name, mData, 0, mData.length); + } + + byte[] mData; + } + + + /* + * Simple test: manually load two class files that have the same class + * name but different contents. + */ + public void testClassLoader() throws Exception { + Class test1, test2; + MyLoader loader1 = new MyLoader(test1class); + MyLoader loader2 = new MyLoader(test2class); + + test1 = loader1.loadClass("my.pkg.CLTest"); + test2 = loader2.loadClass("my.pkg.CLTest"); + + methodTest(test1, "This is test 1"); + methodTest(test2, "This is test 2"); + } + + /* + * Invoke the test() method and verify that the string returned + * matches what we expect. + */ + private static void methodTest(Class clazz, String expect) + throws NoSuchMethodException, InstantiationException, + IllegalAccessException, InvocationTargetException { + Method meth = clazz.getMethod("test", (Class[]) null); + Object obj = clazz.newInstance(); + Object result = meth.invoke(obj, (Object[]) null); + + assertEquals(result, expect); + } +} + diff --git a/tests/CoreTests/android/core/ClassTest.java b/tests/CoreTests/android/core/ClassTest.java new file mode 100644 index 0000000000000000000000000000000000000000..cc1b4ca8ef72a8ad078233a956655e66678c83ca --- /dev/null +++ b/tests/CoreTests/android/core/ClassTest.java @@ -0,0 +1,337 @@ +/* + * 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 android.core; + +import android.test.suitebuilder.annotation.MediumTest; +import android.test.suitebuilder.annotation.SmallTest; +import android.widget.Button; +import junit.framework.TestCase; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.util.HashSet; +import java.util.Set; + + +class ClassWithPrivateConstructor { + private ClassWithPrivateConstructor() { + } +} + +public class ClassTest extends TestCase { + + @SmallTest + public void testClass() throws Exception { + // Now, never mind the fact that most of this stuff has to work + // for the test harness to get this far.... + + //System.out.println("Class.forName()"); + Class helloClass = Class.forName(ClassTest.class.getName()); + + //System.out.println("Class.newInstance()"); + Object instance = helloClass.newInstance(); + assertNotNull(instance); + + //System.out.println("Class.forName() nonexisting class"); + try { + Class.forName("this.class.DoesNotExist"); + fail("unexpected success"); + } catch (ClassNotFoundException ex) { + // expected + } + + //System.out.println("Class.newInstance() private constructor"); + try { + Class.forName("android.core.ClassWithPrivateConstructor").newInstance(); + fail("unexpected success"); + } catch (IllegalAccessException ex) { + // this is expected + } + + //System.out.println("Class.getDeclaredMethod()"); + + Method method = helloClass.getDeclaredMethod("method", (Class[]) null); + + method.invoke(new ClassTest(), (Object[]) null); + + //System.out.println("Class.getDeclaredMethod() w/ args"); + + method = helloClass.getDeclaredMethod("methodWithArgs", Object.class); + + Object invokeArgs[] = new Object[1]; + invokeArgs[0] = "Hello"; + Object ret = method.invoke(new ClassTest(), invokeArgs); + assertEquals(ret, invokeArgs[0]); + + //System.out.println("Class.getDeclaredMethod() -- private"); + + method = helloClass.getDeclaredMethod("privateMethod", (Class[]) null); + + method.invoke(new ClassTest(), (Object[]) null); + //fail("unexpected success"); + // TODO: I think this actually *should* succeed, because the + // call to the private method is being made from the same class. + // This needs to be replaced with a private call to a different + // class. + + //System.out.println("Class.getSuperclass"); + Class objectClass = Class.forName("java.lang.Object"); + assertEquals(helloClass.getSuperclass().getSuperclass().getSuperclass(), objectClass); + + //System.out.println("Class.isAssignableFrom"); + assertTrue(objectClass.isAssignableFrom(helloClass)); + assertFalse(helloClass.isAssignableFrom(objectClass)); + + //System.out.println("Class.getConstructor"); + + Constructor constructor = helloClass.getConstructor((Class[]) null); + assertNotNull(constructor); + + //System.out.println("Class.getModifiers"); + + assertTrue(Modifier.isPublic(helloClass.getModifiers())); + //System.out.println("Modifiers: " + Modifier.toString(helloClass.getModifiers())); + + //System.out.println("Class.getMethod"); + + helloClass.getMethod("method", (Class[]) null); + + try { + Class[] argTypes = new Class[1]; + argTypes[0] = helloClass; + helloClass.getMethod("method", argTypes); + fail("unexpected success"); + } catch (NoSuchMethodException ex) { + // exception expected + } + + // Test for public tracker issue 14 + SimpleClass obj = new SimpleClass(); + Field field = obj.getClass().getDeclaredField("str"); + field.set(obj, null); + } + + public class SimpleClass { + public String str; + } + + public Object methodWithArgs(Object o) { + return o; + } + + boolean methodInvoked; + + public void method() { + methodInvoked = true; + } + + boolean privateMethodInvoked; + + public void privateMethod() { + privateMethodInvoked = true; + } + + // Regression for 1018067: Class.getMethods() returns the same method over + // and over again from all base classes + @MediumTest + public void testClassGetMethodsNoDupes() { + Method[] methods = Button.class.getMethods(); + Set set = new HashSet(); + + for (int i = 0; i < methods.length; i++) { + String signature = methods[i].toString(); + + int par = signature.indexOf('('); + int dot = signature.lastIndexOf('.', par); + + signature = signature.substring(dot + 1); + + assertFalse("Duplicate " + signature, set.contains(signature)); + set.add(signature); + } + } + + interface MyInterface { + void foo(); + } + + interface MyOtherInterface extends MyInterface { + void bar(); + } + + abstract class MyClass implements MyOtherInterface { + public void gabba() { + } + + public void hey() { + } + } + + // Check if we also reflect methods from interfaces + @SmallTest + public void testGetMethodsInterfaces() { + Method[] methods = MyInterface.class.getMethods(); + assertTrue("Interface method must be there", hasMethod(methods, ".foo(")); + + methods = MyOtherInterface.class.getMethods(); + assertTrue("Interface method must be there", hasMethod(methods, ".foo(")); + assertTrue("Interface method must be there", hasMethod(methods, ".bar(")); + + methods = MyClass.class.getMethods(); + assertTrue("Interface method must be there", hasMethod(methods, ".foo(")); + assertTrue("Interface method must be there", hasMethod(methods, ".bar(")); + + assertTrue("Declared method must be there", hasMethod(methods, ".gabba(")); + assertTrue("Declared method must be there", hasMethod(methods, ".hey(")); + + assertTrue("Inherited method must be there", hasMethod(methods, ".toString(")); + } + + private boolean hasMethod(Method[] methods, String signature) { + for (int i = 0; i < methods.length; i++) { + if (methods[i].toString().contains(signature)) { + return true; + } + } + + return false; + } + + // Test for Class.getPackage(); + @SmallTest + public void testClassGetPackage() { + assertNotNull("Package must be non-null", getClass().getPackage()); + assertEquals("Package must have expected name", "android.core", getClass().getPackage().getName()); + assertEquals("Package must have expected title", "Unknown", getClass().getPackage().getSpecificationTitle()); + + Package p = java.lang.Object.class.getPackage(); + assertNotNull("Package must be non-null", p); + assertEquals("Package must have expected name", "java.lang", p.getName()); + assertSame("Package object must be same for each call", p, java.lang.Object.class.getPackage()); + } + + // Regression test for #1123708: Problem with getCanonicalName(), + // getSimpleName(), and getPackage(). + // + // A couple of interesting cases need to be checked: Top-level classes, + // member classes, local classes, and anonymous classes. Also, boundary + // cases with '$' in the class names are checked, since the '$' is used + // as the separator between outer and inner class, so this might lead + // to problems (it did in the previous implementation). + // + // Caution: Adding local or anonymous classes elsewhere in this + // file might affect the test. + private class MemberClass { + // This space intentionally left blank. + } + + private class Mi$o$oup { + // This space intentionally left blank. + } + + @SmallTest + public void testVariousClassNames() { + Class clazz = this.getClass(); + String pkg = (clazz.getPackage() == null ? "" : clazz.getPackage().getName() + "."); + + // Simple, top-level class + + assertEquals("Top-level class name must be correct", pkg + "ClassTest", clazz.getName()); + assertEquals("Top-level class simple name must be correct", "ClassTest", clazz.getSimpleName()); + assertEquals("Top-level class canonical name must be correct", pkg + "ClassTest", clazz.getCanonicalName()); + + clazz = MemberClass.class; + + assertEquals("Member class name must be correct", pkg + "ClassTest$MemberClass", clazz.getName()); + assertEquals("Member class simple name must be correct", "MemberClass", clazz.getSimpleName()); + assertEquals("Member class canonical name must be correct", pkg + "ClassTest.MemberClass", clazz.getCanonicalName()); + + class LocalClass { + // This space intentionally left blank. + } + + clazz = LocalClass.class; + + assertEquals("Local class name must be correct", pkg + "ClassTest$1LocalClass", clazz.getName()); + assertEquals("Local class simple name must be correct", "LocalClass", clazz.getSimpleName()); + assertNull("Local class canonical name must be null", clazz.getCanonicalName()); + + clazz = new Object() { }.getClass(); + + assertEquals("Anonymous class name must be correct", pkg + "ClassTest$1", clazz.getName()); + assertEquals("Anonymous class simple name must be empty", "", clazz.getSimpleName()); + assertNull("Anonymous class canonical name must be null", clazz.getCanonicalName()); + + // Weird special cases with dollar in name. + + clazz = Mou$$aka.class; + + assertEquals("Top-level class name must be correct", pkg + "Mou$$aka", clazz.getName()); + assertEquals("Top-level class simple name must be correct", "Mou$$aka", clazz.getSimpleName()); + assertEquals("Top-level class canonical name must be correct", pkg + "Mou$$aka", clazz.getCanonicalName()); + + clazz = Mi$o$oup.class; + + assertEquals("Member class name must be correct", pkg + "ClassTest$Mi$o$oup", clazz.getName()); + assertEquals("Member class simple name must be correct", "Mi$o$oup", clazz.getSimpleName()); + assertEquals("Member class canonical name must be correct", pkg + "ClassTest.Mi$o$oup", clazz.getCanonicalName()); + + class Ma$hedPotatoe$ { + // This space intentionally left blank. + } + + clazz = Ma$hedPotatoe$.class; + + assertEquals("Member class name must be correct", pkg + "ClassTest$1Ma$hedPotatoe$", clazz.getName()); + assertEquals("Member class simple name must be correct", "Ma$hedPotatoe$", clazz.getSimpleName()); + assertNull("Member class canonical name must be null", clazz.getCanonicalName()); + } + + @SmallTest + public void testLocalMemberClass() { + Class clazz = this.getClass(); + + assertFalse("Class must not be member", clazz.isMemberClass()); + assertFalse("Class must not be local", clazz.isLocalClass()); + + clazz = MemberClass.class; + + assertTrue("Class must be member", clazz.isMemberClass()); + assertFalse("Class must not be local", clazz.isLocalClass()); + + class OtherLocalClass { + // This space intentionally left blank. + } + + clazz = OtherLocalClass.class; + + assertFalse("Class must not be member", clazz.isMemberClass()); + assertTrue("Class must be local", clazz.isLocalClass()); + + clazz = new Object() { }.getClass(); + + assertFalse("Class must not be member", clazz.isMemberClass()); + assertFalse("Class must not be local", clazz.isLocalClass()); + } + +} + +class Mou$$aka { + // This space intentionally left blank. +} diff --git a/tests/CoreTests/android/core/CoreTests.java b/tests/CoreTests/android/core/CoreTests.java new file mode 100644 index 0000000000000000000000000000000000000000..e4f835c0573716cb607b0785b7ce4ffb64143ff5 --- /dev/null +++ b/tests/CoreTests/android/core/CoreTests.java @@ -0,0 +1,66 @@ +/* + * 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 android.core; + +import com.android.internal.telephony.TelephonyTests; + +import junit.framework.TestSuite; + +import android.graphics.ColorStateListTest; +import android.location.LocationManagerProximityTest; +import android.location.LocationTest; +import android.test.AndroidTestRunnerTest; +import android.test.InstrumentationTestRunnerTest; +import android.util.*; +import android.view.FocusFinderTest; +import android.view.ViewGroupAttributesTest; +import android.webkit.*; + +public class CoreTests extends TestSuite { + + /** + * To run these tests: + * $ mmm java/tests && adb sync + * $ adb shell am instrument -w \ + * -e class android.core.CoreTests \ + * android.core/android.test.InstrumentationTestRunner + */ + public static TestSuite suite() { + TestSuite suite = new TestSuite(CoreTests.class.getName()); + + // Re-enable StateListDrawableTest when we are running in the + // framework-test directory which allows access to package private + // access for MockView + // suite.addTestSuite(StateListDrawableTest.class); + suite.addTestSuite(DayOfMonthCursorTest.class); + suite.addTestSuite(MonthDisplayHelperTest.class); + suite.addTestSuite(StateSetTest.class); + suite.addTestSuite(ColorStateListTest.class); + suite.addTestSuite(FocusFinderTest.class); + suite.addTestSuite(ViewGroupAttributesTest.class); + suite.addTest(TelephonyTests.suite()); + suite.addTestSuite(FloatMathTest.class); + suite.addTest(JavaTests.suite()); + suite.addTestSuite(LocationTest.class); + suite.addTestSuite(LocationManagerProximityTest.class); + suite.addTestSuite(AndroidTestRunnerTest.class); + suite.addTestSuite(InstrumentationTestRunnerTest.class); + suite.addTestSuite(CookieTest.class); + + return suite; + } +} diff --git a/tests/CoreTests/android/core/CryptoTest.java b/tests/CoreTests/android/core/CryptoTest.java new file mode 100644 index 0000000000000000000000000000000000000000..f00d49ff0f219e2085b4be16d1430647a6da6aff --- /dev/null +++ b/tests/CoreTests/android/core/CryptoTest.java @@ -0,0 +1,137 @@ +/* + * 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 android.core; + +import junit.framework.Assert; +import junit.framework.TestCase; + +import org.apache.harmony.xnet.provider.jsse.OpenSSLMessageDigest; +import org.bouncycastle.crypto.Digest; +import org.bouncycastle.crypto.ExtendedDigest; +import org.bouncycastle.crypto.digests.MD2Digest; +import org.bouncycastle.crypto.digests.MD4Digest; +import org.bouncycastle.crypto.digests.MD5Digest; +import org.bouncycastle.crypto.digests.SHA1Digest; +import android.test.suitebuilder.annotation.LargeTest; +import android.test.suitebuilder.annotation.MediumTest; + +/** + * Implements unit tests for our JNI wrapper around OpenSSL. We use the + * existing Bouncy Castle implementation as our test oracle. + */ +public class CryptoTest extends TestCase { + + /** + * Processes the two given message digests for the same data and checks + * the results. Requirement is that the results must be equal, the digest + * implementations must have the same properties, and the new implementation + * must be faster than the old one. + * + * @param oldDigest The old digest implementation, provided by Bouncy Castle + * @param newDigest The new digest implementation, provided by OpenSSL + */ + public void doTestMessageDigest(Digest oldDigest, Digest newDigest) { + final int ITERATIONS = 10; + + byte[] data = new byte[1024]; + + byte[] oldHash = new byte[oldDigest.getDigestSize()]; + byte[] newHash = new byte[newDigest.getDigestSize()]; + + Assert.assertEquals("Hash names must be equal", oldDigest.getAlgorithmName(), newDigest.getAlgorithmName()); + Assert.assertEquals("Hash sizes must be equal", oldHash.length, newHash.length); + Assert.assertEquals("Hash block sizes must be equal", ((ExtendedDigest)oldDigest).getByteLength(), ((ExtendedDigest)newDigest).getByteLength()); + for (int i = 0; i < data.length; i++) { + data[i] = (byte)i; + } + + long oldTime = 0; + long newTime = 0; + + for (int j = 0; j < ITERATIONS; j++) { + long t0 = System.currentTimeMillis(); + for (int i = 0; i < 4; i++) { + oldDigest.update(data, 0, data.length); + } + int oldLength = oldDigest.doFinal(oldHash, 0); + long t1 = System.currentTimeMillis(); + + oldTime = oldTime + (t1 - t0); + + long t2 = System.currentTimeMillis(); + for (int i = 0; i < 4; i++) { + newDigest.update(data, 0, data.length); + } + int newLength = newDigest.doFinal(newHash, 0); + long t3 = System.currentTimeMillis(); + + newTime = newTime + (t3 - t2); + + Assert.assertEquals("Hash sizes must be equal", oldLength, newLength); + + for (int i = 0; i < oldLength; i++) { + Assert.assertEquals("Hashes[" + i + "] must be equal", oldHash[i], newHash[i]); + } + } + + android.util.Log.d("CryptoTest", "Time for " + ITERATIONS + " x old hash processing: " + oldTime + " ms"); + android.util.Log.d("CryptoTest", "Time for " + ITERATIONS + " x new hash processing: " + newTime + " ms"); + + // Assert.assertTrue("New hash should be faster", newTime < oldTime); + } + + /** + * Tests the MD2 implementation. + */ + @LargeTest + public void testMD2() { + Digest oldDigest = new MD2Digest(); + Digest newDigest = OpenSSLMessageDigest.getInstance("MD2"); + doTestMessageDigest(oldDigest, newDigest); + } + + /** + * Tests the MD4 implementation. + */ + @MediumTest + public void testMD4() { + Digest oldDigest = new MD4Digest(); + Digest newDigest = OpenSSLMessageDigest.getInstance("MD4"); + doTestMessageDigest(oldDigest, newDigest); + } + + /** + * Tests the MD5 implementation. + */ + @MediumTest + public void testMD5() { + Digest oldDigest = new MD5Digest(); + Digest newDigest = OpenSSLMessageDigest.getInstance("MD5"); + doTestMessageDigest(oldDigest, newDigest); + } + + /** + * Tests the SHA-1 implementation. + */ + @MediumTest + public void testSHA1() { + Digest oldDigest = new SHA1Digest(); + Digest newDigest = OpenSSLMessageDigest.getInstance("SHA-1"); + doTestMessageDigest(oldDigest, newDigest); + } + +} diff --git a/tests/CoreTests/android/core/DataInputStreamTest.java b/tests/CoreTests/android/core/DataInputStreamTest.java new file mode 100644 index 0000000000000000000000000000000000000000..ca801d64f1ec180a6adeb0de55949f576b7af076 --- /dev/null +++ b/tests/CoreTests/android/core/DataInputStreamTest.java @@ -0,0 +1,107 @@ +/* + * 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 android.core; + +import junit.framework.TestCase; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import android.test.suitebuilder.annotation.SmallTest; + +public class DataInputStreamTest extends TestCase { + + @SmallTest + public void testDataInputStream() throws Exception { + String str = "AbCdEfGhIjKlM\nOpQ\rStUvWxYz"; + ByteArrayInputStream aa = new ByteArrayInputStream(str.getBytes()); + ByteArrayInputStream ba = new ByteArrayInputStream(str.getBytes()); + ByteArrayInputStream ca = new ByteArrayInputStream(str.getBytes()); + ByteArrayInputStream da = new ByteArrayInputStream(str.getBytes()); + + DataInputStream a = new DataInputStream(aa); + try { + assertEquals(str, IOUtil.read(a)); + } finally { + a.close(); + } + + DataInputStream b = new DataInputStream(ba); + try { + assertEquals("AbCdEfGhIj", IOUtil.read(b, 10)); + } finally { + b.close(); + } + + DataInputStream c = new DataInputStream(ca); + try { + assertEquals("bdfhjl\np\rtvxz", IOUtil.skipRead(c)); + } finally { + c.close(); + } + + DataInputStream d = new DataInputStream(da); + try { + assertEquals("AbCdEfGhIjKlM", d.readLine()); + assertEquals("OpQ", d.readLine()); + assertEquals("StUvWxYz", d.readLine()); + } finally { + d.close(); + } + + ByteArrayOutputStream e = new ByteArrayOutputStream(); + DataOutputStream f = new DataOutputStream(e); + try { + f.writeBoolean(true); + f.writeByte('a'); + f.writeBytes("BCD"); + f.writeChar('e'); + f.writeChars("FGH"); + f.writeUTF("ijklm"); + f.writeDouble(1); + f.writeFloat(2); + f.writeInt(3); + f.writeLong(4); + f.writeShort(5); + } finally { + f.close(); + } + + ByteArrayInputStream ga = new ByteArrayInputStream(e.toByteArray()); + DataInputStream g = new DataInputStream(ga); + + try { + assertTrue(g.readBoolean()); + assertEquals('a', g.readByte()); + assertEquals(2, g.skipBytes(2)); + assertEquals('D', g.readByte()); + assertEquals('e', g.readChar()); + assertEquals('F', g.readChar()); + assertEquals('G', g.readChar()); + assertEquals('H', g.readChar()); + assertEquals("ijklm", g.readUTF()); + assertEquals(1, g.readDouble(), 0); + assertEquals(2f, g.readFloat(), 0f); + assertEquals(3, g.readInt()); + assertEquals(4, g.readLong()); + assertEquals(5, g.readShort()); + } finally { + g.close(); + } + } +} diff --git a/tests/CoreTests/android/core/DataOutputStreamTest.java b/tests/CoreTests/android/core/DataOutputStreamTest.java new file mode 100644 index 0000000000000000000000000000000000000000..95502b354bc59c4471053ef6e2fc9b723d3e8223 --- /dev/null +++ b/tests/CoreTests/android/core/DataOutputStreamTest.java @@ -0,0 +1,51 @@ +/* + * 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 android.core; + +import junit.framework.TestCase; + +import java.io.ByteArrayOutputStream; +import java.io.DataOutputStream; +import android.test.suitebuilder.annotation.SmallTest; + +/** + * Basic tests for DataOutputStreams. + */ +public class DataOutputStreamTest extends TestCase { + + @SmallTest + public void testDataOutputStream() throws Exception { + String str = "AbCdEfGhIjKlMnOpQrStUvWxYz"; + ByteArrayOutputStream aa = new ByteArrayOutputStream(); + DataOutputStream a = new DataOutputStream(aa); + + try { + a.write(str.getBytes(), 0, 26); + a.write('A'); + + assertEquals(27, aa.size()); + assertEquals("AbCdEfGhIjKlMnOpQrStUvWxYzA", aa.toString()); + + a.writeByte('B'); + assertEquals("AbCdEfGhIjKlMnOpQrStUvWxYzAB", aa.toString()); + a.writeBytes("BYTES"); + assertEquals("AbCdEfGhIjKlMnOpQrStUvWxYzABBYTES", aa.toString()); + } finally { + a.close(); + } + } +} diff --git a/tests/CoreTests/android/core/DatagramTest.java b/tests/CoreTests/android/core/DatagramTest.java new file mode 100644 index 0000000000000000000000000000000000000000..355a267edcdc46528bd06fcad85d0bf0e73584cc --- /dev/null +++ b/tests/CoreTests/android/core/DatagramTest.java @@ -0,0 +1,192 @@ +/* + * 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 android.core; + +import junit.framework.TestCase; + +import java.io.IOException; +import java.net.DatagramPacket; +import java.net.DatagramSocket; +import java.net.InetAddress; +import java.net.SocketTimeoutException; +import android.test.suitebuilder.annotation.LargeTest; + +/** + * Implements some simple tests for datagrams. Not as excessive as the core + * tests, but good enough for the harness. + */ +public class DatagramTest extends TestCase { + + /** + * Helper class that listens to incoming datagrams and reflects them to the + * sender. Incoming datagram is interpreted as a String. It is uppercased + * before being sent back. + */ + + class Reflector extends Thread { + // Helper class for reflecting incoming datagrams. + DatagramSocket socket; + + boolean alive = true; + + byte[] buffer = new byte[256]; + + DatagramPacket packet; + + /** + * Main loop. Receives datagrams and reflects them. + */ + @Override + public void run() { + try { + while (alive) { + try { + packet.setLength(buffer.length); + socket.receive(packet); + String s = stringFromPacket(packet); + // System.out.println(s + " (from " + packet.getAddress() + ":" + packet.getPort() + ")"); + + try { + Thread.sleep(100); + } catch (InterruptedException ex) { + // Ignore. + } + + stringToPacket(s.toUpperCase(), packet); + + packet.setAddress(InetAddress.getLocalHost()); + packet.setPort(2345); + + socket.send(packet); + } catch (java.io.InterruptedIOException e) { + } + } + } catch (java.io.IOException ex) { + ex.printStackTrace(); + } finally { + socket.close(); + } + } + + /** + * Creates a new Relfector object for the given local address and port. + */ + public Reflector(int port, InetAddress address) { + try { + packet = new DatagramPacket(buffer, buffer.length); + socket = new DatagramSocket(port, address); + } catch (IOException ex) { + throw new RuntimeException( + "Creating datagram reflector failed", ex); + } + } + } + + /** + * Converts a given datagram packet's contents to a String. + */ + static String stringFromPacket(DatagramPacket packet) { + return new String(packet.getData(), 0, packet.getLength()); + } + + /** + * Converts a given String into a datagram packet. + */ + static void stringToPacket(String s, DatagramPacket packet) { + byte[] bytes = s.getBytes(); + System.arraycopy(bytes, 0, packet.getData(), 0, bytes.length); + packet.setLength(bytes.length); + } + + /** + * Implements the main part of the Datagram test. + */ + @LargeTest + public void testDatagram() throws Exception { + + Reflector reflector = null; + DatagramSocket socket = null; + + try { + // Setup the reflector, so we have a partner to send to + reflector = new Reflector(1234, InetAddress.getLocalHost()); + reflector.start(); + + byte[] buffer = new byte[256]; + + DatagramPacket packet = new DatagramPacket(buffer, buffer.length); + socket = new DatagramSocket(2345, InetAddress.getLocalHost()); + + // Send ten simple packets and check for the expected responses. + for (int i = 1; i <= 10; i++) { + String s = "Hello, Android world #" + i + "!"; + stringToPacket(s, packet); + + packet.setAddress(InetAddress.getLocalHost()); + packet.setPort(1234); + + socket.send(packet); + + try { + Thread.sleep(100); + } catch (InterruptedException ex) { + // Ignore. + } + + packet.setLength(buffer.length); + socket.receive(packet); + String t = stringFromPacket(packet); + // System.out.println(t + " (from " + packet.getAddress() + ":" + packet.getPort() + ")"); + + assertEquals(s.toUpperCase(), t); + } + } finally { + if (reflector != null) { + reflector.alive = false; + } + + if (socket != null) { + socket.close(); + } + } + } + + // Regression test for issue 1018003: DatagramSocket ignored a set timeout. + @LargeTest + public void testDatagramSocketSetSOTimeout() throws Exception { + DatagramSocket sock = null; + int timeout = 5000; + long start = System.currentTimeMillis(); + try { + sock = new DatagramSocket(); + DatagramPacket pack = new DatagramPacket(new byte[100], 100); + sock.setSoTimeout(timeout); + sock.receive(pack); + } catch (SocketTimeoutException e) { + // expected + long delay = System.currentTimeMillis() - start; + if (Math.abs(delay - timeout) > 1000) { + fail("timeout was not accurate. expected: " + timeout + + " actual: " + delay + " miliseconds."); + } + } finally { + if (sock != null) { + sock.close(); + } + } + } +} diff --git a/tests/CoreTests/android/core/DeflateTest.java b/tests/CoreTests/android/core/DeflateTest.java new file mode 100644 index 0000000000000000000000000000000000000000..d68d697f59ed8e812ba8ee709ba3fd8d86e10368 --- /dev/null +++ b/tests/CoreTests/android/core/DeflateTest.java @@ -0,0 +1,199 @@ +/* + * 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 android.core; + +import junit.framework.TestCase; + +import java.io.UnsupportedEncodingException; +import java.util.zip.DataFormatException; +import java.util.zip.Deflater; +import java.util.zip.Inflater; +import android.test.suitebuilder.annotation.LargeTest; + +public class DeflateTest extends TestCase { + + @LargeTest + public void testDeflate() throws Exception { + simpleTest(); + + bigTest(0, 1738149618); + bigTest(1, 934350518); + bigTest(2, -532869390); + } + + /* + * Simple inflate/deflate test, taken from the reference docs for the + * Inflater/Deflater classes. + */ + private void simpleTest() + throws UnsupportedEncodingException, DataFormatException { + // Encode a String into bytes + String inputString = "blahblahblah??"; + byte[] input = inputString.getBytes("UTF-8"); + + // Compress the bytes + byte[] output = new byte[100]; + Deflater compresser = new Deflater(); + compresser.setInput(input); + compresser.finish(); + int compressedDataLength = compresser.deflate(output); + + // Decompress the bytes + Inflater decompresser = new Inflater(); + decompresser.setInput(output, 0, compressedDataLength); + byte[] result = new byte[100]; + int resultLength = decompresser.inflate(result); + + // Decode the bytes into a String + String outputString = new String(result, 0, resultLength, "UTF-8"); + + assertEquals(inputString, outputString); + assertEquals(compresser.getAdler(), decompresser.getAdler()); + + decompresser.end(); + } + + /* + * "step" determines how compressible the data is. + * + * Note we must set "nowrap" to false, or the Adler-32 doesn't get + * computed. + */ + private void bigTest(int step, int expectedAdler) + throws UnsupportedEncodingException, DataFormatException { + byte[] input = new byte[128 * 1024]; + byte[] comp = new byte[128 * 1024 + 512]; + byte[] output = new byte[128 * 1024 + 512]; + Inflater inflater = new Inflater(false); + Deflater deflater = new Deflater(Deflater.BEST_COMPRESSION, false); + + createSample(input, step); + + compress(deflater, input, comp); + expand(inflater, comp, (int) deflater.getBytesWritten(), output); + + assertEquals(inflater.getBytesWritten(), input.length); + assertEquals(deflater.getAdler(), inflater.getAdler()); + assertEquals(deflater.getAdler(), expectedAdler); + } + + /* + * Create a large data sample. + * stepStep = 0 --> >99% compression + * stepStep = 1 --> ~30% compression + * stepStep = 2 --> no compression + */ + private void createSample(byte[] sample, int stepStep) { + byte val, step; + int i, j, offset; + + assertTrue(sample.length >= 128 * 1024); + + val = 0; + step = 1; + offset = 0; + for (i = 0; i < (128 * 1024) / 256; i++) { + for (j = 0; j < 256; j++) { + sample[offset++] = val; + val += step; + } + + step += stepStep; + } + } + + private static final int LOCAL_BUF_SIZE = 256; + + /* + * Compress all data in "in" to "out". We use a small window on input + * and output to exercise that part of the code. + * + * It's the caller's responsibility to ensure that "out" has enough + * space. + */ + private void compress(Deflater deflater, byte[] inBuf, byte[] outBuf) { + int inCount = inBuf.length; // use all + int inPosn; + int outPosn; + + inPosn = outPosn = 0; + + //System.out.println("### starting compress"); + + while (!deflater.finished()) { + int want = -1, got; + + // only read if the input buffer is empty + if (deflater.needsInput() && inCount != 0) { + want = (inCount < LOCAL_BUF_SIZE) ? inCount : LOCAL_BUF_SIZE; + + deflater.setInput(inBuf, inPosn, want); + + inCount -= want; + inPosn += want; + if (inCount == 0) { + deflater.finish(); + } + } + + // deflate to current position in output buffer + int compCount; + + compCount = deflater.deflate(outBuf, outPosn, LOCAL_BUF_SIZE); + outPosn += compCount; + + //System.out.println("Compressed " + want + ", output " + compCount); + } + } + + /* + * Expand data from "inBuf" to "outBuf". Uses a small window to better + * exercise the code. + */ + private void expand(Inflater inflater, byte[] inBuf, int inCount, + byte[] outBuf) throws DataFormatException { + int inPosn; + int outPosn; + + inPosn = outPosn = 0; + + //System.out.println("### starting expand, inCount is " + inCount); + + while (!inflater.finished()) { + int want = -1, got; + + // only read if the input buffer is empty + if (inflater.needsInput() && inCount != 0) { + want = (inCount < LOCAL_BUF_SIZE) ? inCount : LOCAL_BUF_SIZE; + + inflater.setInput(inBuf, inPosn, want); + + inCount -= want; + inPosn += want; + } + + // inflate to current position in output buffer + int compCount; + + compCount = inflater.inflate(outBuf, outPosn, LOCAL_BUF_SIZE); + outPosn += compCount; + + //System.out.println("Expanded " + want + ", output " + compCount); + } + } +} + diff --git a/tests/CoreTests/android/core/EnumTest.java b/tests/CoreTests/android/core/EnumTest.java new file mode 100644 index 0000000000000000000000000000000000000000..d47949180a8ba229eeeecd7c728f35a7a101bc23 --- /dev/null +++ b/tests/CoreTests/android/core/EnumTest.java @@ -0,0 +1,64 @@ +/* + * 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 android.core; + +import junit.framework.TestCase; +import android.test.suitebuilder.annotation.SmallTest; + +/** + * Tests basic behavior of enums. + */ +public class EnumTest extends TestCase { + enum MyEnum { + ZERO, ONE, TWO, THREE, FOUR {boolean isFour() { + return true; + }}; + + boolean isFour() { + return false; + } + } + + enum MyEnumTwo { + FIVE, SIX + } + + @SmallTest + public void testEnum() throws Exception { + assertTrue(MyEnum.ZERO.compareTo(MyEnum.ONE) < 0); + assertEquals(MyEnum.ZERO, MyEnum.ZERO); + assertTrue(MyEnum.TWO.compareTo(MyEnum.ONE) > 0); + assertTrue(MyEnum.FOUR.compareTo(MyEnum.ONE) > 0); + + assertEquals("ONE", MyEnum.ONE.name()); + assertSame(MyEnum.ONE.getDeclaringClass(), MyEnum.class); + assertSame(MyEnum.FOUR.getDeclaringClass(), MyEnum.class); + + assertTrue(MyEnum.FOUR.isFour()); + + MyEnum e; + + e = MyEnum.ZERO; + + switch (e) { + case ZERO: + break; + default: + fail("wrong switch"); + } + } +} diff --git a/tests/CoreTests/android/core/FileTest.java b/tests/CoreTests/android/core/FileTest.java new file mode 100644 index 0000000000000000000000000000000000000000..980452e044baa1a42df7ce89592a18a6af41292e --- /dev/null +++ b/tests/CoreTests/android/core/FileTest.java @@ -0,0 +1,38 @@ +/* + * 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 android.core; + +import junit.framework.TestCase; + +import java.io.File; +import android.test.suitebuilder.annotation.SmallTest; + +/** + * Checks creation and deletion of a file. + */ +public class FileTest extends TestCase { + + @SmallTest + public void testFile() throws Exception { + + File file = File.createTempFile(String.valueOf(System.currentTimeMillis()), null, null); + + assertTrue(file.exists()); + assertTrue(file.delete()); + assertFalse(file.exists()); + } +} diff --git a/tests/CoreTests/android/core/FloatDoubleTest.java b/tests/CoreTests/android/core/FloatDoubleTest.java new file mode 100644 index 0000000000000000000000000000000000000000..8c8455b031cc5ce8bb29ddaa3ac25109efde3f89 --- /dev/null +++ b/tests/CoreTests/android/core/FloatDoubleTest.java @@ -0,0 +1,152 @@ +/* + * 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 android.core; + +import junit.framework.TestCase; +import android.test.suitebuilder.annotation.SmallTest; + +/** + * Tests for basic functionality of floats and doubles. + */ +public class FloatDoubleTest extends TestCase { + + @SmallTest + public void testFloatDouble() throws Exception { + Double d = Double.valueOf(1.0); + Float f = Float.valueOf(1.0f); + Object o = new Object(); + + assertFalse(f.equals(d)); + assertFalse(d.equals(f)); + assertFalse(f.equals(o)); + assertFalse(d.equals(o)); + assertFalse(f.equals(null)); + assertFalse(d.equals(null)); + } + + @SmallTest + public void testFloat() throws Exception { + float pz = 0.0f; + float nz = -0.0f; + + float pzero = 1.0f / Float.POSITIVE_INFINITY; + float nzero = 1.0f / Float.NEGATIVE_INFINITY; + + // Everything compares as '==' + assertTrue(pz == pz); + assertTrue(pz == nz); + assertTrue(pz == pzero); + assertTrue(pz == nzero); + + assertTrue(nz == pz); + assertTrue(nz == nz); + assertTrue(nz == pzero); + assertTrue(nz == nzero); + + assertTrue(pzero == pz); + assertTrue(pzero == nz); + assertTrue(pzero == pzero); + assertTrue(pzero == nzero); + + assertTrue(nzero == pz); + assertTrue(nzero == nz); + assertTrue(nzero == pzero); + assertTrue(nzero == nzero); + + // +-0 are distinct as Floats + assertEquals(Float.valueOf(pz), Float.valueOf(pz)); + assertTrue(!Float.valueOf(pz).equals(Float.valueOf(nz))); + assertEquals(Float.valueOf(pz), Float.valueOf(pzero)); + assertTrue(!Float.valueOf(pz).equals(Float.valueOf(nzero))); + + assertTrue(!Float.valueOf(nz).equals(Float.valueOf(pz))); + assertEquals(Float.valueOf(nz), Float.valueOf(nz)); + assertTrue(!Float.valueOf(nz).equals(Float.valueOf(pzero))); + assertEquals(Float.valueOf(nz), Float.valueOf(nzero)); + + assertEquals(Float.valueOf(pzero), Float.valueOf(pz)); + assertTrue(!Float.valueOf(pzero).equals(Float.valueOf(nz))); + assertEquals(Float.valueOf(pzero), Float.valueOf(pzero)); + assertTrue(!Float.valueOf(pzero).equals(Float.valueOf(nzero))); + + assertTrue(!Float.valueOf(nzero).equals(Float.valueOf(pz))); + assertEquals(Float.valueOf(nzero), Float.valueOf(nz)); + assertTrue(!Float.valueOf(nzero).equals(Float.valueOf(pzero))); + assertEquals(Float.valueOf(nzero), Float.valueOf(nzero)); + + // Nan's compare as equal + Float sqrtm2 = Float.valueOf((float) Math.sqrt(-2.0f)); + Float sqrtm3 = Float.valueOf((float) Math.sqrt(-3.0f)); + assertEquals(sqrtm2, sqrtm3); + } + + @SmallTest + public void testDouble() throws Exception { + double pz = 0.0; + double nz = -0.0; + + double pzero = 1.0 / Double.POSITIVE_INFINITY; + double nzero = 1.0 / Double.NEGATIVE_INFINITY; + + // Everything compares as '==' + assertTrue(pz == pz); + assertTrue(pz == nz); + assertTrue(pz == pzero); + assertTrue(pz == nzero); + + assertTrue(nz == pz); + assertTrue(nz == nz); + assertTrue(nz == pzero); + assertTrue(nz == nzero); + + assertTrue(pzero == pz); + assertTrue(pzero == nz); + assertTrue(pzero == pzero); + assertTrue(pzero == nzero); + + assertTrue(nzero == pz); + assertTrue(nzero == nz); + assertTrue(nzero == pzero); + assertTrue(nzero == nzero); + + // +-0 are distinct as Doubles + assertEquals(Double.valueOf(pz), Double.valueOf(pz)); + assertTrue(!Double.valueOf(pz).equals(Double.valueOf(nz))); + assertEquals(Double.valueOf(pz), Double.valueOf(pzero)); + assertTrue(!Double.valueOf(pz).equals(Double.valueOf(nzero))); + + assertTrue(!Double.valueOf(nz).equals(Double.valueOf(pz))); + assertEquals(Double.valueOf(nz), Double.valueOf(nz)); + assertTrue(!Double.valueOf(nz).equals(Double.valueOf(pzero))); + assertEquals(Double.valueOf(nz), Double.valueOf(nzero)); + + assertEquals(Double.valueOf(pzero), Double.valueOf(pz)); + assertTrue(!Double.valueOf(pzero).equals(Double.valueOf(nz))); + assertEquals(Double.valueOf(pzero), Double.valueOf(pzero)); + assertTrue(!Double.valueOf(pzero).equals(Double.valueOf(nzero))); + + assertTrue(!Double.valueOf(nzero).equals(Double.valueOf(pz))); + assertEquals(Double.valueOf(nzero), Double.valueOf(nz)); + assertTrue(!Double.valueOf(nzero).equals(Double.valueOf(pzero))); + assertEquals(Double.valueOf(nzero), Double.valueOf(nzero)); + + // Nan's compare as equal + Double sqrtm2 = Double.valueOf(Math.sqrt(-2.0)); + Double sqrtm3 = Double.valueOf(Math.sqrt(-3.0)); + assertEquals(sqrtm2, sqrtm3); + } +} diff --git a/tests/CoreTests/android/core/GZIPStreamTest.java b/tests/CoreTests/android/core/GZIPStreamTest.java new file mode 100644 index 0000000000000000000000000000000000000000..dd56fb7b43bd396d99cb35d5f544204e3486243e --- /dev/null +++ b/tests/CoreTests/android/core/GZIPStreamTest.java @@ -0,0 +1,114 @@ +/* + * 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 android.core; + +import junit.framework.TestCase; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.util.zip.GZIPInputStream; +import java.util.zip.GZIPOutputStream; +import android.test.suitebuilder.annotation.MediumTest; + +/** + * Deflates and inflates some test data with GZipStreams + */ +public class GZIPStreamTest extends TestCase { + + @MediumTest + public void testGZIPStream() throws Exception { + ByteArrayOutputStream bytesOut = new ByteArrayOutputStream(); + createGZIP(bytesOut); + + byte[] zipData; + zipData = bytesOut.toByteArray(); + + /* + FileOutputStream outFile = new FileOutputStream("/tmp/foo.gz"); + outFile.write(zipData, 0, zipData.length); + outFile.close(); + */ + + /* + FileInputStream inFile = new FileInputStream("/tmp/foo.gz"); + int inputLength = inFile.available(); + zipData = new byte[inputLength]; + if (inFile.read(zipData) != inputLength) + throw new RuntimeException(); + inFile.close(); + */ + + ByteArrayInputStream bytesIn = new ByteArrayInputStream(zipData); + scanGZIP(bytesIn); + } + + /* + * stepStep == 0 --> >99% compression + * stepStep == 1 --> ~30% compression + * stepStep == 2 --> no compression + */ + static byte[] makeSampleFile(int stepStep) throws IOException { + byte[] sample = new byte[128 * 1024]; + byte val, step; + int i, j, offset; + + val = 0; + step = 1; + offset = 0; + for (i = 0; i < (128 * 1024) / 256; i++) { + for (j = 0; j < 256; j++) { + sample[offset++] = val; + val += step; + } + + step += stepStep; + } + + return sample; + } + + static void createGZIP(ByteArrayOutputStream bytesOut) throws IOException { + GZIPOutputStream out = new GZIPOutputStream(bytesOut); + try { + byte[] input = makeSampleFile(1); + out.write(input, 0, input.length); + //out.finish(); + } finally { + out.close(); + } + } + + static void scanGZIP(ByteArrayInputStream bytesIn) throws IOException { + GZIPInputStream in = new GZIPInputStream(bytesIn); + try { + ByteArrayOutputStream contents = new ByteArrayOutputStream(); + byte[] buf = new byte[4096]; + int len, totalLen = 0; + + while ((len = in.read(buf)) > 0) { + contents.write(buf, 0, len); + totalLen += len; + } + + assertEquals(totalLen, 128 * 1024); + } finally { + in.close(); + } + } +} + diff --git a/tests/CoreTests/android/core/HashMapPerfTest.java b/tests/CoreTests/android/core/HashMapPerfTest.java new file mode 100644 index 0000000000000000000000000000000000000000..84752229e23c3ac12b7f589dcf375bfd454616b1 --- /dev/null +++ b/tests/CoreTests/android/core/HashMapPerfTest.java @@ -0,0 +1,93 @@ +/* + * 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 android.core; + +import android.os.SystemClock; +import android.test.suitebuilder.annotation.LargeTest; +import junit.framework.TestCase; + +import java.util.HashMap; +import java.util.Random; + +/** + * Tests basic functionality of HashMaps and prints the time needed to System.out + */ +public class HashMapPerfTest extends TestCase { + + private static final Random sRandom = new Random(1); + + class StringThing { + + String mId; + + public StringThing() { + int len = sRandom.nextInt(20) + 1; + char[] chars = new char[len]; + chars[0] = 't'; + for (int i = 1; i < len; i++) { + chars[i] = (char) ('q' + sRandom.nextInt(4)); + } + mId = new String(chars, 0, len); + } + + public String getId() { + return mId; + } + } + + private static final int NUM_ELTS = 1000; + private static final int ITERS = 100; + + String[] keyCopies = new String[NUM_ELTS]; + + private static final boolean lookupByOriginals = false; + + @LargeTest + public void testHashMapPerformance() throws Exception { + StringThing[] st = new StringThing[NUM_ELTS]; + for (int i = 0; i < NUM_ELTS; i++) { + st[i] = new StringThing(); + keyCopies[i] = st[i].getId(); + } + + // android.os.Debug.startMethodTracing(); + long start = SystemClock.uptimeMillis(); + for (int i = 0; i < ITERS; i++) { + HashMap map = new HashMap(); + for (int j = 0; j < NUM_ELTS; j++) { + StringThing s = st[i]; + map.put(s.getId(), s); + } + for (int j = 0; j < NUM_ELTS; j++) { + if (lookupByOriginals) { + StringThing s = st[i]; + map.get(s.getId()); + } else { + map.get(keyCopies[j]); + } + } + } + long finish = SystemClock.uptimeMillis(); + // android.os.Debug.stopMethodTracing(); + + // This should be an assertion instead + +// System.out.println("time (" + NUM_ELTS + +// ", elts, " + ITERS + +// " iters) = " + (finish - start)); + } +} diff --git a/tests/CoreTests/android/core/HashMapTest.java b/tests/CoreTests/android/core/HashMapTest.java new file mode 100644 index 0000000000000000000000000000000000000000..99b2a478113c31fd69b8e4e3ba2c4e958afaffdd --- /dev/null +++ b/tests/CoreTests/android/core/HashMapTest.java @@ -0,0 +1,281 @@ +/* + * 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 android.core; + +import junit.framework.TestCase; + +import java.util.HashMap; +import java.util.Iterator; +import android.test.suitebuilder.annotation.SmallTest; + +/** + * Test cases for Hashmap. + */ +public class HashMapTest extends TestCase { + private static final Integer ONE = new Integer(1); + private static final Integer TWO = new Integer(2); + private static final Integer THREE = new Integer(3); + private static final Integer FOUR = new Integer(4); + + private void addItems(HashMap map) { + map.put("one", ONE); + map.put("two", TWO); + map.put("three", THREE); + map.put("four", FOUR); + + assertEquals(4, map.size()); + + assertEquals(ONE, map.get("one")); + assertEquals(TWO, map.get("two")); + assertEquals(THREE, map.get("three")); + assertEquals(FOUR, map.get("four")); + } + + /** + * checks if simple adding elements works. + */ + @SmallTest + public void testAdd() throws Exception { + HashMap map = new HashMap(); + addItems(map); + } + + /** + * checks if clearing the map works. + */ + @SmallTest + public void testClear() throws Exception { + HashMap map = new HashMap(); + + addItems(map); + map.clear(); + assertEquals(0, map.size()); + } + + /** + * checks if removing an elemt works. + */ + @SmallTest + public void testRemove() throws Exception { + HashMap map = new HashMap(); + + addItems(map); + map.remove("three"); + assertNull(map.get("three")); + } + + /** + * does some manipulation with a filled HashMap and checks + * if they work as intended + */ + @SmallTest + public void testManipulate() throws Exception { + HashMap map = new HashMap(); + + assertTrue(map.isEmpty()); + assertEquals(0, map.size()); + assertNull(map.get(null)); + assertNull(map.get("one")); + assertFalse(map.containsKey("one")); + assertFalse(map.containsValue(new Integer(1))); + assertNull(map.remove(null)); + assertNull(map.remove("one")); + + assertNull(map.put(null, new Integer(-1))); + assertNull(map.put("one", new Integer(1))); + assertNull(map.put("two", new Integer(2))); + assertNull(map.put("three", new Integer(3))); + assertEquals(-1, ((Integer) map.put(null, new Integer(0))).intValue()); + + assertEquals(0, ((Integer) map.get(null)).intValue()); + assertEquals(1, ((Integer) map.get("one")).intValue()); + assertEquals(2, ((Integer) map.get("two")).intValue()); + assertEquals(3, ((Integer) map.get("three")).intValue()); + + assertTrue(map.containsKey(null)); + assertTrue(map.containsKey("one")); + assertTrue(map.containsKey("two")); + assertTrue(map.containsKey("three")); + + assertTrue(map.containsValue(new Integer(0))); + assertTrue(map.containsValue(new Integer(1))); + assertTrue(map.containsValue(new Integer(2))); + assertTrue(map.containsValue(new Integer(3))); + + assertEquals(0, ((Integer) map.remove(null)).intValue()); + assertEquals(1, ((Integer) map.remove("one")).intValue()); + assertEquals(2, ((Integer) map.remove("two")).intValue()); + assertEquals(3, ((Integer) map.remove("three")).intValue()); + + assertTrue(map.isEmpty()); + assertEquals(0, map.size()); + assertNull(map.get(null)); + assertNull(map.get("one")); + assertFalse(map.containsKey("one")); + assertFalse(map.containsValue(new Integer(1))); + assertNull(map.remove(null)); + assertNull(map.remove("one")); + } + + /** + * checks if the key iterator of HashMaps work. + */ + @SmallTest + public void testKeyIterator() throws Exception { + HashMap map = new HashMap(); + + boolean[] slots = new boolean[4]; + + addItems(map); + + Iterator iter = map.keySet().iterator(); + + while (iter.hasNext()) { + int slot = 0; + Object key = iter.next(); + + if (key.equals("one")) + slot = 0; + else if (key.equals("two")) + slot = 1; + else if (key.equals("three")) + slot = 2; + else if (key.equals("four")) + slot = 3; + else + fail("Unkown key in hashmap"); + + if (slots[slot]) + fail("key returned more than once"); + else + slots[slot] = true; + } + + assertTrue(slots[0]); + assertTrue(slots[1]); + assertTrue(slots[2]); + assertTrue(slots[3]); + } + + /** + * checks if the value iterator works. + */ + @SmallTest + public void testValueIterator() throws Exception { + HashMap map = new HashMap(); + + boolean[] slots = new boolean[4]; + + addItems(map); + + Iterator iter = map.values().iterator(); + + while (iter.hasNext()) { + int slot = 0; + Object value = iter.next(); + + if (value.equals(ONE)) + slot = 0; + else if (value.equals(TWO)) + slot = 1; + else if (value.equals(THREE)) + slot = 2; + else if (value.equals(FOUR)) + slot = 3; + else + fail("Unkown value in hashmap"); + + if (slots[slot]) + fail("value returned more than once"); + else + slots[slot] = true; + } + + assertTrue(slots[0]); + assertTrue(slots[1]); + assertTrue(slots[2]); + assertTrue(slots[3]); + } + + /** + * checks if the entry iterator works for HashMaps. + */ + @SmallTest + public void testEntryIterator() throws Exception { + HashMap map = new HashMap(); + + boolean[] slots = new boolean[4]; + + addItems(map); + + Iterator iter = map.entrySet().iterator(); + + while (iter.hasNext()) { + int slot = 0; + Object entry = iter.next(); + + if (entry.toString().equals("one=1")) + slot = 0; + else if (entry.toString().equals("two=2")) + slot = 1; + else if (entry.toString().equals("three=3")) + slot = 2; + else if (entry.toString().equals("four=4")) + slot = 3; + else + fail("Unkown entry in hashmap"); + + if (slots[slot]) + fail("entry returned more than once"); + else + slots[slot] = true; + } + + assertTrue(slots[0]); + assertTrue(slots[1]); + assertTrue(slots[2]); + assertTrue(slots[3]); + } + + /** + * checks if the HashMap equals method works. + */ + @SmallTest + public void testEquals() throws Exception { + HashMap map1 = new HashMap(); + HashMap map2 = new HashMap(); + HashMap map3 = new HashMap(); + + map1.put("one", "1"); + map1.put("two", "2"); + map1.put("three", "3"); + + map2.put("one", new String("1")); + map2.put(new String("two"), "2"); + map2.put(new String("three"), new String("3")); + + assertTrue(map1.equals(map2)); + + map3.put("one", "1"); + map3.put("two", "1"); + map3.put("three", "1"); + + assertFalse(map1.equals(map3)); + assertFalse(map2.equals(map3)); + } +} + diff --git a/tests/CoreTests/android/core/HttpConstants.java b/tests/CoreTests/android/core/HttpConstants.java new file mode 100644 index 0000000000000000000000000000000000000000..d655d52680aed169aea8b5830c2d3a43d3616dd8 --- /dev/null +++ b/tests/CoreTests/android/core/HttpConstants.java @@ -0,0 +1,157 @@ +/* + * Copyright (C) 2007 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 android.core; + +interface HttpConstants { + /** 2XX: generally "OK" */ + public static final int HTTP_OK = 200; + public static final int HTTP_CREATED = 201; + public static final int HTTP_ACCEPTED = 202; + public static final int HTTP_NOT_AUTHORITATIVE = 203; + public static final int HTTP_NO_CONTENT = 204; + public static final int HTTP_RESET = 205; + public static final int HTTP_PARTIAL = 206; + + /** 3XX: relocation/redirect */ + public static final int HTTP_MULT_CHOICE = 300; + public static final int HTTP_MOVED_PERM = 301; + public static final int HTTP_MOVED_TEMP = 302; + public static final int HTTP_SEE_OTHER = 303; + public static final int HTTP_NOT_MODIFIED = 304; + public static final int HTTP_USE_PROXY = 305; + + /** 4XX: client error */ + public static final int HTTP_BAD_REQUEST = 400; + public static final int HTTP_UNAUTHORIZED = 401; + public static final int HTTP_PAYMENT_REQUIRED = 402; + public static final int HTTP_FORBIDDEN = 403; + public static final int HTTP_NOT_FOUND = 404; + public static final int HTTP_BAD_METHOD = 405; + public static final int HTTP_NOT_ACCEPTABLE = 406; + public static final int HTTP_PROXY_AUTH = 407; + public static final int HTTP_CLIENT_TIMEOUT = 408; + public static final int HTTP_CONFLICT = 409; + public static final int HTTP_GONE = 410; + public static final int HTTP_LENGTH_REQUIRED = 411; + public static final int HTTP_PRECON_FAILED = 412; + public static final int HTTP_ENTITY_TOO_LARGE = 413; + public static final int HTTP_REQ_TOO_LONG = 414; + public static final int HTTP_UNSUPPORTED_TYPE = 415; + + /** 5XX: server error */ + public static final int HTTP_SERVER_ERROR = 500; + public static final int HTTP_INTERNAL_ERROR = 501; + public static final int HTTP_BAD_GATEWAY = 502; + public static final int HTTP_UNAVAILABLE = 503; + public static final int HTTP_GATEWAY_TIMEOUT = 504; + public static final int HTTP_VERSION = 505; + + /** Method IDs */ + public static final int UNKNOWN_METHOD = 0; + public static final int GET_METHOD = 1; + public static final int HEAD_METHOD = 2; + public static final int POST_METHOD = 3; + + public static final String[] requestHeaders = { + "cache-control", + "connection", + "date", + "pragma", + "trailer", + "transfer-encoding", + "upgrade", + "via", + "warning", + "accept", + "accept-charset", + "accept-encoding", + "accept-language", + "authorization", + "expect", + "from", + "host", + "if-match", + "if-modified-since", + "if-none-match", + "if-range", + "if-unmodified-since", + "max-forwards", + "proxy-authentication", + "range", + "referer", + "te", + "user-agent", + "keep-alive", + "allow", + "content-encoding", + "content-language", + "content-length", + "content-location", + "content-md5", + "content-range", + "content-type", + "expires", + "last-modified", + "location", + "server" + + }; + + public static final int REQ_UNKNOWN = -1; + public static final int REQ_CACHE_CONTROL = 0; + public static final int REQ_CONNECTION = 1; + public static final int REQ_DATE = 2; + public static final int REQ_PRAGMA = 3; + public static final int REQ_TRAILER = 4; + public static final int REQ_TRANSFER_ENCODING = 5; + public static final int REQ_UPGRADE = 6; + public static final int REQ_VIA = 7; + public static final int REQ_WARNING = 8; + public static final int REQ_ACCEPT = 9; + public static final int REQ_ACCEPT_CHARSET = 10; + public static final int REQ_ACCEPT_ENCODING = 11; + public static final int REQ_ACCEPT_LANGUAGE = 12; + public static final int REQ_AUTHORIZATION = 13; + public static final int REQ_EXPECT = 14; + public static final int REQ_FROM = 15; + public static final int REQ_HOST = 16; + public static final int REQ_IF_MATCH = 17; + public static final int REQ_IF_MODIFIED_SINCE = 18; + public static final int REQ_IF_NONE_MATCH = 19; + public static final int REQ_IF_RANGE = 20; + public static final int REQ_IF_UNMODIFIED_SINCE = 21; + public static final int REQ_MAX_FORWARDS = 22; + public static final int REQ_PROXY_AUTHENTICATION = 23; + public static final int REQ_RANGE = 24; + public static final int REQ_REFERER = 25; + public static final int REQ_TE = 26; + public static final int REQ_USER_AGENT = 27; + public static final int REQ_KEEP_ALIVE = 28; + public static final int REQ_ALLOW = 29; + public static final int REQ_CONTENT_ENCODING = 30; + public static final int REQ_CONTENT_LANGUAGE = 31; + public static final int REQ_CONTENT_LENGTH = 32; + public static final int REQ_CONTENT_LOCATION = 33; + public static final int REQ_CONTENT_MD5 = 34; + public static final int REQ_CONTENT_RANGE = 35; + public static final int REQ_CONTENT_TYPE = 36; + public static final int REQ_EXPIRES = 37; + public static final int REQ_LAST_MODIFIED = 38; + public static final int REQ_LOCATION = 39; + public static final int REQ_SERVER = 40; + +} diff --git a/tests/CoreTests/android/core/IOUtil.java b/tests/CoreTests/android/core/IOUtil.java new file mode 100644 index 0000000000000000000000000000000000000000..6f69418ccf0079123fc782f70a7b035eb4891cca --- /dev/null +++ b/tests/CoreTests/android/core/IOUtil.java @@ -0,0 +1,193 @@ +/* + * Copyright (C) 2007 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 android.core; + +import java.io.InputStream; +import java.io.IOException; +import java.io.Reader; +import java.io.InputStreamReader; + +public final class IOUtil { + + private IOUtil() { + } + + /** + * returns the content of an InputStream as a String. + * + * @param a the input stream. + * @return the string + * @throws java.io.IOException + */ + public static String read(InputStream a) throws IOException { + int r; + StringBuilder builder = new StringBuilder(); + do { + r = a.read(); + if (r != -1) + builder.append((char) r); + } while (r != -1); + return builder.toString(); + } + + /** + * reads characters from a reader and returns them as a string. + * + * @param a the reader. + * @return the string. + * @throws IOException + */ + public static String read(Reader a) throws IOException { + int r; + StringBuilder builder = new StringBuilder(); + do { + r = a.read(); + if (r != -1) + builder.append((char) r); + } while (r != -1); + return builder.toString(); + } + + /** + * returns the content of an InputStream as a String. It reads x characters. + * + * @param a the input stream. + * @param x number of characters to read. + * @return the string + * @throws IOException + */ + public static String read(InputStream a, int x) throws IOException { + byte[] b = new byte[x]; + int len = a.read(b, 0, x); + if (len < 0) { + return ""; + } + return new String(b, 0, len); + } + + /** + * reads a number of characters from a reader and returns them as a string. + * + * @param a the reader. + * @param x the number of characters to read. + * @return the string. + * @throws IOException + */ + public static String read(Reader a, int x) throws IOException { + char[] b = new char[x]; + int len = a.read(b, 0, x); + if (len < 0) { + return ""; + } + return new String(b, 0, len); + } + + /** + * returns the content of the input stream as a String. It only appends + * every second character. + * + * @param a the input stream. + * @return the string created from every second character of the input stream. + * @throws IOException + */ + public static String skipRead(InputStream a) throws IOException { + int r; + StringBuilder builder = new StringBuilder(); + do { + a.skip(1); + r = a.read(); + if (r != -1) + builder.append((char) r); + } while (r != -1); + return builder.toString(); + } + + /** + * reads every second characters from a reader and returns them as a string. + * + * @param a the reader. + * @return the string. + * @throws IOException + */ + public static String skipRead(Reader a) throws IOException { + int r; + StringBuilder builder = new StringBuilder(); + do { + a.skip(1); + r = a.read(); + if (r != -1) + builder.append((char) r); + } while (r != -1); + return builder.toString(); + } + + /** + * reads characters from a InputStream, skips back y characters and continues + * reading from that new position up to the end. + * + * @param a the InputStream. + * @param x the position of the mark. the marks position is x+y + * @param y the number of characters to jump back after the position x+y was reached. + * @return the string. + * @throws IOException + */ + public static String markRead(InputStream a, int x, int y) throws IOException { + int m = 0; + int r; + StringBuilder builder = new StringBuilder(); + do { + m++; + r = a.read(); + if (m == x) + a.mark((x + y)); + if (m == (x + y)) + a.reset(); + + if (r != -1) + builder.append((char) r); + } while (r != -1); + return builder.toString(); + } + + /** + * reads characters from a reader, skips back y characters and continues + * reading from that new position up to the end. + * + * @param a the reader. + * @param x the position of the mark. the marks position is x+y + * @param y the number of characters to jump back after the position x+y was reached. + * @return the string. + * @throws IOException + */ + public static String markRead(Reader a, int x, int y) throws IOException { + int m = 0; + int r; + StringBuilder builder = new StringBuilder(); + do { + m++; + r = a.read(); + if (m == x) + a.mark((x + y)); + if (m == (x + y)) + a.reset(); + + if (r != -1) + builder.append((char) r); + } while (r != -1); + return builder.toString(); + } +} diff --git a/tests/CoreTests/android/core/InetAddrTest.java b/tests/CoreTests/android/core/InetAddrTest.java new file mode 100644 index 0000000000000000000000000000000000000000..c7b89e1eed9fa6f63cf561be11f491d38f21cf64 --- /dev/null +++ b/tests/CoreTests/android/core/InetAddrTest.java @@ -0,0 +1,100 @@ +/* + * 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 android.core; + +import junit.framework.TestCase; + +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.util.Random; + +import android.test.suitebuilder.annotation.Suppress; + +/** + * Tests InetAddr class by checking methods to resolve domains to IP addresses + * and by checking if the class returns correct addresses for local host address + * and host name. + */ +@Suppress +public class InetAddrTest extends TestCase { + private static final String[] HOSTS = { + "localhost", "www.google.com", "www.slashdot.org", "www.wikipedia.org", + "www.paypal.com", "www.cnn.com", "www.yahoo.com", "www.amazon.com", + "www.ebay.com", "www.android.com" + }; + + public void testInetAddr() throws Exception { + byte[] raw; + + InetAddress ia = InetAddress.getByName("localhost"); + + raw = ia.getAddress(); + + assertEquals(127, raw[0]); + assertEquals(0, raw[1]); + assertEquals(0, raw[2]); + assertEquals(1, raw[3]); + + ia = InetAddress.getByName("127.0.0.1"); + + raw = ia.getAddress(); + + assertEquals(127, raw[0]); + assertEquals(0, raw[1]); + assertEquals(0, raw[2]); + assertEquals(1, raw[3]); + + ia = InetAddress.getByName(null); + + try { + InetAddress.getByName(".0.0.1"); + fail("expected ex"); + } catch (UnknownHostException ex) { + // expected + } + + try { + InetAddress.getByName("thereisagoodchancethisdomaindoesnotexist.weirdtld"); + fail("expected ex"); + } catch (UnknownHostException ex) { + // expected + } + + try { + InetAddress.getByName("127.0.0."); + fail("expected ex"); + } catch (UnknownHostException ex) { + // expected + } + + Random random = new Random(); + int count = 0; + for (int i = 0; i < 100; i++) { + int index = random.nextInt(HOSTS.length); + try { + InetAddress.getByName(HOSTS[index]); + count++; + try { + Thread.sleep(50); + } catch (InterruptedException ex) { + } + } catch (UnknownHostException ex) { + } + } + assertEquals("Not all host lookups succeeded", 100, count); + } +} diff --git a/tests/CoreTests/android/core/InputStreamReaderTest.java b/tests/CoreTests/android/core/InputStreamReaderTest.java new file mode 100644 index 0000000000000000000000000000000000000000..1e8d87cb899970292469dbf10cb3cdefb38a876f --- /dev/null +++ b/tests/CoreTests/android/core/InputStreamReaderTest.java @@ -0,0 +1,114 @@ +/* + * 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 android.core; + +import junit.framework.TestCase; + +import java.io.ByteArrayInputStream; +import java.io.InputStreamReader; +import android.test.suitebuilder.annotation.SmallTest; + +/** + * Checks basic InputStreamReader functionality. + */ +public class InputStreamReaderTest extends TestCase { + + /** + * Checks if ASCII encoding works with InputStreamReader + */ + @SmallTest + public void testAscii() throws Exception { + String str = "AbCdEfGhIjKlMnOpQrStUvWxYzX"; + ByteArrayInputStream aa = new ByteArrayInputStream(str.getBytes("ISO8859_1")); + InputStreamReader a = new InputStreamReader(aa, "ISO8859_1"); + + try { + int x = a.read(); + assertEquals('A', x); + char[] c = new char[26]; + x = a.read(c, 0, 26); + assertTrue(a.getEncoding().equalsIgnoreCase("ISO8859_1")); + assertEquals(26, x); + assertEquals("bCdEfGhIjKlMnOpQrStUvWxYzX", String.valueOf(c)); + } finally { + a.close(); + } + } + + /** + * Checks if Utf8 encoding works with InputStreamReader + */ + @SmallTest + public void testUtf8() throws Exception { + String str = "AbCdEfGhIjKlMnOpQrStUvWxYzX" + + "\u00a3\u00c5\u00c9"; // total of 30 characters + ByteArrayInputStream aa = + new ByteArrayInputStream(str.getBytes()); + + InputStreamReader a = new InputStreamReader(aa); + + try { + assertEquals("UTF8", a.getEncoding()); + + int x = a.read(); + assertEquals('A', x); + + char[] c = new char[29]; + x = a.read(c, 0, 3); + assertEquals(3, x); + assertEquals("bCd", new String(c, 0, 3)); + + x = a.read(c, 3, 26); + assertEquals(26, x); + assertEquals("EfGhIjKlMnOpQrStUvWxYzX\u00a3\u00c5\u00c9", new String(c, 3, 26)); + } finally { + a.close(); + } + } + + /** + * Checks if several encodings works with InputStreamReader + */ + @SmallTest + public void testStringy() throws Exception { + String src = "The quick brown fox\u00A0\u00FF" + + "\uFFFC\uD7C5\uDC03bloof"; + + String[] enc = new String[]{ + "utf-8", "us-ascii", "iso-8859-1", "utf-16be", "utf-16le", + "utf-16", + }; + + for (int i = 0; i < enc.length; i++) { + byte[] ba = src.getBytes(enc[i]); + + String s1 = new String(ba, enc[i]); + + ByteArrayInputStream bais = new ByteArrayInputStream(ba); + InputStreamReader r = new InputStreamReader(bais, enc[i]); + try { + char[] ca = new char[600]; + int n = r.read(ca, 0, 600); + + String s2 = new String(ca, 0, n); + assertEquals(s1, s2); + } finally { + r.close(); + } + } + } +} diff --git a/tests/CoreTests/android/core/JavaTests.java b/tests/CoreTests/android/core/JavaTests.java new file mode 100644 index 0000000000000000000000000000000000000000..bd8cbf0934a3f4e62caee65f9e31502a16f37413 --- /dev/null +++ b/tests/CoreTests/android/core/JavaTests.java @@ -0,0 +1,86 @@ +/* + * 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 android.core; + +import junit.framework.TestSuite; + +public class JavaTests { + public static TestSuite suite() { + TestSuite suite = new TestSuite(JavaTests.class.getName()); + + //Disabling until bug http://b/issue?id=1200337 is resolved + //suite.addTestSuite(RequestAPITest.class); + suite.addTestSuite(MathTest.class); + suite.addTestSuite(StrictMathTest.class); + suite.addTestSuite(HashMapPerfTest.class); + suite.addTestSuite(TreeMapTest.class); + suite.addTestSuite(FloatDoubleTest.class); + suite.addTestSuite(Sha1Test.class); + suite.addTestSuite(NIOTest.class); + suite.addTestSuite(ReflectArrayTest.class); + //Commenting out until we find a better way to exclude from continuous testing. + //suite.addTestSuite(URLTest.class); + suite.addTestSuite(URITest.class); + suite.addTestSuite(RegexTest.class); + suite.addTestSuite(HashMapTest.class); + suite.addTestSuite(ArrayListTest.class); + suite.addTestSuite(BooleanTest.class); + suite.addTestSuite(StringTest.class); + suite.addTestSuite(BufferedReaderTest.class); + suite.addTestSuite(CharArrayReaderTest.class); + suite.addTestSuite(PushbackReaderTest.class); + suite.addTestSuite(StringReaderTest.class); + suite.addTestSuite(StreamTokenizerTest.class); + suite.addTestSuite(ByteArrayInputStreamTest.class); + suite.addTestSuite(DataInputStreamTest.class); + suite.addTestSuite(BufferedInputStreamTest.class); + suite.addTestSuite(PushbackInputStreamTest.class); + suite.addTestSuite(ByteArrayOutputStreamTest.class); + suite.addTestSuite(DataOutputStreamTest.class); + suite.addTestSuite(BufferedOutputStreamTest.class); + suite.addTestSuite(CharArrayWriterTest.class); + suite.addTestSuite(StringWriterTest.class); + suite.addTestSuite(PrintWriterTest.class); + suite.addTestSuite(BufferedWriterTest.class); + suite.addTestSuite(ClassTest.class); + //To be unccommented when Bug #799327 is fixed. + //suite.addTestSuite(ClassLoaderTest.class); + suite.addTestSuite(LineNumberReaderTest.class); + suite.addTestSuite(InputStreamReaderTest.class); + suite.addTestSuite(OutputStreamWriterTest.class); + suite.addTestSuite(EnumTest.class); + suite.addTestSuite(ParseIntTest.class); + suite.addTestSuite(PipedStreamTest.class); + suite.addTestSuite(LocaleTest.class); + //Commenting out until we find a better way to exclude from continuous testing. + //suite.addTestSuite(InetAddrTest.class); + suite.addTestSuite(SocketTest.class); + suite.addTestSuite(ChecksumTest.class); + suite.addTestSuite(DeflateTest.class); + suite.addTestSuite(ZipStreamTest.class); + suite.addTestSuite(GZIPStreamTest.class); + suite.addTestSuite(ZipFileTest.class); + suite.addTestSuite(FileTest.class); + suite.addTestSuite(SQLiteJDBCDriverTest.class); + suite.addTestSuite(AtParserTest.class); + suite.addTestSuite(DatagramTest.class); + suite.addTestSuite(CryptoTest.class); + suite.addTestSuite(MiscRegressionTest.class); + + return suite; + } +} diff --git a/tests/CoreTests/android/core/LineNumberReaderTest.java b/tests/CoreTests/android/core/LineNumberReaderTest.java new file mode 100644 index 0000000000000000000000000000000000000000..6380ebedde168b337c145e6203ba0624b8f98ad8 --- /dev/null +++ b/tests/CoreTests/android/core/LineNumberReaderTest.java @@ -0,0 +1,79 @@ +/* + * 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 android.core; + +import junit.framework.TestCase; + +import java.io.LineNumberReader; +import java.io.StringReader; +import android.test.suitebuilder.annotation.MediumTest; + +/** + * Checks basic functionality for LineNumberReader. + */ +public class LineNumberReaderTest extends TestCase { + + @MediumTest + public void testLineNumberReader() throws Exception { + String str = "AbCdEfGhIjKlM\nOpQrStUvWxYz"; + + StringReader aa = new StringReader(str); + StringReader ba = new StringReader(str); + StringReader ca = new StringReader(str); + StringReader da = new StringReader(str); + StringReader ea = new StringReader(str); + + LineNumberReader a = new LineNumberReader(aa); + try { + assertEquals(0, a.getLineNumber()); + assertEquals(str, IOUtil.read(a)); + assertEquals(1, a.getLineNumber()); + a.setLineNumber(5); + assertEquals(5, a.getLineNumber()); + } finally { + a.close(); + } + + LineNumberReader b = new LineNumberReader(ba); + try { + assertEquals("AbCdEfGhIj", IOUtil.read(b, 10)); + } finally { + b.close(); + } + + LineNumberReader c = new LineNumberReader(ca); + try { + assertEquals("bdfhjl\nprtvxz", IOUtil.skipRead(c)); + } finally { + c.close(); + } + + LineNumberReader d = new LineNumberReader(da); + try { + assertEquals("AbCdEfGdEfGhIjKlM\nOpQrStUvWxYz", IOUtil.markRead(d, 3, 4)); + } finally { + d.close(); + } + + LineNumberReader e = new LineNumberReader(ea); + try { + assertEquals("AbCdEfGhIjKlM", e.readLine()); + } finally { + e.close(); + } + } +} diff --git a/tests/CoreTests/android/core/LocaleTest.java b/tests/CoreTests/android/core/LocaleTest.java new file mode 100644 index 0000000000000000000000000000000000000000..700cf1d2b06e16a1f544eb2298d8f46fb85fa44a --- /dev/null +++ b/tests/CoreTests/android/core/LocaleTest.java @@ -0,0 +1,199 @@ +/* + * 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 android.core; + +import junit.framework.TestCase; + +import java.nio.charset.Charset; +import java.text.DateFormatSymbols; +import java.util.Calendar; +import java.util.Currency; +import java.util.Locale; +import java.util.Set; +import java.util.TimeZone; +import android.test.suitebuilder.annotation.MediumTest; +import android.test.suitebuilder.annotation.SmallTest; +import android.test.suitebuilder.annotation.LargeTest; + +/** + * Test some locale-dependent stuff for Android. This test mainly ensures that + * our ICU configuration is correct and contains all the needed locales and + * resource bundles. + */ +public class LocaleTest extends TestCase { + + // Test basic Locale infrastructure. + @SmallTest + public void testLocale() throws Exception { + Locale locale = new Locale("en"); + assertEquals("en", locale.toString()); + + locale = new Locale("en", "US"); + assertEquals("en_US", locale.toString()); + + locale = new Locale("en", "", "POSIX"); + assertEquals("en__POSIX", locale.toString()); + + locale = new Locale("en", "US", "POSIX"); + assertEquals("en_US_POSIX", locale.toString()); + } + + // Test some must-have locales. + @LargeTest + public void testResourceBundles() throws Exception { + Locale eng = new Locale("en", "US"); + DateFormatSymbols engSymbols = new DateFormatSymbols(eng); + + Locale deu = new Locale("de", "DE"); + DateFormatSymbols deuSymbols = new DateFormatSymbols(deu); + + TimeZone berlin = TimeZone.getTimeZone("Europe/Berlin"); + + assertEquals("January", engSymbols.getMonths()[0]); + assertEquals("Januar", deuSymbols.getMonths()[0]); + + assertEquals("Sunday", engSymbols.getWeekdays()[Calendar.SUNDAY]); + assertEquals("Sonntag", deuSymbols.getWeekdays()[Calendar.SUNDAY]); + + assertEquals("Central European Time", + berlin.getDisplayName(false, TimeZone.LONG, eng)); + assertEquals("Central European Summer Time", + berlin.getDisplayName(true, TimeZone.LONG, eng)); + + assertEquals("Mitteleurop\u00E4ische Zeit", + berlin.getDisplayName(false, TimeZone.LONG, deu)); + assertEquals("Mitteleurop\u00E4ische Sommerzeit", + berlin.getDisplayName(true, TimeZone.LONG, deu)); + + assertTrue(engSymbols.getZoneStrings().length > 100); + } + + // Regression test for 1118570: Create test cases for tracking ICU config + // changes. This one makes sure we have all necessary locales installed. + @MediumTest + public void testICULocales() { + String[] locales = new String[] { + // List of locales currently required for Android. + "en_US", "es_US", "en_GB", "fr_FR", "de_DE", "de_AT", "cs_CZ", "nl_NL" }; + + String[] mondays = new String[] { + "Monday", "lunes", "Monday", "lundi", "Montag", "Montag", "pond\u011bl\u00ed", "maandag" }; + + String[] currencies = new String[] { + "USD", "USD", "GBP", "EUR", "EUR", "EUR", "CZK", "EUR"}; + + for (int i = 0; i < locales.length; i++) { + Locale l = new Locale(locales[i].substring(0, 2), locales[i].substring(3)); + + // Check language part of locale. + DateFormatSymbols d = new DateFormatSymbols(l); + assertEquals("Monday name for " + locales[i] + " must match", + mondays[i], d.getWeekdays()[2]); + + // Check country part of locale. + Currency c = Currency.getInstance(l); + assertEquals("Currency code for " + locales[i] + " must match", + currencies[i], c.getCurrencyCode()); + } + } + + // Regression test for 1118570: Create test cases for tracking ICU config + // changes. This one makes sure we have the necessary converters installed + // and don't lose the changes to the converter alias table. + @MediumTest + public void testICUConverters() { + // List of encodings currently required for Android. + String[] encodings = new String[] { + // Encoding required by the language specification. + "US-ASCII", + "UTF-8", + "UTF-16", + "UTF-16BE", + "UTF-16LE", + "ISO-8859-1", + + // Additional encodings included in standard ICU + "ISO-8859-2", + "ISO-8859-3", + "ISO-8859-4", + "ISO-8859-5", + "ISO-8859-6", + "ISO-8859-7", + "ISO-8859-8", + "ISO-8859-8-I", + "ISO-8859-9", + "ISO-8859-10", + "ISO-8859-11", + "ISO-8859-13", + "ISO-8859-14", + "ISO-8859-15", + "ISO-8859-16", + "ISO-2022-JP", + "Windows-950", + "Windows-1250", + "Windows-1251", + "Windows-1252", + "Windows-1253", + "Windows-1254", + "Windows-1255", + "Windows-1256", + "Windows-1257", + "Windows-1258", + "Big5", + "CP864", + "CP874", + "EUC-CN", + "EUC-JP", + "KOI8-R", + "Macintosh", + "GBK", + "GB2312", + "EUC-KR", + + // Additional encoding not included in standard ICU. + "GSM0338" }; + + for (int i = 0; i < encodings.length; i++) { + assertTrue("Charset " + encodings[i] + " must be supported", + Charset.isSupported(encodings[i])); + + Charset cs = Charset.forName(encodings[i]); + android.util.Log.d("LocaleTest", cs.name()); + + Set aliases = cs.aliases(); + for (String s: aliases) { + android.util.Log.d("LocaleTest", " - " + s); + } + } + + // Test for valid encoding that is not included in Android. IBM-37 is + // a perfect candidate for this, as it is being used for mainframes and + // thus somewhat out of the scope of Android. + assertFalse("Charset IBM-37 must not be supported", + Charset.isSupported("IBM-37")); + + // Test for a bogus encoding. + assertFalse("Charset KLINGON must not be supported", + Charset.isSupported("KLINGON")); + + // Make sure our local change to the real translation table used for + // EUC-JP doesn't get lost. + Charset cs = Charset.forName("EUC-JP"); + assertTrue("EUC-JP must use 'ibm-954_P101-2007'", cs.aliases().contains("ibm-954_P101-2007")); + } + +} diff --git a/tests/CoreTests/android/core/LowLevelNetRunner.java b/tests/CoreTests/android/core/LowLevelNetRunner.java new file mode 100644 index 0000000000000000000000000000000000000000..812ceb54bd8d6d423cef9c1522e0e28fb12a772f --- /dev/null +++ b/tests/CoreTests/android/core/LowLevelNetRunner.java @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2007 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 android.core; + +/** + * Provides synchronization handling for low level Request API tests + */ +public class LowLevelNetRunner extends Thread { + + private int count = 0; + + LowLevelNetRunner() { + } + + public void incrementRunCount() { + count++; + } + + /** + * Decrement the run count. If this returns to zero notify any + * test waiting. + */ + public void decrementRunCount() { + count--; + if (count <= 0) { + synchronized (RequestAPITest.syncObj) { + RequestAPITest.syncObj.notifyAll(); + } + } + } + +} /* LowLevelNetRunner*/ diff --git a/tests/CoreTests/android/core/MathTest.java b/tests/CoreTests/android/core/MathTest.java new file mode 100644 index 0000000000000000000000000000000000000000..50009db7bf02699303e6b75bf74e19ecd36fe534 --- /dev/null +++ b/tests/CoreTests/android/core/MathTest.java @@ -0,0 +1,831 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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 android.core; + +import junit.framework.Assert; +import junit.framework.TestCase; +import android.test.suitebuilder.annotation.SmallTest; +import android.test.suitebuilder.annotation.MediumTest; + +public class MathTest extends TestCase { + + private final double HYP = Math.sqrt(2.0); + + private final double OPP = 1.0; + + private final double ADJ = 1.0; + + /* Required to make previous preprocessor flags work - do not remove */ + int unused = 0; + + public static void assertEquals(String message, double expected, double actual, double delta) { + if (delta == 0D) { + Assert.assertEquals(message, expected, actual, Math.ulp(expected)); + } else { + Assert.assertEquals(message, expected, actual, delta); + } + } + + public static void assertEquals(String message, float expected, float actual, float delta) { + if (delta == 0F) { + Assert.assertEquals(message, expected, actual, Math.ulp(expected)); + } else { + Assert.assertEquals(message, expected, actual, delta); + } + } + + /** + * @tests java.lang.Math#abs(double) + */ + @SmallTest + public void testAbsD() { + // Test for method double java.lang.Math.abs(double) + + assertTrue("Incorrect double abs value", + (Math.abs(-1908.8976) == 1908.8976)); + assertTrue("Incorrect double abs value", + (Math.abs(1908.8976) == 1908.8976)); + } + + /** + * @tests java.lang.Math#abs(float) + */ + @SmallTest + public void testAbsF() { + // Test for method float java.lang.Math.abs(float) + assertTrue("Incorrect float abs value", + (Math.abs(-1908.8976f) == 1908.8976f)); + assertTrue("Incorrect float abs value", + (Math.abs(1908.8976f) == 1908.8976f)); + } + + /** + * @tests java.lang.Math#abs(int) + */ + @SmallTest + public void testAbsI() { + // Test for method int java.lang.Math.abs(int) + assertTrue("Incorrect int abs value", (Math.abs(-1908897) == 1908897)); + assertTrue("Incorrect int abs value", (Math.abs(1908897) == 1908897)); + } + + /** + * @tests java.lang.Math#abs(long) + */ + @SmallTest + public void testAbsJ() { + // Test for method long java.lang.Math.abs(long) + assertTrue("Incorrect long abs value", + (Math.abs(-19088976000089L) == 19088976000089L)); + assertTrue("Incorrect long abs value", + (Math.abs(19088976000089L) == 19088976000089L)); + } + + /** + * @tests java.lang.Math#acos(double) + */ + @SmallTest + public void testAcosD() { + // Test for method double java.lang.Math.acos(double) + double r = Math.cos(Math.acos(ADJ / HYP)); + long lr = Double.doubleToLongBits(r); + long t = Double.doubleToLongBits(ADJ / HYP); + assertTrue("Returned incorrect arc cosine", lr == t || (lr + 1) == t + || (lr - 1) == t); + } + + /** + * @tests java.lang.Math#asin(double) + */ + @SmallTest + public void testAsinD() { + // Test for method double java.lang.Math.asin(double) + double r = Math.sin(Math.asin(OPP / HYP)); + long lr = Double.doubleToLongBits(r); + long t = Double.doubleToLongBits(OPP / HYP); + assertTrue("Returned incorrect arc sine", lr == t || (lr + 1) == t + || (lr - 1) == t); + } + + /** + * @tests java.lang.Math#atan(double) + */ + @SmallTest + public void testAtanD() { + // Test for method double java.lang.Math.atan(double) + double answer = Math.tan(Math.atan(1.0)); + assertTrue("Returned incorrect arc tangent: " + answer, answer <= 1.0 + && answer >= 9.9999999999999983E-1); + } + + /** + * @tests java.lang.Math#atan2(double, double) + */ + @SmallTest + public void testAtan2DD() { + // Test for method double java.lang.Math.atan2(double, double) + double answer = Math.atan(Math.tan(1.0)); + assertTrue("Returned incorrect arc tangent: " + answer, answer <= 1.0 + && answer >= 9.9999999999999983E-1); + } + + /** + * @tests java.lang.Math#cbrt(double) + */ + @SmallTest + public void testCbrtD() { + //Test for special situations + assertTrue("Should return Double.NaN", Double.isNaN(Math + .cbrt(Double.NaN))); + assertEquals("Should return Double.POSITIVE_INFINITY", + Double.POSITIVE_INFINITY, Math + .cbrt(Double.POSITIVE_INFINITY), 0D); + assertEquals("Should return Double.NEGATIVE_INFINITY", + Double.NEGATIVE_INFINITY, Math + .cbrt(Double.NEGATIVE_INFINITY), 0D); + assertEquals(Double.doubleToLongBits(0.0), Double.doubleToLongBits(Math + .cbrt(0.0))); + assertEquals(Double.doubleToLongBits(+0.0), Double.doubleToLongBits(Math + .cbrt(+0.0))); + assertEquals(Double.doubleToLongBits(-0.0), Double.doubleToLongBits(Math + .cbrt(-0.0))); + + assertEquals("Should return 3.0", 3.0, Math.cbrt(27.0), 0D); + assertEquals("Should return 23.111993172558684", 23.111993172558684, + Math.cbrt(12345.6), 0D); + assertEquals("Should return 5.643803094122362E102", + 5.643803094122362E102, Math.cbrt(Double.MAX_VALUE), 0D); + assertEquals("Should return 0.01", 0.01, Math.cbrt(0.000001), 0D); + + assertEquals("Should return -3.0", -3.0, Math.cbrt(-27.0), 0D); + assertEquals("Should return -23.111993172558684", -23.111993172558684, + Math.cbrt(-12345.6), 0D); + assertEquals("Should return 1.7031839360032603E-108", + 1.7031839360032603E-108, Math.cbrt(Double.MIN_VALUE), 0D); + assertEquals("Should return -0.01", -0.01, Math.cbrt(-0.000001), 0D); + } + + /** + * @tests java.lang.Math#ceil(double) + */ + @SmallTest + public void testCeilD() { + // Test for method double java.lang.Math.ceil(double) + assertEquals("Incorrect ceiling for double", + 79, Math.ceil(78.89), 0); + assertEquals("Incorrect ceiling for double", + -78, Math.ceil(-78.89), 0); + } + + /** + * @tests java.lang.Math#cos(double) + */ + @SmallTest + public void testCosD() { + // Test for method double java.lang.Math.cos(double) + assertEquals("Incorrect answer", 1.0, Math.cos(0), 0D); + assertEquals("Incorrect answer", 0.5403023058681398, Math.cos(1), 0D); + } + + /** + * @tests java.lang.Math#cosh(double) + */ + @SmallTest + public void testCoshD() { + // Test for special situations + assertTrue(Double.isNaN(Math.cosh(Double.NaN))); + assertEquals("Should return POSITIVE_INFINITY", + Double.POSITIVE_INFINITY, Math.cosh(Double.POSITIVE_INFINITY), 0D); + assertEquals("Should return POSITIVE_INFINITY", + Double.POSITIVE_INFINITY, Math.cosh(Double.NEGATIVE_INFINITY), 0D); + assertEquals("Should return 1.0", 1.0, Math.cosh(+0.0), 0D); + assertEquals("Should return 1.0", 1.0, Math.cosh(-0.0), 0D); + + assertEquals("Should return POSITIVE_INFINITY", + Double.POSITIVE_INFINITY, Math.cosh(1234.56), 0D); + assertEquals("Should return POSITIVE_INFINITY", + Double.POSITIVE_INFINITY, Math.cosh(-1234.56), 0D); + assertEquals("Should return 1.0000000000005", 1.0000000000005, Math + .cosh(0.000001), 0D); + assertEquals("Should return 1.0000000000005", 1.0000000000005, Math + .cosh(-0.000001), 0D); + assertEquals("Should return 5.212214351945598", 5.212214351945598, Math + .cosh(2.33482), 0D); + + assertEquals("Should return POSITIVE_INFINITY", + Double.POSITIVE_INFINITY, Math.cosh(Double.MAX_VALUE), 0D); + assertEquals("Should return 1.0", 1.0, Math.cosh(Double.MIN_VALUE), 0D); + } + + /** + * @tests java.lang.Math#exp(double) + */ + @SmallTest + public void testExpD() { + // Test for method double java.lang.Math.exp(double) + assertTrue("Incorrect answer returned for simple power", Math.abs(Math + .exp(4D) + - Math.E * Math.E * Math.E * Math.E) < 0.1D); + assertTrue("Incorrect answer returned for larger power", Math.log(Math + .abs(Math.exp(5.5D)) - 5.5D) < 10.0D); + } + + /** + * @tests java.lang.Math#expm1(double) + */ + @SmallTest + public void testExpm1D() { + // Test for special cases + assertTrue("Should return NaN", Double.isNaN(Math.expm1(Double.NaN))); + assertEquals("Should return POSITIVE_INFINITY", + Double.POSITIVE_INFINITY, Math.expm1(Double.POSITIVE_INFINITY), 0D); + assertEquals("Should return -1.0", -1.0, Math + .expm1(Double.NEGATIVE_INFINITY), 0D); + assertEquals(Double.doubleToLongBits(0.0), Double.doubleToLongBits(Math + .expm1(0.0))); + assertEquals(Double.doubleToLongBits(+0.0), Double + .doubleToLongBits(Math.expm1(+0.0))); + assertEquals(Double.doubleToLongBits(-0.0), Double + .doubleToLongBits(Math.expm1(-0.0))); + + assertEquals("Should return -9.999950000166666E-6", + -9.999950000166666E-6, Math.expm1(-0.00001), 0D); + assertEquals("Should return 1.0145103074469635E60", + 1.0145103074469635E60, Math.expm1(138.16951162), 0D); + assertEquals("Should return POSITIVE_INFINITY", + Double.POSITIVE_INFINITY, Math + .expm1(123456789123456789123456789.4521584223), 0D); + assertEquals("Should return POSITIVE_INFINITY", + Double.POSITIVE_INFINITY, Math.expm1(Double.MAX_VALUE), 0D); + assertEquals("Should return MIN_VALUE", Double.MIN_VALUE, Math + .expm1(Double.MIN_VALUE), 0D); + } + + /** + * @tests java.lang.Math#floor(double) + */ + @SmallTest + public void testFloorD() { + // Test for method double java.lang.Math.floor(double) + assertEquals("Incorrect floor for double", + 78, Math.floor(78.89), 0); + assertEquals("Incorrect floor for double", + -79, Math.floor(-78.89), 0); + } + + /** + * @tests java.lang.Math#hypot(double, double) + */ + @SmallTest + public void testHypotDD() { + // Test for special cases + assertEquals("Should return POSITIVE_INFINITY", + Double.POSITIVE_INFINITY, Math.hypot(Double.POSITIVE_INFINITY, + 1.0), 0D); + assertEquals("Should return POSITIVE_INFINITY", + Double.POSITIVE_INFINITY, Math.hypot(Double.NEGATIVE_INFINITY, + 123.324), 0D); + assertEquals("Should return POSITIVE_INFINITY", + Double.POSITIVE_INFINITY, Math.hypot(-758.2587, + Double.POSITIVE_INFINITY), 0D); + assertEquals("Should return POSITIVE_INFINITY", + Double.POSITIVE_INFINITY, Math.hypot(5687.21, + Double.NEGATIVE_INFINITY), 0D); + assertEquals("Should return POSITIVE_INFINITY", + Double.POSITIVE_INFINITY, Math.hypot(Double.POSITIVE_INFINITY, + Double.NEGATIVE_INFINITY), 0D); + assertEquals("Should return POSITIVE_INFINITY", + Double.POSITIVE_INFINITY, Math.hypot(Double.NEGATIVE_INFINITY, + Double.POSITIVE_INFINITY), 0D); + assertTrue("Should be NaN", Double.isNaN(Math.hypot(Double.NaN, + 2342301.89843))); + assertTrue("Should be NaN", Double.isNaN(Math.hypot(-345.2680, + Double.NaN))); + + assertEquals("Should return 2396424.905416697", 2396424.905416697, Math + .hypot(12322.12, -2396393.2258), 0D); + assertEquals("Should return 138.16958070558556", 138.16958070558556, + Math.hypot(-138.16951162, 0.13817035864), 0D); + assertEquals("Should return 1.7976931348623157E308", + 1.7976931348623157E308, Math.hypot(Double.MAX_VALUE, 211370.35), 0D); + assertEquals("Should return 5413.7185", 5413.7185, Math.hypot( + -5413.7185, Double.MIN_VALUE), 0D); + } + + /** + * @tests java.lang.Math#IEEEremainder(double, double) + */ + @SmallTest + public void testIEEEremainderDD() { + // Test for method double java.lang.Math.IEEEremainder(double, double) + assertEquals("Incorrect remainder returned", + 0.0, Math.IEEEremainder(1.0, 1.0), 0D); + assertTrue("Incorrect remainder returned", Math.IEEEremainder(1.32, + 89.765) >= 1.4705063220631647E-2 + || Math.IEEEremainder(1.32, 89.765) >= 1.4705063220631649E-2); + } + + /** + * @tests java.lang.Math#log(double) + */ + @SmallTest + public void testLogD() { + // Test for method double java.lang.Math.log(double) + for (double d = 10; d >= -10; d -= 0.5) { + double answer = Math.log(Math.exp(d)); + assertTrue("Answer does not equal expected answer for d = " + d + + " answer = " + answer, Math.abs(answer - d) <= Math + .abs(d * 0.00000001)); + } + } + + /** + * @tests java.lang.Math#log10(double) + */ + @SuppressWarnings("boxing") + @SmallTest + public void testLog10D() { + // Test for special cases + assertTrue(Double.isNaN(Math.log10(Double.NaN))); + assertTrue(Double.isNaN(Math.log10(-2541.05745687234187532))); + assertTrue(Double.isNaN(Math.log10(-0.1))); + assertEquals(Double.POSITIVE_INFINITY, Math.log10(Double.POSITIVE_INFINITY)); + assertEquals(Double.NEGATIVE_INFINITY, Math.log10(0.0)); + assertEquals(Double.NEGATIVE_INFINITY, Math.log10(+0.0)); + assertEquals(Double.NEGATIVE_INFINITY, Math.log10(-0.0)); + + assertEquals(3.0, Math.log10(1000.0)); + assertEquals(14.0, Math.log10(Math.pow(10, 14))); + assertEquals(3.7389561269540406, Math.log10(5482.2158)); + assertEquals(14.661551142893833, Math.log10(458723662312872.125782332587)); + assertEquals(-0.9083828622192334, Math.log10(0.12348583358871)); + assertEquals(308.25471555991675, Math.log10(Double.MAX_VALUE)); + assertEquals(-323.3062153431158, Math.log10(Double.MIN_VALUE)); + } + + /** + * @tests java.lang.Math#log1p(double) + */ + @SmallTest + public void testLog1pD() { + // Test for special cases + assertTrue("Should return NaN", Double.isNaN(Math.log1p(Double.NaN))); + assertTrue("Should return NaN", Double.isNaN(Math.log1p(-32.0482175))); + assertEquals("Should return POSITIVE_INFINITY", + Double.POSITIVE_INFINITY, Math.log1p(Double.POSITIVE_INFINITY), 0D); + assertEquals(Double.doubleToLongBits(0.0), Double.doubleToLongBits(Math + .log1p(0.0))); + assertEquals(Double.doubleToLongBits(+0.0), Double + .doubleToLongBits(Math.log1p(+0.0))); + assertEquals(Double.doubleToLongBits(-0.0), Double + .doubleToLongBits(Math.log1p(-0.0))); + + assertEquals("Should return -0.2941782295312541", -0.2941782295312541, + Math.log1p(-0.254856327), 0D); + assertEquals("Should return 7.368050685564151", 7.368050685564151, Math + .log1p(1583.542), 0D); + assertEquals("Should return 0.4633708685409921", 0.4633708685409921, + Math.log1p(0.5894227), 0D); + assertEquals("Should return 709.782712893384", 709.782712893384, Math + .log1p(Double.MAX_VALUE), 0D); + assertEquals("Should return Double.MIN_VALUE", Double.MIN_VALUE, Math + .log1p(Double.MIN_VALUE), 0D); + } + + /** + * @tests java.lang.Math#max(double, double) + */ + @SmallTest + public void testMaxDD() { + // Test for method double java.lang.Math.max(double, double) + assertEquals("Incorrect double max value", 1908897.6000089, Math.max(-1908897.6000089, + 1908897.6000089), 0D); + assertEquals("Incorrect double max value", + 1908897.6000089, Math.max(2.0, 1908897.6000089), 0D); + assertEquals("Incorrect double max value", -2.0, Math.max(-2.0, + -1908897.6000089), 0D); + + } + + /** + * @tests java.lang.Math#max(float, float) + */ + @SmallTest + public void testMaxFF() { + // Test for method float java.lang.Math.max(float, float) + assertTrue("Incorrect float max value", Math.max(-1908897.600f, + 1908897.600f) == 1908897.600f); + assertTrue("Incorrect float max value", + Math.max(2.0f, 1908897.600f) == 1908897.600f); + assertTrue("Incorrect float max value", + Math.max(-2.0f, -1908897.600f) == -2.0f); + } + + /** + * @tests java.lang.Math#max(int, int) + */ + @SmallTest + public void testMaxII() { + // Test for method int java.lang.Math.max(int, int) + assertEquals("Incorrect int max value", + 19088976, Math.max(-19088976, 19088976)); + assertEquals("Incorrect int max value", + 19088976, Math.max(20, 19088976)); + assertEquals("Incorrect int max value", -20, Math.max(-20, -19088976)); + } + + /** + * @tests java.lang.Math#max(long, long) + */ + @SmallTest + public void testMaxJJ() { + // Test for method long java.lang.Math.max(long, long) + assertEquals("Incorrect long max value", 19088976000089L, Math.max(-19088976000089L, + 19088976000089L)); + assertEquals("Incorrect long max value", + 19088976000089L, Math.max(20, 19088976000089L)); + assertEquals("Incorrect long max value", + -20, Math.max(-20, -19088976000089L)); + } + + /** + * @tests java.lang.Math#min(double, double) + */ + @SmallTest + public void testMinDD() { + // Test for method double java.lang.Math.min(double, double) + assertEquals("Incorrect double min value", -1908897.6000089, Math.min(-1908897.6000089, + 1908897.6000089), 0D); + assertEquals("Incorrect double min value", + 2.0, Math.min(2.0, 1908897.6000089), 0D); + assertEquals("Incorrect double min value", -1908897.6000089, Math.min(-2.0, + -1908897.6000089), 0D); + } + + /** + * @tests java.lang.Math#min(float, float) + */ + @SmallTest + public void testMinFF() { + // Test for method float java.lang.Math.min(float, float) + assertTrue("Incorrect float min value", Math.min(-1908897.600f, + 1908897.600f) == -1908897.600f); + assertTrue("Incorrect float min value", + Math.min(2.0f, 1908897.600f) == 2.0f); + assertTrue("Incorrect float min value", + Math.min(-2.0f, -1908897.600f) == -1908897.600f); + } + + /** + * @tests java.lang.Math#min(int, int) + */ + @SmallTest + public void testMinII() { + // Test for method int java.lang.Math.min(int, int) + assertEquals("Incorrect int min value", + -19088976, Math.min(-19088976, 19088976)); + assertEquals("Incorrect int min value", 20, Math.min(20, 19088976)); + assertEquals("Incorrect int min value", + -19088976, Math.min(-20, -19088976)); + + } + + /** + * @tests java.lang.Math#min(long, long) + */ + @SmallTest + public void testMinJJ() { + // Test for method long java.lang.Math.min(long, long) + assertEquals("Incorrect long min value", -19088976000089L, Math.min(-19088976000089L, + 19088976000089L)); + assertEquals("Incorrect long min value", + 20, Math.min(20, 19088976000089L)); + assertEquals("Incorrect long min value", + -19088976000089L, Math.min(-20, -19088976000089L)); + } + + /** + * @tests java.lang.Math#pow(double, double) + */ + @SmallTest + public void testPowDD() { + // Test for method double java.lang.Math.pow(double, double) + assertTrue("pow returned incorrect value", + (long) Math.pow(2, 8) == 256l); + assertTrue("pow returned incorrect value", + Math.pow(2, -8) == 0.00390625d); + assertEquals("Incorrect root returned1", + 2, Math.sqrt(Math.pow(Math.sqrt(2), 4)), 0); + } + + /** + * @tests java.lang.Math#rint(double) + */ + @SmallTest + public void testRintD() { + // Test for method double java.lang.Math.rint(double) + assertEquals("Failed to round properly - up to odd", + 3.0, Math.rint(2.9), 0D); + assertTrue("Failed to round properly - NaN", Double.isNaN(Math + .rint(Double.NaN))); + assertEquals("Failed to round properly down to even", + 2.0, Math.rint(2.1), 0D); + assertTrue("Failed to round properly " + 2.5 + " to even", Math + .rint(2.5) == 2.0); + } + + /** + * @tests java.lang.Math#round(double) + */ + @SmallTest + public void testRoundD() { + // Test for method long java.lang.Math.round(double) + assertEquals("Incorrect rounding of a float", -91, Math.round(-90.89d)); + } + + /** + * @tests java.lang.Math#round(float) + */ + @SmallTest + public void testRoundF() { + // Test for method int java.lang.Math.round(float) + assertEquals("Incorrect rounding of a float", -91, Math.round(-90.89f)); + } + + /** + * @tests java.lang.Math#signum(double) + */ + @SmallTest + public void testSignumD() { + assertTrue(Double.isNaN(Math.signum(Double.NaN))); + assertTrue(Double.isNaN(Math.signum(Double.NaN))); + assertEquals(Double.doubleToLongBits(0.0), Double.doubleToLongBits(Math + .signum(0.0))); + assertEquals(Double.doubleToLongBits(+0.0), Double + .doubleToLongBits(Math.signum(+0.0))); + assertEquals(Double.doubleToLongBits(-0.0), Double + .doubleToLongBits(Math.signum(-0.0))); + + assertEquals(1.0, Math.signum(253681.2187962), 0D); + assertEquals(-1.0, Math.signum(-125874693.56), 0D); + assertEquals(1.0, Math.signum(1.2587E-308), 0D); + assertEquals(-1.0, Math.signum(-1.2587E-308), 0D); + + assertEquals(1.0, Math.signum(Double.MAX_VALUE), 0D); + assertEquals(1.0, Math.signum(Double.MIN_VALUE), 0D); + assertEquals(-1.0, Math.signum(-Double.MAX_VALUE), 0D); + assertEquals(-1.0, Math.signum(-Double.MIN_VALUE), 0D); + assertEquals(1.0, Math.signum(Double.POSITIVE_INFINITY), 0D); + assertEquals(-1.0, Math.signum(Double.NEGATIVE_INFINITY), 0D); + } + + /** + * @tests java.lang.Math#signum(float) + */ + @SmallTest + public void testSignumF() { + assertTrue(Float.isNaN(Math.signum(Float.NaN))); + assertEquals(Float.floatToIntBits(0.0f), Float + .floatToIntBits(Math.signum(0.0f))); + assertEquals(Float.floatToIntBits(+0.0f), Float + .floatToIntBits(Math.signum(+0.0f))); + assertEquals(Float.floatToIntBits(-0.0f), Float + .floatToIntBits(Math.signum(-0.0f))); + + assertEquals(1.0f, Math.signum(253681.2187962f), 0f); + assertEquals(-1.0f, Math.signum(-125874693.56f), 0f); + assertEquals(1.0f, Math.signum(1.2587E-11f), 0f); + assertEquals(-1.0f, Math.signum(-1.2587E-11f), 0f); + + assertEquals(1.0f, Math.signum(Float.MAX_VALUE), 0f); + assertEquals(1.0f, Math.signum(Float.MIN_VALUE), 0f); + assertEquals(-1.0f, Math.signum(-Float.MAX_VALUE), 0f); + assertEquals(-1.0f, Math.signum(-Float.MIN_VALUE), 0f); + assertEquals(1.0f, Math.signum(Float.POSITIVE_INFINITY), 0f); + assertEquals(-1.0f, Math.signum(Float.NEGATIVE_INFINITY), 0f); + } + + /** + * @tests java.lang.Math#sin(double) + */ + @SmallTest + public void testSinD() { + // Test for method double java.lang.Math.sin(double) + assertEquals("Incorrect answer", 0.0, Math.sin(0), 0D); + assertEquals("Incorrect answer", 0.8414709848078965, Math.sin(1), 0D); + } + + /** + * @tests java.lang.Math#sinh(double) + */ + @SmallTest + public void testSinhD() { + // Test for special situations + assertTrue("Should return NaN", Double.isNaN(Math.sinh(Double.NaN))); + assertEquals("Should return POSITIVE_INFINITY", + Double.POSITIVE_INFINITY, Math.sinh(Double.POSITIVE_INFINITY), 0D); + assertEquals("Should return NEGATIVE_INFINITY", + Double.NEGATIVE_INFINITY, Math.sinh(Double.NEGATIVE_INFINITY), 0D); + assertEquals(Double.doubleToLongBits(0.0), Double.doubleToLongBits(Math + .sinh(0.0))); + assertEquals(Double.doubleToLongBits(+0.0), Double + .doubleToLongBits(Math.sinh(+0.0))); + assertEquals(Double.doubleToLongBits(-0.0), Double + .doubleToLongBits(Math.sinh(-0.0))); + + assertEquals("Should return POSITIVE_INFINITY", + Double.POSITIVE_INFINITY, Math.sinh(1234.56), 0D); + assertEquals("Should return NEGATIVE_INFINITY", + Double.NEGATIVE_INFINITY, Math.sinh(-1234.56), 0D); + assertEquals("Should return 1.0000000000001666E-6", + 1.0000000000001666E-6, Math.sinh(0.000001), 0D); + assertEquals("Should return -1.0000000000001666E-6", + -1.0000000000001666E-6, Math.sinh(-0.000001), 0D); + assertEquals("Should return 5.115386441963859", 5.115386441963859, Math + .sinh(2.33482), 0D); + assertEquals("Should return POSITIVE_INFINITY", + Double.POSITIVE_INFINITY, Math.sinh(Double.MAX_VALUE), 0D); + assertEquals("Should return 4.9E-324", 4.9E-324, Math + .sinh(Double.MIN_VALUE), 0D); + } + + /** + * @tests java.lang.Math#sqrt(double) + */ + @SmallTest + public void testSqrtD() { + // Test for method double java.lang.Math.sqrt(double) + assertEquals("Incorrect root returned2", 7, Math.sqrt(49), 0); + } + + /** + * @tests java.lang.Math#tan(double) + */ + @SmallTest + public void testTanD() { + // Test for method double java.lang.Math.tan(double) + assertEquals("Incorrect answer", 0.0, Math.tan(0), 0D); + assertEquals("Incorrect answer", 1.5574077246549023, Math.tan(1), 0D); + + } + + /** + * @tests java.lang.Math#tanh(double) + */ + @SmallTest + public void testTanhD() { + // Test for special situations + assertTrue("Should return NaN", Double.isNaN(Math.tanh(Double.NaN))); + assertEquals("Should return +1.0", +1.0, Math + .tanh(Double.POSITIVE_INFINITY), 0D); + assertEquals("Should return -1.0", -1.0, Math + .tanh(Double.NEGATIVE_INFINITY), 0D); + assertEquals(Double.doubleToLongBits(0.0), Double.doubleToLongBits(Math + .tanh(0.0))); + assertEquals(Double.doubleToLongBits(+0.0), Double + .doubleToLongBits(Math.tanh(+0.0))); + assertEquals(Double.doubleToLongBits(-0.0), Double + .doubleToLongBits(Math.tanh(-0.0))); + + assertEquals("Should return 1.0", 1.0, Math.tanh(1234.56), 0D); + assertEquals("Should return -1.0", -1.0, Math.tanh(-1234.56), 0D); + assertEquals("Should return 9.999999999996666E-7", + 9.999999999996666E-7, Math.tanh(0.000001), 0D); + assertEquals("Should return 0.981422884124941", 0.981422884124941, Math + .tanh(2.33482), 0D); + assertEquals("Should return 1.0", 1.0, Math.tanh(Double.MAX_VALUE), 0D); + assertEquals("Should return 4.9E-324", 4.9E-324, Math + .tanh(Double.MIN_VALUE), 0D); + } + + /** + * @tests java.lang.Math#random() + */ + @MediumTest + public void testRandom() { + // There isn't a place for these tests so just stick them here + assertEquals("Wrong value E", + 4613303445314885481L, Double.doubleToLongBits(Math.E)); + assertEquals("Wrong value PI", + 4614256656552045848L, Double.doubleToLongBits(Math.PI)); + + for (int i = 500; i >= 0; i--) { + double d = Math.random(); + assertTrue("Generated number is out of range: " + d, d >= 0.0 + && d < 1.0); + } + } + + /** + * @tests java.lang.Math#toRadians(double) + */ + @MediumTest + public void testToRadiansD() { + for (double d = 500; d >= 0; d -= 1.0) { + double converted = Math.toDegrees(Math.toRadians(d)); + assertTrue("Converted number not equal to original. d = " + d, + converted >= d * 0.99999999 && converted <= d * 1.00000001); + } + } + + /** + * @tests java.lang.Math#toDegrees(double) + */ + @MediumTest + public void testToDegreesD() { + for (double d = 500; d >= 0; d -= 1.0) { + double converted = Math.toRadians(Math.toDegrees(d)); + assertTrue("Converted number not equal to original. d = " + d, + converted >= d * 0.99999999 && converted <= d * 1.00000001); + } + } + + /** + * @tests java.lang.Math#ulp(double) + */ + @SuppressWarnings("boxing") + @SmallTest + public void testUlpD() { + // Test for special cases + assertTrue("Should return NaN", Double.isNaN(Math.ulp(Double.NaN))); + assertEquals("Returned incorrect value", Double.POSITIVE_INFINITY, Math + .ulp(Double.POSITIVE_INFINITY), 0D); + assertEquals("Returned incorrect value", Double.POSITIVE_INFINITY, Math + .ulp(Double.NEGATIVE_INFINITY), 0D); + assertEquals("Returned incorrect value", Double.MIN_VALUE, Math + .ulp(0.0), 0D); + assertEquals("Returned incorrect value", Double.MIN_VALUE, Math + .ulp(+0.0), 0D); + assertEquals("Returned incorrect value", Double.MIN_VALUE, Math + .ulp(-0.0), 0D); + assertEquals("Returned incorrect value", Math.pow(2, 971), Math + .ulp(Double.MAX_VALUE), 0D); + assertEquals("Returned incorrect value", Math.pow(2, 971), Math + .ulp(-Double.MAX_VALUE), 0D); + + assertEquals("Returned incorrect value", Double.MIN_VALUE, Math + .ulp(Double.MIN_VALUE), 0D); + assertEquals("Returned incorrect value", Double.MIN_VALUE, Math + .ulp(-Double.MIN_VALUE), 0D); + + assertEquals("Returned incorrect value", 2.220446049250313E-16, Math + .ulp(1.0), 0D); + assertEquals("Returned incorrect value", 2.220446049250313E-16, Math + .ulp(-1.0), 0D); + assertEquals("Returned incorrect value", 2.2737367544323206E-13, Math + .ulp(1153.0), 0D); + } + + /** + * @tests java.lang.Math#ulp(float) + */ + @SuppressWarnings("boxing") + @SmallTest + public void testUlpf() { + // Test for special cases + assertTrue("Should return NaN", Float.isNaN(Math.ulp(Float.NaN))); + assertEquals("Returned incorrect value", Float.POSITIVE_INFINITY, Math + .ulp(Float.POSITIVE_INFINITY), 0f); + assertEquals("Returned incorrect value", Float.POSITIVE_INFINITY, Math + .ulp(Float.NEGATIVE_INFINITY), 0f); + assertEquals("Returned incorrect value", Float.MIN_VALUE, Math + .ulp(0.0f), 0f); + assertEquals("Returned incorrect value", Float.MIN_VALUE, Math + .ulp(+0.0f), 0f); + assertEquals("Returned incorrect value", Float.MIN_VALUE, Math + .ulp(-0.0f), 0f); + assertEquals("Returned incorrect value", 2.028241E31f, Math + .ulp(Float.MAX_VALUE), 0f); + assertEquals("Returned incorrect value", 2.028241E31f, Math + .ulp(-Float.MAX_VALUE), 0f); + + assertEquals("Returned incorrect value", 1.4E-45f, Math + .ulp(Float.MIN_VALUE), 0f); + assertEquals("Returned incorrect value", 1.4E-45f, Math + .ulp(-Float.MIN_VALUE), 0f); + + assertEquals("Returned incorrect value", 1.1920929E-7f, Math.ulp(1.0f), + 0f); + assertEquals("Returned incorrect value", 1.1920929E-7f, + Math.ulp(-1.0f), 0f); + assertEquals("Returned incorrect value", 1.2207031E-4f, Math + .ulp(1153.0f), 0f); + assertEquals("Returned incorrect value", 5.6E-45f, Math + .ulp(9.403954E-38f), 0f); + } +} diff --git a/tests/CoreTests/android/core/MiscRegressionTest.java b/tests/CoreTests/android/core/MiscRegressionTest.java new file mode 100644 index 0000000000000000000000000000000000000000..8fe064c556ad2d79108e613431f55a6d7848b933 --- /dev/null +++ b/tests/CoreTests/android/core/MiscRegressionTest.java @@ -0,0 +1,506 @@ +/* + * 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 android.core; + +import junit.framework.Assert; +import junit.framework.TestCase; + +import java.io.File; +import java.io.InputStream; +import java.io.ObjectInputStream; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.security.KeyStore; +import java.security.cert.Certificate; +import java.util.Arrays; +import java.util.ConcurrentModificationException; +import java.util.Enumeration; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.Random; +import java.util.jar.JarEntry; +import java.util.jar.JarFile; +import java.util.logging.Logger; +import java.util.zip.Deflater; +import java.util.zip.Inflater; +import java.util.zip.ZipEntry; +import java.util.zip.ZipFile; +import android.test.suitebuilder.annotation.MediumTest; +import android.test.suitebuilder.annotation.SmallTest; +import android.test.suitebuilder.annotation.LargeTest; + +public class MiscRegressionTest extends TestCase { + + // Regression test for #857840: want JKS key store + @SmallTest + public void testDefaultKeystore() { + String type = KeyStore.getDefaultType(); + Assert.assertEquals("Default keystore type must be Bouncy Castle", "BKS", type); + + try { + KeyStore store = KeyStore.getInstance(KeyStore.getDefaultType()); + Assert.assertNotNull("Keystore must not be null", store); + } catch (Exception ex) { + throw new RuntimeException(ex); + } + + try { + KeyStore store = KeyStore.getInstance("BKS"); + Assert.assertNotNull("Keystore must not be null", store); + } catch (Exception ex) { + throw new RuntimeException(ex); + } + } + + // Regression test for #1061945: negative Shorts do not + // serialize/deserialize correctly + @SmallTest + public void testShortSerialization() throws Exception { + // create an instance of ObjectInputStream + String x = new String("serialize_foobar"); + java.io.ByteArrayOutputStream baos = new java.io.ByteArrayOutputStream(); + (new java.io.ObjectOutputStream(baos)).writeObject(x); + ObjectInputStream ois = new java.io.ObjectInputStream( + new java.io.ByteArrayInputStream(baos.toByteArray())); + + // get the setField(...,, short val) method in question + Class oClass = ObjectInputStream.class; + Method m = oClass.getDeclaredMethod("setField", new Class[] { Object.class, Class.class, String.class, short.class}); + // compose args + short start = 123; + short origval = -1; // 0xffff + Short obj = new Short(start); + Class declaringClass = Short.class; + String fieldDescName = "value"; + + // test the initial value + assertEquals(obj.shortValue(), start); + // invoke native method to set the field "value" of type short to the newval + m.setAccessible(true); // since the method is private + m.invoke(ois, new Object[]{ obj, declaringClass, fieldDescName, new Short(origval)} ); + // test the set value + short res = obj.shortValue(); + assertEquals("Read and written values must be equal", origval, res); + } + + // Regression test for #951285: Suitable LogHandler should be chosen + // depending on the environment. + @MediumTest + public void testAndroidLogHandler() throws Exception { + Logger.global.severe("This has logging Level.SEVERE, should become ERROR"); + Logger.global.warning("This has logging Level.WARNING, should become WARN"); + Logger.global.info("This has logging Level.INFO, should become INFO"); + Logger.global.config("This has logging Level.CONFIG, should become DEBUG"); + Logger.global.fine("This has logging Level.FINE, should become VERBOSE"); + Logger.global.finer("This has logging Level.FINER, should become VERBOSE"); + Logger.global.finest("This has logging Level.FINEST, should become VERBOSE"); + } + + // Regression test for #1045939: Different output for Method.toString() + @SmallTest + public void testMethodToString() { + try { + Method m1 = Object.class.getMethod("notify", new Class[] { }); + Method m2 = Object.class.getMethod("toString", new Class[] { }); + Method m3 = Object.class.getMethod("wait", new Class[] { long.class, int.class }); + Method m4 = Object.class.getMethod("equals", new Class[] { Object.class }); + Method m5 = String.class.getMethod("valueOf", new Class[] { char[].class }); + Method m6 = Runtime.class.getMethod("exec", new Class[] { String[].class }); + + assertEquals("Method.toString() must match expectations", + "public final native void java.lang.Object.notify()", + m1.toString()); + + assertEquals("Method.toString() must match expectations", + "public java.lang.String java.lang.Object.toString()", + m2.toString()); + + assertEquals("Method.toString() must match expectations", + "public final native void java.lang.Object.wait(long,int) throws java.lang.InterruptedException", + m3.toString()); + + assertEquals("Method.toString() must match expectations", + "public boolean java.lang.Object.equals(java.lang.Object)", + m4.toString()); + + assertEquals("Method.toString() must match expectations", + "public static java.lang.String java.lang.String.valueOf(char[])", + m5.toString()); + + assertEquals("Method.toString() must match expectations", + "public java.lang.Process java.lang.Runtime.exec(java.lang.String[]) throws java.io.IOException", + m6.toString()); + + } catch (Exception ex) { + throw new RuntimeException(ex); + } + + } + + // Regression test for #1062200: Enum fails to deserialize. Actual problem + // was that Class.isEnum() erroneously returned true for indirect + // descendants of Enum. + enum TrafficLights { + RED, + YELLOW {}, + GREEN { + @SuppressWarnings("unused") + int i; + @SuppressWarnings("unused") + void foobar() {} + }; + } + + @SmallTest + public void testClassIsEnum() { + Class trafficClass = TrafficLights.class; + + Class redClass = TrafficLights.RED.getClass(); + Class yellowClass = TrafficLights.YELLOW.getClass(); + Class greenClass = TrafficLights.GREEN.getClass(); + + Assert.assertSame("Classes must be equal", trafficClass, redClass); + Assert.assertNotSame("Classes must be different", trafficClass, yellowClass); + Assert.assertNotSame("Classes must be different", trafficClass, greenClass); + Assert.assertNotSame("Classes must be different", yellowClass, greenClass); + + Assert.assertTrue("Must be an enum", trafficClass.isEnum()); + Assert.assertTrue("Must be an enum", redClass.isEnum()); + Assert.assertFalse("Must not be an enum", yellowClass.isEnum()); + Assert.assertFalse("Must not be an enum", greenClass.isEnum()); + + Assert.assertNotNull("Must have enum constants", trafficClass.getEnumConstants()); + Assert.assertNull("Must not have enum constants", yellowClass.getEnumConstants()); + Assert.assertNull("Must not have enum constants", greenClass.getEnumConstants()); + } + + // Regression test for #1046174: JarEntry.getCertificates() is really slow. + public void checkJarCertificates(File file) { + try { + JarFile jarFile = new JarFile(file); + JarEntry je = jarFile.getJarEntry("AndroidManifest.xml"); + byte[] readBuffer = new byte[1024]; + + long t0 = System.currentTimeMillis(); + + // We must read the stream for the JarEntry to retrieve + // its certificates. + InputStream is = jarFile.getInputStream(je); + while (is.read(readBuffer, 0, readBuffer.length) != -1) { + // not using + } + is.close(); + Certificate[] certs = je != null ? je.getCertificates() : null; + + long t1 = System.currentTimeMillis(); + android.util.Log.d("TestHarness", "loadCertificates() took " + (t1 - t0) + " ms"); + if (certs == null) { + android.util.Log.d("TestHarness", "We have no certificates"); + } else { + android.util.Log.d("TestHarness", "We have " + certs.length + " certificates"); + } + } catch (Exception ex) { + throw new RuntimeException(ex); + } + } + + @LargeTest + public void testJarCertificates() { + File[] files = new File("/system/app").listFiles(); + for (int i = 0; i < files.length; i++) { + checkJarCertificates(files[i]); + } + } + + // Regression test for #1120750: Reflection for static long fields is broken + private static final long MY_LONG = 5073258162644648461L; + + @SmallTest + public void testLongFieldReflection() { + try { + Field field = getClass().getDeclaredField("MY_LONG"); + assertEquals(5073258162644648461L, field.getLong(null)); + } catch (Exception ex) { + throw new RuntimeException(ex); + } + } + + // Regression test for Harmony LinkedHashMap bug. Copied from core, just + // to make sure it doesn't get lost. + @SmallTest + public void testLinkedHashMap() { + // we want to test the LinkedHashMap in access ordering mode. + LinkedHashMap map = new LinkedHashMap(10, 0.75f, true); + + map.put("key1", "value1"); + map.put("key2", "value2"); + map.put("key3", "value3"); + + Iterator iterator = map.keySet().iterator(); + String id = (String) iterator.next(); + map.get(id); + try { + iterator.next(); + // A LinkedHashMap is supposed to throw this Exception when a + // iterator.next() Operation takes place after a get + // Operation. This is because the get Operation is considered + // a structural modification if the LinkedHashMap is in + // access order mode. + fail("expected ConcurrentModificationException was not thrown."); + } catch(ConcurrentModificationException e) { + // expected + } + + LinkedHashMap mapClone = (LinkedHashMap) map.clone(); + + iterator = map.keySet().iterator(); + id = (String) iterator.next(); + mapClone.get(id); + try { + iterator.next(); + } catch(ConcurrentModificationException e) { + fail("expected ConcurrentModificationException was not thrown."); + } + } + + // Regression test for #1212257: Boot-time package scan is slow. Not + // expected to fail. Please see log if you are interested in the results. + @LargeTest + public void testZipStressManifest() { + android.util.Log.d("MiscRegressionTest", "ZIP stress test started"); + + long time0 = System.currentTimeMillis(); + + try { + File[] files = new File("/system/app").listFiles(); + + byte[] buffer = new byte[512]; + + if (files != null) { + for (int i = 0; i < files.length; i++) { + android.util.Log.d("MiscRegressionTest", + "ZIP stress test processing " + files[i] + "..."); + + ZipFile zip = new ZipFile(files[i]); + + ZipEntry entry = zip.getEntry("AndroidManifest.xml"); + InputStream stream = zip.getInputStream(entry); + + int j = stream.read(buffer); + while (j != -1) { + j = stream.read(buffer); + } + + stream.close(); + } + } + } catch (Exception ex) { + throw new RuntimeException(ex); + } + + long time1 = System.currentTimeMillis(); + + android.util.Log.d("MiscRegressionTest", "ZIP stress test finished, " + + "time was " + (time1- time0) + "ms"); + } + + @LargeTest + public void testZipStressAllFiles() { + android.util.Log.d("MiscRegressionTest", "ZIP stress test started"); + + long time0 = System.currentTimeMillis(); + + try { + File[] files = new File("/system/app").listFiles(); + + byte[] buffer = new byte[512]; + + if (files != null) { + for (int i = 0; i < files.length; i++) { + android.util.Log.d("MiscRegressionTest", + "ZIP stress test processing " + files[i] + "..."); + + ZipFile zip = new ZipFile(files[i]); + + Enumeration entries = zip.entries(); + while (entries.hasMoreElements()) { + InputStream stream = zip.getInputStream(entries.nextElement()); + + int j = stream.read(buffer); + while (j != -1) { + j = stream.read(buffer); + } + + stream.close(); + } + } + } + } catch (Exception ex) { + throw new RuntimeException(ex); + } + + long time1 = System.currentTimeMillis(); + + android.util.Log.d("MiscRegressionTest", "ZIP stress test finished, " + + "time was " + (time1- time0) + "ms"); + } + + @SmallTest + public void testOsEncodingProperty() { + long time0 = System.currentTimeMillis(); + String[] files = new File("/system/app").list(); + long time1 = System.currentTimeMillis(); + android.util.Log.d("MiscRegressionTest", "File.list() test finished, " + + "time was " + (time1- time0) + "ms"); + } + + // ------------------------------------------------------------------------- + // Regression test for #1185084: Native memory allocated by + // java.util.zip.Deflater in system_server. The fix reduced some internal + // ZLIB buffers in size, so this test is trying to execute a lot of + // deflating to ensure that things are still working properly. + private void assertEquals(byte[] a, byte[] b) { + assertEquals("Arrays must have same length", a.length, b.length); + + for (int i = 0; i < a.length; i++) { + assertEquals("Array elements #" + i + " must be equal", a[i], b[i]); + } + } + + @LargeTest + public void testZipDeflateInflateStress() { + + final int DATA_SIZE = 16384; + + Random random = new Random(42); // Seed makes test reproducible + + try { + // Outer loop selects "mode" of test. + for (int j = 1; j <=2 ; j++) { + + byte[] input = new byte[DATA_SIZE]; + + if (j == 1) { + // Totally random content + random.nextBytes(input); + } else { + // Random contents with longer repetitions + int pos = 0; + while (pos < input.length) { + byte what = (byte)random.nextInt(256); + int howMany = random.nextInt(32); + if (pos + howMany >= input.length) { + howMany = input.length - pos; + } + Arrays.fill(input, pos, pos + howMany, what); + pos += howMany; + } + } + + // Inner loop tries all 9 compression levels. + for (int i = 1; i <= 9; i++) { + android.util.Log.d("MiscRegressionTest", "ZipDeflateInflateStress test (" + j + "," + i + ")..."); + + byte[] zipped = new byte[2 * DATA_SIZE]; // Just to make sure... + + Deflater deflater = new Deflater(i); + deflater.setInput(input); + deflater.finish(); + + deflater.deflate(zipped); + + byte[] output = new byte[DATA_SIZE]; + + Inflater inflater = new Inflater(); + inflater.setInput(zipped); + inflater.finished(); + + inflater.inflate(output); + + assertEquals(input, output); + } + } + } catch (Exception ex) { + throw new RuntimeException(ex); + } + } + + // ------------------------------------------------------------------------- + // Regression test for #1252043: Thread.getStackTrace() is broken + class MyThread extends Thread { + public MyThread(String name) { + super(name); + } + + @Override + public void run() { + doSomething(); + } + + public void doSomething() { + for (int i = 0; i < 20;) { + try { + Thread.sleep(100); + } catch (InterruptedException ex) { + } + } + } + } + + class MyOtherThread extends Thread { + public int visibleTraces; + + public MyOtherThread(ThreadGroup group, String name) { + super(group, name); + } + + @Override + public void run() { + visibleTraces = Thread.getAllStackTraces().size(); + } + } + + @LargeTest + public void testThreadGetStackTrace() { + MyThread t1 = new MyThread("t1"); + t1.start(); + + try { + Thread.sleep(1000); + } catch (InterruptedException ex) { + } + + StackTraceElement[] traces = t1.getStackTrace(); + StackTraceElement trace = traces[traces.length - 2]; + + // Expect to find MyThread.doSomething in the trace + assertTrue("Must find MyThread.doSomething in trace", + trace.getClassName().endsWith("$MyThread") && + trace.getMethodName().equals("doSomething")); + + ThreadGroup g1 = new ThreadGroup("1"); + MyOtherThread t2 = new MyOtherThread(g1, "t2"); + t2.start(); + try { + t2.join(); + } catch (InterruptedException ex) { + } + + // Expect to see the traces of all threads (not just t2) + assertTrue("Must have traces for all threads", t2.visibleTraces > 1); + } +} diff --git a/tests/CoreTests/android/core/NIOTest.java b/tests/CoreTests/android/core/NIOTest.java new file mode 100644 index 0000000000000000000000000000000000000000..fd279caec0912321453dce0054c2e857f34c6fcb --- /dev/null +++ b/tests/CoreTests/android/core/NIOTest.java @@ -0,0 +1,694 @@ +/* + * 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 android.core; + +import junit.framework.TestCase; + +import java.nio.Buffer; +import java.nio.BufferOverflowException; +import java.nio.BufferUnderflowException; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.nio.FloatBuffer; +import java.nio.IntBuffer; +import java.nio.ShortBuffer; +import android.test.suitebuilder.annotation.SmallTest; + +/** + * Tests for some buffers from the java.nio package. + */ +public class NIOTest extends TestCase { + + void checkBuffer(Buffer b) { + assertTrue(0 <= b.position()); + assertTrue(b.position() <= b.limit()); + assertTrue(b.limit() <= b.capacity()); + } + + @SmallTest + public void testNIO() throws Exception { + ByteBuffer b; + + // Test byte array-based buffer + b = ByteBuffer.allocate(12); + byteBufferTest(b); + + // Test native heap-allocated buffer + b = ByteBuffer.allocateDirect(12); + byteBufferTest(b); + + // Test short array-based buffer + short[] shortArray = new short[8]; + ShortBuffer sb = ShortBuffer.wrap(shortArray); + shortBufferTest(sb); + + // Test int array-based buffer + int[] intArray = new int[8]; + IntBuffer ib = IntBuffer.wrap(intArray); + intBufferTest(ib); + + // Test float array-based buffer + float[] floatArray = new float[8]; + FloatBuffer fb = FloatBuffer.wrap(floatArray); + floatBufferTest(fb); + } + + private void byteBufferTest(ByteBuffer b) { + checkBuffer(b); + + // Bounds checks + try { + b.put(-1, (byte) 0); + fail("expected exception not thrown"); + } catch (IndexOutOfBoundsException e) { + // expected + } + + try { + b.put(b.limit(), (byte) 0); + fail("expected exception not thrown"); + } catch (IndexOutOfBoundsException e) { + // expected + } + + // IndexOutOfBoundsException: offset < 0 + try { + byte[] data = new byte[8]; + b.position(0); + b.put(data, -1, 2); + fail("expected exception not thrown"); + } catch (IndexOutOfBoundsException e) { + // expected + } + + // IndexOutOfBoundsException: length > array.length - offset + try { + byte[] data = new byte[8]; + b.position(0); + b.put(data, 1, 8); + fail("expected exception not thrown"); + } catch (IndexOutOfBoundsException e) { + // expected + } + + // BufferOverflowException: length > remaining() + try { + byte[] data = new byte[8]; + b.position(b.limit() - 2); + b.put(data, 0, 3); + fail("expected exception not thrown"); + } catch (BufferOverflowException e) { + // expected + } + + // Fill buffer with bytes A0 A1 A2 A3 ... + b.position(0); + for (int i = 0; i < b.capacity(); i++) { + b.put((byte) (0xA0 + i)); + } + try { + b.put((byte) 0xFF); + fail("expected exception not thrown"); + } catch (BufferOverflowException e) { + // expected + } + + b.position(0); + assertEquals((byte) 0xA7, b.get(7)); + try { + b.get(12); + fail("expected exception not thrown"); + } catch (IndexOutOfBoundsException e) { + // expected + } + try { + b.get(-10); + fail("expected exception not thrown"); + } catch (IndexOutOfBoundsException e) { + // expected + } + + b.position(0); + b.order(ByteOrder.LITTLE_ENDIAN); + assertEquals((byte) 0xA0, b.get()); + assertEquals((byte) 0xA1, b.get()); + assertEquals((byte) 0xA2, b.get()); + assertEquals((byte) 0xA3, b.get()); + assertEquals((byte) 0xA4, b.get()); + assertEquals((byte) 0xA5, b.get()); + assertEquals((byte) 0xA6, b.get()); + assertEquals((byte) 0xA7, b.get()); + assertEquals((byte) 0xA8, b.get()); + assertEquals((byte) 0xA9, b.get()); + assertEquals((byte) 0xAA, b.get()); + assertEquals((byte) 0xAB, b.get()); + try { + b.get(); + fail("expected exception not thrown"); + } catch (BufferUnderflowException e) { + // expected + } + + b.position(0); + b.order(ByteOrder.BIG_ENDIAN); + assertEquals((byte) 0xA0, b.get()); + assertEquals((byte) 0xA1, b.get()); + assertEquals((byte) 0xA2, b.get()); + assertEquals((byte) 0xA3, b.get()); + assertEquals((byte) 0xA4, b.get()); + assertEquals((byte) 0xA5, b.get()); + assertEquals((byte) 0xA6, b.get()); + assertEquals((byte) 0xA7, b.get()); + assertEquals((byte) 0xA8, b.get()); + assertEquals((byte) 0xA9, b.get()); + assertEquals((byte) 0xAA, b.get()); + assertEquals((byte) 0xAB, b.get()); + try { + b.get(); + fail("expected exception not thrown"); + } catch (BufferUnderflowException e) { + // expected + } + + b.position(6); + b.limit(10); + assertEquals((byte) 0xA6, b.get()); + + // Check sliced buffer + b.position(6); + + ByteBuffer bb = b.slice(); + checkBuffer(bb); + + assertEquals(0, bb.position()); + assertEquals(4, bb.limit()); + assertEquals(4, bb.capacity()); + + assertEquals((byte) 0xA6, bb.get()); + assertEquals((byte) 0xA7, bb.get()); + assertEquals((byte) 0xA8, bb.get()); + assertEquals((byte) 0xA9, bb.get()); + try { + bb.get(); + fail("expected exception not thrown"); + } catch (BufferUnderflowException e) { + // expected + } + + // Reset position and limit + b.position(0); + b.limit(b.capacity()); + + // Check 'getShort' + b.order(ByteOrder.LITTLE_ENDIAN); + b.position(0); + assertEquals((short) 0xA1A0, b.getShort()); + assertEquals((short) 0xA3A2, b.getShort()); + assertEquals((short) 0xA5A4, b.getShort()); + assertEquals((short) 0xA7A6, b.getShort()); + assertEquals((short) 0xA9A8, b.getShort()); + assertEquals((short) 0xABAA, b.getShort()); + try { + bb.getShort(); + fail("expected exception not thrown"); + } catch (BufferUnderflowException e) { + // expected + } + + b.order(ByteOrder.BIG_ENDIAN); + b.position(0); + assertEquals((short) 0xA0A1, b.getShort()); + assertEquals((short) 0xA2A3, b.getShort()); + assertEquals((short) 0xA4A5, b.getShort()); + assertEquals((short) 0xA6A7, b.getShort()); + assertEquals((short) 0xA8A9, b.getShort()); + assertEquals((short) 0xAAAB, b.getShort()); + try { + bb.getShort(); + fail("expected exception not thrown"); + } catch (BufferUnderflowException e) { + // expected + } + + // Check 'getInt' + b.order(ByteOrder.LITTLE_ENDIAN); + b.position(0); + assertEquals(0xA3A2A1A0, b.getInt()); + assertEquals(0xA7A6A5A4, b.getInt()); + assertEquals(0xABAAA9A8, b.getInt()); + try { + bb.getInt(); + fail("expected exception not thrown"); + } catch (BufferUnderflowException e) { + // expected + } + + b.order(ByteOrder.BIG_ENDIAN); + b.position(0); + assertEquals(0xA0A1A2A3, b.getInt()); + assertEquals(0xA4A5A6A7, b.getInt()); + assertEquals(0xA8A9AAAB, b.getInt()); + try { + bb.getInt(); + fail("expected exception not thrown"); + } catch (BufferUnderflowException e) { + // expected + } + + // Check 'getFloat' + b.order(ByteOrder.LITTLE_ENDIAN); + b.position(0); + assertEquals(0xA3A2A1A0, Float.floatToIntBits(b.getFloat())); + assertEquals(0xA7A6A5A4, Float.floatToIntBits(b.getFloat())); + assertEquals(0xABAAA9A8, Float.floatToIntBits(b.getFloat())); + try { + b.getFloat(); + fail("expected exception not thrown"); + } catch (BufferUnderflowException e) { + // expected + } + + b.order(ByteOrder.BIG_ENDIAN); + b.position(0); + assertEquals(0xA0A1A2A3, Float.floatToIntBits(b.getFloat())); + assertEquals(0xA4A5A6A7, Float.floatToIntBits(b.getFloat())); + assertEquals(0xA8A9AAAB, Float.floatToIntBits(b.getFloat())); + try { + b.getFloat(); + fail("expected exception not thrown"); + } catch (BufferUnderflowException e) { + // expected + } + + // Check 'getDouble(int position)' + b.order(ByteOrder.LITTLE_ENDIAN); + assertEquals(0xA7A6A5A4A3A2A1A0L, Double.doubleToLongBits(b.getDouble(0))); + assertEquals(0xA8A7A6A5A4A3A2A1L, Double.doubleToLongBits(b.getDouble(1))); + try { + b.getDouble(-1); + fail("expected exception not thrown"); + } catch (IndexOutOfBoundsException e) { + // expected + } + try { + b.getDouble(5); + fail("expected exception not thrown"); + } catch (IndexOutOfBoundsException e) { + // expected + } + + b.order(ByteOrder.BIG_ENDIAN); + assertEquals(0xA0A1A2A3A4A5A6A7L, Double.doubleToLongBits(b.getDouble(0))); + assertEquals(0xA1A2A3A4A5A6A7A8L, Double.doubleToLongBits(b.getDouble(1))); + try { + b.getDouble(-1); + fail("expected exception not thrown"); + } catch (IndexOutOfBoundsException e) { + // expected + } + try { + b.getDouble(5); + fail("expected exception not thrown"); + } catch (IndexOutOfBoundsException e) { + // expected + } + + // Slice and check 'getInt' + b.position(1); + b.limit(5); + b.order(ByteOrder.LITTLE_ENDIAN); + bb = b.slice(); + assertEquals(4, bb.capacity()); + assertEquals(0xA4A3A2A1, bb.getInt(0)); + + bb.order(ByteOrder.LITTLE_ENDIAN); + ShortBuffer sb = bb.asShortBuffer(); + + checkBuffer(sb); + assertEquals(2, sb.capacity()); + assertEquals((short) 0xA2A1, sb.get()); + assertEquals((short) 0xA4A3, sb.get()); + + bb.order(ByteOrder.BIG_ENDIAN); + sb = bb.asShortBuffer(); + + checkBuffer(sb); + assertEquals(2, sb.capacity()); + assertEquals((short) 0xA1A2, sb.get()); + assertEquals((short) 0xA3A4, sb.get()); + + bb.order(ByteOrder.LITTLE_ENDIAN); + IntBuffer ib = bb.asIntBuffer(); + + checkBuffer(ib); + assertEquals(1, ib.capacity()); + assertEquals(0xA4A3A2A1, ib.get()); + + bb.order(ByteOrder.BIG_ENDIAN); + ib = bb.asIntBuffer(); + + checkBuffer(ib); + assertEquals(1, ib.capacity()); + assertEquals(0xA1A2A3A4, ib.get()); + + bb.order(ByteOrder.LITTLE_ENDIAN); + FloatBuffer fb = bb.asFloatBuffer(); + + checkBuffer(fb); + assertEquals(1, fb.capacity()); + assertEquals(0xA4A3A2A1, Float.floatToIntBits(fb.get())); + + bb.order(ByteOrder.BIG_ENDIAN); + fb = bb.asFloatBuffer(); + + checkBuffer(fb); + assertEquals(1, fb.capacity()); + assertEquals(0xA1A2A3A4, Float.floatToIntBits(fb.get())); + } + + private void shortBufferTest(ShortBuffer sb) { + checkBuffer(sb); + + try { + sb.put(-1, (short) 0); + fail("expected exception not thrown"); + } catch (IndexOutOfBoundsException e) { + // expected + } + + try { + sb.put(sb.limit(), (short) 0); + fail("expected exception not thrown"); + } catch (IndexOutOfBoundsException e) { + // expected + } + + // IndexOutOfBoundsException: offset < 0 + try { + short[] data = new short[8]; + sb.position(0); + sb.put(data, -1, 2); + fail("expected exception not thrown"); + } catch (IndexOutOfBoundsException e) { + // expected + } + + // IndexOutOfBoundsException: length > array.length - offset + try { + short[] data = new short[8]; + sb.position(0); + sb.put(data, 1, 8); + fail("expected exception not thrown"); + } catch (IndexOutOfBoundsException e) { + // expected + } + + // BufferOverflowException: length > remaining() + try { + short[] data = new short[8]; + sb.position(sb.limit() - 2); + sb.put(data, 0, 3); + fail("expected exception not thrown"); + } catch (BufferOverflowException e) { + // expected + } + + short[] data = {0, 10, 20, 30, 40, 50, 60, 70}; + sb.position(0); + sb.put(data); + + try { + sb.get(); + fail("expected exception not thrown"); + } catch (BufferUnderflowException e) { + // expected + } + + sb.position(0); + assertEquals((short) 0, sb.get()); + assertEquals((short) 10, sb.get()); + assertEquals((short) 20, sb.get()); + assertEquals((short) 30, sb.get()); + assertEquals((short) 40, sb.get()); + assertEquals((short) 50, sb.get()); + assertEquals((short) 60, sb.get()); + assertEquals((short) 70, sb.get()); + try { + sb.get(); + fail("expected exception not thrown"); + } catch (BufferUnderflowException e) { + // expected + } + sb.position(1); + sb.put((short) 11); + assertEquals((short) 11, sb.get(1)); + + short[] ss1 = {33, 44, 55, 66}; + sb.position(3); + sb.put(ss1); + sb.position(0); + assertEquals((short) 0, sb.get()); + assertEquals((short) 11, sb.get()); + assertEquals((short) 20, sb.get()); + assertEquals((short) 33, sb.get()); + assertEquals((short) 44, sb.get()); + assertEquals((short) 55, sb.get()); + assertEquals((short) 66, sb.get()); + assertEquals((short) 70, sb.get()); + + short[] ss2 = {10, 22, 30}; + sb.position(2); + sb.put(ss2, 1, 1); + sb.position(0); + assertEquals((short) 0, sb.get()); + assertEquals((short) 11, sb.get()); + assertEquals((short) 22, sb.get()); + assertEquals((short) 33, sb.get()); + assertEquals((short) 44, sb.get()); + assertEquals((short) 55, sb.get()); + assertEquals((short) 66, sb.get()); + assertEquals((short) 70, sb.get()); + } + + private void intBufferTest(IntBuffer ib) { + checkBuffer(ib); + + try { + ib.put(-1, (int) 0); + fail("expected exception not thrown"); + } catch (IndexOutOfBoundsException e) { + // expected + } + + try { + ib.put(ib.limit(), (int) 0); + fail("expected exception not thrown"); + } catch (IndexOutOfBoundsException e) { + // expected + } + + // IndexOutOfBoundsException: offset < 0 + try { + int[] data = new int[8]; + ib.position(0); + ib.put(data, -1, 2); + fail("expected exception not thrown"); + } catch (IndexOutOfBoundsException e) { + // expected + } + + // IndexOutOfBoundsException: length > array.length - offset + try { + int[] data = new int[8]; + ib.position(0); + ib.put(data, 1, 8); + fail("expected exception not thrown"); + } catch (IndexOutOfBoundsException e) { + // expected + } + + // BufferOverflowException: length > remaining() + try { + int[] data = new int[8]; + ib.position(ib.limit() - 2); + ib.put(data, 0, 3); + fail("expected exception not thrown"); + } catch (BufferOverflowException e) { + // expected + } + + int[] data = {0, 10, 20, 30, 40, 50, 60, 70}; + ib.position(0); + ib.put(data); + + try { + ib.get(); + fail("expected exception not thrown"); + } catch (BufferUnderflowException e) { + // expected + } + + ib.position(0); + assertEquals((int) 0, ib.get()); + assertEquals((int) 10, ib.get()); + assertEquals((int) 20, ib.get()); + assertEquals((int) 30, ib.get()); + assertEquals((int) 40, ib.get()); + assertEquals((int) 50, ib.get()); + assertEquals((int) 60, ib.get()); + assertEquals((int) 70, ib.get()); + try { + ib.get(); + fail("expected exception not thrown"); + } catch (BufferUnderflowException e) { + // expected + } + ib.position(1); + ib.put((int) 11); + assertEquals((int) 11, ib.get(1)); + + int[] ss1 = {33, 44, 55, 66}; + ib.position(3); + ib.put(ss1); + ib.position(0); + assertEquals((int) 0, ib.get()); + assertEquals((int) 11, ib.get()); + assertEquals((int) 20, ib.get()); + assertEquals((int) 33, ib.get()); + assertEquals((int) 44, ib.get()); + assertEquals((int) 55, ib.get()); + assertEquals((int) 66, ib.get()); + assertEquals((int) 70, ib.get()); + + int[] ss2 = {10, 22, 30}; + ib.position(2); + ib.put(ss2, 1, 1); + ib.position(0); + assertEquals((int) 0, ib.get()); + assertEquals((int) 11, ib.get()); + assertEquals((int) 22, ib.get()); + assertEquals((int) 33, ib.get()); + assertEquals((int) 44, ib.get()); + assertEquals((int) 55, ib.get()); + assertEquals((int) 66, ib.get()); + assertEquals((int) 70, ib.get()); + } + + void floatBufferTest(FloatBuffer fb) { + checkBuffer(fb); + + try { + fb.put(-1, (float) 0); + fail("expected exception not thrown"); + } catch (IndexOutOfBoundsException e) { + // expected + } + + try { + fb.put(fb.limit(), (float) 0); + fail("expected exception not thrown"); + } catch (IndexOutOfBoundsException e) { + // expected + } + + // IndexOutOfBoundsException: offset < 0 + try { + float[] data = new float[8]; + fb.position(0); + fb.put(data, -1, 2); + fail("expected exception not thrown"); + } catch (IndexOutOfBoundsException e) { + // expected + } + + // IndexOutOfBoundsException: length > array.length - offset + try { + float[] data = new float[8]; + fb.position(0); + fb.put(data, 1, 8); + fail("expected exception not thrown"); + } catch (IndexOutOfBoundsException e) { + // expected + } + + // BufferOverflowException: length > remaining() + try { + float[] data = new float[8]; + fb.position(fb.limit() - 2); + fb.put(data, 0, 3); + fail("expected exception not thrown"); + } catch (BufferOverflowException e) { + // expected + } + + float[] data = {0, 10, 20, 30, 40, 50, 60, 70}; + fb.position(0); + fb.put(data); + + try { + fb.get(); + fail("expected exception not thrown"); + } catch (BufferUnderflowException e) { + // expected + } + + fb.position(0); + assertEquals((float) 0, fb.get()); + assertEquals((float) 10, fb.get()); + assertEquals((float) 20, fb.get()); + assertEquals((float) 30, fb.get()); + assertEquals((float) 40, fb.get()); + assertEquals((float) 50, fb.get()); + assertEquals((float) 60, fb.get()); + assertEquals((float) 70, fb.get()); + try { + fb.get(); + fail("expected exception not thrown"); + } catch (BufferUnderflowException e) { + // expected + } + fb.position(1); + fb.put((float) 11); + assertEquals((float) 11, fb.get(1)); + + float[] ss1 = {33, 44, 55, 66}; + fb.position(3); + fb.put(ss1); + fb.position(0); + assertEquals((float) 0, fb.get()); + assertEquals((float) 11, fb.get()); + assertEquals((float) 20, fb.get()); + assertEquals((float) 33, fb.get()); + assertEquals((float) 44, fb.get()); + assertEquals((float) 55, fb.get()); + assertEquals((float) 66, fb.get()); + assertEquals((float) 70, fb.get()); + + float[] ss2 = {10, 22, 30}; + fb.position(2); + fb.put(ss2, 1, 1); + fb.position(0); + assertEquals((float) 0, fb.get()); + assertEquals((float) 11, fb.get()); + assertEquals((float) 22, fb.get()); + assertEquals((float) 33, fb.get()); + assertEquals((float) 44, fb.get()); + assertEquals((float) 55, fb.get()); + assertEquals((float) 66, fb.get()); + assertEquals((float) 70, fb.get()); + } +} diff --git a/tests/CoreTests/android/core/OutputStreamWriterTest.java b/tests/CoreTests/android/core/OutputStreamWriterTest.java new file mode 100644 index 0000000000000000000000000000000000000000..1c0901e0fb366b164488972a501a4deb6f00d451 --- /dev/null +++ b/tests/CoreTests/android/core/OutputStreamWriterTest.java @@ -0,0 +1,48 @@ +/* + * 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 android.core; + +import junit.framework.TestCase; + +import java.io.ByteArrayOutputStream; +import java.io.OutputStreamWriter; +import android.test.suitebuilder.annotation.SmallTest; + +/** + * Tests basic functionality of an OutputStreamWriter. + */ +public class OutputStreamWriterTest extends TestCase { + + @SmallTest + public void testOutputStreamWriter() throws Exception { + String str = "AbCdEfGhIjKlMnOpQrStUvWxYz"; + ByteArrayOutputStream aa = new ByteArrayOutputStream(); + OutputStreamWriter a = new OutputStreamWriter(aa, "ISO8859_1"); + try { + a.write(str, 0, 4); + a.write('A'); + // We have to flush the OutputStreamWriter to guarantee + // that the results will appear in the underlying OutputStream + a.flush(); + assertEquals("ISO8859_1", a.getEncoding()); + assertEquals(5, aa.size()); + assertEquals("AbCdA", aa.toString()); + } finally { + a.close(); + } + } +} diff --git a/tests/CoreTests/android/core/ParseIntTest.java b/tests/CoreTests/android/core/ParseIntTest.java new file mode 100644 index 0000000000000000000000000000000000000000..0e3b0c61e1e55c8aa74d5eb2a07bca3a7e1ac517 --- /dev/null +++ b/tests/CoreTests/android/core/ParseIntTest.java @@ -0,0 +1,110 @@ +/* + * 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 android.core; + +import junit.framework.TestCase; +import android.test.suitebuilder.annotation.SmallTest; + +/** + * Tests for functionality of class Integer to parse integers. + */ +public class ParseIntTest extends TestCase { + + @SmallTest + public void testParseInt() throws Exception { + assertEquals(0, Integer.parseInt("0", 10)); + assertEquals(473, Integer.parseInt("473", 10)); + assertEquals(0, Integer.parseInt("-0", 10)); + assertEquals(-255, Integer.parseInt("-FF", 16)); + assertEquals(102, Integer.parseInt("1100110", 2)); + assertEquals(2147483647, Integer.parseInt("2147483647", 10)); + assertEquals(-2147483648, Integer.parseInt("-2147483648", 10)); + + try { + Integer.parseInt("2147483648", 10); + fail(); + } catch (NumberFormatException e) { + // ok + } + + try { + Integer.parseInt("-2147483649", 10); + fail(); + } catch (NumberFormatException e) { + // ok + } + + // One digit too many + try { + Integer.parseInt("21474836470", 10); + fail(); + } catch (NumberFormatException e) { + // ok + } + + try { + Integer.parseInt("-21474836480", 10); + fail(); + } catch (NumberFormatException e) { + // ok + } + + try { + Integer.parseInt("21474836471", 10); + fail(); + } catch (NumberFormatException e) { + // ok + } + + try { + Integer.parseInt("-21474836481", 10); + fail(); + } catch (NumberFormatException e) { + // ok + } + + try { + Integer.parseInt("214748364710", 10); + fail(); + } catch (NumberFormatException e) { + // ok + } + + try { + Integer.parseInt("-214748364811", 10); + fail(); + } catch (NumberFormatException e) { + // ok + } + + try { + Integer.parseInt("99", 8); + fail(); + } catch (NumberFormatException e) { + // ok + } + + try { + Integer.parseInt("Kona", 10); + fail(); + } catch (NumberFormatException e) { + // ok + } + + assertEquals(411787, Integer.parseInt("Kona", 27)); + } +} diff --git a/tests/CoreTests/android/core/PipedStreamTest.java b/tests/CoreTests/android/core/PipedStreamTest.java new file mode 100644 index 0000000000000000000000000000000000000000..564b337df42aa6f00f1d0dca55bba7309767e2bf --- /dev/null +++ b/tests/CoreTests/android/core/PipedStreamTest.java @@ -0,0 +1,303 @@ +/* + * Copyright (C) 2007 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 android.core; + +import junit.framework.TestCase; + +import java.io.PipedInputStream; +import java.io.PipedOutputStream; +import android.test.suitebuilder.annotation.MediumTest; +import android.test.suitebuilder.annotation.SmallTest; + +class Fibonacci { + int n1 = -1; + int n2; + + public int next() { + if (n1 < 0) { + n1 = 0; + return 0; + } else if (n1 == 0) { + n2 = 0; + n1 = 1; + return 1; + } else { + int ret = n1 + n2; + n2 = n1; + n1 = ret; + return ret; + } + } +} + + +public class PipedStreamTest extends TestCase { + + private abstract static class TestThread extends Thread { + public abstract void runTest() throws Exception; + + public final void run() { + try { + runTest(); + } catch (Throwable e) { + android.util.Log.e("PST", "Got exception " + e, e); + android.util.Log.e("PST", android.util.Log.getStackTraceString(e)); + exception = e; + } + } + + Throwable exception; + int countRead = 0; + } + + @MediumTest + public void testA() throws Exception { + + final PipedInputStream in = new PipedInputStream(); + final PipedOutputStream out = new PipedOutputStream(in); + + assertEquals(0, in.available()); + + TestThread reader, writer; + + reader = new TestThread() { + Fibonacci fib = new Fibonacci(); + + @Override + public void runTest() throws Exception { + int readInt; + byte readByte; + + for (; ;) { + readInt = in.read(); + + if (readInt == -1) { + return; + } + + readByte = (byte) readInt; + assertEquals(readByte, (byte) fib.next()); + countRead++; + } + } + }; + + reader.start(); + + writer = new TestThread() { + Fibonacci fib = new Fibonacci(); + + @Override + public void runTest() throws Exception { + for (int i = 0; i < 2000; i++) { + int toWrite = fib.next(); + out.write(toWrite); + } + out.close(); + } + }; + + writer.start(); + + + for (; ;) { + try { + reader.join(60 * 1000); + writer.join(1 * 1000); + break; + } catch (InterruptedException ex) { + } + } + + assertEquals(2000, reader.countRead); + + if (writer.exception != null) { + throw new Exception(writer.exception); + } + if (reader.exception != null) { + throw new Exception(reader.exception); + } + } + + @MediumTest + public void testB() throws Exception { + final PipedInputStream in = new PipedInputStream(); + final PipedOutputStream out = new PipedOutputStream(in); + + assertEquals(0, in.available()); + + TestThread reader, writer; + + reader = new TestThread() { + Fibonacci fib = new Fibonacci(); + + @Override + public void runTest() throws Exception { + byte readBytes[] = new byte[5]; + int ret; + + for (; ;) { + int nread = 0; + while (nread < 5) { + ret = in.read(readBytes, nread, readBytes.length - nread); + + if (ret == -1) { + return; + } + nread += ret; + } + + assertEquals(5, nread); + + int readInt = (((int) readBytes[0] & 0xff) << 24) + | (((int) readBytes[1] & 0xff) << 16) + | (((int) readBytes[2] & 0xff) << 8) + | (((int) readBytes[3] & 0xff) << 0); + + + assertEquals(readInt, fib.next()); + assertEquals(0, readBytes[4]); + countRead++; + } + } + }; + + reader.start(); + + writer = new TestThread() { + Fibonacci fib = new Fibonacci(); + + @Override + public void runTest() throws Exception { + byte writeBytes[] = new byte[5]; + for (int i = 0; i < 2000; i++) { + int toWrite = fib.next(); + writeBytes[0] = (byte) (toWrite >> 24); + writeBytes[1] = (byte) (toWrite >> 16); + writeBytes[2] = (byte) (toWrite >> 8); + writeBytes[3] = (byte) (toWrite >> 0); + writeBytes[4] = 0; + out.write(writeBytes, 0, writeBytes.length); + } + out.close(); + } + }; + + writer.start(); + + + for (; ;) { + try { + reader.join(60 * 1000); + writer.join(1 * 1000); + break; + } catch (InterruptedException ex) { + } + } + + assertEquals(2000, reader.countRead); + + if (writer.exception != null) { + throw new Exception(writer.exception); + } + if (reader.exception != null) { + throw new Exception(reader.exception); + } + } + + @SmallTest + public void testC() throws Exception { + final PipedInputStream in = new PipedInputStream(); + final PipedOutputStream out = new PipedOutputStream(in); + + assertEquals(0, in.available()); + + TestThread reader, writer; + + reader = new TestThread() { + Fibonacci fib = new Fibonacci(); + + @Override + public void runTest() throws Exception { + byte readBytes[] = new byte[1024 * 2]; + int ret; + + for (; ;) { + int nread = 0; + while (nread < readBytes.length) { + ret = in.read(readBytes, nread, readBytes.length - nread); + + if (ret == -1) { + return; + } + nread += ret; + } + + assertEquals(nread, readBytes.length); + + for (int i = 0; i < (readBytes.length - 4); i += 4) { + int readInt = (((int) readBytes[i + 0] & 0xff) << 24) + | (((int) readBytes[i + 1] & 0xff) << 16) + | (((int) readBytes[i + 2] & 0xff) << 8) + | (((int) readBytes[i + 3] & 0xff) << 0); + + assertEquals(readInt, fib.next()); + } + } + } + }; + + reader.start(); + + writer = new TestThread() { + Fibonacci fib = new Fibonacci(); + + @Override + public void runTest() throws Exception { + byte writeBytes[] = new byte[1024 * 2]; + for (int i = 0; i < (writeBytes.length - 4); i += 4) { + int toWrite = fib.next(); + writeBytes[i + 0] = (byte) (toWrite >> 24); + writeBytes[i + 1] = (byte) (toWrite >> 16); + writeBytes[i + 2] = (byte) (toWrite >> 8); + writeBytes[i + 3] = (byte) (toWrite >> 0); + } + out.write(writeBytes, 0, writeBytes.length); + out.close(); + } + }; + + writer.start(); + + + for (; ;) { + try { + reader.join(60 * 1000); + writer.join(1 * 100); + break; + } catch (InterruptedException ex) { + } + } + + if (writer.exception != null) { + throw new Exception(writer.exception); + } + if (reader.exception != null) { + throw new Exception(reader.exception); + } + } +} diff --git a/tests/CoreTests/android/core/PrintWriterTest.java b/tests/CoreTests/android/core/PrintWriterTest.java new file mode 100644 index 0000000000000000000000000000000000000000..09ee3898ff069ff5510271365a799d58553bb2c5 --- /dev/null +++ b/tests/CoreTests/android/core/PrintWriterTest.java @@ -0,0 +1,75 @@ +/* + * 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 android.core; + +import junit.framework.TestCase; + +import java.io.PrintWriter; +import java.io.StringWriter; +import android.test.suitebuilder.annotation.SmallTest; + +public class PrintWriterTest extends TestCase { + + @SmallTest + public void testPrintWriter() throws Exception { + String str = "AbCdEfGhIjKlMnOpQrStUvWxYz"; + StringWriter aa = new StringWriter(); + PrintWriter a = new PrintWriter(aa); + + try { + a.write(str, 0, 26); + a.write('X'); + + assertEquals("AbCdEfGhIjKlMnOpQrStUvWxYzX", aa.toString()); + + a.write("alphabravodelta", 5, 5); + a.append('X'); + assertEquals("AbCdEfGhIjKlMnOpQrStUvWxYzXbravoX", aa.toString()); + a.append("omega"); + assertEquals("AbCdEfGhIjKlMnOpQrStUvWxYzXbravoXomega", aa.toString()); + a.print("ZZZ"); + assertEquals("AbCdEfGhIjKlMnOpQrStUvWxYzXbravoXomegaZZZ", aa.toString()); + } finally { + a.close(); + } + + StringWriter ba = new StringWriter(); + PrintWriter b = new PrintWriter(ba); + try { + b.print(true); + b.print((char) 'A'); + b.print("BCD".toCharArray()); + b.print((double) 1.2); + b.print((float) 3); + b.print((int) 4); + b.print((long) 5); + assertEquals("trueABCD1.23.045", ba.toString()); + b.println(); + b.println(true); + b.println((char) 'A'); + b.println("BCD".toCharArray()); + b.println((double) 1.2); + b.println((float) 3); + b.println((int) 4); + b.println((long) 5); + b.print("THE END"); + assertEquals("trueABCD1.23.045\ntrue\nA\nBCD\n1.2\n3.0\n4\n5\nTHE END", ba.toString()); + } finally { + b.close(); + } + } +} diff --git a/tests/CoreTests/android/core/PushbackInputStreamTest.java b/tests/CoreTests/android/core/PushbackInputStreamTest.java new file mode 100644 index 0000000000000000000000000000000000000000..44cfd8a1805949c9298c054c0e45b749cbcd2691 --- /dev/null +++ b/tests/CoreTests/android/core/PushbackInputStreamTest.java @@ -0,0 +1,57 @@ +/* + * 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 android.core; + +import junit.framework.TestCase; + +import java.io.ByteArrayInputStream; +import java.io.PushbackInputStream; +import android.test.suitebuilder.annotation.SmallTest; + +public class PushbackInputStreamTest extends TestCase { + + @SmallTest + public void testPushbackInputStream() throws Exception { + String str = "AbCdEfGhIjKlM\nOpQrStUvWxYz"; + ByteArrayInputStream aa = new ByteArrayInputStream(str.getBytes()); + ByteArrayInputStream ba = new ByteArrayInputStream(str.getBytes()); + ByteArrayInputStream ca = new ByteArrayInputStream(str.getBytes()); + + PushbackInputStream a = new PushbackInputStream(aa, 7); + try { + a.unread("push".getBytes()); + assertEquals("pushAbCdEfGhIjKlM\nOpQrStUvWxYz", IOUtil.read(a)); + } finally { + a.close(); + } + + PushbackInputStream b = new PushbackInputStream(ba, 9); + try { + b.unread('X'); + assertEquals("XAbCdEfGhI", IOUtil.read(b, 10)); + } finally { + b.close(); + } + + PushbackInputStream c = new PushbackInputStream(ca); + try { + assertEquals("bdfhjl\nprtvxz", IOUtil.skipRead(c)); + } finally { + c.close(); + } + } +} diff --git a/tests/CoreTests/android/core/PushbackReaderTest.java b/tests/CoreTests/android/core/PushbackReaderTest.java new file mode 100644 index 0000000000000000000000000000000000000000..ef62c282265c779c83b846a6077a336c3b52b2e6 --- /dev/null +++ b/tests/CoreTests/android/core/PushbackReaderTest.java @@ -0,0 +1,57 @@ +/* + * 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 android.core; + +import junit.framework.TestCase; + +import java.io.PushbackReader; +import java.io.StringReader; +import android.test.suitebuilder.annotation.SmallTest; + +public class PushbackReaderTest extends TestCase { + + @SmallTest + public void testPushbackReader() throws Exception { + String str = "AbCdEfGhIjKlMnOpQrStUvWxYz"; + StringReader aa = new StringReader(str); + StringReader ba = new StringReader(str); + StringReader ca = new StringReader(str); + + PushbackReader a = new PushbackReader(aa, 5); + try { + a.unread("PUSH".toCharArray()); + assertEquals("PUSHAbCdEfGhIjKlMnOpQrStUvWxYz", IOUtil.read(a)); + } finally { + a.close(); + } + + PushbackReader b = new PushbackReader(ba, 15); + try { + b.unread('X'); + assertEquals("XAbCdEfGhI", IOUtil.read(b, 10)); + } finally { + b.close(); + } + + PushbackReader c = new PushbackReader(ca); + try { + assertEquals("bdfhjlnprtvxz", IOUtil.skipRead(c)); + } finally { + c.close(); + } + } +} diff --git a/tests/CoreTests/android/core/ReflectArrayTest.java b/tests/CoreTests/android/core/ReflectArrayTest.java new file mode 100644 index 0000000000000000000000000000000000000000..20ee8a45b6f202c06c0d0f50298f0184844d5481 --- /dev/null +++ b/tests/CoreTests/android/core/ReflectArrayTest.java @@ -0,0 +1,136 @@ +/* + * 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 android.core; + +import junit.framework.TestCase; + +import java.lang.reflect.Array; +import android.test.suitebuilder.annotation.SmallTest; + +/** + * Test java.lang.reflect.Array methods. + */ +public class ReflectArrayTest extends TestCase { + + @SmallTest + public void testSingleInt() throws Exception { + Object intArray = Array.newInstance(Integer.TYPE, 2); + + int[] array = (int[]) intArray; + array[0] = 5; + Array.setInt(intArray, 1, 6); + + assertEquals(5, Array.getInt(intArray, 0)); + assertEquals(6, array[1]); + + try { + array[2] = 27; + fail("store should have failed"); + } catch (ArrayIndexOutOfBoundsException abe) { + // expected + } + + assertEquals(2, array.length); + assertEquals(Array.getLength(intArray), array.length); + + try { + int[][] wrongArray = (int[][]) intArray; + fail("cast should have failed"); + } catch (ClassCastException cce) { + // expected + } + + intArray = Array.newInstance(Integer.TYPE, 0); + assertEquals(0, Array.getLength(intArray)); + } + + @SmallTest + public void testSingle() throws Exception { + Object strArray = Array.newInstance(String.class, 2); + + String[] array = (String[]) strArray; + array[0] = "entry zero"; + Array.set(strArray, 1, "entry one"); + + //System.out.println("array: " + array); + + assertEquals("entry zero", Array.get(strArray, 0)); + assertEquals("entry one", array[1]); + + assertEquals(2, array.length); + assertEquals(Array.getLength(strArray), array.length); + } + + @SmallTest + public void testMultiInt() throws Exception { + int[] dimensions = {3, 2, 1}; + Object intIntIntArray = Array.newInstance(Integer.TYPE, dimensions); + int[][][] array3 = (int[][][]) intIntIntArray; + + array3[0][0][0] = 123; + array3[2][1][0] = 456; + + try { + array3[2][1][1] = 768; + fail("store should have failed"); + } catch (ArrayIndexOutOfBoundsException abe) { + // expected + } + + //System.out.println("array3: " + array3); + } + + @SmallTest + public void testMulti() throws Exception { + int[] dimensions = {1, 2, 3}; + Object strStrStrArray = Array.newInstance(String.class, dimensions); + String[][][] array3 = (String[][][]) strStrStrArray; + + array3[0][0][0] = "zero zero zero"; + array3[0][1][2] = "zero one two"; + + try { + array3[1][0][0] = "bad store"; + fail("store should have failed"); + } catch (ArrayIndexOutOfBoundsException abe) { + // expected + } + + try { + String[][] array2 = (String[][]) strStrStrArray; + fail("expecting bad cast"); + } catch (ClassCastException cce) { + // expected + } + //System.out.println("array3: " + array3); + + + int[] dimensions2 = {1, 2}; + strStrStrArray = Array.newInstance(String[].class, dimensions2); + array3 = (String[][][]) strStrStrArray; + array3[0][1] = new String[3]; + array3[0][1][2] = "zero one two"; + try { + array3[1][0][0] = "bad store"; + fail("store should have failed"); + } catch (ArrayIndexOutOfBoundsException abe) { + // expected + } + //System.out.println("array3: " + array3); + } +} + diff --git a/tests/CoreTests/android/core/RegexTest.java b/tests/CoreTests/android/core/RegexTest.java new file mode 100644 index 0000000000000000000000000000000000000000..a7f79e80334d573ddd38947b9f42f6c1222be732 --- /dev/null +++ b/tests/CoreTests/android/core/RegexTest.java @@ -0,0 +1,288 @@ +/* + * 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 android.core; + +import android.test.suitebuilder.annotation.SmallTest; +import android.text.util.Regex; + +import junit.framework.TestCase; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * Tests basic functionality of Pattern and Matcher classes. + */ +public class RegexTest extends TestCase { + + @SmallTest + public void testMatches() throws Exception { + /* Tests class Matcher */ + + Pattern p = Pattern.compile("bcd"); + Matcher m = p.matcher("bcd"); + assertTrue("Should match.", m.matches()); + + /* Pattern in the middle */ + p = Pattern.compile("bcd"); + m = p.matcher("abcdefg"); + assertFalse("Should not match.", m.matches()); + + /* Pattern at the head */ + m = p.matcher("bcdefg"); + assertFalse("Should not match.", m.matches()); + + /* Pattern at the tail */ + m = p.matcher("abcd"); + assertFalse("Should not match.", m.matches()); + + /* Make sure matches() doesn't change after calls to find() */ + p = Pattern.compile(".*"); + m = p.matcher("abc"); + assertTrue(m.matches()); + assertTrue(m.find()); + assertTrue(m.matches()); + + p = Pattern.compile("."); + m = p.matcher("abc"); + assertFalse(m.matches()); + assertTrue(m.find()); + assertFalse(m.matches()); + + /* Make sure matches() agrees after a reset() */ + m.reset("z"); + assertTrue(m.matches()); + + m.reset("xyz"); + assertFalse(m.matches()); + + /* Tests class Pattern */ + + assertFalse("Erroneously matched partial string. " + + "See http://b/issue?id=754601", Pattern.matches("er", "xer")); + assertFalse("Erroneously matched partial string. " + + "See http://b/issue?id=754601", Pattern.matches("xe", "xer")); + assertTrue("Generic regex should match.", + Pattern.matches(".*", "bcd")); + assertTrue("Grouped regex should match.", + Pattern.matches("(b(c(d)))", "bcd")); + assertTrue("Grouped regex should match.", + Pattern.matches("(b)(c)(d)", "bcd")); + } + + @SmallTest + public void testGroupCount() throws Exception { + Pattern p = Pattern.compile( + "\\b(?:\\+?1)?" + + "(?:[ -\\.])?" + + "\\(?(\\d{3})?\\)?" + + "(?:[ -\\.\\/])?" + + "(\\d{3})" + + "(?:[ -\\.])?" + + "(\\d{4})\\b" + ); + + Matcher m = p.matcher("1 (919) 555-1212"); + + assertEquals("groupCount is incorrect, see http://b/issue?id=759412", + 3, m.groupCount()); + } + + @SmallTest + public void testGroups() throws Exception { + Pattern p = Pattern.compile("(b)([c|d])(z*)"); + Matcher m = p.matcher("abcdefg"); + + /* Must call find() first, otherwise group*() are undefined. */ + assertTrue(m.find()); + + assertEquals(3, m.groupCount()); + + assertEquals("bc", m.group(0)); + assertEquals("b", m.group(1)); + assertEquals("c", m.group(2)); + assertEquals("", m.group(3)); + } + + @SmallTest + public void testFind() throws Exception { + Pattern p = Pattern.compile("."); + Matcher m = p.matcher("abc"); + + assertTrue(m.find()); + assertEquals("a", m.group(0)); + + assertTrue(m.find()); + assertEquals("b", m.group(0)); + + assertTrue(m.find()); + assertEquals("c", m.group(0)); + + assertFalse(m.find()); + } + + @SmallTest + public void testReplaceAll() throws Exception { + // Begins with non-matching text, ends with matching text + Pattern p = Pattern.compile("a*b"); + Matcher m = p.matcher("fooaabfooaabfooabfoob"); + + String r = m.replaceAll("-"); + assertEquals("foo-foo-foo-foo-", r); + + // Begins with matching text, ends with non-matching text + p = Pattern.compile("a*b"); + m = p.matcher("aabfooaabfooabfoobfoo"); + + r = m.replaceAll("-"); + assertEquals("-foo-foo-foo-foo", r); + } + + @SmallTest + public void testReplaceFirst() throws Exception { + // Begins with non-matching text, ends with matching text + Pattern p = Pattern.compile("a*b"); + Matcher m = p.matcher("fooaabfooaabfooabfoob"); + + String r = m.replaceFirst("-"); + assertEquals("foo-fooaabfooabfoob", r); + + // Begins with matching text, ends with non-matching text + p = Pattern.compile("a*b"); + m = p.matcher("aabfooaabfooabfoobfoo"); + + r = m.replaceFirst("-"); + assertEquals("-fooaabfooabfoobfoo", r); + } + + @SmallTest + public void testSplit() throws Exception { + Pattern p = Pattern.compile(":"); + String[] strings; + + strings = p.split("boo:and:foo"); + assertEquals(3, strings.length); + assertEquals("boo", strings[0]); + assertEquals("and", strings[1]); + assertEquals("foo", strings[2]); + + strings = p.split("boo:and:foo", 2); + assertEquals(2, strings.length); + assertEquals("boo", strings[0]); + assertEquals("and:foo", strings[1]); + + strings = p.split("boo:and:foo", 5); + assertEquals(3, strings.length); + assertEquals("boo", strings[0]); + assertEquals("and", strings[1]); + assertEquals("foo", strings[2]); + + strings = p.split("boo:and:foo", -2); + assertEquals(3, strings.length); + assertEquals("boo", strings[0]); + assertEquals("and", strings[1]); + assertEquals("foo", strings[2]); + + p = Pattern.compile("o"); + + strings = p.split("boo:and:foo"); + assertEquals(3, strings.length); + assertEquals("b", strings[0]); + assertEquals("", strings[1]); + assertEquals(":and:f", strings[2]); + + strings = p.split("boo:and:foo", 5); + assertEquals(5, strings.length); + assertEquals("b", strings[0]); + assertEquals("", strings[1]); + assertEquals(":and:f", strings[2]); + assertEquals("", strings[3]); + assertEquals("", strings[4]); + + strings = p.split("boo:and:foo", -2); + assertEquals(5, strings.length); + assertEquals("b", strings[0]); + assertEquals("", strings[1]); + assertEquals(":and:f", strings[2]); + assertEquals("", strings[3]); + assertEquals("", strings[4]); + + strings = p.split("boo:and:foo", 0); + assertEquals(3, strings.length); + assertEquals("b", strings[0]); + assertEquals("", strings[1]); + assertEquals(":and:f", strings[2]); + } + + // ------------------------------------------------------------------- + // Regression test for #1172774: Bug in Regex.java + // Regression test for #1216887: Regular expression match is very slow + public static final Pattern TOP_LEVEL_DOMAIN_PATTERN = Pattern.compile( + "((aero|arpa|asia|a[cdefgilmnoqrstuwxz])" + + "|(biz|b[abdefghijmnorstvwyz])" + + "|(cat|com|coop|c[acdfghiklmnoruvxyz])" + + "|d[ejkmoz]" + + "|(edu|e[cegrstu])" + + "|f[ijkmor]" + + "|(gov|g[abdefghilmnpqrstuwy])" + + "|h[kmnrtu]" + + "|(info|int|i[delmnoqrst])" + + "|(jobs|j[emop])" + + "|k[eghimnrwyz]" + + "|l[abcikrstuvy]" + + "|(mil|mobi|museum|m[acdghklmnopqrstuvwxyz])" + + "|(name|net|n[acefgilopruz])" + + "|(org|om)" + + "|(pro|p[aefghklmnrstwy])" + + "|qa" + + "|r[eouw]" + + "|s[abcdeghijklmnortuvyz]" + + "|(tel|travel|t[cdfghjklmnoprtvwz])" + + "|u[agkmsyz]" + + "|v[aceginu]" + + "|w[fs]" + + "|y[etu]" + + "|z[amw])"); + + public static final Pattern EMAIL_ADDRESS_PATTERN = Pattern.compile( + "[\\+a-zA-Z0-9\\.\\_\\%\\-]+\\@" + + "((" + + "[a-zA-Z0-9]\\.|" + + "([a-zA-Z0-9][a-zA-Z0-9\\-]*[a-zA-Z0-9]\\.)+)" + + TOP_LEVEL_DOMAIN_PATTERN + + ")"); + + @SmallTest + public void testMonsterRegexCorrectness() { + assertTrue(EMAIL_ADDRESS_PATTERN.matcher("a+b@gmail.com").matches()); + } + + @SmallTest + public void testMonsterRegexPerformance() { + android.util.Log.e("RegexTest", "RegEx performance test started."); + long t0 = System.currentTimeMillis(); + Matcher m = EMAIL_ADDRESS_PATTERN.matcher("donot repeate@RC8jjjjjjjjjjjjjjj"); + assertFalse(m.find()); + long t1 = System.currentTimeMillis(); + android.util.Log.e("RegexTest", "RegEx performance test finished, " + + "took " + (t1 - t0) + " ms."); + } + + // + // ------------------------------------------------------------------- + +} diff --git a/tests/CoreTests/android/core/RequestAPITest.java b/tests/CoreTests/android/core/RequestAPITest.java new file mode 100644 index 0000000000000000000000000000000000000000..d89f5ae9825566e2e11afcb4437eb6c3e9bcb1c8 --- /dev/null +++ b/tests/CoreTests/android/core/RequestAPITest.java @@ -0,0 +1,483 @@ +/* + * Copyright (C) 2007 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 android.core; + +import android.net.http.RequestHandle; +import android.net.http.RequestQueue; +import android.test.AndroidTestCase; +import android.test.suitebuilder.annotation.Suppress; +import android.util.Log; +import android.webkit.CookieSyncManager; +import com.google.android.collect.Maps; + +import java.io.ByteArrayInputStream; +import java.io.InputStream; +import java.util.HashMap; +import java.util.Map; + +/** + * Container class for all RequestAPI tests + */ +//http://b/issue?id=1200337 +@Suppress +public class RequestAPITest extends AndroidTestCase implements HttpConstants { + private static final String LOGTAG = "http"; + + /* + Other tests to write + GET, HEAD, POST with differing parameters to RequestQueue + More reuse and pipelining tests - testing for server closing unexpectedly + */ + + // Sync object for synchronizing end of each test that does communications + public static Object syncObj = new Object(); + + private RequestQueue mRequestQueue; + private TestWebServer mTestWebServer; + + protected void setUp() throws Exception { + super.setUp(); + Log.d(LOGTAG, "Base setup context = " + mContext); + mRequestQueue = new RequestQueue(mContext); + CookieSyncManager.createInstance(mContext); + + mTestWebServer = new TestWebServer(); + mTestWebServer.initServer(8080, true); + } + + protected void tearDown() throws Exception { + Log.d(LOGTAG, "Base tearDown"); + mTestWebServer.close(); + Log.d(LOGTAG, "Base teardown done"); + + super.tearDown(); + } + + public void verifyFailure(Map headers) { + try { + RequestHandle handle = + mRequestQueue.queueRequest( + "http://localhost:8080/test1", "GET", headers, null, + null, 0, false); + + handle.waitUntilComplete(); + fail("expected exception not thrown"); + } catch (RuntimeException e) { + // expected + } + } + + public void testRequestAddNullHeader() throws Exception { + /** + * Test Request.addHeader throws a NullPointerException if a null + * header is attempted to be set + */ + Log.d(LOGTAG, "testRequestAddNullHeader start "); + Map headers = Maps.newHashMap(); + headers.put(null, null); + verifyFailure(headers); + Log.d(LOGTAG, "testRequestAddNullHeader - returning"); + } + + public void testRequestAddNullValue() throws Exception { + /** + * Test Request.addHeader throws a RuntimeException if a null + * value is attempted to be set + */ + Log.d(LOGTAG, "testRequestAddNullValue start "); + Map headers = Maps.newHashMap(); + headers.put("TestHeader", null); + verifyFailure(headers); + Log.d(LOGTAG, "testRequestAddNullValue - returning"); + } + + public void testRequestAddEmptyValue() throws Exception { + /** + * Test Request.addEmptyValue throws a RuntimeException if an empty + * header is attempted to be set + */ + Log.d(LOGTAG, "testRequestAddEmptyValue start "); + Map headers = Maps.newHashMap(); + headers.put("TestHeader", ""); + verifyFailure(headers); + Log.d(LOGTAG, "testRequestAddEmptyValue - returning"); + } + + public void verifySuccess(Map headers) { + mTestWebServer.setKeepAlive(false); + RequestHandle handle = mRequestQueue.queueRequest( + "http://localhost:8080/test1", "GET", headers, null, + null, 0, false); + handle.waitUntilComplete(); + } + + public void testRequestAddHeader() throws Exception { + /** + * Test Request.addHeader with a valid header and value can be set without + * generating and exception + */ + Log.d(LOGTAG, "testRequestAddHeader start "); + Map headers = Maps.newHashMap(); + headers.put("TestHeader", "RequestAddHeader"); + verifySuccess(headers); + Log.d(LOGTAG, "testRequestAddHeader - returning"); + } + + public void testRequestAddMultiHeader() throws Exception { + /** + * Test multiple calls to Request.addHeader with valid headers and values + * can be set without generating and exception + */ + Log.d(LOGTAG, "testRequestAddMultiHeader start "); + Map headers = Maps.newHashMap(); + headers.put("TestHeader", "RequestAddMultiHeader"); + headers.put("TestHeader2", "RequestAddMultiHeader"); + headers.put("TestHeader3", "RequestAddMultiHeader"); + verifySuccess(headers); + Log.d(LOGTAG, "testRequestAddMultiHeader - returning"); + } + + public void testRequestAddSameHeader() throws Exception { + /** + * Test multiple calls to Request.addHeader with valid identical headers + * and values can be set without generating and exception + */ + Log.d(LOGTAG, "testRequestAddSameHeader start "); + Map headers = Maps.newHashMap(); + headers.put("TestHeader", "RequestAddSameHeader"); + headers.put("TestHeader", "RequestAddSameHeader"); + headers.put("TestHeader", "RequestAddSameHeader"); + verifySuccess(headers); + Log.d(LOGTAG, "testRequestAddSameHeader - returning"); + } + + public void testRequestAddNullHeaders() throws Exception { + /** + * Test Request.addHeaders with a null header map. This should not generate + * any exceptions but accept that there are no headers to add. + */ + Log.d(LOGTAG, "testRequestAddNullHeaders start "); + verifySuccess(null); + Log.d(LOGTAG, "testRequestAddNullHeaders - returning"); + } + + public void testGet() throws Exception { + /** + * Test sending a GET request. Test will pass if the events received + * correspond with the expected response. This should respond with the + * test data requested. + */ + TestEventHandler testEventHandler = new TestEventHandler(); + + mTestWebServer.setKeepAlive(false); + + Log.d(LOGTAG, "testGet start "); + + // Load up expected response + testEventHandler.expectStatus(200); + testEventHandler.expectHeaders(); + testEventHandler.expectHeaderAdd(requestHeaders[REQ_CONNECTION], "Close"); + testEventHandler.expectHeaderAdd(requestHeaders[REQ_CONTENT_LENGTH], "52"); + testEventHandler.expectHeaderAdd(requestHeaders[REQ_CONTENT_TYPE], "text/html"); + testEventHandler.expectData(52); + + RequestHandle handle = mRequestQueue.queueRequest( + "http://localhost:8080/test1", "GET", null, testEventHandler, + null, 0, false); + + Log.d(LOGTAG, "testGet - sent request. Waiting"); + handle.waitUntilComplete(); + Log.d(LOGTAG, "testGet - sent request. Notified"); + + if (!testEventHandler.expectPassed()) { + Log.d(LOGTAG, testEventHandler.getFailureMessage()); + fail("expectPassed was false " + testEventHandler.getFailureMessage()); + } + } + + public void testReuse() throws Exception { + /** + * Test sending two GET requests. Test will pass if the events + * received correspond with the expected response. + */ + final String TEST_NAME = "testReuse"; + Log.d(LOGTAG, TEST_NAME + " start "); + + TestEventHandler testEventHandler = new TestEventHandler(); + + // Load up expected response + testEventHandler.expectStatus(200); + testEventHandler.expectHeaders(); + + TestEventHandler testEventHandler2 = new TestEventHandler(); + testEventHandler2.expectStatus(200); + testEventHandler2.expectHeaders(); + + mTestWebServer.setAcceptLimit(2); + + RequestHandle handle0 = mRequestQueue.queueRequest( + "http://localhost:8080/test1", "GET", null, testEventHandler, + null, 0, false); + handle0.waitUntilComplete(); + RequestHandle handle1 = mRequestQueue.queueRequest( + "http://localhost:8080/test1", "GET", null, testEventHandler2, + null, 0, false); + handle1.waitUntilComplete(); + + /* It's not correct to use same listener for multiple + requests. Otherwise there would be no distiction between + events delivered for either request. */ + + if (!testEventHandler.expectPassed() && !testEventHandler2.expectPassed()) { + Log.d(LOGTAG, testEventHandler.getFailureMessage()); + Log.d(LOGTAG, testEventHandler2.getFailureMessage()); + fail(); + } + Log.d(LOGTAG, TEST_NAME + " - sent request. Notified"); + } + + public void testHead() throws Exception { + /** + * Test sending a HEAD request. Test will pass if the events + * delivered match the expected response. + */ + TestEventHandler testEventHandler = new TestEventHandler(); + + // Load up expected response + testEventHandler.expectStatus(200); + testEventHandler.expectHeaders(); + testEventHandler.expectNoData(); + + mTestWebServer.setKeepAlive(false); + mTestWebServer.setAcceptLimit(1); + + + Log.d(LOGTAG, "testHead start - rq = " + mRequestQueue); + + RequestHandle handle = mRequestQueue.queueRequest( + "http://localhost:8080/test1", "HEAD", null, testEventHandler, + null, 0, false); + + Log.d(LOGTAG, "testHead - sent request waiting"); + handle.waitUntilComplete(); + + if (!testEventHandler.expectPassed()) { + Log.d(LOGTAG, testEventHandler.getFailureMessage()); + fail("expectPassed was false " + testEventHandler.getFailureMessage()); + } + } + + public void testChunked() throws Exception { + TestEventHandler testEventHandler = new TestEventHandler(); + + // Load up expected response + testEventHandler.expectStatus(200); + testEventHandler.expectHeaders(); + + mTestWebServer.setKeepAlive(false); + mTestWebServer.setChunked(true); + mTestWebServer.setAcceptLimit(1); + + + Log.d(LOGTAG, "testChunked start - rq = " + mRequestQueue); + + RequestHandle handle = mRequestQueue.queueRequest( + "http://localhost:8080/test1", "GET", null, testEventHandler, + null, 0, false); + + Log.d(LOGTAG, "testChunked - sent request waiting"); + handle.waitUntilComplete(); + + if (!testEventHandler.expectPassed()) { + Log.d(LOGTAG, testEventHandler.getFailureMessage()); + fail("expectPassed was false " + testEventHandler.getFailureMessage()); + } + } + + public void verifyRedirect(int statusCode, String testName) throws Exception { + final String REDIRECT_TO = "http://localhost:8081/test1"; + + mTestWebServer.setKeepAlive(false); + TestWebServer redirectWebServer = new TestWebServer(); + redirectWebServer.initServer(8081, true); + redirectWebServer.setKeepAlive(false); + + try { + TestEventHandler testEventHandler = new TestEventHandler(); + // Load up expected response + testEventHandler.expectStatus(statusCode); + testEventHandler.expectHeaders(); + testEventHandler.expectHeaderAdd(requestHeaders[REQ_LOCATION], REDIRECT_TO); + + mTestWebServer.setAcceptLimit(1); + mTestWebServer.setRedirect(REDIRECT_TO, statusCode); + redirectWebServer.setAcceptLimit(1); + + Log.d(LOGTAG, testName + " start - rq = " + mRequestQueue); + + RequestHandle requestHandle = mRequestQueue.queueRequest( + "http://localhost:8080/test1", "GET", null, testEventHandler, null, 0, false); + Log.d(LOGTAG, testName + " - sent request waiting"); + + requestHandle.waitUntilComplete(); + + if (!testEventHandler.expectPassed()) { + Log.d(LOGTAG, testEventHandler.getFailureMessage()); + fail("expectPassed was false " + testEventHandler.getFailureMessage()); + } + + requestHandle.setupRedirect(REDIRECT_TO, statusCode, new HashMap()); + + testEventHandler.expectStatus(HttpConstants.HTTP_OK); + testEventHandler.expectHeaders(); + testEventHandler.expectHeaderAdd(requestHeaders[REQ_CONTENT_LENGTH], "52"); + testEventHandler.expectHeaderAdd(requestHeaders[REQ_CONTENT_TYPE], "text/html"); + // Server name should be TestWebServer+port + // we ignore the server tag, so don't test it + // testEventHandler.expectHeaderAdd(requestHeaders[REQ_SERVER], "TestWebServer8081"); + testEventHandler.expectData(52); + testEventHandler.expectEndData(); + + requestHandle.waitUntilComplete(); + + if (!testEventHandler.expectPassed()) { + Log.d(LOGTAG, testEventHandler.getFailureMessage()); + fail("expectPassed was false " + testEventHandler.getFailureMessage()); + } + } finally { + Log.d(LOGTAG, testName + " - returning"); + redirectWebServer.close(); + } + } + + public void testRedirect301() throws Exception { + verifyRedirect(HttpConstants.HTTP_MOVED_PERM, "testRedirect301"); + } + + public void testRedirect302() throws Exception { + verifyRedirect(HttpConstants.HTTP_MOVED_TEMP, "testRedirect302"); + } + + public void testRedirect303() throws Exception { + verifyRedirect(HttpConstants.HTTP_SEE_OTHER, "testRedirect303"); + } + + public void testRedirect307() throws Exception { + verifyRedirect(307, "testRedirect307"); + } + + public void testGetAndHead() throws Exception { + /** + * Test sending a GET and a HEAD request. Test will pass if the + * event received correspond with the expected response. The two + * requests should respond the same test data. + */ + mTestWebServer.setKeepAlive(true); + mTestWebServer.setAcceptLimit(2); + + TestEventHandler testEventHandler = new TestEventHandler(); + testEventHandler.expectStatus(200); + testEventHandler.expectHeaders(); + + TestEventHandler leh2 = new TestEventHandler(); + leh2.expectStatus(200); + leh2.expectHeaders(); + + RequestHandle handle0 = mRequestQueue.queueRequest( + "http://localhost:8080/test1", "GET", null, testEventHandler, null, 0, false); + handle0.waitUntilComplete(); + RequestHandle handle1 = mRequestQueue.queueRequest( + "http://localhost:8080/test1", "HEAD", null, testEventHandler, null, 0, false); + + Log.d(LOGTAG, "testGetAndHead - sent request. Waiting"); + handle1.waitUntilComplete(); + + if (!testEventHandler.expectPassed() && !leh2.expectPassed()) { + Log.d(LOGTAG, testEventHandler.getFailureMessage()); + Log.d(LOGTAG, leh2.getFailureMessage()); + fail(); + } + } + + public void testPost() throws Exception { + /** + * Test sending a POST request with no body data. Test will pass if the event + * received correspond with the expected response. This should respond with + * the test data requested. + */ + TestEventHandler testEventHandler = new TestEventHandler(); + + // Load up expected response + testEventHandler.expectStatus(200); + testEventHandler.expectHeaders(); + testEventHandler.expectData(52); + + mTestWebServer.setKeepAlive(false); + mTestWebServer.setAcceptLimit(1); + + Log.d(LOGTAG, "testPost start - rq = " + mRequestQueue); + + RequestHandle handle = mRequestQueue.queueRequest( + "http://localhost:8080/test1", "POST", null, testEventHandler, null, 0, false); + + Log.d(LOGTAG, "testPost - sent request waiting"); + handle.waitUntilComplete(); + + if (!testEventHandler.expectPassed()) { + Log.d(LOGTAG, testEventHandler.getFailureMessage()); + fail("expectPassed was false " + testEventHandler.getFailureMessage()); + } + } + + + public void testPostWithData() throws Exception { + /** + * Test sending a POST request with body data. Test will pass if the event + * received correspond with the expected response. This should respond with + * the test data requested. + */ + + TestEventHandler testEventHandler = new TestEventHandler(); + // Load up expected response + testEventHandler.expectStatus(200); + testEventHandler.expectHeaders(); + testEventHandler.expectData(52); + + mTestWebServer.setKeepAlive(false); + mTestWebServer.setAcceptLimit(1); + + Log.d(LOGTAG, "testPostWithData start - rq = " + mRequestQueue); + + String mBody = TestWebData.postContent; + int bodyLength = mBody.length(); + if (bodyLength > 0) { + Log.v(LOGTAG, "testPostWithData: body " + mBody); + } + InputStream bodyProvider = new ByteArrayInputStream(mBody.getBytes()); + + RequestHandle handle = mRequestQueue.queueRequest( + "http://localhost:8080/test1", "POST", null, testEventHandler, bodyProvider, bodyLength, false); + + Log.d(LOGTAG, "testPostWithData - sent request waiting"); + handle.waitUntilComplete(); + + if (!testEventHandler.expectPassed()) { + Log.d(LOGTAG, testEventHandler.getFailureMessage()); + fail("expectPassed was false " + testEventHandler.getFailureMessage()); + } + } +} diff --git a/tests/CoreTests/android/core/SQLiteJDBCDriverTest.java b/tests/CoreTests/android/core/SQLiteJDBCDriverTest.java new file mode 100644 index 0000000000000000000000000000000000000000..eec82aa7e37142d7450a6102c8efa8c32279d288 --- /dev/null +++ b/tests/CoreTests/android/core/SQLiteJDBCDriverTest.java @@ -0,0 +1,137 @@ +/* + * 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 android.core; + +import java.io.File; +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.PreparedStatement; +import java.sql.SQLException; +import java.sql.Statement; +import android.test.suitebuilder.annotation.MediumTest; + +/** + * Minimal test for JDBC driver + */ +public class SQLiteJDBCDriverTest extends AbstractJDBCDriverTest { + + private File dbFile; + + @Override + protected void setUp() throws Exception { + super.setUp(); + dbFile = File.createTempFile("sqliteTestDB", null); + } + + @Override + protected void tearDown() throws Exception { + if(dbFile != null) { + dbFile.delete(); + } + super.tearDown(); + } + + @Override + protected String getConnectionURL() { + return "jdbc:sqlite:/" + dbFile; + } + + @Override + protected File getDbFile() { + return dbFile; + } + + @Override + protected String getJDBCDriverClassName() { + return "SQLite.JDBCDriver"; + } + + // Regression test for (Noser) #255: PreparedStatement.executeUpdate results + // in VM crashing with SIGABRT. + @MediumTest + public void test_connection3() throws Exception { + PreparedStatement prst = null; + Statement st = null; + Connection conn = null; + try { + Class.forName("SQLite.JDBCDriver").newInstance(); + if (dbFile.exists()) { + dbFile.delete(); + } + conn = DriverManager.getConnection("jdbc:sqlite:/" + + dbFile.getPath()); + assertNotNull(conn); + + // create table + st = conn.createStatement(); + String sql = "CREATE TABLE zoo (ZID INTEGER NOT NULL, family VARCHAR (20) NOT NULL, name VARCHAR (20) NOT NULL, PRIMARY KEY(ZID) )"; + st.executeUpdate(sql); + + String update = "update zoo set family = ? where name = ?;"; + prst = conn.prepareStatement(update); + prst.setString(1, "cat"); + prst.setString(2, "Yasha"); + // st = conn.createStatement(); + // st.execute("select * from zoo where family = 'cat'"); + // ResultSet rs = st.getResultSet(); + // assertEquals(0, getCount(rs)); + prst.executeUpdate(); + // st.execute("select * from zoo where family = 'cat'"); + // ResultSet rs1 = st.getResultSet(); + // assertEquals(1, getCount(rs1)); + try { + prst = conn.prepareStatement(""); + prst.execute(); + fail("SQLException is not thrown"); + } catch (SQLException e) { + // expected + } + + try { + conn.prepareStatement(null); + fail("NPE is not thrown"); + } catch (Exception e) { + // expected + } + try { + st = conn.createStatement(); + st.execute("drop table if exists zoo"); + + } catch (SQLException e) { + fail("Couldn't drop table: " + e.getMessage()); + } finally { + try { + st.close(); + conn.close(); + } catch (SQLException ee) { + } + } + } finally { + try { + if (prst != null) { + prst.close(); + } + if (st != null) { + st.close(); + } + } catch (SQLException ee) { + } + } + + } + +} diff --git a/tests/CoreTests/android/core/SSLSocketTest.java b/tests/CoreTests/android/core/SSLSocketTest.java new file mode 100644 index 0000000000000000000000000000000000000000..922090af19a791409462b701c99322ad311c4b93 --- /dev/null +++ b/tests/CoreTests/android/core/SSLSocketTest.java @@ -0,0 +1,872 @@ +/* + * 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 android.core; + +import junit.framework.TestCase; + +import org.apache.commons.codec.binary.Base64; + +import java.io.ByteArrayInputStream; +import java.io.DataInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.PrintWriter; +import java.net.InetSocketAddress; +import java.net.Socket; +import java.security.KeyStore; +import java.security.cert.X509Certificate; +import java.util.Random; + +import javax.net.ssl.KeyManager; +import javax.net.ssl.KeyManagerFactory; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLServerSocket; +import javax.net.ssl.SSLSocket; +import javax.net.ssl.SSLSocketFactory; +import javax.net.ssl.TrustManager; +import javax.net.ssl.X509TrustManager; + +public class SSLSocketTest extends TestCase { + + private static SSLSocketFactory clientFactory = + (SSLSocketFactory) SSLSocketFactory.getDefault(); + + /** + * Does a number of HTTPS requests on some host and consumes the response. + * We don't use the HttpsUrlConnection class, but do this on our own + * with the SSLSocket class. This gives us a chance to test the basic + * behavior of SSL. + * + * @param host The host name the request is being sent to. + * @param port The port the request is being sent to. + * @param path The path being requested (e.g. "/index.html"). + * @param outerLoop The number of times we reconnect and do the request. + * @param innerLoop The number of times we do the request for each + * connection (using HTTP keep-alive). + * @param delay The delay after each request (in seconds). + * @throws IOException When a problem occurs. + */ + private void fetch(String host, int port, boolean secure, String path, + int outerLoop, int innerLoop, int delay, int timeout) throws IOException { + InetSocketAddress address = new InetSocketAddress(host, port); + + for (int i = 0; i < outerLoop; i++) { + // Connect to the remote host + Socket socket = secure ? clientFactory.createSocket() : new Socket(); + if (timeout >= 0) { + socket.setKeepAlive(true); + socket.setSoTimeout(timeout * 1000); + } + socket.connect(address); + + // Get the streams + OutputStream output = socket.getOutputStream(); + PrintWriter writer = new PrintWriter(output); + + try { + DataInputStream input = new DataInputStream(socket.getInputStream()); + try { + for (int j = 0; j < innerLoop; j++) { + android.util.Log.d("SSLSocketTest", + "GET https://" + host + path + " HTTP/1.1"); + + // Send a request + writer.println("GET https://" + host + path + " HTTP/1.1\r"); + writer.println("Host: " + host + "\r"); + writer.println("Connection: " + + (j == innerLoop - 1 ? "Close" : "Keep-Alive") + + "\r"); + writer.println("\r"); + writer.flush(); + + int length = -1; + boolean chunked = false; + + String line = input.readLine(); + + if (line == null) { + throw new IOException("No response from server"); + // android.util.Log.d("SSLSocketTest", "No response from server"); + } + + // Consume the headers, check content length and encoding type + while (line != null && line.length() != 0) { +// System.out.println(line); + int dot = line.indexOf(':'); + if (dot != -1) { + String key = line.substring(0, dot).trim(); + String value = line.substring(dot + 1).trim(); + + if ("Content-Length".equalsIgnoreCase(key)) { + length = Integer.valueOf(value); + } else if ("Transfer-Encoding".equalsIgnoreCase(key)) { + chunked = "Chunked".equalsIgnoreCase(value); + } + + } + line = input.readLine(); + } + + assertTrue("Need either content length or chunked encoding", length != -1 + || chunked); + + // Consume the content itself + if (chunked) { + length = Integer.parseInt(input.readLine(), 16); + while (length != 0) { + byte[] buffer = new byte[length]; + input.readFully(buffer); + input.readLine(); + length = Integer.parseInt(input.readLine(), 16); + } + input.readLine(); + } else { + byte[] buffer = new byte[length]; + input.readFully(buffer); + } + + // Sleep for the given number of seconds + try { + Thread.sleep(delay * 1000); + } catch (InterruptedException ex) { + // Shut up! + } + } + } finally { + input.close(); + } + } finally { + writer.close(); + } + // Close the connection + socket.close(); + } + } + + /** + * Does a single request for each of the hosts. Consumes the response. + * + * @throws IOException If a problem occurs. + */ + public void testSimple() throws IOException { + fetch("www.fortify.net", 443, true, "/sslcheck.html", 1, 1, 0, 60); + fetch("mail.google.com", 443, true, "/mail/", 1, 1, 0, 60); + fetch("www.paypal.com", 443, true, "/", 1, 1, 0, 60); + fetch("www.yellownet.ch", 443, true, "/", 1, 1, 0, 60); + } + + /** + * Does repeated requests for each of the hosts, with the connection being + * closed in between. + * + * @throws IOException If a problem occurs. + */ + public void testRepeatedClose() throws IOException { + fetch("www.fortify.net", 443, true, "/sslcheck.html", 10, 1, 0, 60); + fetch("mail.google.com", 443, true, "/mail/", 10, 1, 0, 60); + fetch("www.paypal.com", 443, true, "/", 10, 1, 0, 60); + fetch("www.yellownet.ch", 443, true, "/", 10, 1, 0, 60); + } + + /** + * Does repeated requests for each of the hosts, with the connection being + * kept alive in between. + * + * @throws IOException If a problem occurs. + */ + public void testRepeatedKeepAlive() throws IOException { + fetch("www.fortify.net", 443, true, "/sslcheck.html", 1, 10, 0, 60); + fetch("mail.google.com", 443, true, "/mail/", 1, 10, 0, 60); + + // These two don't accept keep-alive + // fetch("www.paypal.com", 443, "/", 1, 10); + // fetch("www.yellownet.ch", 443, "/", 1, 10); + } + + /** + * Does repeated requests for each of the hosts, with the connection being + * closed in between. Waits a couple of seconds after each request, but + * stays within a reasonable timeout. Expectation is that the connection + * stays open. + * + * @throws IOException If a problem occurs. + */ + public void testShortTimeout() throws IOException { + fetch("www.fortify.net", 443, true, "/sslcheck.html", 1, 10, 5, 60); + fetch("mail.google.com", 443, true, "/mail/", 1, 10, 5, 60); + + // These two don't accept keep-alive + // fetch("www.paypal.com", 443, "/", 1, 10); + // fetch("www.yellownet.ch", 443, "/", 1, 10); + } + + /** + * Does repeated requests for each of the hosts, with the connection being + * kept alive in between. Waits a longer time after each request. + * Expectation is that the host closes the connection. + */ + public void testLongTimeout() { + // Seems to have a veeeery long timeout. + // fetch("www.fortify.net", 443, "/sslcheck.html", 1, 2, 60); + + // Google has a 60s timeout, so 90s of waiting should trigger it. + try { + fetch("mail.google.com", 443, true, "/mail/", 1, 2, 90, 180); + fail("Oops - timeout expected."); + } catch (IOException ex) { + // Expected. + } + + // These two don't accept keep-alive + // fetch("www.paypal.com", 443, "/", 1, 10); + // fetch("www.yellownet.ch", 443, "/", 1, 10); + } + + /** + * Does repeated requests for each of the hosts, with the connection being + * closed in between. Waits a longer time after each request. Expectation is + * that the host closes the connection. + */ + // These two need manual interaction to reproduce... + public void xxtestBrokenConnection() { + try { + fetch("www.fortify.net", 443, true, "/sslcheck.html", 1, 2, 60, 60); + fail("Oops - timeout expected."); + } catch (IOException ex) { + android.util.Log.d("SSLSocketTest", "Exception", ex); + // Expected. + } + + // These two don't accept keep-alive + // fetch("www.paypal.com", 443, "/", 1, 10); + // fetch("www.yellownet.ch", 443, "/", 1, 10); + } + + /** + * Does repeated requests for each of the hosts, with the connection being + * closed in between. Waits a longer time after each request. Expectation is + * that the host closes the connection. + */ + // These two need manual interaction to reproduce... + public void xxtestBrokenConnection2() { + try { + fetch("www.heise.de", 80, false, "/index.html", 1, 2, 60, 60); + fail("Oops - timeout expected."); + } catch (IOException ex) { + android.util.Log.d("SSLSocketTest", "Exception", ex); + // Expected. + } + + // These two don't accept keep-alive + // fetch("www.paypal.com", 443, "/", 1, 10); + // fetch("www.yellownet.ch", 443, "/", 1, 10); + } + + /** + * Regression test for 865926: SSLContext.init() should + * use default values for null arguments. + */ + public void testContextInitNullArgs() throws Exception { + SSLContext ctx = SSLContext.getInstance("TLS"); + ctx.init(null, null, null); + } + + /** + * Regression test for 963650: javax.net.ssl.KeyManager has no implemented + * (documented?) algorithms. + */ + public void testDefaultAlgorithms() throws Exception { + SSLContext ctx = SSLContext.getInstance("TLS"); + KeyManagerFactory kmf = KeyManagerFactory.getInstance("X509"); + KeyStore ks = KeyStore.getInstance("BKS"); + + assertEquals("X509", kmf.getAlgorithm()); + assertEquals("X509", KeyManagerFactory.getDefaultAlgorithm()); + + assertEquals("BKS", ks.getType()); + assertEquals("BKS", KeyStore.getDefaultType()); + } + + /** + * Regression test for problem where close() resulted in a hand if + * a different thread was sitting in a blocking read or write. + */ + public void testMultithreadedClose() throws Exception { + InetSocketAddress address = new InetSocketAddress("www.fortify.net", 443); + final Socket socket = clientFactory.createSocket(); + socket.connect(address); + + Thread reader = new Thread() { + @Override + public void run() { + try { + byte[] buffer = new byte[512]; + InputStream stream = socket.getInputStream(); + socket.getInputStream().read(buffer); + } catch (Exception ex) { + android.util.Log.d("SSLSocketTest", + "testMultithreadedClose() reader got " + ex.toString()); + } + } + }; + + Thread closer = new Thread() { + @Override + public void run() { + try { + Thread.sleep(5000); + socket.close(); + } catch (Exception ex) { + android.util.Log.d("SSLSocketTest", + "testMultithreadedClose() closer got " + ex.toString()); + } + } + }; + + android.util.Log.d("SSLSocketTest", "testMultithreadedClose() starting reader..."); + reader.start(); + android.util.Log.d("SSLSocketTest", "testMultithreadedClose() starting closer..."); + closer.start(); + + long t1 = System.currentTimeMillis(); + android.util.Log.d("SSLSocketTest", "testMultithreadedClose() joining reader..."); + reader.join(30000); + android.util.Log.d("SSLSocketTest", "testMultithreadedClose() joining closer..."); + closer.join(30000); + long t2 = System.currentTimeMillis(); + + assertTrue("Concurrent close() hangs", t2 - t1 < 30000); + } + + private int multithreadedFetchRuns; + + private int multithreadedFetchWins; + + private Random multithreadedFetchRandom = new Random(); + + /** + * Regression test for problem where multiple threads with multiple SSL + * connection would cause problems due to either missing native locking + * or the slowness of the SSL connections. + */ + public void testMultithreadedFetch() { + Thread[] threads = new Thread[10]; + + for (int i = 0; i < threads.length; i++) { + threads[i] = new Thread() { + @Override + public void run() { + for (int i = 0; i < 10; i++) { + try { + multithreadedFetchRuns++; + switch (multithreadedFetchRandom.nextInt(4)) { + case 0: { + fetch("www.fortify.net", 443, + true, "/sslcheck.html", 1, 1, 0, 60); + break; + } + + case 1: { + fetch("mail.google.com", 443, true, "/mail/", 1, 1, 0, 60); + break; + } + + case 2: { + fetch("www.paypal.com", 443, true, "/", 1, 1, 0, 60); + break; + } + + case 3: { + fetch("www.yellownet.ch", 443, true, "/", 1, 1, 0, 60); + break; + } + } + multithreadedFetchWins++; + } catch (Exception ex) { + android.util.Log.d("SSLSocketTest", + "testMultithreadedFetch() got Exception", ex); + } + } + } + }; + threads[i].start(); + + android.util.Log.d("SSLSocketTest", "testMultithreadedFetch() started thread #" + i); + } + + for (int i = 0; i < threads.length; i++) { + try { + threads[i].join(); + android.util.Log.d("SSLSocketTest", "testMultithreadedFetch() joined thread #" + i); + } catch (InterruptedException ex) { + // Not interested. + } + } + + assertTrue("At least 95% of multithreaded SSL connections must succeed", + multithreadedFetchWins >= (multithreadedFetchRuns * 95) / 100); + } + + // ------------------------------------------------------------------------- + // Regression test for #1204316: Missing client cert unit test. Passes on + // both Android and the RI. To use on the RI, install Apache Commons and + // replace the references to the base64-encoded keys by the JKS versions. + // ------------------------------------------------------------------------- + + /** + * Defines the keystore contents for the server, JKS version. Holds just a + * single self-generated key. The subject name is "Test Server". + */ + private static final String SERVER_KEYS_JKS = + "/u3+7QAAAAIAAAABAAAAAQAFbXlrZXkAAAEaWFfBeAAAArowggK2MA4GCisGAQQBKgIRAQEFAASC" + + "AqI2kp5XjnF8YZkhcF92YsJNQkvsmH7zqMM87j23zSoV4DwyE3XeC/gZWq1ToScIhoqZkzlbWcu4" + + "T/Zfc/DrfGk/rKbBL1uWKGZ8fMtlZk8KoAhxZk1JSyJvdkyKxqmzUbxk1OFMlN2VJNu97FPVH+du" + + "dvjTvmpdoM81INWBW/1fZJeQeDvn4mMbbe0IxgpiLnI9WSevlaDP/sm1X3iO9yEyzHLL+M5Erspo" + + "Cwa558fOu5DdsICMXhvDQxjWFKFhPHnKtGe+VvwkG9/bAaDgx3kfhk0w5zvdnkKb+8Ed9ylNRzdk" + + "ocAa/mxlMTOsTvDKXjjsBupNPIIj7OP4GNnZaxkJjSs98pEO67op1GX2qhy6FSOPNuq8k/65HzUc" + + "PYn6voEeh6vm02U/sjEnzRevQ2+2wXoAdp0EwtQ/DlMe+NvcwPGWKuMgX4A4L93DZGb04N2VmAU3" + + "YLOtZwTO0LbuWrcCM/q99G/7LcczkxIVrO2I/rh8RXVczlf9QzcrFObFv4ATuspWJ8xG7DhsMbnk" + + "rT94Pq6TogYeoz8o8ZMykesAqN6mt/9+ToIemmXv+e+KU1hI5oLwWMnUG6dXM6hIvrULY6o+QCPH" + + "172YQJMa+68HAeS+itBTAF4Clm/bLn6reHCGGU6vNdwU0lYldpiOj9cB3t+u2UuLo6tiFWjLf5Zs" + + "EQJETd4g/EK9nHxJn0GAKrWnTw7pEHQJ08elzUuy04C/jEEG+4QXU1InzS4o/kR0Sqz2WTGDoSoq" + + "ewuPRU5bzQs/b9daq3mXrnPtRBL6HfSDAdpTK76iHqLCGdqx3avHjVSBm4zFvEuYBCev+3iKOBmg" + + "yh7eQRTjz4UOWfy85omMBr7lK8PtfVBDzOXpasxS0uBgdUyBDX4tO6k9jZ8a1kmQRQAAAAEABVgu" + + "NTA5AAACSDCCAkQwggGtAgRIR8SKMA0GCSqGSIb3DQEBBAUAMGkxCzAJBgNVBAYTAlVTMRMwEQYD" + + "VQQIEwpDYWxpZm9ybmlhMQwwCgYDVQQHEwNNVFYxDzANBgNVBAoTBkdvb2dsZTEQMA4GA1UECxMH" + + "QW5kcm9pZDEUMBIGA1UEAxMLVGVzdCBTZXJ2ZXIwHhcNMDgwNjA1MTA0ODQyWhcNMDgwOTAzMTA0" + + "ODQyWjBpMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEMMAoGA1UEBxMDTVRWMQ8w" + + "DQYDVQQKEwZHb29nbGUxEDAOBgNVBAsTB0FuZHJvaWQxFDASBgNVBAMTC1Rlc3QgU2VydmVyMIGf" + + "MA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCwoC6chqCI84rj1PrXuJgbiit4EV909zR6N0jNlYfg" + + "itwB39bP39wH03rFm8T59b3mbSptnGmCIpLZn25KPPFsYD3JJ+wFlmiUdEP9H05flfwtFQJnw9uT" + + "3rRIdYVMPcQ3RoZzwAMliGr882I2thIDbA6xjGU/1nRIdvk0LtxH3QIDAQABMA0GCSqGSIb3DQEB" + + "BAUAA4GBAJn+6YgUlY18Ie+0+Vt8oEi81DNi/bfPrAUAh63fhhBikx/3R9dl3wh09Z6p7cIdNxjW" + + "n2ll+cRW9eqF7z75F0Omm0C7/KAEPjukVbszmzeU5VqzkpSt0j84YWi+TfcHRrfvhLbrlmGITVpY" + + "ol5pHLDyqGmDs53pgwipWqsn/nEXEBgj3EoqPeqHbDf7YaP8h/5BSt0="; + + /** + * Defines the keystore contents for the server, BKS version. Holds just a + * single self-generated key. The subject name is "Test Server". + */ + private static final String SERVER_KEYS_BKS = + "AAAAAQAAABQDkebzoP1XwqyWKRCJEpn/t8dqIQAABDkEAAVteWtleQAAARpYl20nAAAAAQAFWC41" + + "MDkAAAJNMIICSTCCAbKgAwIBAgIESEfU1jANBgkqhkiG9w0BAQUFADBpMQswCQYDVQQGEwJVUzET" + + "MBEGA1UECBMKQ2FsaWZvcm5pYTEMMAoGA1UEBxMDTVRWMQ8wDQYDVQQKEwZHb29nbGUxEDAOBgNV" + + "BAsTB0FuZHJvaWQxFDASBgNVBAMTC1Rlc3QgU2VydmVyMB4XDTA4MDYwNTExNTgxNFoXDTA4MDkw" + + "MzExNTgxNFowaTELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExDDAKBgNVBAcTA01U" + + "VjEPMA0GA1UEChMGR29vZ2xlMRAwDgYDVQQLEwdBbmRyb2lkMRQwEgYDVQQDEwtUZXN0IFNlcnZl" + + "cjCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA0LIdKaIr9/vsTq8BZlA3R+NFWRaH4lGsTAQy" + + "DPMF9ZqEDOaL6DJuu0colSBBBQ85hQTPa9m9nyJoN3pEi1hgamqOvQIWcXBk+SOpUGRZZFXwniJV" + + "zDKU5nE9MYgn2B9AoiH3CSuMz6HRqgVaqtppIe1jhukMc/kHVJvlKRNy9XMCAwEAATANBgkqhkiG" + + "9w0BAQUFAAOBgQC7yBmJ9O/eWDGtSH9BH0R3dh2NdST3W9hNZ8hIa8U8klhNHbUCSSktZmZkvbPU" + + "hse5LI3dh6RyNDuqDrbYwcqzKbFJaq/jX9kCoeb3vgbQElMRX8D2ID1vRjxwlALFISrtaN4VpWzV" + + "yeoHPW4xldeZmoVtjn8zXNzQhLuBqX2MmAAAAqwAAAAUvkUScfw9yCSmALruURNmtBai7kQAAAZx" + + "4Jmijxs/l8EBaleaUru6EOPioWkUAEVWCxjM/TxbGHOi2VMsQWqRr/DZ3wsDmtQgw3QTrUK666sR" + + "MBnbqdnyCyvM1J2V1xxLXPUeRBmR2CXorYGF9Dye7NkgVdfA+9g9L/0Au6Ugn+2Cj5leoIgkgApN" + + "vuEcZegFlNOUPVEs3SlBgUF1BY6OBM0UBHTPwGGxFBBcetcuMRbUnu65vyDG0pslT59qpaR0TMVs" + + "P+tcheEzhyjbfM32/vwhnL9dBEgM8qMt0sqF6itNOQU/F4WGkK2Cm2v4CYEyKYw325fEhzTXosck" + + "MhbqmcyLab8EPceWF3dweoUT76+jEZx8lV2dapR+CmczQI43tV9btsd1xiBbBHAKvymm9Ep9bPzM" + + "J0MQi+OtURL9Lxke/70/MRueqbPeUlOaGvANTmXQD2OnW7PISwJ9lpeLfTG0LcqkoqkbtLKQLYHI" + + "rQfV5j0j+wmvmpMxzjN3uvNajLa4zQ8l0Eok9SFaRr2RL0gN8Q2JegfOL4pUiHPsh64WWya2NB7f" + + "V+1s65eA5ospXYsShRjo046QhGTmymwXXzdzuxu8IlnTEont6P4+J+GsWk6cldGbl20hctuUKzyx" + + "OptjEPOKejV60iDCYGmHbCWAzQ8h5MILV82IclzNViZmzAapeeCnexhpXhWTs+xDEYSKEiG/camt" + + "bhmZc3BcyVJrW23PktSfpBQ6D8ZxoMfF0L7V2GQMaUg+3r7ucrx82kpqotjv0xHghNIm95aBr1Qw" + + "1gaEjsC/0wGmmBDg1dTDH+F1p9TInzr3EFuYD0YiQ7YlAHq3cPuyGoLXJ5dXYuSBfhDXJSeddUkl" + + "k1ufZyOOcskeInQge7jzaRfmKg3U94r+spMEvb0AzDQVOKvjjo1ivxMSgFRZaDb/4qw="; + + /** + * Defines the keystore contents for the client, JKS version. Holds just a + * single self-generated key. The subject name is "Test Client". + */ + private static final String CLIENT_KEYS_JKS = + "/u3+7QAAAAIAAAABAAAAAQAFbXlrZXkAAAEaWFhyMAAAArkwggK1MA4GCisGAQQBKgIRAQEFAASC" + + "AqGVSfXolBStZy4nnRNn4fAr+S7kfU2BS23wwW8uB2Ru3GvtLzlK9q08Gvq/LNqBafjyFTVL5FV5" + + "SED/8YomO5a98GpskSeRvytCiTBLJdgGhws5TOGekgIAcBROPGIyOtJPQ0HfOQs+BqgzGDHzHQhw" + + "u/8Tm6yQwiP+W/1I9B1QnaEztZA3mhTyMMJsmsFTYroGgAog885D5Cmzd8sYGfxec3R6I+xcmBAY" + + "eibR5kGpWwt1R+qMvRrtBqh5r6WSKhCBNax+SJVbtUNRiKyjKccdJg6fGqIWWeivwYTy0OhjA6b4" + + "NiZ/ZZs5pxFGWUj/Rlp0RYy8fCF6aw5/5s4Bf4MI6dPSqMG8Hf7sJR91GbcELyzPdM0h5lNavgit" + + "QPEzKeuDrGxhY1frJThBsNsS0gxeu+OgfJPEb/H4lpYX5IvuIGbWKcxoO9zq4/fimIZkdA8A+3eY" + + "mfDaowvy65NBVQPJSxaOyFhLHfeLqOeCsVENAea02vA7andZHTZehvcrqyKtm+z8ncHGRC2H9H8O" + + "jKwKHfxxrYY/jMAKLl00+PBb3kspO+BHI2EcQnQuMw/zr83OR9Meq4TJ0TMuNkApZELAeFckIBbS" + + "rBr8NNjAIfjuCTuKHhsTFWiHfk9ZIzigxXagfeDRiyVc6khOuF/bGorj23N2o7Rf3uLoU6PyXWi4" + + "uhctR1aL6NzxDoK2PbYCeA9hxbDv8emaVPIzlVwpPK3Ruvv9mkjcOhZ74J8bPK2fQmbplbOljcZi" + + "tZijOfzcO/11JrwhuJZRA6wanTqHoujgChV9EukVrmbWGGAcewFnAsSbFXIik7/+QznXaDIt5NgL" + + "H/Bcz4Z/fdV7Ae1eUaxKXdPbI//4J+8liVT/d8awjW2tldIaDlmGMR3aoc830+3mAAAAAQAFWC41" + + "MDkAAAJIMIICRDCCAa0CBEhHxLgwDQYJKoZIhvcNAQEEBQAwaTELMAkGA1UEBhMCVVMxEzARBgNV" + + "BAgTCkNhbGlmb3JuaWExDDAKBgNVBAcTA01UVjEPMA0GA1UEChMGR29vZ2xlMRAwDgYDVQQLEwdB" + + "bmRyb2lkMRQwEgYDVQQDEwtUZXN0IENsaWVudDAeFw0wODA2MDUxMDQ5MjhaFw0wODA5MDMxMDQ5" + + "MjhaMGkxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMQwwCgYDVQQHEwNNVFYxDzAN" + + "BgNVBAoTBkdvb2dsZTEQMA4GA1UECxMHQW5kcm9pZDEUMBIGA1UEAxMLVGVzdCBDbGllbnQwgZ8w" + + "DQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAIK3Q+KiFbmCGg422TAo4gggdhMH6FJhiuz8DxRyeMKR" + + "UAfP4MK0wtc8N42waZ6OKvxpBFUy0BRfBsX0GD4Ku99yu9/tavSigTraeJtwV3WWRRjIqk7L3wX5" + + "cmgS2KSD43Y0rNUKrko26lnt9N4qiYRBSj+tcAN3Lx9+ptqk1LApAgMBAAEwDQYJKoZIhvcNAQEE" + + "BQADgYEANb7Q1GVSuy1RPJ0FmiXoMYCCtvlRLkmJphwxovK0cAQK12Vll+yAzBhHiQHy/RA11mng" + + "wYudC7u3P8X/tBT8GR1Yk7QW3KgFyPafp3lQBBCraSsfrjKj+dCLig1uBLUr4f68W8VFWZWWTHqp" + + "NMGpCX6qmjbkJQLVK/Yfo1ePaUexPSOX0G9m8+DoV3iyNw6at01NRw=="; + + /** + * Defines the keystore contents for the client, BKS version. Holds just a + * single self-generated key. The subject name is "Test Client". + */ + private static final String CLIENT_KEYS_BKS = + "AAAAAQAAABT4Rka6fxbFps98Y5k2VilmbibNkQAABfQEAAVteWtleQAAARpYl+POAAAAAQAFWC41" + + "MDkAAAJNMIICSTCCAbKgAwIBAgIESEfU9TANBgkqhkiG9w0BAQUFADBpMQswCQYDVQQGEwJVUzET" + + "MBEGA1UECBMKQ2FsaWZvcm5pYTEMMAoGA1UEBxMDTVRWMQ8wDQYDVQQKEwZHb29nbGUxEDAOBgNV" + + "BAsTB0FuZHJvaWQxFDASBgNVBAMTC1Rlc3QgQ2xpZW50MB4XDTA4MDYwNTExNTg0NVoXDTA4MDkw" + + "MzExNTg0NVowaTELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExDDAKBgNVBAcTA01U" + + "VjEPMA0GA1UEChMGR29vZ2xlMRAwDgYDVQQLEwdBbmRyb2lkMRQwEgYDVQQDEwtUZXN0IENsaWVu" + + "dDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEApUvmWsQDHPpbDKK13Yez2/q54tTOmRml/qva" + + "2K6dZjkjSTW0iRuk7ztaVEvdJpfVIDv1oBsCI51ttyLHROy1epjF+GoL74mJb7fkcd0VOoSOTjtD" + + "+3GgZkHPAm5YmUYxiJXqxKKJJqMCTIW46eJaA2nAep9QIwZ14/NFAs4ObV8CAwEAATANBgkqhkiG" + + "9w0BAQUFAAOBgQCJrCr3hZQFDlLIfsSKI1/w+BLvyf4fubOid0pBxfklR8KBNPTiqjSmu7pd/C/F" + + "1FR8CdZUDoPflZHCOU+fj5r5KUC1HyigY/tEUvlforBpfB0uCF+tXW4DbUfOWhfMtLV4nCOJOOZg" + + "awfZLJWBJouLKOp427vDftxTSB+Ks8YjlgAAAqwAAAAU+NH6TtrzjyDdCXm5B6Vo7xX5G4YAAAZx" + + "EAUkcZtmykn7YdaYxC1jRFJ+GEJpC8nZVg83QClVuCSIS8a5f8Hl44Bk4oepOZsPzhtz3RdVzDVi" + + "RFfoyZFsrk9F5bDTVJ6sQbb/1nfJkLhZFXokka0vND5AXMSoD5Bj1Fqem3cK7fSUyqKvFoRKC3XD" + + "FQvhqoam29F1rbl8FaYdPvhhZo8TfZQYUyUKwW+RbR44M5iHPx+ykieMe/C/4bcM3z8cwIbYI1aO" + + "gjQKS2MK9bs17xaDzeAh4sBKrskFGrDe+2dgvrSKdoakJhLTNTBSG6m+rzqMSCeQpafLKMSjTSSz" + + "+KoQ9bLyax8cbvViGGju0SlVhquloZmKOfHr8TukIoV64h3uCGFOVFtQjCYDOq6NbfRvMh14UVF5" + + "zgDIGczoD9dMoULWxBmniGSntoNgZM+QP6Id7DBasZGKfrHIAw3lHBqcvB5smemSu7F4itRoa3D8" + + "N7hhUEKAc+xA+8NKmXfiCBoHfPHTwDvt4IR7gWjeP3Xv5vitcKQ/MAfO5RwfzkYCXQ3FfjfzmsE1" + + "1IfLRDiBj+lhQSulhRVStKI88Che3M4JUNGKllrc0nt1pWa1vgzmUhhC4LSdm6trTHgyJnB6OcS9" + + "t2furYjK88j1AuB4921oxMxRm8c4Crq8Pyuf+n3YKi8Pl2BzBtw++0gj0ODlgwut8SrVj66/nvIB" + + "jN3kLVahR8nZrEFF6vTTmyXi761pzq9yOVqI57wJGx8o3Ygox1p+pWUPl1hQR7rrhUbgK/Q5wno9" + + "uJk07h3IZnNxE+/IKgeMTP/H4+jmyT4mhsexJ2BFHeiKF1KT/FMcJdSi+ZK5yoNVcYuY8aZbx0Ef" + + "lHorCXAmLFB0W6Cz4KPP01nD9YBB4olxiK1t7m0AU9zscdivNiuUaB5OIEr+JuZ6dNw="; + /** + * Defines the password for the keystore. + */ + private static final String PASSWORD = "android"; + + /** + * Implements basically a dummy TrustManager. It stores the certificate + * chain it sees, so it can later be queried. + */ + class TestTrustManager implements X509TrustManager { + + private X509Certificate[] chain; + + private String authType; + + public void checkClientTrusted(X509Certificate[] chain, String authType) { + this.chain = chain; + this.authType = authType; + } + + public void checkServerTrusted(X509Certificate[] chain, String authType) { + this.chain = chain; + this.authType = authType; + } + + public X509Certificate[] getAcceptedIssuers() { + return new X509Certificate[0]; + } + + public X509Certificate[] getChain() { + return chain; + } + + public String getAuthType() { + return authType; + } + + } + + /** + * Implements a test SSL socket server. It wait for a connection on a given + * port, requests client authentication (if specified), and read 256 bytes + * from the socket. + */ + class TestServer implements Runnable { + + public static final int CLIENT_AUTH_NONE = 0; + + public static final int CLIENT_AUTH_WANTED = 1; + + public static final int CLIENT_AUTH_NEEDED = 2; + + private TestTrustManager trustManager; + + private Exception exception; + + private int port; + + private int clientAuth; + + private boolean provideKeys; + + public TestServer(int port, boolean provideKeys, int clientAuth) { + this.port = port; + this.clientAuth = clientAuth; + this.provideKeys = provideKeys; + + trustManager = new TestTrustManager(); + } + + public void run() { + try { + KeyManager[] keyManagers = provideKeys ? getKeyManagers(SERVER_KEYS_BKS) : null; + TrustManager[] trustManagers = new TrustManager[] { trustManager }; + + SSLContext sslContext = SSLContext.getInstance("TLS"); + sslContext.init(keyManagers, trustManagers, null); + + SSLServerSocket serverSocket = (SSLServerSocket)sslContext.getServerSocketFactory().createServerSocket(); + + if (clientAuth == CLIENT_AUTH_WANTED) { + serverSocket.setWantClientAuth(true); + } else if (clientAuth == CLIENT_AUTH_NEEDED) { + serverSocket.setNeedClientAuth(true); + } else { + serverSocket.setWantClientAuth(false); + } + + serverSocket.bind(new InetSocketAddress(port)); + + SSLSocket clientSocket = (SSLSocket)serverSocket.accept(); + + InputStream stream = clientSocket.getInputStream(); + + for (int i = 0; i < 256; i++) { + int j = stream.read(); + if (i != j) { + throw new RuntimeException("Error reading socket, expected " + i + ", got " + j); + } + } + + stream.close(); + clientSocket.close(); + serverSocket.close(); + + } catch (Exception ex) { + exception = ex; + } + } + + public Exception getException() { + return exception; + } + + public X509Certificate[] getChain() { + return trustManager.getChain(); + } + + } + + /** + * Implements a test SSL socket client. It open a connection to localhost on + * a given port and writes 256 bytes to the socket. + */ + class TestClient implements Runnable { + + private TestTrustManager trustManager; + + private Exception exception; + + private int port; + + private boolean provideKeys; + + public TestClient(int port, boolean provideKeys) { + this.port = port; + this.provideKeys = provideKeys; + + trustManager = new TestTrustManager(); + } + + public void run() { + try { + KeyManager[] keyManagers = provideKeys ? getKeyManagers(CLIENT_KEYS_BKS) : null; + TrustManager[] trustManagers = new TrustManager[] { trustManager }; + + SSLContext sslContext = SSLContext.getInstance("TLS"); + sslContext.init(keyManagers, trustManagers, null); + + SSLSocket socket = (SSLSocket)sslContext.getSocketFactory().createSocket(); + + socket.connect(new InetSocketAddress(port)); + socket.startHandshake(); + + OutputStream stream = socket.getOutputStream(); + + for (int i = 0; i < 256; i++) { + stream.write(i); + } + + stream.flush(); + stream.close(); + socket.close(); + + } catch (Exception ex) { + exception = ex; + } + } + + public Exception getException() { + return exception; + } + + public X509Certificate[] getChain() { + return trustManager.getChain(); + } + + } + + /** + * Loads a keystore from a base64-encoded String. Returns the KeyManager[] + * for the result. + */ + private KeyManager[] getKeyManagers(String keys) throws Exception { + byte[] bytes = new Base64().decode(keys.getBytes()); + InputStream inputStream = new ByteArrayInputStream(bytes); + + KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType()); + keyStore.load(inputStream, PASSWORD.toCharArray()); + inputStream.close(); + + String algorithm = KeyManagerFactory.getDefaultAlgorithm(); + KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(algorithm); + keyManagerFactory.init(keyStore, PASSWORD.toCharArray()); + + return keyManagerFactory.getKeyManagers(); + } + + /** + * Implements the actual test case. Launches a server and a client, requires + * client authentication and checks the certificates afterwards (not in the + * usual sense, we just make sure that we got the expected certificates, + * because our self-signed test certificates are not valid.) + */ + public void testClientAuth() { + try { + TestServer server = new TestServer(8088, true, TestServer.CLIENT_AUTH_WANTED); + TestClient client = new TestClient(8088, true); + + Thread serverThread = new Thread(server); + Thread clientThread = new Thread(client); + + serverThread.start(); + clientThread.start(); + + serverThread.join(); + clientThread.join(); + + // The server must have completed without an exception. + if (server.getException() != null) { + throw new RuntimeException(server.getException()); + } + + // The client must have completed without an exception. + if (client.getException() != null) { + throw new RuntimeException(client.getException()); + } + + // Caution: The clientChain is the certificate chain from our + // client object. It contains the server certificates, of course! + X509Certificate[] clientChain = client.getChain(); + assertTrue("Client cert chain must not be null", clientChain != null); + assertTrue("Client cert chain must not be empty", clientChain.length != 0); + assertEquals("CN=Test Server, OU=Android, O=Google, L=MTV, ST=California, C=US", clientChain[0].getSubjectDN().toString()); + // Important part ------^ + + // Caution: The serverChain is the certificate chain from our + // server object. It contains the client certificates, of course! + X509Certificate[] serverChain = server.getChain(); + assertTrue("Server cert chain must not be null", serverChain != null); + assertTrue("Server cert chain must not be empty", serverChain.length != 0); + assertEquals("CN=Test Client, OU=Android, O=Google, L=MTV, ST=California, C=US", serverChain[0].getSubjectDN().toString()); + // Important part ------^ + + } catch (Exception ex) { + throw new RuntimeException(ex); + } + } + + // ------------------------------------------------------------------------- + private SSLSocket handshakeSocket; + + private Exception handshakeException; + + + public void testSSLHandshakeHangTimeout() { + + Thread thread = new Thread() { + @Override + public void run() { + try { + SSLSocket socket = (SSLSocket)clientFactory.createSocket( + "www.heise.de", 80); + socket.setSoTimeout(5000); + socket.startHandshake(); + socket.close(); + } catch (Exception ex) { + handshakeException = ex; + } + } + }; + + thread.start(); + + try { + thread.join(10000); + } catch (InterruptedException ex) { + // Ignore. + } + + if (handshakeException == null) { + fail("SSL handshake should have failed."); + } + } + + public void testSSLHandshakeHangClose() { + + Thread thread = new Thread() { + @Override + public void run() { + try { + handshakeSocket = (SSLSocket)clientFactory.createSocket( + "www.heise.de", 80); + handshakeSocket.startHandshake(); + } catch (Exception ex) { + handshakeException = ex; + } + } + }; + + thread.start(); + + + try { + Thread.sleep(5000); + try { + handshakeSocket.close(); + } catch (Exception ex) { + throw new RuntimeException(ex); + } + + thread.join(5000); + } catch (InterruptedException ex) { + // Ignore. + } + + if (handshakeException == null) { + fail("SSL handshake should have failed."); + } + } + + +} diff --git a/tests/CoreTests/android/core/Sha1Test.java b/tests/CoreTests/android/core/Sha1Test.java new file mode 100644 index 0000000000000000000000000000000000000000..dcd4c046cdb7947a020484b2da8c9d466155b412 --- /dev/null +++ b/tests/CoreTests/android/core/Sha1Test.java @@ -0,0 +1,69 @@ +/* + * 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 android.core; + +import android.security.MessageDigest; +import android.test.suitebuilder.annotation.SmallTest; +import junit.framework.TestCase; + +/** + * Tests SHA1 message digest algorithm. + */ +public class Sha1Test extends TestCase { + class TestData { + private String input; + private String result; + + public TestData(String i, String r) { + input = i; + result = r; + } + } + + TestData[] mTestData = new TestData[]{ + new TestData("abc", "a9993e364706816aba3e25717850c26c9cd0d89d"), + new TestData("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", + "84983e441c3bd26ebaae4aa1f95129e5e54670f1") + }; + + @SmallTest + public void testSha1() throws Exception { + MessageDigest digest = MessageDigest.getInstance("SHA-1"); + + int numTests = mTestData.length; + for (int i = 0; i < numTests; i++) { + digest.update(mTestData[i].input.getBytes()); + byte[] hash = digest.digest(); + String encodedHash = encodeHex(hash); + assertEquals(encodedHash, mTestData[i].result); + } + } + + private static String encodeHex(byte[] bytes) { + StringBuffer hex = new StringBuffer(bytes.length * 2); + + for (int i = 0; i < bytes.length; i++) { + if (((int) bytes[i] & 0xff) < 0x10) { + hex.append("0"); + } + hex.append(Integer.toString((int) bytes[i] & 0xff, 16)); + } + + return hex.toString(); + } +} + diff --git a/tests/CoreTests/android/core/SocketTest.java b/tests/CoreTests/android/core/SocketTest.java new file mode 100644 index 0000000000000000000000000000000000000000..b64c1568ec9eed80bf9ac16d316d36d419940d4b --- /dev/null +++ b/tests/CoreTests/android/core/SocketTest.java @@ -0,0 +1,288 @@ +/* + * 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 android.core; + +import junit.framework.Assert; +import junit.framework.TestCase; + +import java.io.IOException; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.ServerSocket; +import java.net.Socket; +import java.net.SocketException; +import java.net.SocketTimeoutException; +import java.nio.channels.SocketChannel; +import java.util.concurrent.Semaphore; + +import android.test.suitebuilder.annotation.LargeTest; +import android.test.suitebuilder.annotation.SmallTest; +import android.test.suitebuilder.annotation.Suppress; + +/** + * Regression tests for various socket related problems. And a few general + * socket tests. + */ +public class SocketTest extends TestCase { + + private static final String NON_EXISTING_ADDRESS = "123.123.123.123"; + + private static final String KNOW_GOOD_ADDRESS = "209.85.129.147"; + + private static final String PACKAGE_DROPPING_ADDRESS = "191.167.0.1"; + + // Test for basic bind/connect/accept behavior. + @SmallTest + public void testSocketSimple() throws Exception { + ServerSocket ss; + Socket s, s1; + int port; + + IOException lastEx = null; + + ss = new ServerSocket(); + + for (port = 9900; port < 9999; port++) { + try { + ss.bind(new InetSocketAddress("127.0.0.1", port)); + lastEx = null; + break; + } catch (IOException ex) { + lastEx = ex; + } + } + + if (lastEx != null) { + throw lastEx; + } + + s = new Socket("127.0.0.1", port); + + s1 = ss.accept(); + + s.getOutputStream().write(0xa5); + + assertEquals(0xa5, s1.getInputStream().read()); + + s1.getOutputStream().write(0x5a); + assertEquals(0x5a, s.getInputStream().read()); + } + + // Regression test for #820068: Wildcard address + @SmallTest + public void testWildcardAddress() throws Exception { + Socket s2 = new Socket(); + s2.bind(new InetSocketAddress((InetAddress) null, 12345)); + byte[] addr = s2.getLocalAddress().getAddress(); + for (int i = 0; i < 4; i++) { + assertEquals("Not the wildcard address", 0, addr[i]); + } + } + + // Regression test for #865753: server sockets not closing properly + @SmallTest + public void testServerSocketClose() throws Exception { + ServerSocket s3 = new ServerSocket(23456); + s3.close(); + ServerSocket s4 = new ServerSocket(23456); + s4.close(); + } + + // Regression test for #876985: SO_REUSEADDR not working properly + + private Exception serverError = null; + + @LargeTest + public void testSetReuseAddress() throws IOException { + InetSocketAddress addr = new InetSocketAddress(8383); + + final ServerSocket serverSock = new ServerSocket(); + serverSock.setReuseAddress(true); + serverSock.bind(addr); + + final Semaphore semThreadEnd = new Semaphore(0); + new Thread() { + @Override + public void run() { + try { + Socket sock = serverSock.accept(); + sock.getInputStream().read(); + sock.close(); + } catch (IOException e) { + serverError = e; + } + semThreadEnd.release(); + } + }.start(); + + // Give the server a bit of time for startup + try { + Thread.sleep(2000); + } catch (InterruptedException ex) { + // Ignored. + } + + Socket client = new Socket("localhost", 8383); + client.getOutputStream().write(1); + // Just leave this connection open from the client side. It will be + // closed from the server side so the server stays in the TIME_WAIT + // state for a while. setReuseAddress() should be able to handle this. + + try { + semThreadEnd.acquire(); + } catch (InterruptedException e) { + // ignore + } + serverSock.close(); + + ServerSocket serverSock2 = new ServerSocket(); + serverSock2.setReuseAddress(true); + serverSock2.bind(addr); + serverSock2.close(); + + if (serverError != null) { + throw new RuntimeException("Server must complete without error", serverError); + } + } + + // Regression for 916701, a wrong exception was thrown after timeout of + // a ServerSocket. + @LargeTest + public void testTimeoutException() throws IOException { + ServerSocket s = new ServerSocket(9800); + s.setSoTimeout(2000); + try { + s.accept(); + } catch (SocketTimeoutException e) { + // this is ok. + } + } + + // Regression for issue 1001980, openening a SocketChannel threw an Exception + @SmallTest + public void testNativeSocketChannelOpen() throws IOException { + SocketChannel.open(); + } + + // Regression test for issue 1018016, connecting ignored a set timeout. + @LargeTest + public void testSocketSetSOTimeout() throws IOException { + Socket sock = new Socket(); + int timeout = 5000; + long start = System.currentTimeMillis(); + try { + sock.connect(new InetSocketAddress(NON_EXISTING_ADDRESS, 80), timeout); + } catch (SocketTimeoutException e) { + // expected + long delay = System.currentTimeMillis() - start; + if (Math.abs(delay - timeout) > 1000) { + fail("timeout was not accurate. expected: " + timeout + + " actual: " + delay + " miliseconds."); + } + } finally { + try { + sock.close(); + } catch (IOException ioe) { + // ignore + } + } + } + + /** + * Regression test for 1062928: Dotted IP addresses (e.g., 192.168.100.1) + * appear to be broken in the M5 SDK. + * + * Tests that a connection given a ip-addressv4 such as 192.168.100.100 does + * not fail - sdk m5 seems only to accept dns names instead of ip numbers. + * ip 209.85.129.147 (one address of www.google.com) on port 80 (http) is + * used to test the connection. + */ + +// Commenting out this test since it is flaky, even at the best of times. See +// #1191317 for Info. + @Suppress + public void disable_testConnectWithIP4IPAddr() { + // call a Google Web server + InetSocketAddress scktAddrss = new InetSocketAddress(KNOW_GOOD_ADDRESS, + 80); + Socket clntSckt = new Socket(); + try { + clntSckt.connect(scktAddrss, 5000); + } catch (Throwable e) { + fail("connection problem:" + e.getClass().getName() + ": " + + e.getMessage()); + } finally { + try { + clntSckt.close(); + } catch (Exception e) { + // ignore + } + } + } + + + // Regression test for #1058962: Socket.close() does not cause + // socket.connect() to return immediately. + private Socket client; + + private Exception error; + + private boolean connected; + +// This test isn't working now, but really should work. +// TODO Enable this test again. + + @Suppress + public void disable_testSocketConnectClose() { + try { + client = new Socket(); + + new Thread() { + @Override + public void run() { + try { + client.connect(new InetSocketAddress(PACKAGE_DROPPING_ADDRESS, 1357)); + } catch (Exception ex) { + error = ex; + } + + connected = true; + } + }.start(); + + Thread.sleep(1000); + + Assert.assertNull("Connect must not fail immediately. Maybe try different address.", error); + Assert.assertFalse("Connect must not succeed. Maybe try different address.", connected); + + client.close(); + + Thread.sleep(1000); + + if (error == null) { + fail("Socket connect still ongoing"); + } else if (!(error instanceof SocketException)) { + fail("Socket connect interrupted with wrong error: " + error.toString()); + } + + } catch (Exception ex) { + throw new RuntimeException(ex); + } + + } + +} diff --git a/tests/CoreTests/android/core/StreamTokenizerTest.java b/tests/CoreTests/android/core/StreamTokenizerTest.java new file mode 100644 index 0000000000000000000000000000000000000000..5013860a1fbe03c8dfa8b1ac62e967587b47a480 --- /dev/null +++ b/tests/CoreTests/android/core/StreamTokenizerTest.java @@ -0,0 +1,96 @@ +/* + * 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 android.core; + +import junit.framework.TestCase; + +import java.io.ByteArrayInputStream; +import java.io.StreamTokenizer; +import java.io.StringReader; +import android.test.suitebuilder.annotation.MediumTest; + +/** + * Tests for the StreamTokenizer + */ +public class StreamTokenizerTest extends TestCase { + + @MediumTest + public void testStreamTokenizer() throws Exception { + String str = "Testing 12345 \n alpha \r\n omega"; + String strb = "-3.8 'BLIND mice' \r sEe /* how */ they run"; + StringReader aa = new StringReader(str); + StringReader ba = new StringReader(strb); + StreamTokenizer a = new StreamTokenizer(aa); + StreamTokenizer b = new StreamTokenizer(ba); + + assertEquals(1, a.lineno()); + assertEquals(StreamTokenizer.TT_WORD, a.nextToken()); + assertEquals("Token[Testing], line 1", a.toString()); + assertEquals(StreamTokenizer.TT_NUMBER, a.nextToken()); + assertEquals("Token[n=12345.0], line 1", a.toString()); + assertEquals(StreamTokenizer.TT_WORD, a.nextToken()); + assertEquals("Token[alpha], line 2", a.toString()); + assertEquals(StreamTokenizer.TT_WORD, a.nextToken()); + assertEquals("Token[omega], line 3", a.toString()); + assertEquals(StreamTokenizer.TT_EOF, a.nextToken()); + assertEquals("Token[EOF], line 3", a.toString()); + + b.commentChar('u'); + b.eolIsSignificant(true); + b.lowerCaseMode(true); + b.ordinaryChar('y'); + b.slashStarComments(true); + + assertEquals(StreamTokenizer.TT_NUMBER, b.nextToken()); + assertEquals(-3.8, b.nval); + assertEquals("Token[n=-3.8], line 1", b.toString()); + assertEquals(39, b.nextToken()); // ' + assertEquals("Token[BLIND mice], line 1", b.toString()); + assertEquals(10, b.nextToken()); // \n + assertEquals("Token[EOL], line 2", b.toString()); + assertEquals(StreamTokenizer.TT_WORD, b.nextToken()); + assertEquals("Token[see], line 2", b.toString()); + assertEquals(StreamTokenizer.TT_WORD, b.nextToken()); + assertEquals("Token[the], line 2", b.toString()); + assertEquals(121, b.nextToken()); // y + assertEquals("Token['y'], line 2", b.toString()); + assertEquals(StreamTokenizer.TT_WORD, b.nextToken()); + assertEquals("Token[r], line 2", b.toString()); + assertEquals(StreamTokenizer.TT_EOF, b.nextToken()); + assertEquals("Token[EOF], line 2", b.toString()); + + // A harmony regression test + byte[] data = new byte[]{(byte) '-'}; + StreamTokenizer tokenizer = new StreamTokenizer(new ByteArrayInputStream(data)); + tokenizer.nextToken(); + String result = tokenizer.toString(); + assertEquals("Token['-'], line 1", result); + + // another harmony regression test + byte[] data2 = new byte[]{(byte) '"', + (byte) 'H', + (byte) 'e', + (byte) 'l', + (byte) 'l', + (byte) 'o', + (byte) '"'}; + StreamTokenizer tokenizer2 = new StreamTokenizer(new ByteArrayInputStream(data2)); + tokenizer2.nextToken(); + result = tokenizer2.toString(); + assertEquals("Token[Hello], line 1", result); + } +} diff --git a/tests/CoreTests/android/core/StrictMathTest.java b/tests/CoreTests/android/core/StrictMathTest.java new file mode 100644 index 0000000000000000000000000000000000000000..92e6cb6463fbac24ed2bbadeea8e5ac4778568d8 --- /dev/null +++ b/tests/CoreTests/android/core/StrictMathTest.java @@ -0,0 +1,855 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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 android.core; + +import junit.framework.TestCase; +import android.test.suitebuilder.annotation.SmallTest; +import android.test.suitebuilder.annotation.MediumTest; + +public class StrictMathTest extends TestCase { + + private final double HYP = StrictMath.sqrt(2.0); + + private final double OPP = 1.0; + + private final double ADJ = 1.0; + + /* Required to make previous preprocessor flags work - do not remove */ + int unused = 0; + + /** + * @tests java.lang.StrictMath#abs(double) + */ + @SmallTest + public void testAbsD() { + // Test for method double java.lang.StrictMath.abs(double) + + assertTrue("Incorrect double abs value", + (StrictMath.abs(-1908.8976) == 1908.8976)); + assertTrue("Incorrect double abs value", + (StrictMath.abs(1908.8976) == 1908.8976)); + } + + /** + * @tests java.lang.StrictMath#abs(float) + */ + @SmallTest + public void testAbsF() { + // Test for method float java.lang.StrictMath.abs(float) + assertTrue("Incorrect float abs value", + (StrictMath.abs(-1908.8976f) == 1908.8976f)); + assertTrue("Incorrect float abs value", + (StrictMath.abs(1908.8976f) == 1908.8976f)); + } + + /** + * @tests java.lang.StrictMath#abs(int) + */ + @SmallTest + public void testAbsI() { + // Test for method int java.lang.StrictMath.abs(int) + assertTrue("Incorrect int abs value", + (StrictMath.abs(-1908897) == 1908897)); + assertTrue("Incorrect int abs value", + (StrictMath.abs(1908897) == 1908897)); + } + + /** + * @tests java.lang.StrictMath#abs(long) + */ + @SmallTest + public void testAbsJ() { + // Test for method long java.lang.StrictMath.abs(long) + assertTrue("Incorrect long abs value", (StrictMath + .abs(-19088976000089L) == 19088976000089L)); + assertTrue("Incorrect long abs value", + (StrictMath.abs(19088976000089L) == 19088976000089L)); + } + + /** + * @tests java.lang.StrictMath#acos(double) + */ + @SmallTest + public void testAcosD() { + // Test for method double java.lang.StrictMath.acos(double) + assertTrue("Returned incorrect arc cosine", StrictMath.cos(StrictMath + .acos(ADJ / HYP)) == ADJ / HYP); + } + + /** + * @tests java.lang.StrictMath#asin(double) + */ + @SmallTest + public void testAsinD() { + // Test for method double java.lang.StrictMath.asin(double) + assertTrue("Returned incorrect arc sine", StrictMath.sin(StrictMath + .asin(OPP / HYP)) == OPP / HYP); + } + + /** + * @tests java.lang.StrictMath#atan(double) + */ + @SmallTest + public void testAtanD() { + // Test for method double java.lang.StrictMath.atan(double) + double answer = StrictMath.tan(StrictMath.atan(1.0)); + assertTrue("Returned incorrect arc tangent: " + answer, answer <= 1.0 + && answer >= 9.9999999999999983E-1); + } + + /** + * @tests java.lang.StrictMath#atan2(double,double) + */ + @SmallTest + public void testAtan2DD() { + // Test for method double java.lang.StrictMath.atan2(double, double) + double answer = StrictMath.atan(StrictMath.tan(1.0)); + assertTrue("Returned incorrect arc tangent: " + answer, answer <= 1.0 + && answer >= 9.9999999999999983E-1); + } + + /** + * @tests java.lang.StrictMath#cbrt(double) + */ + @SuppressWarnings("boxing") + @SmallTest + public void testCbrtD() { + // Test for special situations + assertTrue("Should return Double.NaN", Double.isNaN(StrictMath + .cbrt(Double.NaN))); + assertEquals("Should return Double.POSITIVE_INFINITY", + Double.POSITIVE_INFINITY, StrictMath + .cbrt(Double.POSITIVE_INFINITY)); + assertEquals("Should return Double.NEGATIVE_INFINITY", + Double.NEGATIVE_INFINITY, StrictMath + .cbrt(Double.NEGATIVE_INFINITY)); + assertEquals(Double.doubleToLongBits(0.0), Double + .doubleToLongBits(StrictMath.cbrt(0.0))); + assertEquals(Double.doubleToLongBits(+0.0), Double + .doubleToLongBits(StrictMath.cbrt(+0.0))); + assertEquals(Double.doubleToLongBits(-0.0), Double + .doubleToLongBits(StrictMath.cbrt(-0.0))); + + assertEquals("Should return 3.0", 3.0, StrictMath.cbrt(27.0)); + assertEquals("Should return 23.111993172558684", 23.111993172558684, + StrictMath.cbrt(12345.6)); + assertEquals("Should return 5.643803094122362E102", + 5.643803094122362E102, StrictMath.cbrt(Double.MAX_VALUE)); + assertEquals("Should return 0.01", 0.01, StrictMath.cbrt(0.000001)); + + assertEquals("Should return -3.0", -3.0, StrictMath.cbrt(-27.0)); + assertEquals("Should return -23.111993172558684", -23.111993172558684, + StrictMath.cbrt(-12345.6)); + assertEquals("Should return 1.7031839360032603E-108", + 1.7031839360032603E-108, StrictMath.cbrt(Double.MIN_VALUE)); + assertEquals("Should return -0.01", -0.01, StrictMath.cbrt(-0.000001)); + + try { + StrictMath.cbrt((Double) null); + fail("Should throw NullPointerException"); + } catch (NullPointerException e) { + //expected + } + } + + /** + * @tests java.lang.StrictMath#ceil(double) + */ + @SmallTest + public void testCeilD() { + // Test for method double java.lang.StrictMath.ceil(double) + assertEquals("Incorrect ceiling for double", + 79, StrictMath.ceil(78.89), 0.0); + assertEquals("Incorrect ceiling for double", + -78, StrictMath.ceil(-78.89), 0.0); + } + + /** + * @tests java.lang.StrictMath#cos(double) + */ + @SmallTest + public void testCosD() { + // Test for method double java.lang.StrictMath.cos(double) + + assertTrue("Returned incorrect cosine", StrictMath.cos(StrictMath + .acos(ADJ / HYP)) == ADJ / HYP); + } + + /** + * @tests java.lang.StrictMath#cosh(double) + */ + @SuppressWarnings("boxing") + @SmallTest + public void testCosh_D() { + // Test for special situations + assertTrue("Should return NaN", Double.isNaN(StrictMath + .cosh(Double.NaN))); + assertEquals("Should return POSITIVE_INFINITY", + Double.POSITIVE_INFINITY, StrictMath + .cosh(Double.POSITIVE_INFINITY)); + assertEquals("Should return POSITIVE_INFINITY", + Double.POSITIVE_INFINITY, StrictMath + .cosh(Double.NEGATIVE_INFINITY)); + assertEquals("Should return 1.0", 1.0, StrictMath.cosh(+0.0)); + assertEquals("Should return 1.0", 1.0, StrictMath.cosh(-0.0)); + + assertEquals("Should return POSITIVE_INFINITY", + Double.POSITIVE_INFINITY, StrictMath.cosh(1234.56)); + assertEquals("Should return POSITIVE_INFINITY", + Double.POSITIVE_INFINITY, StrictMath.cosh(-1234.56)); + assertEquals("Should return 1.0000000000005", 1.0000000000005, + StrictMath.cosh(0.000001)); + assertEquals("Should return 1.0000000000005", 1.0000000000005, + StrictMath.cosh(-0.000001)); + assertEquals("Should return 5.212214351945598", 5.212214351945598, + StrictMath.cosh(2.33482)); + + assertEquals("Should return POSITIVE_INFINITY", + Double.POSITIVE_INFINITY, StrictMath.cosh(Double.MAX_VALUE)); + assertEquals("Should return 1.0", 1.0, StrictMath + .cosh(Double.MIN_VALUE)); + } + + /** + * @tests java.lang.StrictMath#exp(double) + */ + @SmallTest + public void testExpD() { + // Test for method double java.lang.StrictMath.exp(double) + assertTrue("Incorrect answer returned for simple power", StrictMath + .abs(StrictMath.exp(4D) - StrictMath.E * StrictMath.E + * StrictMath.E * StrictMath.E) < 0.1D); + assertTrue("Incorrect answer returned for larger power", StrictMath + .log(StrictMath.abs(StrictMath.exp(5.5D)) - 5.5D) < 10.0D); + } + + /** + * @tests java.lang.StrictMath#expm1(double) + */ + @SuppressWarnings("boxing") + @SmallTest + public void testExpm1D() { + //Test for special cases + assertTrue("Should return NaN", Double.isNaN(StrictMath.expm1(Double.NaN))); + assertEquals("Should return POSITIVE_INFINITY", + Double.POSITIVE_INFINITY, StrictMath.expm1(Double.POSITIVE_INFINITY)); + assertEquals("Should return -1.0", -1.0, StrictMath + .expm1(Double.NEGATIVE_INFINITY)); + assertEquals(Double.doubleToLongBits(0.0), Double + .doubleToLongBits(StrictMath.expm1(0.0))); + assertEquals(Double.doubleToLongBits(+0.0), Double + .doubleToLongBits(StrictMath.expm1(+0.0))); + assertEquals(Double.doubleToLongBits(-0.0), Double + .doubleToLongBits(StrictMath.expm1(-0.0))); + + assertEquals("Should return -9.999950000166666E-6", + -9.999950000166666E-6, StrictMath.expm1(-0.00001)); + assertEquals("Should return 1.0145103074469635E60", + 1.0145103074469635E60, StrictMath.expm1(138.16951162)); + assertEquals("Should return POSITIVE_INFINITY", + Double.POSITIVE_INFINITY, StrictMath + .expm1(123456789123456789123456789.4521584223)); + assertEquals("Should return POSITIVE_INFINITY", + Double.POSITIVE_INFINITY, StrictMath.expm1(Double.MAX_VALUE)); + assertEquals("Should return MIN_VALUE", Double.MIN_VALUE, StrictMath + .expm1(Double.MIN_VALUE)); + + } + + /** + * @tests java.lang.StrictMath#floor(double) + */ + @SmallTest + public void testFloorD() { + // Test for method double java.lang.StrictMath.floor(double) + assertEquals("Incorrect floor for double", + 78, StrictMath.floor(78.89), 0.0); + assertEquals("Incorrect floor for double", + -79, StrictMath.floor(-78.89), 0.0); + } + + /** + * @tests java.lang.StrictMath#hypot(double,double) + */ + @SuppressWarnings("boxing") + @SmallTest + public void testHypotDD() { + // Test for special cases + assertEquals("Should return POSITIVE_INFINITY", + Double.POSITIVE_INFINITY, StrictMath.hypot(Double.POSITIVE_INFINITY, + 1.0)); + assertEquals("Should return POSITIVE_INFINITY", + Double.POSITIVE_INFINITY, StrictMath.hypot(Double.NEGATIVE_INFINITY, + 123.324)); + assertEquals("Should return POSITIVE_INFINITY", + Double.POSITIVE_INFINITY, StrictMath.hypot(-758.2587, + Double.POSITIVE_INFINITY)); + assertEquals("Should return POSITIVE_INFINITY", + Double.POSITIVE_INFINITY, StrictMath.hypot(5687.21, + Double.NEGATIVE_INFINITY)); + assertEquals("Should return POSITIVE_INFINITY", + Double.POSITIVE_INFINITY, StrictMath.hypot(Double.POSITIVE_INFINITY, + Double.NEGATIVE_INFINITY)); + assertEquals("Should return POSITIVE_INFINITY", + Double.POSITIVE_INFINITY, StrictMath.hypot(Double.NEGATIVE_INFINITY, + Double.POSITIVE_INFINITY)); + assertTrue("Should return NaN", Double.isNaN(StrictMath.hypot(Double.NaN, + 2342301.89843))); + assertTrue("Should return NaN", Double.isNaN(StrictMath.hypot(-345.2680, + Double.NaN))); + + assertEquals("Should return 2396424.905416697", 2396424.905416697, StrictMath + .hypot(12322.12, -2396393.2258)); + assertEquals("Should return 138.16958070558556", 138.16958070558556, + StrictMath.hypot(-138.16951162, 0.13817035864)); + assertEquals("Should return 1.7976931348623157E308", + 1.7976931348623157E308, StrictMath.hypot(Double.MAX_VALUE, 211370.35)); + assertEquals("Should return 5413.7185", 5413.7185, StrictMath.hypot( + -5413.7185, Double.MIN_VALUE)); + + } + + /** + * @tests java.lang.StrictMath#IEEEremainder(double,double) + */ + @SmallTest + public void testIEEEremainderDD() { + // Test for method double java.lang.StrictMath.IEEEremainder(double, + // double) + assertEquals("Incorrect remainder returned", 0.0, StrictMath.IEEEremainder( + 1.0, 1.0), 0.0); + assertTrue( + "Incorrect remainder returned", + StrictMath.IEEEremainder(1.32, 89.765) >= 1.4705063220631647E-2 + || StrictMath.IEEEremainder(1.32, 89.765) >= 1.4705063220631649E-2); + } + + /** + * @tests java.lang.StrictMath#log(double) + */ + @SmallTest + public void testLogD() { + // Test for method double java.lang.StrictMath.log(double) + for (double d = 10; d >= -10; d -= 0.5) { + double answer = StrictMath.log(StrictMath.exp(d)); + assertTrue("Answer does not equal expected answer for d = " + d + + " answer = " + answer, + StrictMath.abs(answer - d) <= StrictMath + .abs(d * 0.00000001)); + } + } + + /** + * @tests java.lang.StrictMath#log10(double) + */ + @SuppressWarnings("boxing") + @SmallTest + public void testLog10D() { + // Test for special cases + assertTrue("Should return NaN", Double.isNaN(StrictMath + .log10(Double.NaN))); + assertTrue("Should return NaN", Double.isNaN(StrictMath + .log10(-2541.05745687234187532))); + assertEquals("Should return POSITIVE_INFINITY", + Double.POSITIVE_INFINITY, StrictMath + .log10(Double.POSITIVE_INFINITY)); + assertEquals("Should return NEGATIVE_INFINITY", + Double.NEGATIVE_INFINITY, StrictMath.log10(0.0)); + assertEquals("Should return NEGATIVE_INFINITY", + Double.NEGATIVE_INFINITY, StrictMath.log10(+0.0)); + assertEquals("Should return NEGATIVE_INFINITY", + Double.NEGATIVE_INFINITY, StrictMath.log10(-0.0)); + assertEquals("Should return 14.0", 14.0, StrictMath.log10(StrictMath + .pow(10, 14))); + + assertEquals("Should return 3.7389561269540406", 3.7389561269540406, + StrictMath.log10(5482.2158)); + assertEquals("Should return 14.661551142893833", 14.661551142893833, + StrictMath.log10(458723662312872.125782332587)); + assertEquals("Should return -0.9083828622192334", -0.9083828622192334, + StrictMath.log10(0.12348583358871)); + assertEquals("Should return 308.25471555991675", 308.25471555991675, + StrictMath.log10(Double.MAX_VALUE)); + assertEquals("Should return -323.3062153431158", -323.3062153431158, + StrictMath.log10(Double.MIN_VALUE)); + } + + /** + * @tests java.lang.StrictMath#log1p(double) + */ + @SuppressWarnings("boxing") + @SmallTest + public void testLog1pD() { + // Test for special cases + assertTrue("Should return NaN", Double.isNaN(StrictMath + .log1p(Double.NaN))); + assertTrue("Should return NaN", Double.isNaN(StrictMath + .log1p(-32.0482175))); + assertEquals("Should return POSITIVE_INFINITY", + Double.POSITIVE_INFINITY, StrictMath + .log1p(Double.POSITIVE_INFINITY)); + assertEquals(Double.doubleToLongBits(0.0), Double + .doubleToLongBits(StrictMath.log1p(0.0))); + assertEquals(Double.doubleToLongBits(+0.0), Double + .doubleToLongBits(StrictMath.log1p(+0.0))); + assertEquals(Double.doubleToLongBits(-0.0), Double + .doubleToLongBits(StrictMath.log1p(-0.0))); + + assertEquals("Should return -0.2941782295312541", -0.2941782295312541, + StrictMath.log1p(-0.254856327)); + assertEquals("Should return 7.368050685564151", 7.368050685564151, + StrictMath.log1p(1583.542)); + assertEquals("Should return 0.4633708685409921", 0.4633708685409921, + StrictMath.log1p(0.5894227)); + assertEquals("Should return 709.782712893384", 709.782712893384, + StrictMath.log1p(Double.MAX_VALUE)); + assertEquals("Should return Double.MIN_VALUE", Double.MIN_VALUE, + StrictMath.log1p(Double.MIN_VALUE)); + } + + /** + * @tests java.lang.StrictMath#max(double,double) + */ + @SmallTest + public void testMaxDD() { + // Test for method double java.lang.StrictMath.max(double, double) + assertEquals("Incorrect double max value", 1908897.6000089, StrictMath.max( + -1908897.6000089, 1908897.6000089), 0D); + assertEquals("Incorrect double max value", 1908897.6000089, StrictMath.max(2.0, + 1908897.6000089), 0D); + assertEquals("Incorrect double max value", -2.0, StrictMath.max(-2.0, + -1908897.6000089), 0D); + + } + + /** + * @tests java.lang.StrictMath#max(float,float) + */ + @SmallTest + public void testMaxFF() { + // Test for method float java.lang.StrictMath.max(float, float) + assertTrue("Incorrect float max value", StrictMath.max(-1908897.600f, + 1908897.600f) == 1908897.600f); + assertTrue("Incorrect float max value", StrictMath.max(2.0f, + 1908897.600f) == 1908897.600f); + assertTrue("Incorrect float max value", StrictMath.max(-2.0f, + -1908897.600f) == -2.0f); + } + + /** + * @tests java.lang.StrictMath#max(int,int) + */ + @SmallTest + public void testMaxII() { + // Test for method int java.lang.StrictMath.max(int, int) + assertEquals("Incorrect int max value", 19088976, StrictMath.max(-19088976, + 19088976)); + assertEquals("Incorrect int max value", + 19088976, StrictMath.max(20, 19088976)); + assertEquals("Incorrect int max value", + -20, StrictMath.max(-20, -19088976)); + } + + /** + * @tests java.lang.StrictMath#max(long,long) + */ + @SmallTest + public void testMaxJJ() { + // Test for method long java.lang.StrictMath.max(long, long) + assertEquals("Incorrect long max value", 19088976000089L, StrictMath.max(-19088976000089L, + 19088976000089L)); + assertEquals("Incorrect long max value", 19088976000089L, StrictMath.max(20, + 19088976000089L)); + assertEquals("Incorrect long max value", -20, StrictMath.max(-20, + -19088976000089L)); + } + + /** + * @tests java.lang.StrictMath#min(double,double) + */ + @SmallTest + public void testMinDD() { + // Test for method double java.lang.StrictMath.min(double, double) + assertEquals("Incorrect double min value", -1908897.6000089, StrictMath.min( + -1908897.6000089, 1908897.6000089), 0D); + assertEquals("Incorrect double min value", 2.0, StrictMath.min(2.0, + 1908897.6000089), 0D); + assertEquals("Incorrect double min value", -1908897.6000089, StrictMath.min(-2.0, + -1908897.6000089), 0D); + } + + /** + * @tests java.lang.StrictMath#min(float,float) + */ + @SmallTest + public void testMinFF() { + // Test for method float java.lang.StrictMath.min(float, float) + assertTrue("Incorrect float min value", StrictMath.min(-1908897.600f, + 1908897.600f) == -1908897.600f); + assertTrue("Incorrect float min value", StrictMath.min(2.0f, + 1908897.600f) == 2.0f); + assertTrue("Incorrect float min value", StrictMath.min(-2.0f, + -1908897.600f) == -1908897.600f); + } + + /** + * @tests java.lang.StrictMath#min(int,int) + */ + @SmallTest + public void testMinII() { + // Test for method int java.lang.StrictMath.min(int, int) + assertEquals("Incorrect int min value", -19088976, StrictMath.min(-19088976, + 19088976)); + assertEquals("Incorrect int min value", + 20, StrictMath.min(20, 19088976)); + assertEquals("Incorrect int min value", + -19088976, StrictMath.min(-20, -19088976)); + + } + + /** + * @tests java.lang.StrictMath#min(long,long) + */ + @SmallTest + public void testMinJJ() { + // Test for method long java.lang.StrictMath.min(long, long) + assertEquals("Incorrect long min value", -19088976000089L, StrictMath.min(-19088976000089L, + 19088976000089L)); + assertEquals("Incorrect long min value", 20, StrictMath.min(20, + 19088976000089L)); + assertEquals("Incorrect long min value", -19088976000089L, StrictMath.min(-20, + -19088976000089L)); + } + + /** + * @tests java.lang.StrictMath#pow(double,double) + */ + @SmallTest + public void testPowDD() { + // Test for method double java.lang.StrictMath.pow(double, double) + assertTrue("pow returned incorrect value", + (long) StrictMath.pow(2, 8) == 256l); + assertTrue("pow returned incorrect value", + StrictMath.pow(2, -8) == 0.00390625d); + } + + /** + * @tests java.lang.StrictMath#rint(double) + */ + @SmallTest + public void testRintD() { + // Test for method double java.lang.StrictMath.rint(double) + assertEquals("Failed to round properly - up to odd", + 3.0, StrictMath.rint(2.9), 0D); + assertTrue("Failed to round properly - NaN", Double.isNaN(StrictMath + .rint(Double.NaN))); + assertEquals("Failed to round properly down to even", 2.0, StrictMath + .rint(2.1), 0D); + assertTrue("Failed to round properly " + 2.5 + " to even", StrictMath + .rint(2.5) == 2.0); + } + + /** + * @tests java.lang.StrictMath#round(double) + */ + @SmallTest + public void testRoundD() { + // Test for method long java.lang.StrictMath.round(double) + assertEquals("Incorrect rounding of a float", + -91, StrictMath.round(-90.89d)); + } + + /** + * @tests java.lang.StrictMath#round(float) + */ + @SmallTest + public void testRoundF() { + // Test for method int java.lang.StrictMath.round(float) + assertEquals("Incorrect rounding of a float", + -91, StrictMath.round(-90.89f)); + } + + /** + * @tests java.lang.StrictMath#signum(double) + */ + @SmallTest + public void testSignumD() { + assertTrue(Double.isNaN(StrictMath.signum(Double.NaN))); + assertEquals(Double.doubleToLongBits(0.0), Double + .doubleToLongBits(StrictMath.signum(0.0))); + assertEquals(Double.doubleToLongBits(+0.0), Double + .doubleToLongBits(StrictMath.signum(+0.0))); + assertEquals(Double.doubleToLongBits(-0.0), Double + .doubleToLongBits(StrictMath.signum(-0.0))); + + assertEquals(1.0, StrictMath.signum(253681.2187962), 0D); + assertEquals(-1.0, StrictMath.signum(-125874693.56), 0D); + assertEquals(1.0, StrictMath.signum(1.2587E-308), 0D); + assertEquals(-1.0, StrictMath.signum(-1.2587E-308), 0D); + + assertEquals(1.0, StrictMath.signum(Double.MAX_VALUE), 0D); + assertEquals(1.0, StrictMath.signum(Double.MIN_VALUE), 0D); + assertEquals(-1.0, StrictMath.signum(-Double.MAX_VALUE), 0D); + assertEquals(-1.0, StrictMath.signum(-Double.MIN_VALUE), 0D); + assertEquals(1.0, StrictMath.signum(Double.POSITIVE_INFINITY), 0D); + assertEquals(-1.0, StrictMath.signum(Double.NEGATIVE_INFINITY), 0D); + + } + + /** + * @tests java.lang.StrictMath#signum(float) + */ + @SmallTest + public void testSignumF() { + assertTrue(Float.isNaN(StrictMath.signum(Float.NaN))); + assertEquals(Float.floatToIntBits(0.0f), Float + .floatToIntBits(StrictMath.signum(0.0f))); + assertEquals(Float.floatToIntBits(+0.0f), Float + .floatToIntBits(StrictMath.signum(+0.0f))); + assertEquals(Float.floatToIntBits(-0.0f), Float + .floatToIntBits(StrictMath.signum(-0.0f))); + + assertEquals(1.0f, StrictMath.signum(253681.2187962f), 0f); + assertEquals(-1.0f, StrictMath.signum(-125874693.56f), 0f); + assertEquals(1.0f, StrictMath.signum(1.2587E-11f), 0f); + assertEquals(-1.0f, StrictMath.signum(-1.2587E-11f), 0f); + + assertEquals(1.0f, StrictMath.signum(Float.MAX_VALUE), 0f); + assertEquals(1.0f, StrictMath.signum(Float.MIN_VALUE), 0f); + assertEquals(-1.0f, StrictMath.signum(-Float.MAX_VALUE), 0f); + assertEquals(-1.0f, StrictMath.signum(-Float.MIN_VALUE), 0f); + assertEquals(1.0f, StrictMath.signum(Float.POSITIVE_INFINITY), 0f); + assertEquals(-1.0f, StrictMath.signum(Float.NEGATIVE_INFINITY), 0f); + } + + /** + * @tests java.lang.StrictMath#sin(double) + */ + @SmallTest + public void testSinD() { + // Test for method double java.lang.StrictMath.sin(double) + assertTrue("Returned incorrect sine", StrictMath.sin(StrictMath + .asin(OPP / HYP)) == OPP / HYP); + } + + /** + * @tests java.lang.StrictMath#sinh(double) + */ + @SmallTest + public void testSinhD() { + // Test for special situations + assertTrue(Double.isNaN(StrictMath.sinh(Double.NaN))); + assertEquals("Should return POSITIVE_INFINITY", + Double.POSITIVE_INFINITY, StrictMath + .sinh(Double.POSITIVE_INFINITY), 0D); + assertEquals("Should return NEGATIVE_INFINITY", + Double.NEGATIVE_INFINITY, StrictMath + .sinh(Double.NEGATIVE_INFINITY), 0D); + assertEquals(Double.doubleToLongBits(0.0), Double + .doubleToLongBits(StrictMath.sinh(0.0))); + assertEquals(Double.doubleToLongBits(+0.0), Double + .doubleToLongBits(StrictMath.sinh(+0.0))); + assertEquals(Double.doubleToLongBits(-0.0), Double + .doubleToLongBits(StrictMath.sinh(-0.0))); + + assertEquals("Should return POSITIVE_INFINITY", + Double.POSITIVE_INFINITY, StrictMath.sinh(1234.56), 0D); + assertEquals("Should return NEGATIVE_INFINITY", + Double.NEGATIVE_INFINITY, StrictMath.sinh(-1234.56), 0D); + assertEquals("Should return 1.0000000000001666E-6", + 1.0000000000001666E-6, StrictMath.sinh(0.000001), 0D); + assertEquals("Should return -1.0000000000001666E-6", + -1.0000000000001666E-6, StrictMath.sinh(-0.000001), 0D); + assertEquals("Should return 5.115386441963859", 5.115386441963859, + StrictMath.sinh(2.33482), 0D); + assertEquals("Should return POSITIVE_INFINITY", + Double.POSITIVE_INFINITY, StrictMath.sinh(Double.MAX_VALUE), 0D); + assertEquals("Should return 4.9E-324", 4.9E-324, StrictMath + .sinh(Double.MIN_VALUE), 0D); + } + + /** + * @tests java.lang.StrictMath#sqrt(double) + */ + @SmallTest + public void testSqrtD() { + // Test for method double java.lang.StrictMath.sqrt(double) + assertEquals("Incorrect root returned1", + 2, StrictMath.sqrt(StrictMath.pow(StrictMath.sqrt(2), 4)), 0.0); + assertEquals("Incorrect root returned2", 7, StrictMath.sqrt(49), 0.0); + } + + /** + * @tests java.lang.StrictMath#tan(double) + */ + @SmallTest + public void testTanD() { + // Test for method double java.lang.StrictMath.tan(double) + assertTrue( + "Returned incorrect tangent: ", + StrictMath.tan(StrictMath.atan(1.0)) <= 1.0 + || StrictMath.tan(StrictMath.atan(1.0)) >= 9.9999999999999983E-1); + } + + /** + * @tests java.lang.StrictMath#tanh(double) + */ + @SmallTest + public void testTanhD() { + // Test for special situations + assertTrue(Double.isNaN(StrictMath.tanh(Double.NaN))); + assertEquals("Should return +1.0", +1.0, StrictMath + .tanh(Double.POSITIVE_INFINITY), 0D); + assertEquals("Should return -1.0", -1.0, StrictMath + .tanh(Double.NEGATIVE_INFINITY), 0D); + assertEquals(Double.doubleToLongBits(0.0), Double + .doubleToLongBits(StrictMath.tanh(0.0))); + assertEquals(Double.doubleToLongBits(+0.0), Double + .doubleToLongBits(StrictMath.tanh(+0.0))); + assertEquals(Double.doubleToLongBits(-0.0), Double + .doubleToLongBits(StrictMath.tanh(-0.0))); + + assertEquals("Should return 1.0", 1.0, StrictMath.tanh(1234.56), 0D); + assertEquals("Should return -1.0", -1.0, StrictMath.tanh(-1234.56), 0D); + assertEquals("Should return 9.999999999996666E-7", + 9.999999999996666E-7, StrictMath.tanh(0.000001), 0D); + assertEquals("Should return 0.981422884124941", 0.981422884124941, + StrictMath.tanh(2.33482), 0D); + assertEquals("Should return 1.0", 1.0, StrictMath + .tanh(Double.MAX_VALUE), 0D); + assertEquals("Should return 4.9E-324", 4.9E-324, StrictMath + .tanh(Double.MIN_VALUE), 0D); + } + + /** + * @tests java.lang.StrictMath#random() + */ + @MediumTest + public void testRandom() { + // There isn't a place for these tests so just stick them here + assertEquals("Wrong value E", + 4613303445314885481L, Double.doubleToLongBits(StrictMath.E)); + assertEquals("Wrong value PI", + 4614256656552045848L, Double.doubleToLongBits(StrictMath.PI)); + + for (int i = 500; i >= 0; i--) { + double d = StrictMath.random(); + assertTrue("Generated number is out of range: " + d, d >= 0.0 + && d < 1.0); + } + } + + /** + * @tests java.lang.StrictMath#toRadians(double) + */ + @MediumTest + public void testToRadiansD() { + for (double d = 500; d >= 0; d -= 1.0) { + double converted = StrictMath.toDegrees(StrictMath.toRadians(d)); + assertTrue("Converted number not equal to original. d = " + d, + converted >= d * 0.99999999 && converted <= d * 1.00000001); + } + } + + /** + * @tests java.lang.StrictMath#toDegrees(double) + */ + @MediumTest + public void testToDegreesD() { + for (double d = 500; d >= 0; d -= 1.0) { + double converted = StrictMath.toRadians(StrictMath.toDegrees(d)); + assertTrue("Converted number not equal to original. d = " + d, + converted >= d * 0.99999999 && converted <= d * 1.00000001); + } + } + + /** + * @tests java.lang.StrictMath#ulp(double) + */ + @SuppressWarnings("boxing") + @SmallTest + public void testUlp_D() { + // Test for special cases + assertTrue("Should return NaN", Double + .isNaN(StrictMath.ulp(Double.NaN))); + assertEquals("Returned incorrect value", Double.POSITIVE_INFINITY, + StrictMath.ulp(Double.POSITIVE_INFINITY), 0D); + assertEquals("Returned incorrect value", Double.POSITIVE_INFINITY, + StrictMath.ulp(Double.NEGATIVE_INFINITY), 0D); + assertEquals("Returned incorrect value", Double.MIN_VALUE, StrictMath + .ulp(0.0), 0D); + assertEquals("Returned incorrect value", Double.MIN_VALUE, StrictMath + .ulp(+0.0), 0D); + assertEquals("Returned incorrect value", Double.MIN_VALUE, StrictMath + .ulp(-0.0), 0D); + assertEquals("Returned incorrect value", StrictMath.pow(2, 971), + StrictMath.ulp(Double.MAX_VALUE), 0D); + assertEquals("Returned incorrect value", StrictMath.pow(2, 971), + StrictMath.ulp(-Double.MAX_VALUE), 0D); + + assertEquals("Returned incorrect value", Double.MIN_VALUE, StrictMath + .ulp(Double.MIN_VALUE), 0D); + assertEquals("Returned incorrect value", Double.MIN_VALUE, StrictMath + .ulp(-Double.MIN_VALUE), 0D); + + assertEquals("Returned incorrect value", 2.220446049250313E-16, + StrictMath.ulp(1.0), 0D); + assertEquals("Returned incorrect value", 2.220446049250313E-16, + StrictMath.ulp(-1.0), 0D); + assertEquals("Returned incorrect value", 2.2737367544323206E-13, + StrictMath.ulp(1153.0), 0D); + } + + /** + * @tests java.lang.StrictMath#ulp(float) + */ + @SuppressWarnings("boxing") + @SmallTest + public void testUlpF() { + // Test for special cases + assertTrue("Should return NaN", Float.isNaN(StrictMath.ulp(Float.NaN))); + assertEquals("Returned incorrect value", Float.POSITIVE_INFINITY, + StrictMath.ulp(Float.POSITIVE_INFINITY), 0f); + assertEquals("Returned incorrect value", Float.POSITIVE_INFINITY, + StrictMath.ulp(Float.NEGATIVE_INFINITY), 0f); + assertEquals("Returned incorrect value", Float.MIN_VALUE, StrictMath + .ulp(0.0f), 0f); + assertEquals("Returned incorrect value", Float.MIN_VALUE, StrictMath + .ulp(+0.0f), 0f); + assertEquals("Returned incorrect value", Float.MIN_VALUE, StrictMath + .ulp(-0.0f), 0f); + assertEquals("Returned incorrect value", 2.028241E31f, StrictMath + .ulp(Float.MAX_VALUE), 0f); + assertEquals("Returned incorrect value", 2.028241E31f, StrictMath + .ulp(-Float.MAX_VALUE), 0f); + + assertEquals("Returned incorrect value", 1.4E-45f, StrictMath + .ulp(Float.MIN_VALUE), 0f); + assertEquals("Returned incorrect value", 1.4E-45f, StrictMath + .ulp(-Float.MIN_VALUE), 0f); + + assertEquals("Returned incorrect value", 1.1920929E-7f, StrictMath + .ulp(1.0f), 0f); + assertEquals("Returned incorrect value", 1.1920929E-7f, StrictMath + .ulp(-1.0f), 0f); + assertEquals("Returned incorrect value", 1.2207031E-4f, StrictMath + .ulp(1153.0f), 0f); + assertEquals("Returned incorrect value", 5.6E-45f, Math + .ulp(9.403954E-38f), 0f); + } +} diff --git a/tests/CoreTests/android/core/StringReaderTest.java b/tests/CoreTests/android/core/StringReaderTest.java new file mode 100644 index 0000000000000000000000000000000000000000..66b3e8141389da50b5406a4d25d4297bc21b4310 --- /dev/null +++ b/tests/CoreTests/android/core/StringReaderTest.java @@ -0,0 +1,40 @@ +/* + * 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 android.core; + +import junit.framework.TestCase; + +import java.io.StringReader; +import android.test.suitebuilder.annotation.SmallTest; + +public class StringReaderTest extends TestCase { + + @SmallTest + public void testStringReader() throws Exception { + String str = "AbCdEfGhIjKlMnOpQrStUvWxYz"; + + StringReader a = new StringReader(str); + StringReader b = new StringReader(str); + StringReader c = new StringReader(str); + StringReader d = new StringReader(str); + + assertEquals(str, IOUtil.read(a)); + assertEquals("AbCdEfGhIj", IOUtil.read(b, 10)); + assertEquals("bdfhjlnprtvxz", IOUtil.skipRead(c)); + assertEquals("AbCdEfGdEfGhIjKlMnOpQrStUvWxYz", IOUtil.markRead(d, 3, 4)); + } +} diff --git a/tests/CoreTests/android/core/StringTest.java b/tests/CoreTests/android/core/StringTest.java new file mode 100644 index 0000000000000000000000000000000000000000..957dd40f94fa98672c0a4c85088d2bec59873988 --- /dev/null +++ b/tests/CoreTests/android/core/StringTest.java @@ -0,0 +1,149 @@ +/* + * 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 android.core; + +import com.ibm.icu4jni.text.RuleBasedNumberFormat; +import com.ibm.icu4jni.text.RuleBasedNumberFormat.RBNFType; + +import junit.framework.TestCase; +import android.test.suitebuilder.annotation.SmallTest; + +/** + * Some String tests. + */ +public class StringTest extends TestCase { + private String germanSpelloutRule = "%alt-ones:" + + " -x: minus >>;" + + " x.x: << komma >>;" + + " null; eins; =%%main=;" + + "%%main:" + + " null; ein; zwei; drei; vier; f\u00fcnf; sechs; sieben; acht; neun;\n" + + " zehn; elf; zwu00f6lf; >>zehn;" + + " 20: [>>und]zwanzig;" + + " 30: [>>und]dreiu00dfig;" + + " 40: [>>und]vierzig;" + + " 50: [>>und]fu00fcnfzig;" + + " 60: [>>und]sechzig;" + + " 70: [>>und]siebzig;" + + " 80: [>>und]achtzig;" + + " 90: [>>und]neunzig;" + + " 100: hundert[>%alt-ones>];" + + " 200: <%alt-ones>];" + + " 1000: tausend[>%alt-ones>];" + + " 1100: tausendein[>%alt-ones>];" + + " 1200: tausend[>%alt-ones>];" + + " 2000: <%alt-ones>];"; + + @SmallTest + public void testString() throws Exception { + String test = "0123456789"; + String test1 = new String("0123456789"); // different object + String test2 = new String("0123456780"); // different value + String offset = new String("xxx0123456789yyy"); + String sub = offset.substring(3, 13); + + assertEquals(test, test); + assertEquals(test, test1); + assertFalse(test.equals(test2)); + + assertEquals(0, test.compareTo(test1)); + assertTrue(test1.compareTo(test2) > 0); + assertTrue(test2.compareTo(test1) < 0); + + /* compare string with a nonzero offset, in left/right side */ + assertEquals(0, test.compareTo(sub)); + assertEquals(0, sub.compareTo(test)); + assertEquals(test, sub); + assertEquals(sub, test); + /* same base, one is a substring */ + assertFalse(offset.equals(sub)); + assertFalse(sub.equals(offset)); + /* wrong class */ + assertFalse(test.equals(this)); + + /* null ptr - throw */ + try { + test.compareTo(null); + fail("didn't get expected npe"); + } catch (NullPointerException npe) { + // expected + } + /* null ptr - ok */ + assertFalse(test.equals(null)); + + test = test.substring(1); + assertEquals("123456789", test); + assertFalse(test.equals(test1)); + + test = test.substring(1); + assertEquals("23456789", test); + + test = test.substring(1); + assertEquals("3456789", test); + + test = test.substring(1); + assertEquals("456789", test); + + test = test.substring(3, 5); + assertEquals("78", test); + + test = "this/is/a/path"; + String[] strings = test.split("/"); + assertEquals(4, strings.length); + + assertEquals("this is a path", test.replaceAll("/", " ")); + assertEquals("this is a path", test.replace("/", " ")); + + assertEquals(0, "abc".compareToIgnoreCase("ABC")); + assertTrue("abc".compareToIgnoreCase("DEF") < 0); + assertTrue("ABC".compareToIgnoreCase("def") < 0); + assertTrue("Now".compareTo("Mow") > 0); + assertTrue("Now".compareToIgnoreCase("Mow") > 0); + + // RuleBasedNumberFormnat tests + RuleBasedNumberFormat format = new RuleBasedNumberFormat(); + format.open(RBNFType.SPELLOUT); + String result = format.format(15); + assertEquals("Expected spellout format: 'fifteen' but was " + + result, "fifteen", result); + format.close(); + + format.open(RBNFType.DURATION); + result = format.format(15); + assertEquals("Expected spellout format: '15 sec.' but was " + + result, "15 sec.", result); + format.close(); + + format.open(RBNFType.ORDINAL); + result = format.format(15); + assertEquals("Expected spellout format: '15th' but was " + + result, "15th", result); + format.close(); + format.open(germanSpelloutRule); + + result = format.format(1323); + assertEquals("Expected spellout format: 'tausenddrei" + + "hundertdreiundzwanzig' but was " + result, "tausend" + + "dreihundertdreiundzwanzig", result); + int res = format.parse("tausenddreihundertdreiundzwanzig") + .intValue(); + assertEquals("Expected spellout format: 'tausend" + + "dreihundertdreiundzwanzig' but was " + res , 1323, res); + format.close(); + } +} + diff --git a/tests/CoreTests/android/core/StringWriterTest.java b/tests/CoreTests/android/core/StringWriterTest.java new file mode 100644 index 0000000000000000000000000000000000000000..fed2221ea00db48bee2c62483d87fdca440a14ac --- /dev/null +++ b/tests/CoreTests/android/core/StringWriterTest.java @@ -0,0 +1,42 @@ +/* + * 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 android.core; + +import junit.framework.TestCase; + +import java.io.StringWriter; +import android.test.suitebuilder.annotation.SmallTest; + +public class StringWriterTest extends TestCase { + + @SmallTest + public void testStringWriter() throws Exception { + String str = "AbCdEfGhIjKlMnOpQrStUvWxYz"; + StringWriter a = new StringWriter(10); + + a.write(str, 0, 26); + a.write('X'); + + assertEquals("AbCdEfGhIjKlMnOpQrStUvWxYzX", a.toString()); + + a.write("alphabravodelta", 5, 5); + a.append('X'); + assertEquals("AbCdEfGhIjKlMnOpQrStUvWxYzXbravoX", a.toString()); + a.append("omega"); + assertEquals("AbCdEfGhIjKlMnOpQrStUvWxYzXbravoXomega", a.toString()); + } +} diff --git a/tests/CoreTests/android/core/TestEventHandler.java b/tests/CoreTests/android/core/TestEventHandler.java new file mode 100644 index 0000000000000000000000000000000000000000..4cfcadeaca997eee833f71e3df746c508b228522 --- /dev/null +++ b/tests/CoreTests/android/core/TestEventHandler.java @@ -0,0 +1,811 @@ +/* + * Copyright (C) 2007 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 android.core; + +import java.util.ArrayList; +import java.util.Map; + +import org.apache.http.protocol.HTTP; +import android.util.Log; +import android.util.Config; +import android.net.http.*; + +/** + * Implements EventHandler and provides test functionality to validate + * responses to requests from the test server + */ +public class TestEventHandler implements EventHandler { + + /** + * Status variables + */ + private int majorVersion = -1; + private int minorVersion = -1; + private int responseCode = -1; + private String reasonPhrase; + + /* List of headers received */ + private Map headerMap; + + /* Used to sync low level delayed requests */ + public static final Object syncObj = new Object(); + + /* Indicates whether the low level request testing is in operation */ + private boolean useLowLevel = false; + + /* Indicates whether responses should be automatically generated or + * delayed + */ + private boolean delayResponse = false; + + /* Test method expectation identifiers */ + public final static int TEST_REQUEST_SENT = 0; + public final static int TEST_STATUS = 1; + public final static int TEST_HEADERS = 2; + public final static int TEST_LOCATION_CHANGED = 3; + public final static int TEST_DATA = 4; + public final static int TEST_ENDDATA = 5; + public final static int TEST_ERROR = 6; + public final static int TEST_SSL_CERTIFICATE_ERROR = 7; + + public final static int TEST_NUM_EXPECTS = 8; + + /* Expected status codes */ + private int expectMajor = -1; + private int expectMinor = -1; + private int expectCode = -1; + + /* Array indicating which event types are expected */ + private boolean[] expects = new boolean[TEST_NUM_EXPECTS]; + + /* Array indicating which event types are not expected */ + private boolean[] notExpecting = new boolean[TEST_NUM_EXPECTS]; + + /* Indicates which events have been received */ + private boolean[] eventsReceived = new boolean[TEST_NUM_EXPECTS]; + + /* Redirection variables */ + private String expectLocation; + private int expectPermanent = -1; + + /* Content data expected to be received */ + private byte[] expectData; + private int expectDataLength = -1; + + private int expectErrorId = -1; + + private int expectSslErrors = -1; + private SslCertificate expectCertificate; + + public class TestHeader { + public TestHeader(String n, String v) { + name = n; + value = v; + } + public String name; + public String value; + } + + private ArrayList expectHeaders = new ArrayList(); + + /* Holds failure details */ + private StringBuffer expectDetails = new StringBuffer(); + + /* If we use a request handle, we retain a reference here for redirects + * using setupRedirect + */ + private RequestHandle mRequestHandle; + + /* The low level API uses this reference also for non-delayed requests */ + private LowLevelNetRunner netRunner; + + public TestEventHandler() { + for (int i = 0; i < TEST_NUM_EXPECTS; i++) { + expects[i] = false; + notExpecting[i] = false; + eventsReceived[i] = false; + } + } + + /** + * Implementation of EventHandler method called when a request has been + * sent. If the test is waiting for this call, it will be signalled, + * otherwise this method will trigger the response to be read + * automatically. + */ + public void requestSent() { + Log.v(LOGTAG, "TestEventHandler:requestSent()"); + expects[TEST_REQUEST_SENT] = false; + eventsReceived[TEST_REQUEST_SENT] = true; + if (notExpecting[TEST_REQUEST_SENT]) { + expectDetails.append("Request sent event received but not expected"); + expectDetails.append("\r\n"); + } + + if (useLowLevel) { + if (delayResponse) { + synchronized (syncObj) { + syncObj.notifyAll(); + } + } else { + // mRequest.startReadingResponse(); + } + } + } + + /** + * Implements the EventHandler status method called when a server status + * response is received. + * @param major_version The HTTP major version + * @param minor_version The HTTP minor version + * @param code The status code + * @param reason_phrase A reason phrase passed to us by the server + */ + public void status(int major_version, int minor_version, + int code, String reason_phrase) { + if (Config.LOGV) { + Log.v(LOGTAG, "TestEventHandler:status() major: " + major_version + + " minor: " + minor_version + + " code: " + code + + " reason: " + reason_phrase); + } + + eventsReceived[TEST_STATUS] = true; + if (notExpecting[TEST_STATUS]) { + expectDetails.append("Status event received but not expected"); + expectDetails.append("\r\n"); + } + + majorVersion = major_version; + minorVersion = minor_version; + responseCode = code; + reasonPhrase = reason_phrase; + + if (expectMajor != -1) { + if (expectMajor == major_version) { + expectMajor = -1; + } else { + expectDetails.append("Major version expected:"+expectMajor+ + " got:"+major_version); + expectDetails.append("\r\n"); + } + } + + if (expectMinor != -1) { + if (expectMinor == minor_version) { + expectMinor = -1; + } else { + expectDetails.append("Minor version expected:"+expectMinor+ + " got:"+minor_version); + expectDetails.append("\r\n"); + } + } + + if (expectCode != -1) { + if (expectCode == code) { + expectCode = -1; + } else { + expectDetails.append("Status code expected:"+expectCode+ + " got:"+code); + expectDetails.append("\r\n"); + } + } + + + if ((expectMajor == -1) && (expectMinor == -1) && (expectCode == -1)) { + expects[TEST_STATUS] = false; + } else { + System.out.println("MAJOR = "+expectMajor+" MINOR = "+expectMinor+ + " CODE = "+expectCode); + } + } + + /** + * Implements the EventHandler headers method called when a server + * sends header fields + */ + public void headers(Headers headers) { + if (Config.LOGV) { + Log.v(LOGTAG, "TestEventHandler:headers()"); + } + expects[TEST_HEADERS] = false; + + if (notExpecting[TEST_HEADERS]) { + expectDetails.append("Header event received but not expected"); + expectDetails.append("\r\n"); + } + + /* Check through headers received for matches with expected + * headers */ + if (expectHeaders.isEmpty()) { + return; + } + + for (int i = expectHeaders.size() - 1; i >= 0; i--) { + TestHeader h = expectHeaders.get(i); + System.out.println("Expected header name: " + h.name); + String s = null; + switch (h.name.hashCode()) { + case -1132779846: + s = Long.toString(headers.getContentLength()); + break; + case 785670158: + s = headers.getContentType(); + break; + case 2095084583: + s = headers.getContentEncoding(); + break; + case 1901043637: + s = headers.getLocation(); + break; + case -243037365: + s = headers.getWwwAuthenticate(); + break; + case -301767724: + s = headers.getProxyAuthenticate(); + break; + case -1267267485: + s = headers.getContentDisposition(); + break; + case 1397189435: + s = headers.getAcceptRanges(); + break; + case -1309235404: + s = headers.getExpires(); + break; + case -208775662: + s = headers.getCacheControl(); + break; + case 150043680: + s = headers.getLastModified(); + break; + case 3123477: + s = headers.getEtag(); + break; + case -775651618: + int ct = headers.getConnectionType(); + if (ct == Headers.CONN_CLOSE) { + s = HTTP.CONN_CLOSE; + } else if (ct == Headers.CONN_KEEP_ALIVE) { + s = HTTP.CONN_KEEP_ALIVE; + } + break; + default: + s = null; + + } + if (evaluateHeader(h, s)) { + expectHeaders.remove(i); + } + } + + } + + public boolean evaluateHeader(TestHeader h, String value) { + if (value == null) { + expects[TEST_HEADERS] = true; + System.out.print(" Missing! "); + expectDetails.append(" missing header " + h.name); + return false; + } + if (h.value == null) { + System.out.println("Expect value = null"); + return true; + } + System.out.println("Expect value = " + + (h.value.toLowerCase()) + " got " + + value.toLowerCase()); + + if (!h.value.equalsIgnoreCase(value)) { + expectDetails.append("expect header value " + h.value + + " got " + value); + expects[TEST_HEADERS] = true; + return false; + } + return true; + } + /** + * Implements the EventHandler locationChanged method called when a server + * sends a redirect message + * @param newLocation The URL to the new server + * @param permanent Indicator of whether this is a permanent change + */ + public void locationChanged(String newLocation, boolean permanent) { + if (Config.LOGV) { + Log.v(LOGTAG, "TestEventHandler: locationChanged() " + + newLocation + " permanent " + permanent); + } + + eventsReceived[TEST_LOCATION_CHANGED] = true; + if (notExpecting[TEST_LOCATION_CHANGED]) { + expectDetails.append("Location changed event received but "+ + "not expected"); + expectDetails.append("\r\n"); + } + + if (expectLocation != null) { + if (expectLocation.equals(newLocation)) { + expectLocation = null; + } else { + expectDetails.append("Location expected:"+expectLocation+ + " got:"+newLocation); + expectDetails.append("\r\n"); + } + } + + if (expectPermanent != -1) { + if (((expectPermanent == 0) && !permanent) || + ((expectPermanent == 1) && permanent)){ + expectPermanent = -1; + } else { + expectDetails.append("Location permanent expected:"+ + expectPermanent+" got"+permanent); + expectDetails.append("\r\n"); + } + } + + if ((expectLocation == null) && (expectPermanent == -1)) + expects[TEST_LOCATION_CHANGED] = false; + } + + /** + * Implements the EventHandler data method called when a server + * sends content data + * @param data The byte array content + * @param len The length of the data + */ + public void data(byte[] data, int len) { + boolean mismatch = false; + + if (Config.LOGV) { + Log.v(LOGTAG, "TestEventHandler: data() " + len + " bytes"); + } + + eventsReceived[TEST_DATA] = true; + if (notExpecting[TEST_DATA]) { + expectDetails.append("Data event received but not expected"); + expectDetails.append("\r\n"); + } + + Log.v(LOGTAG, new String(data, 0, len)); + + if (expectDataLength != -1) { + if (expectDataLength == len) { + expectDataLength = -1; + } else { + expectDetails.append("expect data length mismatch expected:"+ + expectDataLength+" got:"+len); + expectDetails.append("\r\n"); + } + + /* Check data only if length is the same */ + if ((expectDataLength == -1) && expectData != null) { + for (int i = 0; i < len; i++) { + if (expectData[i] != data[i]) { + mismatch = true; + expectDetails.append("Expect data mismatch at byte "+ + i+" expected:"+expectData[i]+" got:"+data[i]); + expectDetails.append("\r\n"); + break; + } + } + } + } + + if ((expectDataLength == -1) || !mismatch) + expects[TEST_DATA] = false; + } + + /** + * Implements the EventHandler endData method called to + * indicate completion or a request + */ + public void endData() { + if (Config.LOGV) { + Log.v(LOGTAG, "TestEventHandler: endData() called"); + } + + eventsReceived[TEST_ENDDATA] = true; + if (notExpecting[TEST_ENDDATA]) { + expectDetails.append("End data event received but not expected"); + expectDetails.append("\r\n"); + } + + expects[TEST_ENDDATA] = false; + + if (useLowLevel) { + if (delayResponse) { + synchronized (syncObj) { + syncObj.notifyAll(); + } + } else { + if (netRunner != null) { + System.out.println("TestEventHandler: endData() stopping "+ + netRunner); + netRunner.decrementRunCount(); + } + } + } + } + + /** + * Implements the EventHandler certificate method called every + * time a resource is loaded via a secure connection + */ + public void certificate(SslCertificate certificate) {} + + /** + * Implements the EventHandler error method called when a server + * sends header fields + * @param id Status code of the error + * @param description Brief description of the error + */ + public void error(int id, String description) { + if (Config.LOGV) { + Log.v(LOGTAG, "TestEventHandler: error() called Id:" + id + + " description " + description); + } + + eventsReceived[TEST_ERROR] = true; + if (notExpecting[TEST_ERROR]) { + expectDetails.append("Error event received but not expected"); + expectDetails.append("\r\n"); + } + if (expectErrorId != -1) { + if (expectErrorId == id) { + expectErrorId = -1; + } else { + expectDetails.append("Error Id expected:"+expectErrorId+ + " got:"+id); + expectDetails.append("\r\n"); + } + } + + if (expectErrorId == -1) + expects[TEST_ERROR] = false; + + if (useLowLevel) { + if (delayResponse) { + synchronized (syncObj) { + syncObj.notifyAll(); + } + } else { + if (netRunner != null) { + System.out.println("TestEventHandler: endData() stopping "+ + netRunner); + netRunner.decrementRunCount(); + } + } + } + } + + /** + * SSL certificate error callback. Handles SSL error(s) on the way + * up to the user. + */ + public void handleSslErrorRequest(SslError error) { + int primaryError = error.getPrimaryError(); + + if (Config.LOGV) { + Log.v(LOGTAG, "TestEventHandler: handleSslErrorRequest(): "+ + " primary error:" + primaryError + + " certificate: " + error.getCertificate()); + } + + eventsReceived[TEST_SSL_CERTIFICATE_ERROR] = true; + if (notExpecting[TEST_SSL_CERTIFICATE_ERROR]) { + expectDetails.append("SSL Certificate error event received "+ + "but not expected"); + expectDetails.append("\r\n"); + } + + if (expectSslErrors != -1) { + if (expectSslErrors == primaryError) { + expectSslErrors = -1; + } else { + expectDetails.append("SslCertificateError id expected:"+ + expectSslErrors+" got: " + primaryError); + expectDetails.append("\r\n"); + } + } + + // SslCertificate match here? + + if (expectSslErrors == -1) // && expectSslCertificate == certificate? + expects[TEST_SSL_CERTIFICATE_ERROR] = false; + } + + /** + * Use the low level net runner with no delayed response + * @param runner The LowLevelNetRunner object + */ + public void setNetRunner(LowLevelNetRunner runner) { + setNetRunner(runner, false); + } + + /** + * Use the low level net runner and specify if the response + * should be delayed + * @param runner The LowLevelNetRunner object + * @param delayedResponse Set to true is you will use the + * waitForRequestSent/waitForRequestResponse routines + */ + public void setNetRunner(LowLevelNetRunner runner, + boolean delayedResponse) { + netRunner = runner; + useLowLevel = true; + delayResponse = delayedResponse; + + if (!delayResponse) + netRunner.incrementRunCount(); + } + + /** + * Enable this listeners Request object to read server responses. + * This should only be used in conjunction with setDelayResponse(true) + */ + public void waitForRequestResponse() { + if (!delayResponse || !useLowLevel) { + Log.d(LOGTAG, " Cant do this without delayReponse set "); + return; + } + + //if (mRequest != null) { + // mRequest.startReadingResponse(); + // } + /* Now wait for the response to be completed either through endData + * or an error + */ + synchronized (syncObj) { + try { + syncObj.wait(); + } catch (InterruptedException e) { + } + } + } + + /** + * Enable this listeners Request object to read server responses. + * This should only be used in conjunction with setDelayResponse(true) + */ + public void waitForRequestSent() { + if (!delayResponse || !useLowLevel) { + Log.d(LOGTAG, " Cant do this without delayReponse set "); + return; + } + + /* Now wait for the response to be completed either through endData + * or an error + */ + synchronized (syncObj) { + try { + syncObj.wait(); + } catch (InterruptedException e) { + } + } + } + + /* Test expected values - these routines set the tests expectations */ + + public void expectRequestSent() { + expects[TEST_REQUEST_SENT] = true; + } + + public void expectNoRequestSent() { + notExpecting[TEST_REQUEST_SENT] = true; + } + + public void expectStatus() { + expects[TEST_STATUS] = true; + } + + public void expectNoStatus() { + notExpecting[TEST_STATUS] = true; + } + + public void expectStatus(int major, int minor, int code) { + expects[TEST_STATUS] = true; + expectMajor = major; + expectMinor = minor; + expectCode = code; + } + + public void expectStatus(int code) { + expects[TEST_STATUS] = true; + expectCode = code; + } + + public void expectHeaders() { + expects[TEST_HEADERS] = true; + } + + public void expectNoHeaders() { + notExpecting[TEST_HEADERS] = true; + } + + public void expectHeaderAdd(String name) { + expects[TEST_HEADERS] = true; + TestHeader h = new TestHeader(name.toLowerCase(), null); + expectHeaders.add(h); + } + + public void expectHeaderAdd(String name, String value) { + expects[TEST_HEADERS] = true; + TestHeader h = new TestHeader(name.toLowerCase(), value); + expectHeaders.add(h); + } + + public void expectLocationChanged() { + expects[TEST_LOCATION_CHANGED] = true; + } + + public void expectNoLocationChanged() { + notExpecting[TEST_LOCATION_CHANGED] = true; + } + + public void expectLocationChanged(String newLocation) { + expects[TEST_LOCATION_CHANGED] = true; + expectLocation = newLocation; + } + + public void expectLocationChanged(String newLocation, boolean permanent) { + expects[TEST_LOCATION_CHANGED] = true; + expectLocation = newLocation; + expectPermanent = permanent ? 1 : 0; + } + + public void expectData() { + expects[TEST_DATA] = true; + } + + public void expectNoData() { + notExpecting[TEST_DATA] = true; + } + + public void expectData(int len) { + expects[TEST_DATA] = true; + expectDataLength = len; + } + + public void expectData(byte[] data, int len) { + expects[TEST_DATA] = true; + expectData = new byte[len]; + expectDataLength = len; + + for (int i = 0; i < len; i++) { + expectData[i] = data[i]; + } + } + + public void expectEndData() { + expects[TEST_ENDDATA] = true; + } + + public void expectNoEndData() { + notExpecting[TEST_ENDDATA] = true; + } + + public void expectError() { + expects[TEST_ERROR] = true; + } + + public void expectNoError() { + notExpecting[TEST_ERROR] = true; + } + + public void expectError(int errorId) { + expects[TEST_ERROR] = true; + expectErrorId = errorId; + } + + public void expectSSLCertificateError() { + expects[TEST_SSL_CERTIFICATE_ERROR] = true; + } + + public void expectNoSSLCertificateError() { + notExpecting[TEST_SSL_CERTIFICATE_ERROR] = true; + } + + public void expectSSLCertificateError(int errors) { + expects[TEST_SSL_CERTIFICATE_ERROR] = true; + expectSslErrors = errors; + } + + public void expectSSLCertificateError(SslCertificate certificate) { + expects[TEST_SSL_CERTIFICATE_ERROR] = true; + expectCertificate = certificate; + } + + /** + * Test to see if current expectations match recieved information + * @return True is all expected results have been matched + */ + public boolean expectPassed() { + for (int i = 0; i < TEST_NUM_EXPECTS; i++) { + if (expects[i] == true) { + return false; + } + } + + for (int i = 0; i < TEST_NUM_EXPECTS; i++) { + if (eventsReceived[i] && notExpecting[i]) { + return false; + } + } + return true; + } + + /** + * Return message indicating expectation failures + */ + public String getFailureMessage() { + return expectDetails.toString(); + } + + /** + * Reset all expectation values for re-use + */ + public void resetExpects() { + expectMajor = -1; + expectMinor = -1; + expectCode = -1; + expectLocation = null; + expectPermanent = -1; + expectErrorId = -1; + expectSslErrors = -1; + expectCertificate = null; + expectDetails.setLength(0); + expectHeaders.clear(); + + for (int i = 0; i < TEST_NUM_EXPECTS; i++) { + expects[i] = false; + notExpecting[i] = false; + eventsReceived[i] = false; + } + + for (int i = 0; i < expectDataLength; i++) { + expectData[i] = 0; + } + + expectDataLength = -1; + } + + /** + * Attach the RequestHandle to this handler + * @param requestHandle The RequestHandle + */ + public void attachRequestHandle(RequestHandle requestHandle) { + if (Config.LOGV) { + Log.v(LOGTAG, "TestEventHandler.attachRequestHandle(): " + + "requestHandle: " + requestHandle); + } + mRequestHandle = requestHandle; + } + + /** + * Detach the RequestHandle + */ + public void detachRequestHandle() { + if (Config.LOGV) { + Log.v(LOGTAG, "TestEventHandler.detachRequestHandle(): " + + "requestHandle: " + mRequestHandle); + } + mRequestHandle = null; + } + + protected final static String LOGTAG = "http"; +} diff --git a/tests/CoreTests/android/core/TestHandler.java b/tests/CoreTests/android/core/TestHandler.java new file mode 100644 index 0000000000000000000000000000000000000000..4ff2e6e4d8b6ee4746f3b9e246c47ad3db65851f --- /dev/null +++ b/tests/CoreTests/android/core/TestHandler.java @@ -0,0 +1,174 @@ +/* //device/java/android/com/android/tests/TestHandler.java +** +** Copyright 2007, 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 android.core; + +import com.android.internal.os.HandlerHelper; +import android.os.HandlerInterface; +import android.os.Looper; +import android.os.Message; +import android.os.SystemClock; + +/** + * Naive class that implements a getNextMessage() + * by running a Handler in a new thread.

              + *

              + * This class blocks the Handler thread when the getNextMessage() thread + * is not in getNextMessage(). This allows the getNextMessage() thread to + * inspect state that is otherwise unguarded and would otherwise be prone to + * race conditions.

              + *

              + * Please note that both threads are allowed to run unsynchronized until + * the first message is posted to this handler. + *

              + * Please call hh.looper.quit() when done to clean this up + */ +public class TestHandler implements Runnable, HandlerInterface { + //***** Instance Variables + + public HandlerHelper hh; + public Looper looper; + + Runnable setupRoutine; + Message nextMessage; + long failTimeoutMillis; + boolean waitBeforeReturning = true; + + //***** Class Methods + + public static TestHandler create() { + return create("TestHandler", null); + } + + public static TestHandler create(String name) { + return create(name, null); + } + + public static TestHandler create(String name, Runnable doSetup) { + TestHandler ret; + + ret = new TestHandler(); + + ret.setupRoutine = doSetup; + + synchronized (ret) { + new Thread(ret, name).start(); + while (ret.looper == null) { + try { + ret.wait(); + } catch (InterruptedException ex) { + } + } + } + + return ret; + } + + //***** Public Methods + + /** + * Maximum time to wait for a message before failing + * by throwing exception + */ + public void setFailTimeoutMillis(long msec) { + failTimeoutMillis = msec; + } + + /** + * Waits for the next message to be sent to this handler and returns it. + * Blocks the Handler's looper thread until another call to getNextMessage() + * is made + */ + + public Message getNextMessage() { + Message ret; + + synchronized (this) { + long time = SystemClock.uptimeMillis(); + + waitBeforeReturning = false; + this.notifyAll(); + + try { + while (nextMessage == null) { + if (failTimeoutMillis > 0 + && ((SystemClock.uptimeMillis() - time) + > failTimeoutMillis)) { + throw new RuntimeException("Timeout exceeded exceeded"); + } + + try { + this.wait(failTimeoutMillis); + } catch (InterruptedException ex) { + } + } + ret = nextMessage; + nextMessage = null; + } finally { + waitBeforeReturning = true; + } + } + + return ret; + } + + //***** Overridden from Runnable + + public void run() { + Looper.prepare(); + hh = new HandlerHelper(this); + + if (setupRoutine != null) { + setupRoutine.run(); + } + + synchronized (this) { + looper = Looper.myLooper(); + this.notify(); + } + + Looper.loop(); + } + + //***** HandlerHelper implementation + + public void handleMessage(Message msg) { + synchronized (this) { + while (nextMessage != null) { + try { + this.wait(); + } catch (InterruptedException ex) { + } + } + + // msg will be recycled when this method returns. + // so we need to make a copy of it. + nextMessage = Message.obtain(); + nextMessage.copyFrom(msg); + this.notifyAll(); + + while (waitBeforeReturning) { + try { + this.wait(); + } catch (InterruptedException ex) { + } + } + } + } +} + + diff --git a/tests/CoreTests/android/core/TestWebData.java b/tests/CoreTests/android/core/TestWebData.java new file mode 100644 index 0000000000000000000000000000000000000000..2ef19be697e3afa409076d192814d1477b57a188 --- /dev/null +++ b/tests/CoreTests/android/core/TestWebData.java @@ -0,0 +1,132 @@ +/* + * Copyright (C) 2007 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 android.core; + +/** + * Represents test data used by the Request API tests + */ +public class TestWebData { + + /* + * Simple Html body + * + * + *

              Hello World!

              + * + * + */ + public final static byte[] test1 = { + (byte)0x3c, (byte)0x68, (byte)0x74, (byte)0x6d, + (byte)0x6c, (byte)0x3e, (byte)0x0a, (byte)0x3c, + (byte)0x62, (byte)0x6f, (byte)0x64, (byte)0x79, + (byte)0x3e, (byte)0x0a, (byte)0x3c, (byte)0x68, + (byte)0x31, (byte)0x3e, (byte)0x48, (byte)0x65, + (byte)0x6c, (byte)0x6c, (byte)0x6f, (byte)0x20, + (byte)0x57, (byte)0x6f, (byte)0x72, (byte)0x6c, + (byte)0x64, (byte)0x21, (byte)0x3c, (byte)0x2f, + (byte)0x68, (byte)0x31, (byte)0x3e, (byte)0x0a, + (byte)0x3c, (byte)0x2f, (byte)0x62, (byte)0x6f, + (byte)0x64, (byte)0x79, (byte)0x3e, (byte)0x0a, + (byte)0x3c, (byte)0x2f, (byte)0x68, (byte)0x74, + (byte)0x6d, (byte)0x6c, (byte)0x3e, (byte)0x0a + }; + + /* + * Simple Html body + * + * + *

              Hello World!

              + * + * + */ + public final static byte[] test2 = { + (byte)0x3c, (byte)0x68, (byte)0x74, (byte)0x6d, + (byte)0x6c, (byte)0x3e, (byte)0x0a, (byte)0x3c, + (byte)0x62, (byte)0x6f, (byte)0x64, (byte)0x79, + (byte)0x3e, (byte)0x0a, (byte)0x3c, (byte)0x68, + (byte)0x31, (byte)0x3e, (byte)0x48, (byte)0x65, + (byte)0x6c, (byte)0x6c, (byte)0x6f, (byte)0x20, + (byte)0x57, (byte)0x6f, (byte)0x72, (byte)0x6c, + (byte)0x64, (byte)0x21, (byte)0x3c, (byte)0x2f, + (byte)0x68, (byte)0x31, (byte)0x3e, (byte)0x0a, + (byte)0x3c, (byte)0x2f, (byte)0x62, (byte)0x6f, + (byte)0x64, (byte)0x79, (byte)0x3e, (byte)0x0a, + (byte)0x3c, (byte)0x2f, (byte)0x68, (byte)0x74, + (byte)0x6d, (byte)0x6c, (byte)0x3e, (byte)0x0a + }; + + // string for test request post body + public final static String postContent = "user=111"; + + // Array of all test data + public final static byte[][] tests = { + test1, + test2 + }; + + /** + * List of static test cases for use with test server + */ + public static TestWebData[] testParams = { + new TestWebData(52, 14000000, "test1", "text/html", false), + new TestWebData(52, 14000002, "test2", "unknown/unknown", false) + }; + + /** + * List of response strings for use by the test server + */ + public static String[] testServerResponse = { + "Redirecting 301", + "Redirecting 302", + "Redirecting 303", + "Redirecting 307" + }; + + // Redirection indices into testServerResponse + public final static int REDIRECT_301 = 0; + public final static int REDIRECT_302 = 1; + public final static int REDIRECT_303 = 2; + public final static int REDIRECT_307 = 3; + + /** + * Creates a data package with information used by the server when responding + * to requests + */ + TestWebData(int length, int lastModified, String name, String type, boolean isDir) { + testLength = length; + testLastModified = lastModified; + testName = name; + testType = type; + testDir = isDir; + } + + // Length of test entity body + public int testLength; + + // Last modified date value (milliseconds) + public int testLastModified; + + // Test identification name + public String testName; + + // The MIME type to assume for this test + public String testType; + + // Indicates if this is a directory or not + public boolean testDir; + +} diff --git a/tests/CoreTests/android/core/TestWebServer.java b/tests/CoreTests/android/core/TestWebServer.java new file mode 100644 index 0000000000000000000000000000000000000000..f73e6ff475acab4716cf16a4424bc5dbe821ba0a --- /dev/null +++ b/tests/CoreTests/android/core/TestWebServer.java @@ -0,0 +1,871 @@ +/* + * Copyright (C) 2007 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 android.core; + +import android.util.Log; + +import java.io.*; +import java.lang.Thread; +import java.net.*; +import java.util.*; + +/** + * TestWebServer is a simulated controllable test server that + * can respond to requests from HTTP clients. + * + * The server can be controlled to change how it reacts to any + * requests, and can be told to simulate various events (such as + * network failure) that would happen in a real environment. + */ +class TestWebServer implements HttpConstants { + + /* static class data/methods */ + + /* The ANDROID_LOG_TAG */ + private final static String LOGTAG = "httpsv"; + + /* Where worker threads stand idle */ + Vector threads = new Vector(); + + /* List of all active worker threads */ + Vector activeThreads = new Vector(); + + /* timeout on client connections */ + int timeout = 0; + + /* max # worker threads */ + int workers = 5; + + /* Default port for this server to listen on */ + final static int DEFAULT_PORT = 8080; + + /* Default socket timeout value */ + final static int DEFAULT_TIMEOUT = 5000; + + /* Version string (configurable) */ + protected String HTTP_VERSION_STRING = "HTTP/1.1"; + + /* Indicator for whether this server is configured as a HTTP/1.1 + * or HTTP/1.0 server + */ + private boolean http11 = true; + + /* The thread handling new requests from clients */ + private AcceptThread acceptT; + + /* timeout on client connections */ + int mTimeout; + + /* Server port */ + int mPort; + + /* Switch on/off logging */ + boolean mLog = false; + + /* If set, this will keep connections alive after a request has been + * processed. + */ + boolean keepAlive = true; + + /* If set, this will cause response data to be sent in 'chunked' format */ + boolean chunked = false; + + /* If set, this will indicate a new redirection host */ + String redirectHost = null; + + /* If set, this indicates the reason for redirection */ + int redirectCode = -1; + + /* Set the number of connections the server will accept before shutdown */ + int acceptLimit = 100; + + /* Count of number of accepted connections */ + int acceptedConnections = 0; + + public TestWebServer() { + } + + /** + * Initialize a new server with default port and timeout. + * @param log Set true if you want trace output + */ + public void initServer(boolean log) throws Exception { + initServer(DEFAULT_PORT, DEFAULT_TIMEOUT, log); + } + + /** + * Initialize a new server with default timeout. + * @param port Sets the server to listen on this port + * @param log Set true if you want trace output + */ + public void initServer(int port, boolean log) throws Exception { + initServer(port, DEFAULT_TIMEOUT, log); + } + + /** + * Initialize a new server with default port and timeout. + * @param port Sets the server to listen on this port + * @param timeout Indicates the period of time to wait until a socket is + * closed + * @param log Set true if you want trace output + */ + public void initServer(int port, int timeout, boolean log) throws Exception { + mPort = port; + mTimeout = timeout; + mLog = log; + keepAlive = true; + + if (acceptT == null) { + acceptT = new AcceptThread(); + acceptT.init(); + acceptT.start(); + } + } + + /** + * Print to the log file (if logging enabled) + * @param s String to send to the log + */ + protected void log(String s) { + if (mLog) { + Log.d(LOGTAG, s); + } + } + + /** + * Set the server to be an HTTP/1.0 or HTTP/1.1 server. + * This should be called prior to any requests being sent + * to the server. + * @param set True for the server to be HTTP/1.1, false for HTTP/1.0 + */ + public void setHttpVersion11(boolean set) { + http11 = set; + if (set) { + HTTP_VERSION_STRING = "HTTP/1.1"; + } else { + HTTP_VERSION_STRING = "HTTP/1.0"; + } + } + + /** + * Call this to determine whether server connection should remain open + * @param value Set true to keep connections open after a request + * completes + */ + public void setKeepAlive(boolean value) { + keepAlive = value; + } + + /** + * Call this to indicate whether chunked data should be used + * @param value Set true to make server respond with chunk encoded + * content data. + */ + public void setChunked(boolean value) { + chunked = value; + } + + /** + * Call this to specify the maximum number of sockets to accept + * @param limit The number of sockets to accept + */ + public void setAcceptLimit(int limit) { + acceptLimit = limit; + } + + /** + * Call this to indicate redirection port requirement. + * When this value is set, the server will respond to a request with + * a redirect code with the Location response header set to the value + * specified. + * @param redirect The location to be redirected to + * @param redirectCode The code to send when redirecting + */ + public void setRedirect(String redirect, int code) { + redirectHost = redirect; + redirectCode = code; + log("Server will redirect output to "+redirect+" code "+code); + } + + /** + * Cause the thread accepting connections on the server socket to close + */ + public void close() { + /* Stop the Accept thread */ + if (acceptT != null) { + log("Closing AcceptThread"+acceptT); + acceptT.close(); + acceptT = null; + } + } + /** + * The AcceptThread is responsible for initiating worker threads + * to handle incoming requests from clients. + */ + class AcceptThread extends Thread { + + ServerSocket ss = null; + boolean running = false; + + public void init() { + // Networking code doesn't support ServerSocket(port) yet + InetSocketAddress ia = new InetSocketAddress(mPort); + while (true) { + try { + ss = new ServerSocket(); + // Socket timeout functionality is not available yet + //ss.setSoTimeout(5000); + ss.setReuseAddress(true); + ss.bind(ia); + break; + } catch (IOException e) { + log("IOException in AcceptThread.init()"); + e.printStackTrace(); + // wait and retry + try { + Thread.sleep(1000); + } catch (InterruptedException e1) { + // TODO Auto-generated catch block + e1.printStackTrace(); + } + } + } + } + + /** + * Main thread responding to new connections + */ + public synchronized void run() { + running = true; + try { + while (running) { + // Log.d(LOGTAG, "TestWebServer run() calling accept()"); + Socket s = ss.accept(); + acceptedConnections++; + if (acceptedConnections >= acceptLimit) { + running = false; + } + + Worker w = null; + synchronized (threads) { + if (threads.isEmpty()) { + Worker ws = new Worker(); + ws.setSocket(s); + activeThreads.addElement(ws); + (new Thread(ws, "additional worker")).start(); + } else { + w = (Worker) threads.elementAt(0); + threads.removeElementAt(0); + w.setSocket(s); + } + } + } + } catch (SocketException e) { + log("SocketException in AcceptThread: probably closed during accept"); + running = false; + } catch (IOException e) { + log("IOException in AcceptThread"); + e.printStackTrace(); + running = false; + } + log("AcceptThread terminated" + this); + } + + // Close this socket + public void close() { + try { + running = false; + /* Stop server socket from processing further. Currently + this does not cause the SocketException from ss.accept + therefore the acceptLimit functionality has been added + to circumvent this limitation */ + ss.close(); + + // Stop worker threads from continuing + for (Enumeration e = activeThreads.elements(); e.hasMoreElements();) { + Worker w = (Worker)e.nextElement(); + w.close(); + } + activeThreads.clear(); + + } catch (IOException e) { + /* We are shutting down the server, so we expect + * things to die. Don't propagate. + */ + log("IOException caught by server socket close"); + } + } + } + + // Size of buffer for reading from the connection + final static int BUF_SIZE = 2048; + + /* End of line byte sequence */ + static final byte[] EOL = {(byte)'\r', (byte)'\n' }; + + /** + * The worker thread handles all interactions with a current open + * connection. If pipelining is turned on, this will allow this + * thread to continuously operate on numerous requests before the + * connection is closed. + */ + class Worker implements HttpConstants, Runnable { + + /* buffer to use to hold request data */ + byte[] buf; + + /* Socket to client we're handling */ + private Socket s; + + /* Reference to current request method ID */ + private int requestMethod; + + /* Reference to current requests test file/data */ + private String testID; + + /* Reference to test number from testID */ + private int testNum; + + /* Reference to whether new request has been initiated yet */ + private boolean readStarted; + + /* Indicates whether current request has any data content */ + private boolean hasContent = false; + + boolean running = false; + + /* Request headers are stored here */ + private Hashtable headers = new Hashtable(); + + /* Create a new worker thread */ + Worker() { + buf = new byte[BUF_SIZE]; + s = null; + } + + /** + * Called by the AcceptThread to unblock this Worker to process + * a request. + * @param s The socket on which the connection has been made + */ + synchronized void setSocket(Socket s) { + this.s = s; + notify(); + } + + /** + * Called by the accept thread when it's closing. Potentially unblocks + * the worker thread to terminate properly + */ + synchronized void close() { + running = false; + notify(); + } + + /** + * Main worker thread. This will wait until a request has + * been identified by the accept thread upon which it will + * service the thread. + */ + public synchronized void run() { + running = true; + while(running) { + if (s == null) { + /* nothing to do */ + try { + log(this+" Moving to wait state"); + wait(); + } catch (InterruptedException e) { + /* should not happen */ + continue; + } + if (!running) break; + } + try { + handleClient(); + } catch (Exception e) { + e.printStackTrace(); + } + /* go back in wait queue if there's fewer + * than numHandler connections. + */ + s = null; + Vector pool = threads; + synchronized (pool) { + if (pool.size() >= workers) { + /* too many threads, exit this one */ + activeThreads.remove(this); + return; + } else { + pool.addElement(this); + } + } + } + log(this+" terminated"); + } + + /** + * Zero out the buffer from last time + */ + private void clearBuffer() { + for (int i = 0; i < BUF_SIZE; i++) { + buf[i] = 0; + } + } + + /** + * Utility method to read a line of data from the input stream + * @param is Inputstream to read + * @return number of bytes read + */ + private int readOneLine(InputStream is) { + + int read = 0; + + clearBuffer(); + try { + log("Reading one line: started ="+readStarted+" avail="+is.available()); + while ((!readStarted) || (is.available() > 0)) { + int data = is.read(); + // We shouldn't get EOF but we need tdo check + if (data == -1) { + log("EOF returned"); + return -1; + } + + buf[read] = (byte)data; + + System.out.print((char)data); + + readStarted = true; + if (buf[read++]==(byte)'\n') { + System.out.println(); + return read; + } + } + } catch (IOException e) { + log("IOException from readOneLine"); + e.printStackTrace(); + } + return read; + } + + /** + * Read a chunk of data + * @param is Stream from which to read data + * @param length Amount of data to read + * @return number of bytes read + */ + private int readData(InputStream is, int length) { + int read = 0; + int count; + // At the moment we're only expecting small data amounts + byte[] buf = new byte[length]; + + try { + while (is.available() > 0) { + count = is.read(buf, read, length-read); + read += count; + } + } catch (IOException e) { + log("IOException from readData"); + e.printStackTrace(); + } + return read; + } + + /** + * Read the status line from the input stream extracting method + * information. + * @param is Inputstream to read + * @return number of bytes read + */ + private int parseStatusLine(InputStream is) { + int index; + int nread = 0; + + log("Parse status line"); + // Check for status line first + nread = readOneLine(is); + // Bomb out if stream closes prematurely + if (nread == -1) { + requestMethod = UNKNOWN_METHOD; + return -1; + } + + if (buf[0] == (byte)'G' && + buf[1] == (byte)'E' && + buf[2] == (byte)'T' && + buf[3] == (byte)' ') { + requestMethod = GET_METHOD; + log("GET request"); + index = 4; + } else if (buf[0] == (byte)'H' && + buf[1] == (byte)'E' && + buf[2] == (byte)'A' && + buf[3] == (byte)'D' && + buf[4] == (byte)' ') { + requestMethod = HEAD_METHOD; + log("HEAD request"); + index = 5; + } else if (buf[0] == (byte)'P' && + buf[1] == (byte)'O' && + buf[2] == (byte)'S' && + buf[3] == (byte)'T' && + buf[4] == (byte)' ') { + requestMethod = POST_METHOD; + log("POST request"); + index = 5; + } else { + // Unhandled request + requestMethod = UNKNOWN_METHOD; + return -1; + } + + // A valid method we understand + if (requestMethod > UNKNOWN_METHOD) { + // Read file name + int i = index; + while (buf[i] != (byte)' ') { + // There should be HTTP/1.x at the end + if ((buf[i] == (byte)'\n') || (buf[i] == (byte)'\r')) { + requestMethod = UNKNOWN_METHOD; + return -1; + } + i++; + } + + testID = new String(buf, 0, index, i-index); + if (testID.startsWith("/")) { + testID = testID.substring(1); + } + + return nread; + } + return -1; + } + + /** + * Read a header from the input stream + * @param is Inputstream to read + * @return number of bytes read + */ + private int parseHeader(InputStream is) { + int index = 0; + int nread = 0; + log("Parse a header"); + // Check for status line first + nread = readOneLine(is); + // Bomb out if stream closes prematurely + if (nread == -1) { + requestMethod = UNKNOWN_METHOD; + return -1; + } + // Read header entry 'Header: data' + int i = index; + while (buf[i] != (byte)':') { + // There should be an entry after the header + + if ((buf[i] == (byte)'\n') || (buf[i] == (byte)'\r')) { + return UNKNOWN_METHOD; + } + i++; + } + + String headerName = new String(buf, 0, i); + i++; // Over ':' + while (buf[i] == ' ') { + i++; + } + String headerValue = new String(buf, i, nread-1); + + headers.put(headerName, headerValue); + return nread; + } + + /** + * Read all headers from the input stream + * @param is Inputstream to read + * @return number of bytes read + */ + private int readHeaders(InputStream is) { + int nread = 0; + log("Read headers"); + // Headers should be terminated by empty CRLF line + while (true) { + int headerLen = 0; + headerLen = parseHeader(is); + if (headerLen == -1) + return -1; + nread += headerLen; + if (headerLen <= 2) { + return nread; + } + } + } + + /** + * Read content data from the input stream + * @param is Inputstream to read + * @return number of bytes read + */ + private int readContent(InputStream is) { + int nread = 0; + log("Read content"); + String lengthString = headers.get(requestHeaders[REQ_CONTENT_LENGTH]); + int length = new Integer(lengthString).intValue(); + + // Read content + length = readData(is, length); + return length; + } + + /** + * The main loop, reading requests. + */ + void handleClient() throws IOException { + InputStream is = new BufferedInputStream(s.getInputStream()); + PrintStream ps = new PrintStream(s.getOutputStream()); + int nread = 0; + + /* we will only block in read for this many milliseconds + * before we fail with java.io.InterruptedIOException, + * at which point we will abandon the connection. + */ + s.setSoTimeout(mTimeout); + s.setTcpNoDelay(true); + + do { + nread = parseStatusLine(is); + if (requestMethod != UNKNOWN_METHOD) { + + // If status line found, read any headers + nread = readHeaders(is); + + // Then read content (if any) + // TODO handle chunked encoding from the client + if (headers.get(requestHeaders[REQ_CONTENT_LENGTH]) != null) { + nread = readContent(is); + } + } else { + if (nread > 0) { + /* we don't support this method */ + ps.print(HTTP_VERSION_STRING + " " + HTTP_BAD_METHOD + + " unsupported method type: "); + ps.write(buf, 0, 5); + ps.write(EOL); + ps.flush(); + } else { + } + if (!keepAlive || nread <= 0) { + headers.clear(); + readStarted = false; + + log("SOCKET CLOSED"); + s.close(); + return; + } + } + + // Reset test number prior to outputing data + testNum = -1; + + // Write out the data + printStatus(ps); + printHeaders(ps); + + // Write line between headers and body + psWriteEOL(ps); + + // Write the body + if (redirectCode == -1) { + switch (requestMethod) { + case GET_METHOD: + if ((testNum < 0) || (testNum > TestWebData.tests.length - 1)) { + send404(ps); + } else { + sendFile(ps); + } + break; + case HEAD_METHOD: + // Nothing to do + break; + case POST_METHOD: + // Post method write body data + if ((testNum > 0) || (testNum < TestWebData.tests.length - 1)) { + sendFile(ps); + } + + break; + default: + break; + } + } else { // Redirecting + switch (redirectCode) { + case 301: + // Seems 301 needs a body by neon (although spec + // says SHOULD). + psPrint(ps, TestWebData.testServerResponse[TestWebData.REDIRECT_301]); + break; + case 302: + // + psPrint(ps, TestWebData.testServerResponse[TestWebData.REDIRECT_302]); + break; + case 303: + psPrint(ps, TestWebData.testServerResponse[TestWebData.REDIRECT_303]); + break; + case 307: + psPrint(ps, TestWebData.testServerResponse[TestWebData.REDIRECT_307]); + break; + default: + break; + } + } + + ps.flush(); + + // Reset for next request + readStarted = false; + headers.clear(); + + } while (keepAlive); + + log("SOCKET CLOSED"); + s.close(); + } + + // Print string to log and output stream + void psPrint(PrintStream ps, String s) throws IOException { + log(s); + ps.print(s); + } + + // Print bytes to log and output stream + void psWrite(PrintStream ps, byte[] bytes, int len) throws IOException { + log(new String(bytes)); + ps.write(bytes, 0, len); + } + + // Print CRLF to log and output stream + void psWriteEOL(PrintStream ps) throws IOException { + log("CRLF"); + ps.write(EOL); + } + + + // Print status to log and output stream + void printStatus(PrintStream ps) throws IOException { + // Handle redirects first. + if (redirectCode != -1) { + log("REDIRECTING TO "+redirectHost+" status "+redirectCode); + psPrint(ps, HTTP_VERSION_STRING + " " + redirectCode +" Moved permanently"); + psWriteEOL(ps); + psPrint(ps, "Location: " + redirectHost); + psWriteEOL(ps); + return; + } + + + if (testID.startsWith("test")) { + testNum = Integer.valueOf(testID.substring(4))-1; + } + + if ((testNum < 0) || (testNum > TestWebData.tests.length - 1)) { + psPrint(ps, HTTP_VERSION_STRING + " " + HTTP_NOT_FOUND + " not found"); + psWriteEOL(ps); + } else { + psPrint(ps, HTTP_VERSION_STRING + " " + HTTP_OK+" OK"); + psWriteEOL(ps); + } + + log("Status sent"); + } + /** + * Create the server response and output to the stream + * @param ps The PrintStream to output response headers and data to + */ + void printHeaders(PrintStream ps) throws IOException { + psPrint(ps,"Server: TestWebServer"+mPort); + psWriteEOL(ps); + psPrint(ps, "Date: " + (new Date())); + psWriteEOL(ps); + psPrint(ps, "Connection: " + ((keepAlive) ? "Keep-Alive" : "Close")); + psWriteEOL(ps); + + // Yuk, if we're not redirecting, we add the file details + if (redirectCode == -1) { + + if (!TestWebData.testParams[testNum].testDir) { + if (chunked) { + psPrint(ps, "Transfer-Encoding: chunked"); + } else { + psPrint(ps, "Content-length: "+TestWebData.testParams[testNum].testLength); + } + psWriteEOL(ps); + + psPrint(ps,"Last Modified: " + (new + Date(TestWebData.testParams[testNum].testLastModified))); + psWriteEOL(ps); + + psPrint(ps, "Content-type: " + TestWebData.testParams[testNum].testType); + psWriteEOL(ps); + } else { + psPrint(ps, "Content-type: text/html"); + psWriteEOL(ps); + } + } else { + // Content-length of 301, 302, 303, 307 are the same. + psPrint(ps, "Content-length: "+(TestWebData.testServerResponse[TestWebData.REDIRECT_301]).length()); + psWriteEOL(ps); + psWriteEOL(ps); + } + log("Headers sent"); + + } + + /** + * Sends the 404 not found message + * @param ps The PrintStream to write to + */ + void send404(PrintStream ps) throws IOException { + ps.println("Not Found\n\n"+ + "The requested resource was not found.\n"); + } + + /** + * Sends the data associated with the headers + * @param ps The PrintStream to write to + */ + void sendFile(PrintStream ps) throws IOException { + // For now just make a chunk with the whole of the test data + // It might be worth making this multiple chunks for large + // test data to test multiple chunks. + int dataSize = TestWebData.tests[testNum].length; + if (chunked) { + psPrint(ps, Integer.toHexString(dataSize)); + psWriteEOL(ps); + psWrite(ps, TestWebData.tests[testNum], dataSize); + psWriteEOL(ps); + psPrint(ps, "0"); + psWriteEOL(ps); + psWriteEOL(ps); + } else { + psWrite(ps, TestWebData.tests[testNum], dataSize); + } + } + } +} diff --git a/tests/CoreTests/android/core/TreeMapTest.java b/tests/CoreTests/android/core/TreeMapTest.java new file mode 100644 index 0000000000000000000000000000000000000000..229d86d88d7f86c7b879626d0cc6fb59df24ea07 --- /dev/null +++ b/tests/CoreTests/android/core/TreeMapTest.java @@ -0,0 +1,105 @@ +/* + * 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 android.core; + +import junit.framework.TestCase; + +import java.util.HashMap; +import java.util.Random; +import java.util.TreeMap; +import android.test.suitebuilder.annotation.LargeTest; + +/** + * Tests for basic functinality of TreeMaps + */ +public class TreeMapTest extends TestCase { + + private Random mRandom = new Random(1); + + private static final boolean SPEW = false; + + @LargeTest + public void testTreeMap() { + for (int i = 0; i < 10; i++) { + if (SPEW) System.out.println("Running doTest cycle #" + (i + 1)); + doTest(); + } + } + + private void doTest() { + TreeMap tm = new TreeMap(); + HashMap hm = new HashMap(); + + int minVal = Integer.MAX_VALUE; + int maxVal = Integer.MIN_VALUE; + + for (int i = 0; i < 100; i++) { + int val = mRandom.nextInt(1000); + if (SPEW) System.out.println("Adding val = " + val); + if (val < minVal) { + minVal = val; + } + if (val > maxVal) { + maxVal = val; + } + tm.put(new Integer(val), "V:" + val); + hm.put(new Integer(val), "V:" + val); + + if (SPEW) System.out.println("tm = " + tm); + + if (SPEW) System.out.println("tm.size() = " + tm.size()); + if (SPEW) System.out.println("hm.size() = " + hm.size()); + assertEquals(tm.size(), hm.size()); + + if (SPEW) System.out.println("tm.firstKey() = " + tm.firstKey()); + if (SPEW) System.out.println("minVal = " + minVal); + if (SPEW) System.out.println("tm.lastKey() = " + tm.lastKey()); + if (SPEW) System.out.println("maxVal = " + maxVal); + assertEquals(minVal, tm.firstKey().intValue()); + assertEquals(maxVal, tm.lastKey().intValue()); + } + + // Check for equality + for (int val = 0; val < 1000; val++) { + Integer vv = new Integer(val); + String tms = tm.get(vv); + String hms = hm.get(vv); + assertEquals(tms, hms); + } + + for (int i = 0; i < 1000; i++) { + int val = mRandom.nextInt(1000); + if (SPEW) System.out.println("Removing val = " + val); + + String tms = tm.remove(new Integer(val)); + String hms = hm.remove(new Integer(val)); + + if (SPEW) System.out.println("tm = " + tm); + + assertEquals(tm.size(), hm.size()); + assertEquals(tms, hms); + } + + // Check for equality + for (int val = 0; val < 1000; val++) { + Integer vv = new Integer(val); + String tms = tm.get(vv); + String hms = hm.get(vv); + assertEquals(tms, hms); + } + } +} diff --git a/tests/CoreTests/android/core/URITest.java b/tests/CoreTests/android/core/URITest.java new file mode 100644 index 0000000000000000000000000000000000000000..3b821d85a940f1d4c42ac520da70e6680b13cbfd --- /dev/null +++ b/tests/CoreTests/android/core/URITest.java @@ -0,0 +1,55 @@ +/* + * 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 android.core; + +import junit.framework.TestCase; + +import java.net.URI; +import java.net.URISyntaxException; +import android.test.suitebuilder.annotation.SmallTest; + +public class URITest extends TestCase { + + @SmallTest + public void testConstruct() throws Exception { + construct("http://www.google.com/this/is-the/path?query#fragment", + "www.google.com", "/this/is-the/path", true); + } + + private static void construct(String str, String host, String path, boolean absolute) + throws URISyntaxException { + URI uri = new URI(str); + assertEquals(host, uri.getHost()); + assertEquals(path, uri.getPath()); + assertEquals(absolute, uri.isAbsolute()); + } + + @SmallTest + public void testResolve() throws Exception { + resolve("http://www.google.com/your", + "mom", + "http://www.google.com/mom"); + } + + private static void resolve(String base, String uri, String expected) { + URI b = URI.create(base); + URI resolved = b.resolve(uri); +// System.out.println("base=" + base + " uri=" + uri +// + " resolved=" + resolved); + assertEquals(expected, resolved.toString()); + } +} diff --git a/tests/CoreTests/android/core/URLTest.java b/tests/CoreTests/android/core/URLTest.java new file mode 100644 index 0000000000000000000000000000000000000000..56f9f7b80ae5d31912f2233c6862f4c06e399bb9 --- /dev/null +++ b/tests/CoreTests/android/core/URLTest.java @@ -0,0 +1,200 @@ +/* + * 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 android.core; + +import junit.framework.TestCase; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.io.PrintWriter; +import java.net.HttpURLConnection; +import java.net.ServerSocket; +import java.net.Socket; +import java.net.URL; +import java.net.URLConnection; + +import android.test.suitebuilder.annotation.Suppress; + +@Suppress +public class URLTest extends TestCase { + + private static void get(String u) throws IOException { + URL url = new URL(u); + URLConnection cn = url.openConnection(); + cn.connect(); +// System.out.println("Content-Type: " + cn.getContentType()); +// System.out.println("Content-Length: " + cn.getContentLength()); + + InputStream stream = cn.getInputStream(); + if (stream == null) { + throw new RuntimeException("stream is null"); + } + byte[] data = new byte[1024]; + stream.read(data); + +// if (true) { +// System.out.print("data="); +// System.out.write(data); +// System.out.println(); +// } + +// System.out.println("Content-Type: " + cn.getContentType()); +// System.out.print("data:"); +// System.out.write(data); +// System.out.println(); + + assertTrue(new String(data).indexOf("") >= 0); + } + + public void testGetHTTP() throws Exception { + get("http://www.google.com"); + } + + public void testGetHTTPS() throws Exception { + get("https://www.fortify.net/cgi/ssl_2.pl"); + } + + /** + * Dummy HTTP server class for testing keep-alive behavior. Listens a + * single time and responds to a given number of requests on the same + * socket. Then closes the socket. + */ + private static class DummyServer implements Runnable { + + private int keepAliveCount; + + public DummyServer(int keepAliveCount) { + this.keepAliveCount = keepAliveCount; + } + + public void run() { + try { + ServerSocket server = new ServerSocket(8182); + Socket socket = server.accept(); + + InputStream input = socket.getInputStream(); + BufferedReader reader = new BufferedReader(new InputStreamReader(input)); + try { + for (int i = 0; i < keepAliveCount; i++) { + String header = reader.readLine(); + while (header != null && header.length() != 0) { + header = reader.readLine(); + } + + OutputStream output = socket.getOutputStream(); + PrintWriter writer = new PrintWriter(output); + + try { + writer.println("HTTP/1.1 200 OK"); + String body = "Hello, Android world #" + i + "!"; + writer.println("Content-Length: " + body.length()); + writer.println(""); + writer.print(body); + writer.flush(); + } finally { + writer.close(); + } + } + } finally { + reader.close(); + } + socket.close(); + server.close(); + } catch (Exception ex) { + throw new RuntimeException(ex); + } + } + } + + /** + * Does a request to the given URL, reads and returns the result. + */ + private String request(URL url) throws Exception { + URLConnection connection = url.openConnection(); + connection.connect(); + + InputStream input = connection.getInputStream(); + BufferedReader reader = new BufferedReader(new InputStreamReader(input)); + try { + return reader.readLine(); + } finally { + reader.close(); + } + } + + /** + * Test case for HTTP keep-alive behavior. + */ + public void testGetKeepAlive() throws Exception { + new Thread(new DummyServer(3)).start(); + Thread.sleep(100); + + // We expect the request to work three times, then it fails. + URL url = new URL("http://localhost:8182"); + assertEquals("Hello, Android world #0!", request(url)); + assertEquals("Hello, Android world #1!", request(url)); + assertEquals("Hello, Android world #2!", request(url)); + + try { + request(url); + fail("ConnectException expected."); + } catch (Exception ex) { + // Ok. + } + } + + /** + * Regression for issue 1001814. + */ + public void testHttpConnectionTimeout() throws Exception { + int timeout = 5000; + HttpURLConnection cn = null; + long start = 0; + try { + start = System.currentTimeMillis(); + URL url = new URL("http://123.123.123.123"); + cn = (HttpURLConnection) url.openConnection(); + cn.setConnectTimeout(5000); + cn.connect(); + fail("should have thrown an exception"); + } catch (IOException ioe) { + long delay = System.currentTimeMillis() - start; + if (Math.abs(timeout - delay) > 1000) { + fail("Timeout was not accurate. it needed " + delay + + " instead of " + timeout + "miliseconds"); + } + } finally { + if (cn != null) { + cn.disconnect(); + } + } + } + + /** + * Regression test for issue 1158780 where using '{' and '}' in an URL threw + * an NPE. The RI accepts this URL and returns the status 404. + */ + public void testMalformedUrl() throws Exception { + URL url = new URL("http://www.google.com/cgi-bin/myscript?g={United+States}+Borders+Mexico+{Climate+change}+Marketing+{Automotive+industry}+News+Health+Internet"); + HttpURLConnection conn = (HttpURLConnection)url.openConnection(); + int status = conn.getResponseCode(); + android.util.Log.d("URLTest", "status: " + status); + } +} diff --git a/tests/CoreTests/android/core/ZipFileTest.java b/tests/CoreTests/android/core/ZipFileTest.java new file mode 100644 index 0000000000000000000000000000000000000000..04b476b5323d06cb2821a744516d7bf86d7c61cf --- /dev/null +++ b/tests/CoreTests/android/core/ZipFileTest.java @@ -0,0 +1,200 @@ +/* + * 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 android.core; + +import junit.framework.TestCase; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.Enumeration; +import java.util.zip.ZipEntry; +import java.util.zip.ZipFile; +import java.util.zip.ZipOutputStream; +import android.test.suitebuilder.annotation.MediumTest; + + +/** + * Basic tests for ZipFile. + */ +public class ZipFileTest extends TestCase { + private static final int SAMPLE_SIZE = 128 * 1024; + + @MediumTest + public void testZipFile() throws Exception { + + File file = File.createTempFile("ZipFileTest", ".zip"); + try { + // create a test file; assume it's not going to collide w/anything + FileOutputStream outStream = new FileOutputStream(file); + createCompressedZip(outStream); +// System.out.println("CREATED " + file); + + scanZip(file.getPath()); + read2(file.getPath()); + } finally { + file.delete(); + } + } + + /* + * stepStep == 0 --> >99% compression + * stepStep == 1 --> ~30% compression + * stepStep == 2 --> no compression + */ + static byte[] makeSampleFile(int stepStep) throws IOException { + byte[] sample = new byte[SAMPLE_SIZE]; + byte val, step; + int i, j, offset; + + val = 0; + step = 1; + offset = 0; + for (i = 0; i < SAMPLE_SIZE / 256; i++) { + for (j = 0; j < 256; j++) { + sample[offset++] = val; + val += step; + } + + step += stepStep; + } + + return sample; + } + + static void createCompressedZip(OutputStream bytesOut) throws IOException { + ZipOutputStream out = new ZipOutputStream(bytesOut); + try { + int i; + + for (i = 0; i < 3; i++) { + byte[] input = makeSampleFile(i); + ZipEntry newEntry = new ZipEntry("file-" + i); + + if (i != 1) { + newEntry.setComment("this is file " + i); + } + out.putNextEntry(newEntry); + out.write(input, 0, input.length); + out.closeEntry(); + } + + out.setComment("This is a lovely compressed archive!"); + } finally { + out.close(); + } + } + + static void scanZip(String fileName) throws IOException { + ZipFile zipFile = new ZipFile(fileName); + Enumeration fileList; + int idx = 0; + +// System.out.println("Contents of " + zipFile + ":"); + for (fileList = zipFile.entries(); fileList.hasMoreElements();) { + ZipEntry entry = (ZipEntry) fileList.nextElement(); +// System.out.println(" " + entry.getName()); + assertEquals(entry.getName(), "file-" + idx); + idx++; + } + + zipFile.close(); + } + + /* + * Read compressed data from two different entries at the same time, + * to verify that the streams aren't getting confused. If we do + * something wrong, the inflater will choke and throw a ZipException. + * + * This doesn't test synchronization in multi-threaded use. + */ + static void read2(String fileName) throws IOException { + ZipFile zipFile; + ZipEntry entry1, entry2; + byte buf[] = new byte[16384]; + InputStream stream1, stream2; + int len, totalLen1, totalLen2; + + /* use file-1 and file-2 because the compressed data is large */ + zipFile = new ZipFile(fileName); + entry1 = zipFile.getEntry("file-1"); + entry2 = zipFile.getEntry("file-2"); + + /* make sure we got the right thing */ + assertEquals("file-1", entry1.getName()); + assertEquals("file-2", entry2.getName()); + + /* create streams */ + stream1 = zipFile.getInputStream(entry1); + stream2 = zipFile.getInputStream(entry2); + + /* + * Read a piece of file #1. + */ + totalLen1 = stream1.read(buf); + assertTrue("initial read failed on #1", totalLen1 >= 0); + + /* + * Read a piece of file #2. + */ + totalLen2 = stream2.read(buf); + assertTrue("initial read failed on #2", totalLen2 >= 0); + + /* + * Read the rest of file #1, and close the stream. + * + * If our streams are crossed up, we'll fail here. + */ + while ((len = stream1.read(buf)) > 0) { + totalLen1 += len; + } + assertEquals(SAMPLE_SIZE, totalLen1); + stream1.close(); + + /* + * Read the rest of file #2, and close the stream. + */ + while ((len = stream2.read(buf)) > 0) { + totalLen2 += len; + } + assertEquals(SAMPLE_SIZE, totalLen2); + stream2.close(); + + /* + * Open a new one. + */ + stream1 = zipFile.getInputStream(zipFile.getEntry("file-0")); + + /* + * Close the ZipFile. According to the RI, none if its InputStreams can + * be read after this point. + */ + zipFile.close(); + + Exception error = null; + try { + stream1.read(buf); + } catch (Exception ex) { + error = ex; + } + + assertNotNull("ZipFile shouldn't allow reading of closed files.", error); + } +} + diff --git a/tests/CoreTests/android/core/ZipStreamTest.java b/tests/CoreTests/android/core/ZipStreamTest.java new file mode 100644 index 0000000000000000000000000000000000000000..74cfe82ec5a787cbc4129996bdabf95d177a9cfc --- /dev/null +++ b/tests/CoreTests/android/core/ZipStreamTest.java @@ -0,0 +1,171 @@ +/* + * 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 android.core; + +import junit.framework.TestCase; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.util.zip.ZipEntry; +import java.util.zip.ZipInputStream; +import java.util.zip.ZipOutputStream; +import android.test.suitebuilder.annotation.LargeTest; + +/** + * Basic tests for ZipStream + */ +public class ZipStreamTest extends TestCase { + + @LargeTest + public void testZipStream() throws Exception { + ByteArrayOutputStream bytesOut = new ByteArrayOutputStream(); + createCompressedZip(bytesOut); + + byte[] zipData = bytesOut.toByteArray(); + + /* + FileOutputStream outFile = new FileOutputStream("/tmp/foo.zip"); + outFile.write(zipData, 0, zipData.length); + outFile.close(); + */ + + /* + FileInputStream inFile = new FileInputStream("/tmp/foo.zip"); + int inputLength = inFile.available(); + zipData = new byte[inputLength]; + if (inFile.read(zipData) != inputLength) + throw new RuntimeException(); + inFile.close(); + */ + + ByteArrayInputStream bytesIn = new ByteArrayInputStream(zipData); + scanZip(bytesIn); + + bytesOut = new ByteArrayOutputStream(); + createUncompressedZip(bytesOut); + + zipData = bytesOut.toByteArray(); + + bytesIn = new ByteArrayInputStream(zipData); + scanZip(bytesIn); + } + + /* + * stepStep == 0 --> >99% compression + * stepStep == 1 --> ~30% compression + * stepStep == 2 --> no compression + */ + private static byte[] makeSampleFile(int stepStep) throws IOException { + byte[] sample = new byte[128 * 1024]; + byte val, step; + int i, j, offset; + + val = 0; + step = 1; + offset = 0; + for (i = 0; i < (128 * 1024) / 256; i++) { + for (j = 0; j < 256; j++) { + sample[offset++] = val; + val += step; + } + + step += stepStep; + } + + return sample; + } + + private static void createCompressedZip(ByteArrayOutputStream bytesOut) throws IOException { + ZipOutputStream out = new ZipOutputStream(bytesOut); + try { + int i; + + for (i = 0; i < 3; i++) { + byte[] input = makeSampleFile(i); + ZipEntry newEntry = new ZipEntry("file-" + i); + + if (i != 1) + newEntry.setComment("this is file " + i); + out.putNextEntry(newEntry); + out.write(input, 0, input.length); + out.closeEntry(); + } + + out.setComment("This is a lovely compressed archive!"); + } finally { + out.close(); + } + } + + private static void createUncompressedZip(ByteArrayOutputStream bytesOut) throws IOException { + ZipOutputStream out = new ZipOutputStream(bytesOut); + try { + long[] crcs = {0x205fbff3, 0x906fae57L, 0x2c235131}; + int i; + + for (i = 0; i < 3; i++) { + byte[] input = makeSampleFile(i); + ZipEntry newEntry = new ZipEntry("file-" + i); + + if (i != 1) + newEntry.setComment("this is file " + i); + newEntry.setMethod(ZipEntry.STORED); + newEntry.setSize(128 * 1024); + newEntry.setCrc(crcs[i]); + out.putNextEntry(newEntry); + out.write(input, 0, input.length); + out.closeEntry(); + } + + out.setComment("This is a lovely, but uncompressed, archive!"); + } finally { + out.close(); + } + } + + private static void scanZip(ByteArrayInputStream bytesIn) throws IOException { + ZipInputStream in = new ZipInputStream(bytesIn); + try { + int i; + + for (i = 0; i < 3; i++) { + ZipEntry entry = in.getNextEntry(); + ByteArrayOutputStream contents = new ByteArrayOutputStream(); + byte[] buf = new byte[4096]; + int len, totalLen = 0; + + while ((len = in.read(buf)) > 0) { + contents.write(buf, 0, len); + totalLen += len; + } + + assertEquals(128 * 1024, totalLen); + +// System.out.println("ZipStreamTest: name='" + entry.getName() +// + "', zero=" + contents.toByteArray()[0] +// + ", tfs=" + contents.toByteArray()[257] +// + ", crc=" + Long.toHexString(entry.getCrc())); + } + + assertNull("should only be three entries", in.getNextEntry()); + } finally { + in.close(); + } + } +} + diff --git a/tests/CoreTests/android/database/MatrixCursorTest.java b/tests/CoreTests/android/database/MatrixCursorTest.java new file mode 100644 index 0000000000000000000000000000000000000000..fb8a12f444bf5c55fb878e632ac0363187cb7fba --- /dev/null +++ b/tests/CoreTests/android/database/MatrixCursorTest.java @@ -0,0 +1,146 @@ +/* + * Copyright (C) 2007 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 android.database; + +import junit.framework.TestCase; + +import java.util.*; + +public class MatrixCursorTest extends TestCase { + + public void testEmptyCursor() { + Cursor cursor = new MatrixCursor(new String[] { "a" }); + assertEquals(0, cursor.getCount()); + } + + public void testNullValue() { + MatrixCursor cursor = new MatrixCursor(new String[] { "a" }); + cursor.newRow().add(null); + cursor.moveToNext(); + assertTrue(cursor.isNull(0)); + } + + public void testMatrixCursor() { + MatrixCursor cursor = newMatrixCursor(); + + cursor.newRow() + .add("a") + .add(1) + .add(2) + .add(3) + .add(4) + .add(5); + + cursor.moveToNext(); + + checkValues(cursor); + + cursor.newRow() + .add("a") + .add("1") + .add("2") + .add("3") + .add("4") + .add("5"); + + cursor.moveToNext(); + checkValues(cursor); + + cursor.moveToPrevious(); + checkValues(cursor); + } + + public void testAddArray() { + MatrixCursor cursor = newMatrixCursor(); + + cursor.addRow(new Object[] { "a", 1, 2, 3, 4, 5 }); + cursor.moveToNext(); + checkValues(cursor); + + try { + cursor.addRow(new Object[0]); + fail(); + } catch (IllegalArgumentException e) { /* expected */ } + } + + public void testAddIterable() { + MatrixCursor cursor = newMatrixCursor(); + + cursor.addRow(Arrays.asList("a", 1, 2, 3, 4, 5)); + cursor.moveToNext(); + checkValues(cursor); + + try { + cursor.addRow(Collections.emptyList()); + fail(); + } catch (IllegalArgumentException e) { /* expected */ } + + try { + cursor.addRow(Arrays.asList("a", 1, 2, 3, 4, 5, "Too many!")); + fail(); + } catch (IllegalArgumentException e) { /* expected */ } + } + + public void testAddArrayList() { + MatrixCursor cursor = newMatrixCursor(); + + cursor.addRow(new NonIterableArrayList( + Arrays.asList("a", 1, 2, 3, 4, 5))); + cursor.moveToNext(); + checkValues(cursor); + + try { + cursor.addRow(new NonIterableArrayList()); + fail(); + } catch (IllegalArgumentException e) { /* expected */ } + + try { + cursor.addRow(new NonIterableArrayList( + Arrays.asList("a", 1, 2, 3, 4, 5, "Too many!"))); + fail(); + } catch (IllegalArgumentException e) { /* expected */ } + } + + static class NonIterableArrayList extends ArrayList { + + NonIterableArrayList() {} + + NonIterableArrayList(Collection ts) { + super(ts); + } + + @Override + public Iterator iterator() { + throw new AssertionError(); + } + } + + private MatrixCursor newMatrixCursor() { + return new MatrixCursor(new String[] { + "string", "short", "int", "long", "float", "double" }); + } + + private void checkValues(MatrixCursor cursor) { + assertEquals("a", cursor.getString(0)); + assertEquals(1, cursor.getShort(1)); + assertEquals(2, cursor.getInt(2)); + assertEquals(3, cursor.getLong(3)); + assertEquals(4.0f, cursor.getFloat(4)); + assertEquals(5.0D, cursor.getDouble(5)); + } + +} diff --git a/tests/CoreTests/android/graphics/ColorStateListTest.java b/tests/CoreTests/android/graphics/ColorStateListTest.java new file mode 100644 index 0000000000000000000000000000000000000000..68c2fc19c473b2316ce23203b006bc434a6dc142 --- /dev/null +++ b/tests/CoreTests/android/graphics/ColorStateListTest.java @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2007 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 android.graphics; + +import android.content.res.Resources; +import android.content.res.ColorStateList; +import android.test.AndroidTestCase; +import android.core.R; +import android.test.suitebuilder.annotation.SmallTest; + +/** + * Tests of {@link android.graphics.ColorStateList} + */ + +public class ColorStateListTest extends AndroidTestCase { + + private Resources mResources; + private int mFailureColor; + + @Override + protected void setUp() throws Exception { + super.setUp(); + mResources = mContext.getResources(); + mFailureColor = mResources.getColor(R.color.failColor); + } + + @SmallTest + public void testStateIsInList() throws Exception { + ColorStateList colorStateList = mResources.getColorStateList(R.color.color1); + int[] focusedState = {android.R.attr.state_focused}; + int focusColor = colorStateList.getColorForState(focusedState, R.color.failColor); + assertEquals(mResources.getColor(R.color.testcolor1), focusColor); + } + + @SmallTest + public void testEmptyState() throws Exception { + ColorStateList colorStateList = mResources.getColorStateList(R.color.color1); + int[] emptyState = {}; + int defaultColor = colorStateList.getColorForState(emptyState, mFailureColor); + assertEquals(mResources.getColor(R.color.testcolor2), defaultColor); + } + + @SmallTest + public void testGetColor() throws Exception { + int defaultColor = mResources.getColor(R.color.color1); + assertEquals(mResources.getColor(R.color.testcolor2), defaultColor); + } + + @SmallTest + public void testGetColorWhenListHasNoDefault() throws Exception { + int defaultColor = mResources.getColor(R.color.color_no_default); + assertEquals(mResources.getColor(R.color.testcolor1), defaultColor); + } +} diff --git a/tests/CoreTests/android/graphics/drawable/StateListDrawableTest.java b/tests/CoreTests/android/graphics/drawable/StateListDrawableTest.java new file mode 100644 index 0000000000000000000000000000000000000000..0d9f72e87cebdcbcffc7d339a10f14daead2a94b --- /dev/null +++ b/tests/CoreTests/android/graphics/drawable/StateListDrawableTest.java @@ -0,0 +1,98 @@ +/* + * Copyright (C) 2007 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 android.graphics.drawable; + +import junit.framework.TestCase; + +import android.R; +import android.graphics.Canvas; +import android.graphics.ColorFilter; +import android.util.StateSet; +import android.view.MockView; + +/** + * Tests for StateListDrawable + * + */ + +public class StateListDrawableTest extends TestCase { + + private StateListDrawable slDrawable; + private MockDrawable mockFocusedDrawable; + private MockDrawable mockCheckedDrawable; + private MockView mockView; + private MockDrawable mockDefaultDrawable; + + + // Re-enable tests when we are running in the framework-test directory which allows + // access to package private access for MockView + + public void broken_testFocusScenarioSetStringWildcardFirst() throws Exception { + int focusedStateSet[] = {R.attr.state_focused}; + int checkedStateSet[] = {R.attr.state_checked}; + slDrawable.addState(StateSet.WILD_CARD, + mockDefaultDrawable); + slDrawable.addState(checkedStateSet, mockCheckedDrawable); + slDrawable.addState(focusedStateSet, mockFocusedDrawable); + mockView.requestFocus(); + mockView.getBackground().draw(null); + assertTrue(mockDefaultDrawable.wasDrawn); + } + + public void broken_testFocusScenarioStateSetWildcardLast() throws Exception { + int focusedStateSet[] = {R.attr.state_focused}; + int checkedStateSet[] = {R.attr.state_checked}; + slDrawable.addState(checkedStateSet, mockCheckedDrawable); + slDrawable.addState(focusedStateSet, mockFocusedDrawable); + slDrawable.addState(StateSet.WILD_CARD, + mockDefaultDrawable); + mockView.requestFocus(); + mockView.getBackground().draw(null); + assertTrue(mockFocusedDrawable.wasDrawn); + } + + + protected void setUp() throws Exception { + super.setUp(); + slDrawable = new StateListDrawable(); + mockFocusedDrawable = new MockDrawable(); + mockCheckedDrawable = new MockDrawable(); + mockDefaultDrawable = new MockDrawable(); + mockView = new MockView(); + mockView.setBackgroundDrawable(slDrawable); + } + + static class MockDrawable extends Drawable { + + public boolean wasDrawn = false; + + public void draw(Canvas canvas) { + wasDrawn = true; + } + + public void setAlpha(int alpha) { + } + + public void setColorFilter(ColorFilter cf) { + } + + public int getOpacity() { + return android.graphics.PixelFormat.UNKNOWN; + } + } + +} diff --git a/tests/CoreTests/android/location/LocationManagerProximityTest.java b/tests/CoreTests/android/location/LocationManagerProximityTest.java new file mode 100644 index 0000000000000000000000000000000000000000..f2bff4d19b970aa3a069b14b3ce7f38b3414385a --- /dev/null +++ b/tests/CoreTests/android/location/LocationManagerProximityTest.java @@ -0,0 +1,294 @@ +/* + * Copyright (C) 2008 Google Inc. + * + * 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 android.location; + +import android.app.PendingIntent; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.location.Criteria; +import android.location.Location; +import android.location.LocationManager; +import android.test.AndroidTestCase; +import android.test.suitebuilder.annotation.MediumTest; +import android.util.Log; + +/** + * Tests for LocationManager.addProximityAlert + * + * TODO: add tests for more scenarios + * + * To run: + * adb shell am instrument -e class com.google.android.mapstests.api.LocationProximityTest \ + * -w com.google.android.mapstests/.MapInstrumentationTestRunner + * + */ +@MediumTest +public class LocationManagerProximityTest extends AndroidTestCase { + + private static final int UPDATE_LOCATION_WAIT_TIME = 1000; + private static final int PROXIMITY_WAIT_TIME = 2000; + + private LocationManager mLocationManager; + private PendingIntent mPendingIntent; + private TestIntentReceiver mIntentReceiver; + private String mOriginalAllowedProviders; + + private static final String LOG_TAG = "LocationProximityTest"; + + // use network provider as mock location provider, because: + // - proximity alert is hardcoded to listen to only network or gps + // - 'network' provider is not installed in emulator, so can mock it + // using test provider APIs + private static final String PROVIDER_NAME = LocationManager.NETWORK_PROVIDER; + + @Override + protected void setUp() throws Exception { + super.setUp(); + mOriginalAllowedProviders = + android.provider.Settings.Secure.getString( + getContext().getContentResolver(), + android.provider.Settings.Secure.LOCATION_PROVIDERS_ALLOWED); + + // ensure 'only' the mock provider is enabled + // need to do this so the proximity listener does not ignore the mock + // updates in favor of gps updates + android.provider.Settings.Secure.putString( + getContext().getContentResolver(), + android.provider.Settings.Secure.LOCATION_PROVIDERS_ALLOWED, + PROVIDER_NAME); + + mLocationManager = (LocationManager) getContext(). + getSystemService(Context.LOCATION_SERVICE); + if (mLocationManager.getProvider(PROVIDER_NAME) != null) { + mLocationManager.removeTestProvider(PROVIDER_NAME); + } + + mLocationManager.addTestProvider(PROVIDER_NAME, true, //requiresNetwork, + false, // requiresSatellite, + true, // requiresCell, + false, // hasMonetaryCost, + false, // supportsAltitude, + false, // supportsSpeed, s + false, // upportsBearing, + Criteria.POWER_MEDIUM, // powerRequirement + Criteria.ACCURACY_FINE); // accuracy + } + + @Override + protected void tearDown() throws Exception { + mLocationManager.removeTestProvider(PROVIDER_NAME); + + if (mPendingIntent != null) { + mLocationManager.removeProximityAlert(mPendingIntent); + } + if (mIntentReceiver != null) { + getContext().unregisterReceiver(mIntentReceiver); + } + + if (mOriginalAllowedProviders != null) { + // restore original settings + android.provider.Settings.Secure.putString( + getContext().getContentResolver(), + android.provider.Settings.Secure.LOCATION_PROVIDERS_ALLOWED, + mOriginalAllowedProviders); + mLocationManager.updateProviders(); + } + } + + /** + * Tests basic proximity alert when entering proximity + */ + public void testEnterProximity() throws Exception { + doTestEnterProximity(10000); + } + + /** + * Tests proximity alert when entering proximity, with no expiration + */ + public void testEnterProximity_noexpire() throws Exception { + doTestEnterProximity(-1); + } + + /** + * Helper variant for testing enter proximity scenario + * TODO: add additional parameters as more scenarios are added + * + * @param expiration - expiry of proximity alert + */ + private void doTestEnterProximity(long expiration) throws Exception { + // update location to outside proximity range + synchronousSendLocation(30, 30); + registerProximityListener(0, 0, 1000, expiration); + sendLocation(0, 0); + waitForAlert(); + assertProximityType(true); + } + + /** + * Tests basic proximity alert when exiting proximity + */ + public void testExitProximity() throws Exception { + // first do enter proximity scenario + doTestEnterProximity(-1); + + // now update to trigger exit proximity proximity + mIntentReceiver.clearReceivedIntents(); + sendLocation(20, 20); + waitForAlert(); + assertProximityType(false); + } + + /** + * Registers the proximity intent receiver + */ + private void registerProximityListener(double latitude, double longitude, + float radius, long expiration) { + String intentKey = "testProximity"; + Intent proximityIntent = new Intent(intentKey); + mPendingIntent = PendingIntent.getBroadcast(getContext(), 0, + proximityIntent, PendingIntent.FLAG_CANCEL_CURRENT); + mIntentReceiver = new TestIntentReceiver(intentKey); + + mLocationManager.addProximityAlert(latitude, longitude, radius, + expiration, mPendingIntent); + + getContext().registerReceiver(mIntentReceiver, + mIntentReceiver.getFilter()); + + } + + /** + * Blocks until proximity intent notification is received + * @throws InterruptedException + */ + private void waitForAlert() throws InterruptedException { + Log.d(LOG_TAG, "Waiting for proximity update"); + synchronized (mIntentReceiver) { + mIntentReceiver.wait(PROXIMITY_WAIT_TIME); + } + + assertNotNull("Did not receive proximity alert", + mIntentReceiver.getLastReceivedIntent()); + } + + /** + * Asserts that the received intent had the enter proximity property set as + * expected + * @param expectedEnterProximity - true if enter proximity expected, false if + * exit expected + */ + private void assertProximityType(boolean expectedEnterProximity) + throws Exception { + boolean proximityTest = mIntentReceiver.getLastReceivedIntent(). + getBooleanExtra(LocationManager.KEY_PROXIMITY_ENTERING, + !expectedEnterProximity); + assertEquals("proximity alert not set to expected enter proximity value", + expectedEnterProximity, proximityTest); + } + + /** + * Synchronous variant of sendLocation + */ + private void synchronousSendLocation(final double latitude, + final double longitude) + throws InterruptedException { + sendLocation(latitude, longitude, this); + // wait for location to be set + synchronized (this) { + wait(UPDATE_LOCATION_WAIT_TIME); + } + } + + /** + * Asynchronously update the mock location provider without notification + */ + private void sendLocation(final double latitude, final double longitude) { + sendLocation(latitude, longitude, null); + } + + /** + * Asynchronously update the mock location provider with given latitude and + * longitude + * + * @param latitude - update location + * @param longitude - update location + * @param observer - optionally, object to notify when update is sent.If + * null, no update will be sent + */ + private void sendLocation(final double latitude, final double longitude, + final Object observer) { + Thread locationUpdater = new Thread() { + @Override + public void run() { + Location loc = new Location(PROVIDER_NAME); + loc.setLatitude(latitude); + loc.setLongitude(longitude); + + loc.setTime(java.lang.System.currentTimeMillis()); + Log.d(LOG_TAG, "Sending update for " + PROVIDER_NAME); + mLocationManager.setTestProviderLocation(PROVIDER_NAME, loc); + if (observer != null) { + synchronized (observer) { + observer.notify(); + } + } + } + }; + locationUpdater.start(); + + } + + /** + * Helper class that receives a proximity intent and notifies the main class + * when received + */ + private static class TestIntentReceiver extends BroadcastReceiver { + + private String mExpectedAction; + private Intent mLastReceivedIntent; + + public TestIntentReceiver(String expectedAction) { + mExpectedAction = expectedAction; + mLastReceivedIntent = null; + } + + public IntentFilter getFilter() { + IntentFilter filter = new IntentFilter(mExpectedAction); + return filter; + } + + @Override + public void onReceive(Context context, Intent intent) { + if (intent != null && mExpectedAction.equals(intent.getAction())) { + Log.d(LOG_TAG, "Intent Received: " + intent.toString()); + mLastReceivedIntent = intent; + synchronized (this) { + notify(); + } + } + } + + public Intent getLastReceivedIntent() { + return mLastReceivedIntent; + } + + public void clearReceivedIntents() { + mLastReceivedIntent = null; + } + } +} diff --git a/tests/CoreTests/android/location/LocationTest.java b/tests/CoreTests/android/location/LocationTest.java new file mode 100644 index 0000000000000000000000000000000000000000..847ac7a000be53c1aadb955e9d7c566f043e1240 --- /dev/null +++ b/tests/CoreTests/android/location/LocationTest.java @@ -0,0 +1,230 @@ +/* + * Copyright (C) 2007 Google Inc. + * + * 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 android.location; + +import android.test.suitebuilder.annotation.SmallTest; + +import junit.framework.TestCase; + +/** + * Unit tests for android.location.Location + */ +@SmallTest +public class LocationTest extends TestCase { + + // ***** Tests for Location.convert + public void testConvert_DegreesToDouble(){ + String testDegreesCoord = "-80.075"; + String message; + double result; + + result = Location.convert(testDegreesCoord); + message = "degreesToDoubleTest: Double should be -80.075, actual value is " + + String.valueOf(result); + assertEquals(message, -80.075, result); + } + + public void testConvert_MinutesToDouble(){ + String testMinutesCoord = "-80:05.10000"; + String message; + double result; + + result = Location.convert(testMinutesCoord); + message = "minutesToDoubleTest: Double should be -80.085, actual value is " + + String.valueOf(result); + assertEquals(message, -80.085, result); + } + + public void testConvert_SecondsToDouble(){ + String testSecondsCoord = "-80:04:03.00000"; + String message; + double result; + + result = Location.convert(testSecondsCoord); + message = "secondsToDoubleTest: Double should be -80.0675, actual value is " + + String.valueOf(result); + assertEquals(message, -80.0675, result); + } + + public void testConvert_SecondsToDouble2(){ + String testSecondsCoord = "-80:4:3"; + String message; + double result; + + result = Location.convert(testSecondsCoord); + message = "secondsToDouble2Test: Double should be -80.0675, actual value is " + + String.valueOf(result); + assertEquals(message, -80.0675, result); + } + + // Testing the Convert(Double, Int) + public void testConvert_CoordinateToDegrees(){ + String message; + String result; + + result = Location.convert(-80.075, Location.FORMAT_DEGREES); + message = "coordinateToDegreesTest: Should return a string -80.075, but returned " + result; + assertEquals(message, "-80.075", result); + } + + public void testConvert_CoordinateToDegrees2(){ + String message; + String result; + result = Location.convert(-80.0, Location.FORMAT_DEGREES); + message = "coordinateToDegrees2Test: Should return a string -80, but returned " + result; + assertEquals(message, "-80", result); + } + + public void testConvert_CoordinateToMinutes(){ + String message; + String result; + double input = -80.085; + result = Location.convert(input, Location.FORMAT_MINUTES); + message = "coordinateToMinuteTest: Should return a string -80:5.1, but returned " + + result; + assertEquals(message, "-80:5.1", result); + } + + public void testConvert_CoordinateToMinutes2(){ + String message; + String result; + double input = -80; + result = Location.convert(input, Location.FORMAT_MINUTES); + message = "coordinateToMinute2Test: Should return a string -80:0, but returned " + + result; + assertEquals(message, "-80:0", result); + } + + public void testConvert_CoordinateToSeconds(){ + String message; + String result; + + result = Location.convert(-80.075, Location.FORMAT_SECONDS); + message = "coordinateToSecondsTest: Should return a string -80:4:30, but returned " + + result; + assertEquals(message, "-80:4:30", result); + } + // **** end tests for Location.convert + + + public void testBearingTo(){ + String message; + float bearing; + Location zeroLocation = new Location(""); + zeroLocation.setLatitude(0); + zeroLocation.setLongitude(0); + + Location testLocation = new Location(""); + testLocation.setLatitude(1000000); + testLocation.setLongitude(0); + + bearing = zeroLocation.bearingTo(zeroLocation); + message = "bearingToTest: Bearing should be 0, actual value is " + String.valueOf(bearing); + assertEquals(message, 0, bearing, 0); + + bearing = zeroLocation.bearingTo(testLocation); + message = "bearingToTest: Bearing should be 180, actual value is " + + String.valueOf(bearing); + assertEquals(message, 180, bearing, 0); + + testLocation.setLatitude(0); + testLocation.setLongitude(1000000); + bearing = zeroLocation.bearingTo(testLocation); + message = "bearingToTest: Bearing should be -90, actual value is " + + String.valueOf(bearing); + assertEquals(message, -90, bearing, 0); + + //TODO: Test a Random Middle Value + } + + public void testDistanceTo() { + String message; + boolean result = true; + float distance; + Location zeroLocation = new Location(""); + zeroLocation.setLatitude(0); + zeroLocation.setLongitude(0); + + Location testLocation = new Location(""); + testLocation.setLatitude(1000000); + testLocation.setLongitude(0); + + distance = zeroLocation.distanceTo(zeroLocation); + message = "distanceToTest: Distance should be 0, actual value is " + + String.valueOf(distance); + assertEquals(message, distance, 0, 0); + + distance = zeroLocation.distanceTo(testLocation); + message = "distanceToTest: Distance should be 8885140, actual value is " + + String.valueOf(distance); + assertEquals(message, distance, 8885140.0, 1); + } + + public void testAltitude() { + String message; + Location loc = new Location(""); + + loc.setAltitude(1); + message = "altitudeTest: set/getAltitude to 1 didn't work."; + assertEquals(message, loc.getAltitude(), 1, 0); + message = "altitudeTest: hasAltitude (a) didn't work."; + assertTrue(message, loc.hasAltitude()); + + loc.removeAltitude(); + message = "altitudeTest: hasAltitude (b) didn't work."; + assertFalse(message, loc.hasAltitude()); + message = "altitudeTest: getAltitude didn't return 0 when there was no altitude."; + assertEquals(message, loc.getAltitude(), 0, 0); + } + + public void testSpeed() { + String message; + Location loc = new Location(""); + + loc.setSpeed(1); + message = "speedTest: set/getSpeed to 1 didn't work."; + assertEquals(message, loc.getSpeed(), 1, 0); + message = "speedTest: hasSpeed (a) didn't work."; + assertTrue(message, loc.hasSpeed()); + + loc.removeSpeed(); + message = "speedTest: hasSpeed (b) didn't work."; + assertFalse(message, loc.hasSpeed()); + message = "speedTest: getSpeed didn't return 0 when there was no speed."; + assertEquals(message, loc.getSpeed(), 0, 0); + } + + public void testBearing() { + String message; + Location loc = new Location(""); + + loc.setBearing(1); + message = "bearingTest: set/getBearing to 1 didn't work."; + assertEquals(message, loc.getBearing(), 1, 0); + message = "bearingTest: hasBearing (a) didn't work."; + assertTrue(message, loc.hasBearing()); + + loc.removeBearing(); + message = "bearingTest: hasBearing (b) didn't work."; + assertFalse(message, loc.hasBearing()); + message = "bearingTest: getBearing didn't return 0 when there was no bearing."; + assertEquals(message, loc.getBearing(), 0, 0); + } + +} + + diff --git a/tests/CoreTests/android/res/color/color1.xml b/tests/CoreTests/android/res/color/color1.xml new file mode 100644 index 0000000000000000000000000000000000000000..87034fa2aeb0574083807f0c668fb7b20aecd698 --- /dev/null +++ b/tests/CoreTests/android/res/color/color1.xml @@ -0,0 +1,20 @@ + + + + + + + diff --git a/tests/CoreTests/android/res/color/color_no_default.xml b/tests/CoreTests/android/res/color/color_no_default.xml new file mode 100644 index 0000000000000000000000000000000000000000..41a9b5d83c864cd35310ac3257100d381c59608e --- /dev/null +++ b/tests/CoreTests/android/res/color/color_no_default.xml @@ -0,0 +1,19 @@ + + + + + + diff --git a/tests/CoreTests/android/res/values/colors.xml b/tests/CoreTests/android/res/values/colors.xml new file mode 100644 index 0000000000000000000000000000000000000000..7559e6580793db97c8850b7068650596a074833f --- /dev/null +++ b/tests/CoreTests/android/res/values/colors.xml @@ -0,0 +1,24 @@ + + + + #ff00ff00 + #ffff0000 + #ff0000ff + + diff --git a/tests/CoreTests/android/test/AndroidTestRunnerTest.java b/tests/CoreTests/android/test/AndroidTestRunnerTest.java new file mode 100644 index 0000000000000000000000000000000000000000..05747049dd21c6a18bb95792610fcd59cfe92f6b --- /dev/null +++ b/tests/CoreTests/android/test/AndroidTestRunnerTest.java @@ -0,0 +1,294 @@ +/* + * 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 android.test; + +import android.test.mock.MockContext; +import android.test.suitebuilder.annotation.SmallTest; + +import com.google.android.collect.Lists; + +import junit.framework.TestCase; +import junit.framework.AssertionFailedError; +import junit.framework.Test; +import junit.framework.TestSuite; +import junit.framework.TestListener; + +import java.util.List; +import java.util.Arrays; + +/** + * Unit tests for {@link AndroidTestRunner} + */ +@SmallTest +public class AndroidTestRunnerTest extends TestCase { + private AndroidTestRunner mAndroidTestRunner; + private StubContext mStubContext; + + @Override + protected void setUp() throws Exception { + super.setUp(); + mStubContext = new StubContext(getClass().getClassLoader()); + + mAndroidTestRunner = new AndroidTestRunner(); + mAndroidTestRunner.setContext(mStubContext); + } + + public void testLoadNoTestCases() throws Exception { + mAndroidTestRunner.setTestClassName(TestSuite.class.getName(), null); + + List testCases = mAndroidTestRunner.getTestCases(); + assertNotNull(testCases); + assertEquals(1, testCases.size()); + assertEquals("warning", testCases.get(0).getName()); + assertEquals(TestSuite.class.getSimpleName(), mAndroidTestRunner.getTestClassName()); + } + + public void testSetTestSuiteWithOneTestCase() throws Exception { + mAndroidTestRunner.setTestClassName(OneTestTestCase.class.getName(), null); + + List testCases = mAndroidTestRunner.getTestCases(); + assertNotNull(testCases); + assertEquals(1, testCases.size()); + assertEquals("testOne", testCases.get(0).getName()); + assertEquals(OneTestTestCase.class.getSimpleName(), mAndroidTestRunner.getTestClassName()); + } + + public void testRunTest() throws Exception { + mAndroidTestRunner.setTestClassName(OneTestTestCase.class.getName(), null); + + TestListenerStub testListenerStub = new TestListenerStub(); + mAndroidTestRunner.addTestListener(testListenerStub); + + mAndroidTestRunner.runTest(); + + assertTrue(testListenerStub.saw("testOne")); + } + + public void testRunTestWithAndroidTestCase() throws Exception { + mAndroidTestRunner.setTestClassName( + OneAndroidTestTestCase.class.getName(), "testOneAndroid"); + + TestListenerStub testListenerStub = new TestListenerStub(); + mAndroidTestRunner.addTestListener(testListenerStub); + + assertNull(((AndroidTestCase) mAndroidTestRunner.getTestCases().get(0)).getContext()); + + mAndroidTestRunner.runTest(); + + assertTrue(testListenerStub.saw("testOneAndroid")); + assertSame(mStubContext, + ((AndroidTestCase) mAndroidTestRunner.getTestCases().get(0)).getContext()); + } + + public void testRunTestWithAndroidTestCaseInSuite() throws Exception { + mAndroidTestRunner.setTestClassName(OneAndroidTestTestCase.class.getName(), null); + + TestListenerStub testListenerStub = new TestListenerStub(); + mAndroidTestRunner.addTestListener(testListenerStub); + + mAndroidTestRunner.runTest(); + + assertTrue(testListenerStub.saw("testOneAndroid")); + + List testCases = mAndroidTestRunner.getTestCases(); + for (TestCase testCase : testCases) { + assertSame(mStubContext, ((AndroidTestCase) testCase).getContext()); + } + } + + public void testRunTestWithAndroidTestCaseInNestedSuite() throws Exception { + mAndroidTestRunner.setTestClassName(AndroidTestCaseTestSuite.class.getName(), null); + + TestListenerStub testListenerStub = new TestListenerStub(); + mAndroidTestRunner.addTestListener(testListenerStub); + + mAndroidTestRunner.runTest(); + + assertTrue(testListenerStub.saw("testOneAndroid")); + + List testCases = mAndroidTestRunner.getTestCases(); + for (TestCase testCase : testCases) { + assertSame(mStubContext, ((AndroidTestCase) testCase).getContext()); + } + } + + public void testRunTestWithNullListener() throws Exception { + mAndroidTestRunner.setTestClassName(OneTestTestCase.class.getName(), null); + + mAndroidTestRunner.addTestListener(null); + try { + mAndroidTestRunner.runTest(); + } catch (NullPointerException e) { + fail("Should not add a null TestListener"); + } + } + + public void testSetTestClassWithTestSuiteProvider() throws Exception { + mAndroidTestRunner.setTestClassName(SampleTestSuiteProvider.class.getName(), null); + List testCases = mAndroidTestRunner.getTestCases(); + List testNames = Lists.newArrayList(); + for (TestCase testCase : testCases) { + testNames.add(testCase.getName()); + } + + // Use the test suite provided by the interface method rather than the static suite method. + assertEquals(Arrays.asList("testOne"), testNames); + } + + public void testSetTestClassWithTestSuite() throws Exception { + mAndroidTestRunner.setTestClassName(SampleTestSuite.class.getName(), null); + List testCases = mAndroidTestRunner.getTestCases(); + List testNames = Lists.newArrayList(); + for (TestCase testCase : testCases) { + testNames.add(testCase.getName()); + } + assertEquals(Arrays.asList("testOne", "testOne", "testTwo"), testNames); + } + + public void testRunSingleTestMethod() throws Exception { + String testMethodName = "testTwo"; + mAndroidTestRunner.setTestClassName(TwoTestTestCase.class.getName(), testMethodName); + List testCases = mAndroidTestRunner.getTestCases(); + List testNames = Lists.newArrayList(); + for (TestCase testCase : testCases) { + testNames.add(testCase.getName()); + } + assertEquals(Arrays.asList(testMethodName), testNames); + } + + public void testSetTestClassInvalidClass() throws Exception { + try { + mAndroidTestRunner.setTestClassName("class.that.does.not.exist", null); + fail("expected exception not thrown"); + } catch (RuntimeException e) { + // expected + } + } + + public void testRunSkipExecution() throws Exception { + String testMethodName = "testFail"; + mAndroidTestRunner.setTestClassName( + OnePassOneErrorOneFailTestCase.class.getName(), testMethodName); + + TestListenerStub testListenerStub = new TestListenerStub(); + mAndroidTestRunner.addTestListener(testListenerStub); + + // running the failing test should pass - ie as if its not run + mAndroidTestRunner.runTest(); + + assertTrue(testListenerStub.saw("testFail")); + } + + public static class SampleTestSuiteProvider implements TestSuiteProvider { + + public TestSuite getTestSuite() { + TestSuite testSuite = new TestSuite(); + testSuite.addTestSuite(OneTestTestCase.class); + return testSuite; + } + + public static Test suite() { + return SampleTestSuite.suite(); + } + } + + public static class SampleTestSuite { + public static TestSuite suite() { + TestSuite testSuite = new TestSuite(); + testSuite.addTestSuite(OneTestTestCase.class); + testSuite.addTestSuite(TwoTestTestCase.class); + return testSuite; + } + } + + public static class AndroidTestCaseTestSuite { + public static TestSuite suite() { + TestSuite testSuite = new TestSuite(); + testSuite.addTestSuite(OneAndroidTestTestCase.class); + return testSuite; + } + } + + public static class OneAndroidTestTestCase extends AndroidTestCase { + public void testOneAndroid() throws Exception { + } + } + + public static class OneTestTestCase extends TestCase { + public void testOne() throws Exception { + } + } + + public static class TwoTestTestCase extends TestCase { + public void testOne() throws Exception { + } + + public void testTwo() throws Exception { + } + } + + public static class OnePassOneErrorOneFailTestCase extends TestCase { + public void testPass() throws Exception { + } + + public void testError() throws Exception { + throw new Exception(); + } + + public void testFail() throws Exception { + fail(); + } + } + + private static class TestListenerStub implements TestListener { + List testNames = Lists.newArrayList(); + + public void addError(Test test, Throwable t) { + } + + public void addFailure(Test test, AssertionFailedError t) { + } + + public void endTest(Test test) { + } + + public void startTest(Test test) { + if (test instanceof TestCase) { + testNames.add(((TestCase) test).getName()); + } else if (test instanceof TestSuite) { + testNames.add(((TestSuite) test).getName()); + } + } + + public boolean saw(String testName) { + return testNames.contains(testName); + } + } + + private static class StubContext extends MockContext { + private ClassLoader mClassLoader; + + public StubContext(ClassLoader classLoader) { + this.mClassLoader = classLoader; + } + + @Override + public ClassLoader getClassLoader() { + return mClassLoader; + } + } +} diff --git a/tests/CoreTests/android/test/InstrumentationTestRunnerTest.java b/tests/CoreTests/android/test/InstrumentationTestRunnerTest.java new file mode 100644 index 0000000000000000000000000000000000000000..359c902762e6492866d897da4cb8c7f6ace49e4f --- /dev/null +++ b/tests/CoreTests/android/test/InstrumentationTestRunnerTest.java @@ -0,0 +1,251 @@ +/* + * 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 android.test; + +import android.content.Context; +import android.os.Bundle; +import android.test.mock.MockContext; +import android.test.suitebuilder.ListTestCaseNames; +import android.test.suitebuilder.ListTestCaseNames.TestDescriptor; +import android.test.suitebuilder.annotation.SmallTest; + +import junit.framework.Test; +import junit.framework.TestCase; +import junit.framework.TestSuite; + +import java.util.List; + +/** + * Tests for {@link InstrumentationTestRunner} + */ +@SmallTest +public class InstrumentationTestRunnerTest extends TestCase { + private StubInstrumentationTestRunner mInstrumentationTestRunner; + private StubAndroidTestRunner mStubAndroidTestRunner; + private String mTargetContextPackageName; + + protected void setUp() throws Exception { + super.setUp(); + mStubAndroidTestRunner = new StubAndroidTestRunner(); + mTargetContextPackageName = "android.test.suitebuilder.examples"; + mInstrumentationTestRunner = new StubInstrumentationTestRunner( + new StubContext("com.google.foo.tests"), + new StubContext(mTargetContextPackageName), mStubAndroidTestRunner); + } + + public void testOverrideTestToRunWithClassArgument() throws Exception { + String expectedTestClassName = PlaceHolderTest.class.getName(); + mInstrumentationTestRunner.onCreate(createBundle( + InstrumentationTestRunner.ARGUMENT_TEST_CLASS, expectedTestClassName)); + + assertTestRunnerCalledWithExpectedParameters(expectedTestClassName, "testPlaceHolder"); + } + + public void testOverrideTestToRunWithClassAndMethodArgument() throws Exception { + String expectedTestClassName = PlaceHolderTest.class.getName(); + String expectedTestMethodName = "testPlaceHolder"; + String classAndMethod = expectedTestClassName + "#" + expectedTestMethodName; + mInstrumentationTestRunner.onCreate(createBundle( + InstrumentationTestRunner.ARGUMENT_TEST_CLASS, classAndMethod)); + + assertTestRunnerCalledWithExpectedParameters(expectedTestClassName, + expectedTestMethodName); + } + + public void testUseSelfAsTestSuiteProviderWhenNoMetaDataOrClassArgument() throws Exception { + TestSuite testSuite = new TestSuite(); + testSuite.addTestSuite(PlaceHolderTest.class); + mInstrumentationTestRunner.setAllTestsSuite(testSuite); + mInstrumentationTestRunner.onCreate(null); + assertTestRunnerCalledWithExpectedParameters( + PlaceHolderTest.class.getName(), "testPlaceHolder"); + } + + public void testMultipleTestClass() throws Exception { + String classArg = PlaceHolderTest.class.getName() + "," + + PlaceHolderTest2.class.getName(); + mInstrumentationTestRunner.onCreate(createBundle( + InstrumentationTestRunner.ARGUMENT_TEST_CLASS, classArg)); + + Test test = mStubAndroidTestRunner.getTest(); + + assertContentsInOrder(ListTestCaseNames.getTestNames((TestSuite) test), + new TestDescriptor(PlaceHolderTest.class.getName(), "testPlaceHolder"), + new TestDescriptor(PlaceHolderTest2.class.getName(), "testPlaceHolder2")); + + } + + private void assertContentsInOrder(List actual, TestDescriptor... source) { + TestDescriptor[] clonedSource = source.clone(); + assertEquals("Unexpected number of items.", clonedSource.length, actual.size()); + for (int i = 0; i < actual.size(); i++) { + TestDescriptor actualItem = actual.get(i); + TestDescriptor sourceItem = clonedSource[i]; + assertEquals("Unexpected item. Index: " + i, sourceItem, actualItem); + } + } + + private void assertTestRunnerCalledWithExpectedParameters( + String expectedTestClassName, String expectedTestMethodName) { + Test test = mStubAndroidTestRunner.getTest(); + assertContentsInOrder(ListTestCaseNames.getTestNames((TestSuite) test), + new TestDescriptor(expectedTestClassName, expectedTestMethodName)); + assertTrue(mInstrumentationTestRunner.isStarted()); + assertFalse(mInstrumentationTestRunner.isFinished()); + } + + private Bundle createBundle(String key, String value) { + Bundle bundle = new Bundle(); + bundle.putString(key, value); + return bundle; + } + + private static class StubInstrumentationTestRunner extends InstrumentationTestRunner { + private Context mContext; + private Context mTargetContext; + private boolean mStarted; + private boolean mFinished; + private AndroidTestRunner mAndroidTestRunner; + private TestSuite mTestSuite; + private TestSuite mDefaultTestSuite; + private String mPackageNameForDefaultTests; + + public StubInstrumentationTestRunner(Context context, Context targetContext, + AndroidTestRunner androidTestRunner) { + this.mContext = context; + this.mTargetContext = targetContext; + this.mAndroidTestRunner = androidTestRunner; + } + + public Context getContext() { + return mContext; + } + + public TestSuite getAllTests() { + return mTestSuite; + } + + public Context getTargetContext() { + return mTargetContext; + } + + protected AndroidTestRunner getAndroidTestRunner() { + return mAndroidTestRunner; + } + + public void start() { + mStarted = true; + } + + public void finish(int resultCode, Bundle results) { + mFinished = true; + } + + public boolean isStarted() { + return mStarted; + } + + public boolean isFinished() { + return mFinished; + } + + public void setAllTestsSuite(TestSuite testSuite) { + mTestSuite = testSuite; + } + + public void setDefaultTestsSuite(TestSuite testSuite) { + mDefaultTestSuite = testSuite; + } + + public String getPackageNameForDefaultTests() { + return mPackageNameForDefaultTests; + } + } + + private static class StubContext extends MockContext { + private String mPackageName; + + public StubContext(String packageName) { + this.mPackageName = packageName; + } + + @Override + public String getPackageCodePath() { + return mPackageName; + } + + @Override + public String getPackageName() { + return mPackageName; + } + + @Override + public ClassLoader getClassLoader() { + return getClass().getClassLoader(); + } + } + + private static class StubAndroidTestRunner extends AndroidTestRunner { + private Test mTest; + private boolean mRun; + + public boolean isRun() { + return mRun; + } + + public void setTest(Test test) { + super.setTest(test); + mTest = test; + } + + public Test getTest() { + return mTest; + } + + public void runTest() { + mRun = true; + } + } + + /** + * Empty test used for validation + */ + public static class PlaceHolderTest extends TestCase { + + public PlaceHolderTest() { + super("testPlaceHolder"); + } + + public void testPlaceHolder() throws Exception { + + } + } + + /** + * Empty test used for validation + */ + public static class PlaceHolderTest2 extends TestCase { + + public PlaceHolderTest2() { + super("testPlaceHolder2"); + } + + public void testPlaceHolder2() throws Exception { + + } + } +} diff --git a/tests/CoreTests/android/test/StubTestBrowserActivity.java b/tests/CoreTests/android/test/StubTestBrowserActivity.java new file mode 100644 index 0000000000000000000000000000000000000000..97ed3ce82185da3e4a55d984357a93652d4a5c38 --- /dev/null +++ b/tests/CoreTests/android/test/StubTestBrowserActivity.java @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2007 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 android.test; + +import junit.framework.TestSuite; + +public class StubTestBrowserActivity extends TestBrowserActivity { + + private static TestSuite mTestSuite; + + static void setTopTestSuite(TestSuite testSuite) { + mTestSuite = testSuite; + } + + @Override + public TestSuite getTopTestSuite() { + return mTestSuite; + } +} diff --git a/tests/CoreTests/android/test/TestBrowserActivityTest.java b/tests/CoreTests/android/test/TestBrowserActivityTest.java new file mode 100644 index 0000000000000000000000000000000000000000..6afbe3717a37b9ab086797975128e5d1770201ac --- /dev/null +++ b/tests/CoreTests/android/test/TestBrowserActivityTest.java @@ -0,0 +1,270 @@ +/* + * Copyright (C) 2007 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 android.test; + +import android.app.Activity; +import android.app.Instrumentation; +import android.content.Intent; +import android.net.Uri; +import android.os.RemoteException; +import android.os.ServiceManager; +import android.view.IWindowManager; +import android.widget.ListView; + +import com.google.android.collect.Lists; + +import junit.framework.Test; +import junit.framework.TestCase; +import junit.framework.TestSuite; + +import java.util.List; + +public class TestBrowserActivityTest extends InstrumentationTestCase { + + private TestBrowserActivity mTestBrowserActivity; + private StubTestBrowserController mTestBrowserController; + + @Override + protected void setUp() throws Exception { + super.setUp(); + StubTestBrowserActivity.setTopTestSuite(null); + mTestBrowserController = new StubTestBrowserController(); + ServiceLocator.setTestBrowserController(mTestBrowserController); + } + + @Override + protected void tearDown() throws Exception { + if (mTestBrowserActivity != null) { + mTestBrowserActivity.finish(); + } + mTestBrowserActivity = null; + super.tearDown(); + } + + public void testEmptyListContent() throws Exception { + StubTestBrowserActivity.setTopTestSuite(new TestSuite()); + + mTestBrowserActivity = createActivity(); + + ListView listView = getListView(); + // There is always an item on the list for running all tests. + assertEquals("Unexpected number of items on list view.", 1, listView.getCount()); + + assertEquals("Stubbed Test Browser", mTestBrowserActivity.getTitle().toString()); + } + + public void testOneListContent() throws Exception { + List testCaseNames = Lists.newArrayList("AllTests"); + StubTestBrowserActivity.setTopTestSuite(createTestSuite(testCaseNames)); + + mTestBrowserActivity = createActivity(); + + ListView listView = getListView(); + assertListViewContents(testCaseNames, listView); + } + + public void testListWithTestCases() throws Exception { + List testCaseNames = Lists.newArrayList("AllTests", "Apples", "Bananas", "Oranges"); + StubTestBrowserActivity.setTopTestSuite(createTestSuite(testCaseNames)); + + mTestBrowserActivity = createActivity(); + + ListView listView = getListView(); + assertListViewContents(testCaseNames, listView); + } + + public void testListWithTestSuite() throws Exception { + List testCaseNames = Lists.newArrayList(OneTestTestCase.class.getSimpleName()); + StubTestBrowserActivity.setTopTestSuite(new OneTestInTestSuite()); + + mTestBrowserActivity = createActivity(); + + ListView listView = getListView(); + assertListViewContents(testCaseNames, listView); + } + + public void testSelectATestCase() throws Exception { + List testCaseNames = Lists.newArrayList("AllTests"); + TestSuite testSuite = createTestSuite(testCaseNames); + StubTestBrowserActivity.setTopTestSuite(testSuite); + + mTestBrowserController.setTestCase(OneTestTestCase.class); + mTestBrowserActivity = createActivity(); + + Instrumentation.ActivityMonitor activityMonitor = getInstrumentation().addMonitor( + TestBrowserControllerImpl.TEST_RUNNER_ACTIVITY_CLASS_NAME, null, false); + try { + assertEquals(0, activityMonitor.getHits()); + + ListView listView = getListView(); + int invokedTestCaseIndex = 0; + listView.performItemClick(listView, invokedTestCaseIndex, 0); + + Activity activity = activityMonitor.waitForActivityWithTimeout(2000); + assertNotNull(activity); + try { + assertEquals(1, activityMonitor.getHits()); + assertEquals(invokedTestCaseIndex, mTestBrowserController.getLastPosition()); + } finally { + activity.finish(); + } + } finally { + getInstrumentation().removeMonitor(activityMonitor); + } + } + + public void testCreateFromIntentWithOneTest() throws Exception { + List testCaseNames = Lists.newArrayList("testOne"); + + mTestBrowserActivity = launchTestBrowserActivity(new TestSuite(OneTestTestCase.class)); + + ListView listView = getListView(); + assertListViewContents(testCaseNames, listView); + } + + public void testUpdateListOnStart() throws Exception { + StubTestBrowserActivity.setTopTestSuite(new TestSuite()); + + mTestBrowserActivity = createActivity(); + + ListView listView = getListView(); + assertEquals("Unexpected number of items on list view.", 1, listView.getCount()); + + List testCaseNames = Lists.newArrayList("AllTests"); + StubTestBrowserActivity.setTopTestSuite(createTestSuite(testCaseNames)); + + getInstrumentation().runOnMainSync(new Runnable() { + public void run() { + ((StubTestBrowserActivity) mTestBrowserActivity).onStart(); + } + }); + + listView = getListView(); + assertListViewContents(testCaseNames, listView); + } + + public void testTitleHasTestSuiteName() throws Exception { + final String testSuiteName = "com.android.TestSuite"; + StubTestBrowserActivity.setTopTestSuite(new TestSuite(testSuiteName)); + + mTestBrowserActivity = createActivity(); + + assertEquals("TestSuite", mTestBrowserActivity.getTitle().toString()); + } + + private TestSuite createTestSuite(List testCaseNames) { + return createTestSuite(testCaseNames.toArray(new String[testCaseNames.size()])); + } + + private TestSuite createTestSuite(String... testCaseNames) { + TestSuite testSuite = new TestSuite(); + for (String testCaseName : testCaseNames) { + testSuite.addTest(new FakeTestCase(testCaseName)); + } + + return testSuite; + } + + public static class FakeTestCase extends TestCase { + public FakeTestCase(String name) { + super(name); + } + } + + public static class OneTestTestCase extends TestCase { + public void testOne() throws Exception { + } + } + + public static class OneTestInTestSuite extends TestSuite { + public static Test suite() { + TestSuite suite = new TestSuite(OneTestInTestSuite.class.getName()); + suite.addTestSuite(OneTestTestCase.class); + return suite; + } + } + + private void assertListViewContents(List expectedTestCaseNames, ListView listView) { + assertEquals("Run All", listView.getItemAtPosition(0).toString()); + assertEquals("Unexpected number of items on list view.", + expectedTestCaseNames.size() + 1, listView.getCount()); + for (int i = 0; i < expectedTestCaseNames.size(); i++) { + String expectedTestCaseName = expectedTestCaseNames.get(i); + String actualTestCaseName = listView.getItemAtPosition(i + 1).toString(); + assertEquals("Unexpected test case name. Index: " + i, + expectedTestCaseName, actualTestCaseName); + } + } + + private ListView getListView() { + return mTestBrowserActivity.getListView(); + } + + private TestBrowserActivity createActivity() throws RemoteException { + return launchActivity("android.test", StubTestBrowserActivity.class, null); + } + + private Intent createIntent(TestSuite testSuite) { + Intent intent = new Intent(Intent.ACTION_RUN); + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + String className = StubTestBrowserActivity.class.getName(); + String packageName = className.substring(0, className.lastIndexOf(".")); + intent.setClassName(packageName, className); + intent.setData(Uri.parse(testSuite.getName())); + return intent; + } + + private TestBrowserActivity launchTestBrowserActivity(TestSuite testSuite) + throws RemoteException { + getInstrumentation().setInTouchMode(false); + + TestBrowserActivity activity = + (TestBrowserActivity) getInstrumentation().startActivitySync( + createIntent(testSuite)); + getInstrumentation().waitForIdleSync(); + return activity; + } + + private static class StubTestBrowserController extends TestBrowserControllerImpl { + private int mPosition; + private Class mTestCaseClass; + + public Intent getIntentForTestAt(int position) { + mPosition = position; + + Intent intent = new Intent(); + intent.setAction(Intent.ACTION_RUN); + + String className = TestBrowserControllerImpl.TEST_RUNNER_ACTIVITY_CLASS_NAME; + String testName = mTestCaseClass.getClass().getName(); + + String packageName = className.substring(0, className.lastIndexOf(".")); + intent.setClassName(packageName, className); + intent.setData(Uri.parse(testName)); + + return intent; + } + + public void setTestCase(Class testCaseClass) { + mTestCaseClass = testCaseClass; + } + + public int getLastPosition() { + return mPosition; + } + } +} diff --git a/tests/CoreTests/android/test/TestBrowserControllerImplTest.java b/tests/CoreTests/android/test/TestBrowserControllerImplTest.java new file mode 100644 index 0000000000000000000000000000000000000000..1315606896030f55b19d1eb874c9674eaac4bfe3 --- /dev/null +++ b/tests/CoreTests/android/test/TestBrowserControllerImplTest.java @@ -0,0 +1,134 @@ +/* + * Copyright (C) 2007 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 android.test; + +import android.content.Intent; + +import junit.framework.TestCase; +import junit.framework.TestSuite; + +import java.util.Arrays; +import java.util.List; + +public class TestBrowserControllerImplTest extends TestCase { + private TestBrowserControllerImpl mTestBrowserController; + private TestBrowserViewStub mTestBrowserView; + + @Override + protected void setUp() throws Exception { + super.setUp(); + mTestBrowserController = new TestBrowserControllerImpl(); + mTestBrowserView = new TestBrowserViewStub(); + mTestBrowserController.registerView(mTestBrowserView); + } + + public void testSetTestSuite() throws Exception { + TestSuite testSuite = new TestSuite(); + testSuite.addTestSuite(DummyTestCase.class); + + mTestBrowserController.setTestSuite(testSuite); + + verifyTestNames(Arrays.asList("Run All", DummyTestCase.class.getSimpleName()), + mTestBrowserView.getTestNames()); + } + + private static void verifyTestNames(List expectedTestNames, + List actualTestNames) { + assertEquals(expectedTestNames.size(), actualTestNames.size()); + + // We use endsWith instead of equals because the return value of + // class.getSimpleName(), when called on an inner class, varies + // from one vm to another. + // This allows the test to pass in multiple environments. + for (int i = 0; i < expectedTestNames.size(); i++) { + assertTrue(actualTestNames.get(i).endsWith(expectedTestNames.get(i))); + } + } + + public void testGetIntentForTestSuite() throws Exception { + TestSuite testSuite = new TestSuite(); + testSuite.addTestSuite(DummyTestCase.class); + + String targetBrowserActvityClassName = "com.android.bogus.DummyActivity"; + String expectedTargetPackageName = "com.android.bogus"; + mTestBrowserController.setTargetBrowserActivityClassName(targetBrowserActvityClassName); + mTestBrowserController.setTestSuite(testSuite); + mTestBrowserController.setTargetPackageName(expectedTargetPackageName); + Intent intent = mTestBrowserController.getIntentForTestAt(1); + verifyIntent(intent, DummyTestCase.class, expectedTargetPackageName); + assertEquals(targetBrowserActvityClassName, intent.getComponent().getClassName()); + } + + public void testGetIntentForTestCase() throws Exception { + TestSuite testSuite = new TestSuite(); + testSuite.addTest(new DummyTestCase()); + + mTestBrowserController.setTestSuite(testSuite); + Intent intent = mTestBrowserController.getIntentForTestAt(1); + verifyIntent(intent, DummyTestCase.class, "com.android.testharness"); + assertEquals(TestBrowserControllerImpl.TEST_RUNNER_ACTIVITY_CLASS_NAME, + intent.getComponent().getClassName()); + assertEquals("testDummyTest", + intent.getStringExtra(TestBrowserController.BUNDLE_EXTRA_TEST_METHOD_NAME)); + } + + public void testGetIntentForRunAll() throws Exception { + TestSuite testSuite = new DummyTestSuite(); + testSuite.addTestSuite(DummyTestCase.class); + + mTestBrowserController.setTestSuite(testSuite); + Intent intent = mTestBrowserController.getIntentForTestAt(0); + verifyIntent(intent, DummyTestSuite.class, "com.android.testharness"); + } + + private static void verifyIntent(Intent intent, Class testClass, String expectedPackageName) { + assertEquals(Intent.ACTION_RUN, intent.getAction()); + assertEquals(Intent.FLAG_ACTIVITY_NEW_TASK, + intent.getFlags() & Intent.FLAG_ACTIVITY_NEW_TASK); + assertEquals(Intent.FLAG_ACTIVITY_MULTIPLE_TASK, + intent.getFlags() & Intent.FLAG_ACTIVITY_MULTIPLE_TASK); + assertEquals(testClass.getName(), intent.getData().toString()); + assertEquals(expectedPackageName, intent.getComponent().getPackageName()); + } + + private static class DummyTestSuite extends TestSuite { + private DummyTestSuite() { + super(DummyTestSuite.class.getName()); + } + } + + private static class DummyTestCase extends TestCase { + private DummyTestCase() { + super("testDummyTest"); + } + + public void testDummyTest() throws Exception { + } + } + + private class TestBrowserViewStub implements TestBrowserView { + private List mTestNames; + + public void setTestNames(List testNames) { + mTestNames = testNames; + } + + public List getTestNames() { + return mTestNames; + } + } +} diff --git a/tests/CoreTests/android/test/TestBrowserTests.java b/tests/CoreTests/android/test/TestBrowserTests.java new file mode 100644 index 0000000000000000000000000000000000000000..535e2f8d90c25c3d6408fa6ce413e5b13a9d4949 --- /dev/null +++ b/tests/CoreTests/android/test/TestBrowserTests.java @@ -0,0 +1,22 @@ +// Copyright 2007 The Android Open Source Project + + +package android.test; + +import junit.framework.TestSuite; + +public class TestBrowserTests extends TestBrowserActivity { + + @Override + public TestSuite getTopTestSuite() { + return suite(); + } + + public static TestSuite suite() { + TestSuite testSuite = new TestSuite(TestBrowserTests.class.getName()); + testSuite.addTestSuite(TestBrowserControllerImplTest.class); + testSuite.addTestSuite(TestCaseUtilTest.class); + + return testSuite; + } +} diff --git a/tests/CoreTests/android/test/TestCaseUtilTest.java b/tests/CoreTests/android/test/TestCaseUtilTest.java new file mode 100644 index 0000000000000000000000000000000000000000..bc6fa9200d1b395820fbe7a8be91b9fb3422f356 --- /dev/null +++ b/tests/CoreTests/android/test/TestCaseUtilTest.java @@ -0,0 +1,100 @@ +/* + * Copyright (C) 2007 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 android.test; + +import junit.framework.Test; +import junit.framework.TestCase; +import junit.framework.TestSuite; + +import java.util.List; + +public class TestCaseUtilTest extends TestCase { + + public void testGetTestCaseNamesForTestSuiteWithSuiteMethod() throws Exception { + TestSuite testSuite = new TwoTestsInTestSuite(); + + List testCaseNames = TestCaseUtil.getTestCaseNames(testSuite, false); + + assertEquals(2, testCaseNames.size()); + assertTrue(testCaseNames.get(0).endsWith("OneTestTestCase")); + assertTrue(testCaseNames.get(1).endsWith("OneTestTestSuite")); + } + + public void testGetTestCaseNamesForTestCaseWithSuiteMethod() throws Exception { + TestCase testCase = new OneTestTestCaseWithSuite(); + + List testCaseNames = TestCaseUtil.getTestCaseNames(testCase, false); + + assertEquals(1, testCaseNames.size()); + assertTrue(testCaseNames.get(0).endsWith("testOne")); + } + + public void testCreateTestForTestCase() throws Exception { + Test test = TestCaseUtil.createTestSuite(OneTestTestCase.class); + assertEquals(1, test.countTestCases()); + } + + public void testCreateTestForTestSuiteWithSuiteMethod() throws Exception { + Test test = TestCaseUtil.createTestSuite(TwoTestsInTestSuite.class); + assertEquals(2, test.countTestCases()); + } + + public void testCreateTestForTestCaseWithSuiteMethod() throws Exception { + Test test = TestCaseUtil.createTestSuite(OneTestTestCaseWithSuite.class); + assertEquals(1, test.countTestCases()); + } + + public void testReturnEmptyStringForTestSuiteWithNoName() throws Exception { + assertEquals("", TestCaseUtil.getTestName(new TestSuite())); + } + + public static class OneTestTestCase extends TestCase { + public void testOne() throws Exception { + } + } + + public static class OneTestTestCaseWithSuite extends TestCase { + public static Test suite() { + TestCase testCase = new OneTestTestCase(); + testCase.setName("testOne"); + return testCase; + } + + public void testOne() throws Exception { + } + + public void testTwo() throws Exception { + } + } + + public static class OneTestTestSuite { + public static Test suite() { + TestSuite suite = new TestSuite(OneTestTestSuite.class.getName()); + suite.addTestSuite(OneTestTestCase.class); + return suite; + } + } + + public static class TwoTestsInTestSuite extends TestSuite { + public static Test suite() { + TestSuite suite = new TestSuite(TwoTestsInTestSuite.class.getName()); + suite.addTestSuite(OneTestTestCase.class); + suite.addTest(OneTestTestSuite.suite()); + return suite; + } + } +} diff --git a/tests/CoreTests/android/test/suitebuilder/AssignableFromTest.java b/tests/CoreTests/android/test/suitebuilder/AssignableFromTest.java new file mode 100644 index 0000000000000000000000000000000000000000..0f73e89deb4941624448d266ed3ef4286d7fb607 --- /dev/null +++ b/tests/CoreTests/android/test/suitebuilder/AssignableFromTest.java @@ -0,0 +1,85 @@ +/* + * 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 android.test.suitebuilder; + +import junit.framework.TestCase; + +import java.lang.reflect.Method; + +public class AssignableFromTest extends TestCase { + private AssignableFrom assignableFrom; + + + protected void setUp() throws Exception { + super.setUp(); + assignableFrom = new AssignableFrom(Animal.class); + } + + public void testSelfIsAssignable() throws Exception { + assertTrue(assignableFrom.apply(testMethodFor(Animal.class))); + } + + public void testSubclassesAreAssignable() throws Exception { + assertTrue(assignableFrom.apply(testMethodFor(Mammal.class))); + assertTrue(assignableFrom.apply(testMethodFor(Human.class))); + } + + public void testNotAssignable() throws Exception { + assertFalse(assignableFrom.apply(testMethodFor(Pencil.class))); + } + + public void testImplementorsAreAssignable() throws Exception { + assignableFrom = new AssignableFrom(WritingInstrument.class); + + assertTrue(assignableFrom.apply(testMethodFor(Pencil.class))); + assertTrue(assignableFrom.apply(testMethodFor(Pen.class))); + } + + private TestMethod testMethodFor(Class aClass) + throws NoSuchMethodException { + Method method = aClass.getMethod("testX"); + return new TestMethod(method, aClass); + } + + private class Animal extends TestCase { + public void testX() { + } + } + + private class Mammal extends Animal { + public void testX() { + } + } + + private class Human extends Mammal { + public void testX() { + } + } + + private interface WritingInstrument { + } + + private class Pencil extends TestCase implements WritingInstrument { + public void testX() { + } + } + + private class Pen extends TestCase implements WritingInstrument { + public void testX() { + } + } +} diff --git a/tests/CoreTests/android/test/suitebuilder/InstrumentationTestSuiteBuilderTest.java b/tests/CoreTests/android/test/suitebuilder/InstrumentationTestSuiteBuilderTest.java new file mode 100644 index 0000000000000000000000000000000000000000..1872803bd5cd3faf604aa7ba3ae4dae87f3b5f00 --- /dev/null +++ b/tests/CoreTests/android/test/suitebuilder/InstrumentationTestSuiteBuilderTest.java @@ -0,0 +1,116 @@ +/* + * 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 android.test.suitebuilder; + +import static android.test.suitebuilder.ListTestCaseNames.getTestCaseNames; +import android.test.suitebuilder.examples.OuterTest; +import android.test.suitebuilder.examples.instrumentation.InstrumentationTest; + +import junit.framework.AssertionFailedError; +import junit.framework.Test; +import junit.framework.TestCase; +import junit.framework.TestListener; +import junit.framework.TestResult; +import junit.framework.TestSuite; + +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +public class InstrumentationTestSuiteBuilderTest extends TestCase { + + private InstrumentationTestSuiteBuilder instrumentationTestSuiteBuilder; + + protected void setUp() throws Exception { + super.setUp(); + instrumentationTestSuiteBuilder = new InstrumentationTestSuiteBuilder(getClass()); + } + + public void testShouldIncludeIntrumentationTests() throws Exception { + instrumentationTestSuiteBuilder.includePackages(packageFor(InstrumentationTest.class)); + + SuiteExecutionRecorder recorder = runSuite(instrumentationTestSuiteBuilder); + + assertEquals(1, recorder.testsSeen.size()); + assertTrue(recorder.saw("InstrumentationTest.testInstrumentation")); + } + + public void testShouldOnlyIncludeIntrumentationTests() throws Exception { + TestSuite testSuite = new OuterTest() + .buildTestsUnderHereWith(instrumentationTestSuiteBuilder); + List testCaseNames = getTestCaseNames(testSuite); + assertEquals(1, testCaseNames.size()); + assertEquals("testInstrumentation", testCaseNames.get(0)); + } + + private static String packageFor(Class clazz) { + String className = clazz.getName(); + return className.substring(0, className.lastIndexOf('.')); + } + + private SuiteExecutionRecorder runSuite(TestSuiteBuilder builder) { + TestSuite suite = builder.build(); + SuiteExecutionRecorder recorder = new SuiteExecutionRecorder(); + TestResult result = new TestResult(); + result.addListener(recorder); + suite.run(result); + return recorder; + } + + private class SuiteExecutionRecorder implements TestListener { + + private Set failures = new HashSet(); + private Set errors = new HashSet(); + private Set testsSeen = new HashSet(); + + public void addError(Test test, Throwable t) { + errors.add(testName(test)); + } + + public void addFailure(Test test, AssertionFailedError t) { + failures.add(testName(test)); + } + + public void endTest(Test test) { + } + + public void startTest(Test test) { + testsSeen.add(testName(test)); + } + + public boolean saw(String testName) { + return testsSeen.contains(testName); + } + + public boolean failed(String testName) { + return failures.contains(testName); + } + + public boolean errored(String testName) { + return errors.contains(testName); + } + + public boolean passed(String testName) { + return saw(testName) && !failed(testName) && !errored(testName); + } + + private String testName(Test test) { + TestCase testCase = (TestCase) test; + return testCase.getClass().getSimpleName() + "." + testCase.getName(); + } + } +} diff --git a/tests/CoreTests/android/test/suitebuilder/ListTestCaseNames.java b/tests/CoreTests/android/test/suitebuilder/ListTestCaseNames.java new file mode 100644 index 0000000000000000000000000000000000000000..37ec3281410f236445eb412ca421a1fc34bef2d6 --- /dev/null +++ b/tests/CoreTests/android/test/suitebuilder/ListTestCaseNames.java @@ -0,0 +1,102 @@ +/* + * 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 android.test.suitebuilder; + +import junit.framework.Test; +import junit.framework.TestCase; +import junit.framework.TestSuite; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +public class ListTestCaseNames { + public static List getTestCaseNames(TestSuite suite) { + // TODO: deprecate this method and move all callers to use getTestNames + List tests = Collections.list(suite.tests()); + ArrayList testCaseNames = new ArrayList(); + for (Test test : tests) { + if (test instanceof TestCase) { + testCaseNames.add(((TestCase) test).getName()); + } else if (test instanceof TestSuite) { + testCaseNames.addAll(getTestCaseNames((TestSuite) test)); + } + } + return testCaseNames; + } + + /** + * Returns a list of test class and method names for each TestCase in suite. + */ + public static List getTestNames(TestSuite suite) { + List tests = Collections.list(suite.tests()); + ArrayList testNames = new ArrayList(); + for (Test test : tests) { + if (test instanceof TestCase) { + String className = test.getClass().getName(); + String testName = ((TestCase) test).getName(); + testNames.add(new TestDescriptor(className, testName)); + } else if (test instanceof TestSuite) { + testNames.addAll(getTestNames((TestSuite) test)); + } + } + return testNames; + } + + /** + * Data holder for test case info + */ + public static class TestDescriptor { + private String mClassName; + private String mTestName; + + public TestDescriptor(String className, String testName) { + mClassName = className; + mTestName = testName; + } + + public String getClassName() { + return mClassName; + } + + public String getTestName() { + return mTestName; + } + + /** + * Override parent to do string-based class and test name comparison + */ + @Override + public boolean equals(Object otherObj) { + if (otherObj instanceof TestDescriptor) { + TestDescriptor otherDesc = (TestDescriptor)otherObj; + return otherDesc.getClassName().equals(this.getClassName()) && + otherDesc.getTestName().equals(this.getTestName()); + + } + return false; + } + + /** + * Override parent to return a more user-friendly display string + */ + @Override + public String toString() { + return getClassName() + "#" + getTestName(); + } + } +} diff --git a/tests/CoreTests/android/test/suitebuilder/SmokeTestSuiteBuilderTest.java b/tests/CoreTests/android/test/suitebuilder/SmokeTestSuiteBuilderTest.java new file mode 100644 index 0000000000000000000000000000000000000000..f817297630b830adbc974ffd6a3f69d910c7436a --- /dev/null +++ b/tests/CoreTests/android/test/suitebuilder/SmokeTestSuiteBuilderTest.java @@ -0,0 +1,34 @@ +/* + * 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 android.test.suitebuilder; + +import junit.framework.TestCase; +import junit.framework.TestSuite; + +import java.util.List; + +public class SmokeTestSuiteBuilderTest extends TestCase { + + public void testShouldOnlyIncludeSmokeTests() throws Exception { + TestSuite testSuite = new SmokeTestSuiteBuilder(getClass()) + .includeAllPackagesUnderHere().build(); + + List testCaseNames = ListTestCaseNames.getTestCaseNames(testSuite); + assertEquals("Unexpected number of smoke tests.", 1, testCaseNames.size()); + assertEquals("Unexpected test name", "testSmoke", testCaseNames.get(0)); + } +} diff --git a/tests/CoreTests/android/test/suitebuilder/TestSuiteBuilderTest.java b/tests/CoreTests/android/test/suitebuilder/TestSuiteBuilderTest.java new file mode 100644 index 0000000000000000000000000000000000000000..293c8133eb9552c6455238bbceedbd636612274e --- /dev/null +++ b/tests/CoreTests/android/test/suitebuilder/TestSuiteBuilderTest.java @@ -0,0 +1,218 @@ +/* + * 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 android.test.suitebuilder; + +import com.android.internal.util.Predicate; +import static android.test.suitebuilder.ListTestCaseNames.getTestCaseNames; +import android.test.suitebuilder.examples.OuterTest; +import android.test.suitebuilder.examples.suppress.SuppressedTest; +import android.test.suitebuilder.examples.error.ErrorTest; +import android.test.suitebuilder.examples.error.FailingTest; +import android.test.suitebuilder.examples.nested.Level1Test; +import android.test.suitebuilder.examples.nested.nested.Level2Test; +import android.test.suitebuilder.examples.simple.SimpleTest; +import android.test.suitebuilder.examples.subclass.SubclassTest; +import junit.framework.AssertionFailedError; +import junit.framework.Test; +import junit.framework.TestCase; +import junit.framework.TestListener; +import junit.framework.TestResult; +import junit.framework.TestSuite; + +import java.util.HashSet; +import java.util.List; +import java.util.Set; + + +public class TestSuiteBuilderTest extends TestCase { + + private TestSuiteBuilder testSuiteBuilder; + + protected void setUp() throws Exception { + super.setUp(); + testSuiteBuilder = new TestSuiteBuilder(getClass()); + } + + public void testShouldRunSimpleTests() throws Exception { + testSuiteBuilder.includePackages(packageFor(SimpleTest.class)); + + SuiteExecutionRecorder recorder = runSuite(testSuiteBuilder); + + assertTrue(recorder.passed("SimpleTest.testSimpleOne")); + assertTrue(recorder.passed("SimpleTest.testSimpleTwo")); + assertTrue(recorder.passed("AnotherSimpleTest.testAnotherOne")); + } + + public void testShouldOnlyIncludeTestsThatSatisfyAllPredicates() throws Exception { + testSuiteBuilder.includePackages(packageFor(SimpleTest.class)) + .addRequirements(testsWhoseNameContains("test")) + .addRequirements(testsWhoseNameContains("Simple")) + .addRequirements(testsWhoseNameContains("Two")); + + SuiteExecutionRecorder recorder = runSuite(testSuiteBuilder); + + assertTrue(recorder.passed("SimpleTest.testSimpleTwo")); + } + + public void testShouldAddFailingTestsToSuite() throws Exception { + testSuiteBuilder.includePackages(packageFor(FailingTest.class)); + + SuiteExecutionRecorder recorder = runSuite(testSuiteBuilder); + + assertTrue(recorder.failed("FailingTest.testFailOne")); + assertTrue(recorder.failed("FailingTest.testFailTwo")); + } + + public void testShouldAddTestsWithErrorsToSuite() throws Exception { + testSuiteBuilder.includePackages(packageFor(ErrorTest.class)); + + SuiteExecutionRecorder recorder = runSuite(testSuiteBuilder); + + assertTrue(recorder.errored("ErrorTest.testErrorOne")); + assertTrue(recorder.errored("ErrorTest.testErrorTwo")); + } + + public void testShouldRunTestsInheritedFromSuperclass() throws Exception { + testSuiteBuilder.includePackages(packageFor(SubclassTest.class)); + + SuiteExecutionRecorder recorder = runSuite(testSuiteBuilder); + + assertEquals(2, getTestCaseNames(testSuiteBuilder.build()).size()); + + assertTrue(recorder.passed("SubclassTest.testSubclass")); + assertTrue(recorder.passed("SubclassTest.testSuperclass")); + assertFalse(recorder.saw("SuperclassTest.testSuperclass")); + } + + public void testShouldIncludeTestsInSubPackagesRecursively() throws Exception { + testSuiteBuilder.includePackages(packageFor(Level1Test.class)); + + SuiteExecutionRecorder recorder = runSuite(testSuiteBuilder); + + assertTrue(recorder.passed("Level1Test.testLevel1")); + assertTrue(recorder.passed("Level2Test.testLevel2")); + } + + public void testExcludePackage() throws Exception { + testSuiteBuilder.includePackages(packageFor(SimpleTest.class), + packageFor(Level1Test.class)).excludePackages(packageFor(Level2Test.class)); + + TestSuite testSuite = testSuiteBuilder.build(); + assertContentsInOrder(getTestCaseNames(testSuite), + "testLevel1", "testAnotherOne", "testSimpleOne", "testSimpleTwo"); + } + + public void testShouldExcludeSuppressedTests() throws Exception { + testSuiteBuilder.includePackages(packageFor(SuppressedTest.class)); + testSuiteBuilder.build(); + + SuiteExecutionRecorder recorder = runSuite(testSuiteBuilder); + + assertEquals(1, recorder.testsSeen.size()); + assertTrue(recorder.passed("PartiallySuppressedTest.testUnSuppressedMethod")); + } + + /** + * This test calls {@link OuterTest#buildTestsUnderHereRecursively()} to control + * the packages under test. The call to {@link TestSuiteBuilder#includeAllPackagesUnderHere()} + * is made from there so that only return the example tests. + */ + public void testIncludeAllPackagesUnderHere() throws Exception { + + TestSuite testSuite = new OuterTest().buildTestsUnderHereRecursively(); + assertContentsInOrder(getTestCaseNames(testSuite), + "testOuter", "testErrorOne", "testErrorTwo", "testFailOne", "testFailTwo", + "testInstrumentation", "testLevel1", "testLevel2", "testAnotherOne", + "testSimpleOne", "testSimpleTwo", "testNonSmoke", "testSmoke", "testSubclass", + "testSuperclass", "testUnSuppressedMethod"); + } + + private void assertContentsInOrder(List actual, String... source) { + String[] clonedSource = source.clone(); + assertEquals("Unexpected number of items.", clonedSource.length, actual.size()); + for (int i = 0; i < actual.size(); i++) { + String actualItem = actual.get(i); + String sourceItem = clonedSource[i]; + assertEquals("Unexpected item. Index: " + i, sourceItem, actualItem); + } + } + + private static String packageFor(Class clazz) { + String className = clazz.getName(); + return className.substring(0, className.lastIndexOf('.')); + } + + private Predicate testsWhoseNameContains(final String string) { + return new Predicate() { + public boolean apply(TestMethod testMethod) { + return testMethod.getName().contains(string); + } + }; + } + + private SuiteExecutionRecorder runSuite(TestSuiteBuilder builder) { + TestSuite suite = builder.build(); + SuiteExecutionRecorder recorder = new SuiteExecutionRecorder(); + TestResult result = new TestResult(); + result.addListener(recorder); + suite.run(result); + return recorder; + } + + private class SuiteExecutionRecorder implements TestListener { + + private Set failures = new HashSet(); + private Set errors = new HashSet(); + private Set testsSeen = new HashSet(); + + public void addError(Test test, Throwable t) { + errors.add(testName(test)); + } + + public void addFailure(Test test, AssertionFailedError t) { + failures.add(testName(test)); + } + + public void endTest(Test test) { + } + + public void startTest(Test test) { + testsSeen.add(testName(test)); + } + + public boolean saw(String testName) { + return testsSeen.contains(testName); + } + + public boolean failed(String testName) { + return failures.contains(testName); + } + + public boolean errored(String testName) { + return errors.contains(testName); + } + + public boolean passed(String testName) { + return saw(testName) && !failed(testName) && !errored(testName); + } + + private String testName(Test test) { + TestCase testCase = (TestCase) test; + return testCase.getClass().getSimpleName() + "." + testCase.getName(); + } + } +} diff --git a/tests/CoreTests/android/test/suitebuilder/UnitTestSuiteBuilderTest.java b/tests/CoreTests/android/test/suitebuilder/UnitTestSuiteBuilderTest.java new file mode 100644 index 0000000000000000000000000000000000000000..469938e6bb02e2e216c38387f86157e6e32e4975 --- /dev/null +++ b/tests/CoreTests/android/test/suitebuilder/UnitTestSuiteBuilderTest.java @@ -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. + */ + +package android.test.suitebuilder; + +import android.test.suitebuilder.examples.instrumentation.InstrumentationTest; + +import junit.framework.Assert; +import junit.framework.AssertionFailedError; +import junit.framework.Test; +import junit.framework.TestCase; +import junit.framework.TestListener; +import junit.framework.TestResult; +import junit.framework.TestSuite; + +import java.util.HashSet; +import java.util.Set; + +public class UnitTestSuiteBuilderTest extends TestCase { + + private UnitTestSuiteBuilder unitTestSuiteBuilder; + + protected void setUp() throws Exception { + super.setUp(); + unitTestSuiteBuilder = new UnitTestSuiteBuilder(getClass()); + } + + public void testShouldExcludeIntrumentationTests() throws Exception { + unitTestSuiteBuilder.includePackages(packageFor(InstrumentationTest.class)); + + TestSuite testSuite = unitTestSuiteBuilder.build(); + Assert.assertEquals(0, ListTestCaseNames.getTestCaseNames(testSuite).size()); + + SuiteExecutionRecorder recorder = runSuite(unitTestSuiteBuilder); + + assertFalse(recorder.saw("InstrumentationTest.testInstrumentation")); + assertTrue(recorder.testsSeen.isEmpty()); + } + + private static String packageFor(Class clazz) { + String className = clazz.getName(); + return className.substring(0, className.lastIndexOf('.')); + } + + private SuiteExecutionRecorder runSuite(TestSuiteBuilder builder) { + TestSuite suite = builder.build(); + SuiteExecutionRecorder recorder = new SuiteExecutionRecorder(); + TestResult result = new TestResult(); + result.addListener(recorder); + suite.run(result); + return recorder; + } + + private class SuiteExecutionRecorder implements TestListener { + + private Set failures = new HashSet(); + private Set errors = new HashSet(); + private Set testsSeen = new HashSet(); + + public void addError(Test test, Throwable t) { + errors.add(testName(test)); + } + + public void addFailure(Test test, AssertionFailedError t) { + failures.add(testName(test)); + } + + public void endTest(Test test) { + } + + public void startTest(Test test) { + testsSeen.add(testName(test)); + } + + public boolean saw(String testName) { + return testsSeen.contains(testName); + } + + public boolean failed(String testName) { + return failures.contains(testName); + } + + public boolean errored(String testName) { + return errors.contains(testName); + } + + public boolean passed(String testName) { + return saw(testName) && !failed(testName) && !errored(testName); + } + + private String testName(Test test) { + TestCase testCase = (TestCase) test; + return testCase.getClass().getSimpleName() + "." + testCase.getName(); + } + } +} diff --git a/tests/CoreTests/android/test/suitebuilder/annotation/HasAnnotationTest.java b/tests/CoreTests/android/test/suitebuilder/annotation/HasAnnotationTest.java new file mode 100644 index 0000000000000000000000000000000000000000..edf067dce48b2d4b3215b022eea264d37363f5d8 --- /dev/null +++ b/tests/CoreTests/android/test/suitebuilder/annotation/HasAnnotationTest.java @@ -0,0 +1,76 @@ +/* + * 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 android.test.suitebuilder.annotation; + +import android.test.suitebuilder.TestMethod; +import junit.framework.TestCase; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +import java.lang.reflect.Method; + +public class HasAnnotationTest extends TestCase { + + public void testThatMethodWithAnnotationIsReportedAsBeingAnnotated() throws Exception { + assertTrue(hasExampleAnnotation(ClassWithAnnotation.class, "testWithAnnotation")); + assertTrue(hasExampleAnnotation(ClassWithoutAnnotation.class, "testWithAnnotation")); + } + + public void testThatMethodWithOutAnnotationIsNotReportedAsBeingAnnotated() throws Exception { + assertFalse(hasExampleAnnotation(ClassWithoutAnnotation.class, "testWithoutAnnotation")); + } + + public void testThatClassAnnotatioCausesAllMethodsToBeReportedAsBeingAnnotated() + throws Exception { + assertTrue(hasExampleAnnotation(ClassWithAnnotation.class, "testWithoutAnnotation")); + } + + private boolean hasExampleAnnotation(Class aClass, String methodName) + throws NoSuchMethodException { + Method method = aClass.getMethod(methodName); + TestMethod testMethod = new TestMethod(method, aClass); + return new HasAnnotation(Example.class).apply(testMethod); + } + + @Retention(RetentionPolicy.RUNTIME) + @Target({ElementType.TYPE, ElementType.METHOD}) + public @interface Example { + } + + @Example + static class ClassWithAnnotation extends TestCase { + + @Example + public void testWithAnnotation() { + } + + public void testWithoutAnnotation() { + } + } + + static class ClassWithoutAnnotation extends TestCase { + + @Example + public void testWithAnnotation() { + } + + public void testWithoutAnnotation() { + } + } +} diff --git a/tests/CoreTests/android/test/suitebuilder/annotation/HasClassAnnotationTest.java b/tests/CoreTests/android/test/suitebuilder/annotation/HasClassAnnotationTest.java new file mode 100644 index 0000000000000000000000000000000000000000..051ea547dbbd0ea8ba4dabca614e93117b5f8fff --- /dev/null +++ b/tests/CoreTests/android/test/suitebuilder/annotation/HasClassAnnotationTest.java @@ -0,0 +1,57 @@ +/* + * 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 android.test.suitebuilder.annotation; + +import android.test.suitebuilder.TestMethod; +import junit.framework.TestCase; + +import java.lang.reflect.Method; + +public class HasClassAnnotationTest extends TestCase { + + public void testShouldTellIfParentClassHasSpecifiedClassification() + throws NoSuchMethodException { + assertTrue(classHasAnnotation(SmokeTestExample.class, Smoke.class)); + } + + public void testShouldTellIfParentClassDoesNotHaveSpecifiedClassification() + throws NoSuchMethodException { + assertFalse(classHasAnnotation(NonSmokeTestExample.class, Smoke.class)); + } + + private boolean classHasAnnotation( + Class aClass, + Class expectedClassification) throws NoSuchMethodException { + Method method = aClass.getMethod("testSomeTest"); + + TestMethod testMethod = new TestMethod(method, aClass); + return new HasClassAnnotation(expectedClassification).apply(testMethod); + } + + @Smoke + static class SmokeTestExample extends TestCase { + + public void testSomeTest() { + } + } + + static class NonSmokeTestExample extends TestCase { + + public void testSomeTest() { + } + } +} diff --git a/tests/CoreTests/android/test/suitebuilder/annotation/HasMethodAnnotationTest.java b/tests/CoreTests/android/test/suitebuilder/annotation/HasMethodAnnotationTest.java new file mode 100644 index 0000000000000000000000000000000000000000..c864e288702eba6077e170d2d411df6fd9ff498e --- /dev/null +++ b/tests/CoreTests/android/test/suitebuilder/annotation/HasMethodAnnotationTest.java @@ -0,0 +1,56 @@ +/* + * 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 android.test.suitebuilder.annotation; + +import android.test.suitebuilder.TestMethod; +import junit.framework.TestCase; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Method; + + +public class HasMethodAnnotationTest extends TestCase { + + public void testMethodWithSpecifiedAttribute() throws Exception { + assertTrue(methodHasAnnotation(AnnotatedMethodExample.class, + "testThatIsAnnotated", Smoke.class)); + } + + public void testMethodWithoutSpecifiedAttribute() throws Exception { + assertFalse(methodHasAnnotation(AnnotatedMethodExample.class, + "testThatIsNotAnnotated", Smoke.class)); + } + + private boolean methodHasAnnotation(Class aClass, + String methodName, + Class expectedClassification + ) throws NoSuchMethodException { + Method method = aClass.getMethod(methodName); + TestMethod testMethod = new TestMethod(method, aClass); + return new HasMethodAnnotation(expectedClassification).apply(testMethod); + } + + static class AnnotatedMethodExample extends TestCase { + + @Smoke + public void testThatIsAnnotated() { + } + + public void testThatIsNotAnnotated() { + } + } +} diff --git a/tests/CoreTests/android/test/suitebuilder/examples/OuterTest.java b/tests/CoreTests/android/test/suitebuilder/examples/OuterTest.java new file mode 100644 index 0000000000000000000000000000000000000000..4659bf9ffedf8f0fe4c6b87544e76d14a2c78a74 --- /dev/null +++ b/tests/CoreTests/android/test/suitebuilder/examples/OuterTest.java @@ -0,0 +1,37 @@ +/* + * 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 android.test.suitebuilder.examples; + +import android.test.suitebuilder.TestSuiteBuilder; + +import junit.framework.TestCase; +import junit.framework.TestSuite; + +public class OuterTest extends TestCase { + + public void testOuter() { + assertTrue(true); + } + + public TestSuite buildTestsUnderHereRecursively() { + return buildTestsUnderHereWith(new TestSuiteBuilder(getClass())); + } + + public TestSuite buildTestsUnderHereWith(TestSuiteBuilder testSuiteBuilder) { + return testSuiteBuilder.includeAllPackagesUnderHere().build(); + } +} diff --git a/tests/CoreTests/android/test/suitebuilder/examples/error/ErrorTest.java b/tests/CoreTests/android/test/suitebuilder/examples/error/ErrorTest.java new file mode 100644 index 0000000000000000000000000000000000000000..f1f6113e86d20ee09e143a64b035336e1f26c9c6 --- /dev/null +++ b/tests/CoreTests/android/test/suitebuilder/examples/error/ErrorTest.java @@ -0,0 +1,30 @@ +/* + * 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 android.test.suitebuilder.examples.error; + +import junit.framework.TestCase; + +public class ErrorTest extends TestCase { + + public void testErrorOne() throws Exception { + throw new RuntimeException("Expected"); + } + + public void testErrorTwo() throws Exception { + throw new RuntimeException("Expected"); + } +} diff --git a/tests/CoreTests/android/test/suitebuilder/examples/error/FailingTest.java b/tests/CoreTests/android/test/suitebuilder/examples/error/FailingTest.java new file mode 100644 index 0000000000000000000000000000000000000000..428fd23b819d7caebf16548eb19e68b6d5cfc1ac --- /dev/null +++ b/tests/CoreTests/android/test/suitebuilder/examples/error/FailingTest.java @@ -0,0 +1,30 @@ +/* + * 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 android.test.suitebuilder.examples.error; + +import junit.framework.TestCase; + +public class FailingTest extends TestCase { + + public void testFailOne() throws Exception { + fail("Expected"); + } + + public void testFailTwo() throws Exception { + fail("Expected"); + } +} diff --git a/tests/CoreTests/android/test/suitebuilder/examples/instrumentation/InstrumentationTest.java b/tests/CoreTests/android/test/suitebuilder/examples/instrumentation/InstrumentationTest.java new file mode 100644 index 0000000000000000000000000000000000000000..5158a9049a0ca2b51e12df1fc040430cf3394506 --- /dev/null +++ b/tests/CoreTests/android/test/suitebuilder/examples/instrumentation/InstrumentationTest.java @@ -0,0 +1,26 @@ +/* + * 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 android.test.suitebuilder.examples.instrumentation; + +import android.test.InstrumentationTestCase; + +public class InstrumentationTest extends InstrumentationTestCase { + + public void testInstrumentation() throws Exception { + assertTrue(true); + } +} diff --git a/tests/CoreTests/android/test/suitebuilder/examples/nested/Level1Test.java b/tests/CoreTests/android/test/suitebuilder/examples/nested/Level1Test.java new file mode 100644 index 0000000000000000000000000000000000000000..17d39d67bd7496c57dcca628a78487b96cd416fc --- /dev/null +++ b/tests/CoreTests/android/test/suitebuilder/examples/nested/Level1Test.java @@ -0,0 +1,26 @@ +/* + * 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 android.test.suitebuilder.examples.nested; + +import junit.framework.TestCase; + +public class Level1Test extends TestCase { + + public void testLevel1() throws Exception { + assertTrue(true); + } +} diff --git a/tests/CoreTests/android/test/suitebuilder/examples/nested/nested/Level2Test.java b/tests/CoreTests/android/test/suitebuilder/examples/nested/nested/Level2Test.java new file mode 100644 index 0000000000000000000000000000000000000000..6f0daca94f1a3f7e3de7307b4999302352246000 --- /dev/null +++ b/tests/CoreTests/android/test/suitebuilder/examples/nested/nested/Level2Test.java @@ -0,0 +1,26 @@ +/* + * 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 android.test.suitebuilder.examples.nested.nested; + +import junit.framework.TestCase; + +public class Level2Test extends TestCase { + + public void testLevel2() throws Exception { + assertTrue(true); + } +} diff --git a/tests/CoreTests/android/test/suitebuilder/examples/simple/AnotherSimpleTest.java b/tests/CoreTests/android/test/suitebuilder/examples/simple/AnotherSimpleTest.java new file mode 100644 index 0000000000000000000000000000000000000000..0dfeda821c25bcb26e6b06f00a6e350fbe00b82f --- /dev/null +++ b/tests/CoreTests/android/test/suitebuilder/examples/simple/AnotherSimpleTest.java @@ -0,0 +1,26 @@ +/* + * 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 android.test.suitebuilder.examples.simple; + +import junit.framework.TestCase; + +public class AnotherSimpleTest extends TestCase { + + public void testAnotherOne() throws Exception { + assertTrue(true); + } +} diff --git a/tests/CoreTests/android/test/suitebuilder/examples/simple/SimpleTest.java b/tests/CoreTests/android/test/suitebuilder/examples/simple/SimpleTest.java new file mode 100644 index 0000000000000000000000000000000000000000..4dcac44bd5331eaf665e59f836f5327d87e0c18d --- /dev/null +++ b/tests/CoreTests/android/test/suitebuilder/examples/simple/SimpleTest.java @@ -0,0 +1,30 @@ +/* + * 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 android.test.suitebuilder.examples.simple; + +import junit.framework.TestCase; + +public class SimpleTest extends TestCase { + + public void testSimpleOne() throws Exception { + assertTrue(true); + } + + public void testSimpleTwo() throws Exception { + assertTrue(true); + } +} diff --git a/tests/CoreTests/android/test/suitebuilder/examples/smoke/NonSmokeTest.java b/tests/CoreTests/android/test/suitebuilder/examples/smoke/NonSmokeTest.java new file mode 100644 index 0000000000000000000000000000000000000000..1512ba7b3ff9ecee2e5779b9d3124a737789d718 --- /dev/null +++ b/tests/CoreTests/android/test/suitebuilder/examples/smoke/NonSmokeTest.java @@ -0,0 +1,26 @@ +/* + * 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 android.test.suitebuilder.examples.smoke; + +import junit.framework.TestCase; + +public class NonSmokeTest extends TestCase { + + public void testNonSmoke() throws Exception { + assertTrue(true); + } +} diff --git a/tests/CoreTests/android/test/suitebuilder/examples/smoke/SmokeTest.java b/tests/CoreTests/android/test/suitebuilder/examples/smoke/SmokeTest.java new file mode 100644 index 0000000000000000000000000000000000000000..c3515dfa8eefdd19e7a013f53e1e3712ac49f4da --- /dev/null +++ b/tests/CoreTests/android/test/suitebuilder/examples/smoke/SmokeTest.java @@ -0,0 +1,28 @@ +/* + * 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 android.test.suitebuilder.examples.smoke; + +import android.test.suitebuilder.annotation.Smoke; +import junit.framework.TestCase; + +@Smoke +public class SmokeTest extends TestCase { + + public void testSmoke() throws Exception { + assertTrue(true); + } +} diff --git a/tests/CoreTests/android/test/suitebuilder/examples/subclass/SubclassTest.java b/tests/CoreTests/android/test/suitebuilder/examples/subclass/SubclassTest.java new file mode 100644 index 0000000000000000000000000000000000000000..0ab8c72ab8b137a0f7938e5b69acf9f8c999ef50 --- /dev/null +++ b/tests/CoreTests/android/test/suitebuilder/examples/subclass/SubclassTest.java @@ -0,0 +1,24 @@ +/* + * 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 android.test.suitebuilder.examples.subclass; + +public class SubclassTest extends SuperclassTest { + + public void testSubclass() throws Exception { + assertTrue(true); + } +} diff --git a/tests/CoreTests/android/test/suitebuilder/examples/subclass/SuperclassTest.java b/tests/CoreTests/android/test/suitebuilder/examples/subclass/SuperclassTest.java new file mode 100644 index 0000000000000000000000000000000000000000..05513c5447cace4af1d9d33b7d9aee0c66f902fd --- /dev/null +++ b/tests/CoreTests/android/test/suitebuilder/examples/subclass/SuperclassTest.java @@ -0,0 +1,26 @@ +/* + * 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 android.test.suitebuilder.examples.subclass; + +import junit.framework.TestCase; + +public abstract class SuperclassTest extends TestCase { + + public void testSuperclass() throws Exception { + assertTrue(true); + } +} diff --git a/tests/CoreTests/android/test/suitebuilder/examples/suppress/PartiallySuppressedTest.java b/tests/CoreTests/android/test/suitebuilder/examples/suppress/PartiallySuppressedTest.java new file mode 100644 index 0000000000000000000000000000000000000000..3ca0f7034ca35ca7af66361ec388f86599c59007 --- /dev/null +++ b/tests/CoreTests/android/test/suitebuilder/examples/suppress/PartiallySuppressedTest.java @@ -0,0 +1,33 @@ +/* + * 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 android.test.suitebuilder.examples.suppress; + +import android.test.suitebuilder.annotation.Suppress; + +import junit.framework.TestCase; + +public class PartiallySuppressedTest extends TestCase { + + @Suppress + public void testSuppressedMethod() throws Exception { + assertTrue(true); + } + + public void testUnSuppressedMethod() throws Exception { + assertTrue(true); + } +} diff --git a/tests/CoreTests/android/test/suitebuilder/examples/suppress/SuppressedTest.java b/tests/CoreTests/android/test/suitebuilder/examples/suppress/SuppressedTest.java new file mode 100644 index 0000000000000000000000000000000000000000..c4e0e07499311b7ce806d6835c3b0f24f6eeb8b6 --- /dev/null +++ b/tests/CoreTests/android/test/suitebuilder/examples/suppress/SuppressedTest.java @@ -0,0 +1,29 @@ +/* + * 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 android.test.suitebuilder.examples.suppress; + +import android.test.suitebuilder.annotation.Suppress; + +import junit.framework.TestCase; + +@Suppress +public class SuppressedTest extends TestCase { + + public void testSuppressedClass() throws Exception { + assertTrue(true); + } +} diff --git a/tests/CoreTests/android/util/DayOfMonthCursorTest.java b/tests/CoreTests/android/util/DayOfMonthCursorTest.java new file mode 100644 index 0000000000000000000000000000000000000000..4c5ad76d81933622dacc1b90210e8833e81eaf3a --- /dev/null +++ b/tests/CoreTests/android/util/DayOfMonthCursorTest.java @@ -0,0 +1,157 @@ +/* + * Copyright (C) 2007 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 android.util; + +import junit.framework.TestCase; + +import java.util.Calendar; +import android.test.suitebuilder.annotation.SmallTest; + +/** + * Unit tests for {@link DayOfMonthCursor}. + */ +public class DayOfMonthCursorTest extends TestCase { + + @SmallTest + public void testMonthRows() { + DayOfMonthCursor mc = new DayOfMonthCursor(2007, + Calendar.SEPTEMBER, 11, Calendar.SUNDAY); + + assertArraysEqual(new int[]{26, 27, 28, 29, 30, 31, 1}, + mc.getDigitsForRow(0)); + assertArraysEqual(new int[]{2, 3, 4, 5, 6, 7, 8}, + mc.getDigitsForRow(1)); + assertArraysEqual(new int[]{30, 1, 2, 3, 4, 5, 6}, + mc.getDigitsForRow(5)); + } + + @SmallTest + public void testMoveLeft() { + DayOfMonthCursor mc = new DayOfMonthCursor(2007, + Calendar.SEPTEMBER, 3, Calendar.SUNDAY); + + assertEquals(Calendar.SEPTEMBER, mc.getMonth()); + assertEquals(3, mc.getSelectedDayOfMonth()); + assertEquals(1, mc.getSelectedRow()); + assertEquals(1, mc.getSelectedColumn()); + + // move left, still same row + assertFalse(mc.left()); + assertEquals(2, mc.getSelectedDayOfMonth()); + assertEquals(1, mc.getSelectedRow()); + assertEquals(0, mc.getSelectedColumn()); + + // wrap over to previous column, same month + assertFalse(mc.left()); + assertEquals(1, mc.getSelectedDayOfMonth()); + assertEquals(0, mc.getSelectedRow()); + assertEquals(6, mc.getSelectedColumn()); + + // wrap to previous month + assertTrue(mc.left()); + assertEquals(Calendar.AUGUST, mc.getMonth()); + assertEquals(31, mc.getSelectedDayOfMonth()); + assertEquals(4, mc.getSelectedRow()); + assertEquals(5, mc.getSelectedColumn()); + } + + @SmallTest + public void testMoveRight() { + DayOfMonthCursor mc = new DayOfMonthCursor(2007, + Calendar.SEPTEMBER, 28, Calendar.SUNDAY); + + assertEquals(Calendar.SEPTEMBER, mc.getMonth()); + assertEquals(28, mc.getSelectedDayOfMonth()); + assertEquals(4, mc.getSelectedRow()); + assertEquals(5, mc.getSelectedColumn()); + + // same row + assertFalse(mc.right()); + assertEquals(29, mc.getSelectedDayOfMonth()); + assertEquals(4, mc.getSelectedRow()); + assertEquals(6, mc.getSelectedColumn()); + + // wrap to next column, same month + assertFalse(mc.right()); + assertEquals(30, mc.getSelectedDayOfMonth()); + assertEquals(5, mc.getSelectedRow()); + assertEquals(0, mc.getSelectedColumn()); + + // next month + assertTrue(mc.right()); + assertEquals(Calendar.OCTOBER, mc.getMonth()); + assertEquals(1, mc.getSelectedDayOfMonth()); + assertEquals(0, mc.getSelectedRow()); + assertEquals(1, mc.getSelectedColumn()); + } + + @SmallTest + public void testMoveUp() { + DayOfMonthCursor mc = new DayOfMonthCursor(2007, + Calendar.SEPTEMBER, 13, Calendar.SUNDAY); + + assertEquals(Calendar.SEPTEMBER, mc.getMonth()); + assertEquals(13, mc.getSelectedDayOfMonth()); + assertEquals(2, mc.getSelectedRow()); + assertEquals(4, mc.getSelectedColumn()); + + // up, same month + assertFalse(mc.up()); + assertEquals(6, mc.getSelectedDayOfMonth()); + assertEquals(1, mc.getSelectedRow()); + assertEquals(4, mc.getSelectedColumn()); + + // up, flips back + assertTrue(mc.up()); + assertEquals(Calendar.AUGUST, mc.getMonth()); + assertEquals(30, mc.getSelectedDayOfMonth()); + assertEquals(4, mc.getSelectedRow()); + assertEquals(4, mc.getSelectedColumn()); + } + + @SmallTest + public void testMoveDown() { + DayOfMonthCursor mc = new DayOfMonthCursor(2007, + Calendar.SEPTEMBER, 23, Calendar.SUNDAY); + + assertEquals(Calendar.SEPTEMBER, mc.getMonth()); + assertEquals(23, mc.getSelectedDayOfMonth()); + assertEquals(4, mc.getSelectedRow()); + assertEquals(0, mc.getSelectedColumn()); + + // down, same month + assertFalse(mc.down()); + assertEquals(30, mc.getSelectedDayOfMonth()); + assertEquals(5, mc.getSelectedRow()); + assertEquals(0, mc.getSelectedColumn()); + + // down, next month + assertTrue(mc.down()); + assertEquals(Calendar.OCTOBER, mc.getMonth()); + assertEquals(7, mc.getSelectedDayOfMonth()); + assertEquals(1, mc.getSelectedRow()); + assertEquals(0, mc.getSelectedColumn()); + } + + private void assertArraysEqual(int[] expected, int[] actual) { + assertEquals("array length", expected.length, actual.length); + for (int i = 0; i < expected.length; i++) { + assertEquals("index " + i, + expected[i], actual[i]); + } + } +} diff --git a/tests/CoreTests/android/util/FloatMathTest.java b/tests/CoreTests/android/util/FloatMathTest.java new file mode 100644 index 0000000000000000000000000000000000000000..f479e2b45f3061f66ece3b0ac6860dde0605fa8f --- /dev/null +++ b/tests/CoreTests/android/util/FloatMathTest.java @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2007 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 android.util; + +import junit.framework.TestCase; +import android.test.suitebuilder.annotation.SmallTest; + +public class FloatMathTest extends TestCase { + + @SmallTest + public void testSqrt() { + assertEquals(7, FloatMath.sqrt(49), 0); + assertEquals(10, FloatMath.sqrt(100), 0); + assertEquals(0, FloatMath.sqrt(0), 0); + assertEquals(1, FloatMath.sqrt(1), 0); + } + + @SmallTest + public void testFloor() { + assertEquals(78, FloatMath.floor(78.89f), 0); + assertEquals(-79, FloatMath.floor(-78.89f), 0); + } + + @SmallTest + public void testCeil() { + assertEquals(79, FloatMath.ceil(78.89f), 0); + assertEquals(-78, FloatMath.ceil(-78.89f), 0); + } + + @SmallTest + public void testSin() { + assertEquals(0.0, FloatMath.sin(0), 0); + assertEquals(0.8414709848078965f, FloatMath.sin(1), 0); + } + + @SmallTest + public void testCos() { + assertEquals(1.0f, FloatMath.cos(0), 0); + assertEquals(0.5403023058681398f, FloatMath.cos(1), 0); + } +} diff --git a/tests/CoreTests/android/util/MonthDisplayHelperTest.java b/tests/CoreTests/android/util/MonthDisplayHelperTest.java new file mode 100644 index 0000000000000000000000000000000000000000..5207ad91894318e14970052efe72c5103e3b6f89 --- /dev/null +++ b/tests/CoreTests/android/util/MonthDisplayHelperTest.java @@ -0,0 +1,211 @@ +/* + * Copyright (C) 2007 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 android.util; + +import junit.framework.TestCase; +import junit.framework.Test; +import junit.framework.TestSuite; + +import java.util.Calendar; +import android.test.suitebuilder.annotation.SmallTest; +import android.test.suitebuilder.annotation.MediumTest; + +/** + * Unit tests for {@link MonthDisplayHelper}. + */ +public class MonthDisplayHelperTest extends TestCase { + + + @SmallTest + public void testFirstDayOfMonth() { + + assertEquals("august 2007", + Calendar.WEDNESDAY, + new MonthDisplayHelper(2007, Calendar.AUGUST).getFirstDayOfMonth()); + + assertEquals("september, 2007", + Calendar.SATURDAY, + new MonthDisplayHelper(2007, Calendar.SEPTEMBER).getFirstDayOfMonth()); + } + + @MediumTest + public void testNumberOfDaysInCurrentMonth() { + assertEquals(30, + new MonthDisplayHelper(2007, Calendar.SEPTEMBER).getNumberOfDaysInMonth()); + } + + @SmallTest + public void testMonthRows() { + MonthDisplayHelper helper = new MonthDisplayHelper(2007, Calendar.SEPTEMBER); + + assertArraysEqual(new int[]{26, 27, 28, 29, 30, 31, 1}, + helper.getDigitsForRow(0)); + assertArraysEqual(new int[]{2, 3, 4, 5, 6, 7, 8}, + helper.getDigitsForRow(1)); + assertArraysEqual(new int[]{30, 1, 2, 3, 4, 5, 6}, + helper.getDigitsForRow(5)); + + } + + @SmallTest + public void testMonthRowsWeekStartsMonday() { + MonthDisplayHelper helper = new MonthDisplayHelper(2007, + Calendar.SEPTEMBER, Calendar.MONDAY); + + assertArraysEqual(new int[]{27, 28, 29, 30, 31, 1, 2}, + helper.getDigitsForRow(0)); + assertArraysEqual(new int[]{3, 4, 5, 6, 7, 8, 9}, + helper.getDigitsForRow(1)); + assertArraysEqual(new int[]{24, 25, 26, 27, 28, 29, 30}, + helper.getDigitsForRow(4)); + assertArraysEqual(new int[]{1, 2, 3, 4, 5, 6, 7}, + helper.getDigitsForRow(5)); + } + + @SmallTest + public void testMonthRowsWeekStartsSaturday() { + MonthDisplayHelper helper = new MonthDisplayHelper(2007, + Calendar.SEPTEMBER, Calendar.SATURDAY); + + assertArraysEqual(new int[]{1, 2, 3, 4, 5, 6, 7}, + helper.getDigitsForRow(0)); + assertArraysEqual(new int[]{8, 9, 10, 11, 12, 13, 14}, + helper.getDigitsForRow(1)); + assertArraysEqual(new int[]{29, 30, 1, 2, 3, 4, 5}, + helper.getDigitsForRow(4)); + + + helper = new MonthDisplayHelper(2007, + Calendar.AUGUST, Calendar.SATURDAY); + + assertArraysEqual(new int[]{28, 29, 30, 31, 1, 2, 3}, + helper.getDigitsForRow(0)); + assertArraysEqual(new int[]{4, 5, 6, 7, 8, 9, 10}, + helper.getDigitsForRow(1)); + assertArraysEqual(new int[]{25, 26, 27, 28, 29, 30, 31}, + helper.getDigitsForRow(4)); + } + + @SmallTest + public void testGetDayAt() { + MonthDisplayHelper helper = new MonthDisplayHelper(2007, + Calendar.SEPTEMBER, Calendar.SUNDAY); + + assertEquals(26, helper.getDayAt(0, 0)); + assertEquals(1, helper.getDayAt(0, 6)); + assertEquals(17, helper.getDayAt(3, 1)); + assertEquals(2, helper.getDayAt(5, 2)); + } + + @SmallTest + public void testPrevMonth() { + MonthDisplayHelper helper = new MonthDisplayHelper(2007, + Calendar.SEPTEMBER, Calendar.SUNDAY); + + assertArraysEqual(new int[]{26, 27, 28, 29, 30, 31, 1}, + helper.getDigitsForRow(0)); + + helper.previousMonth(); + + assertEquals(Calendar.AUGUST, helper.getMonth()); + assertArraysEqual(new int[]{29, 30, 31, 1, 2, 3, 4}, + helper.getDigitsForRow(0)); + } + + @SmallTest + public void testPrevMonthRollOver() { + MonthDisplayHelper helper = new MonthDisplayHelper(2007, + Calendar.JANUARY); + + helper.previousMonth(); + + assertEquals(2006, helper.getYear()); + assertEquals(Calendar.DECEMBER, helper.getMonth()); + } + + @SmallTest + public void testNextMonth() { + MonthDisplayHelper helper = new MonthDisplayHelper(2007, + Calendar.AUGUST, Calendar.SUNDAY); + + assertArraysEqual(new int[]{29, 30, 31, 1, 2, 3, 4}, + helper.getDigitsForRow(0)); + + helper.nextMonth(); + + assertEquals(Calendar.SEPTEMBER, helper.getMonth()); + assertArraysEqual(new int[]{26, 27, 28, 29, 30, 31, 1}, + helper.getDigitsForRow(0)); + } + + @SmallTest + public void testGetRowOf() { + MonthDisplayHelper helper = new MonthDisplayHelper(2007, + Calendar.AUGUST, Calendar.SUNDAY); + + assertEquals(0, helper.getRowOf(2)); + assertEquals(0, helper.getRowOf(4)); + assertEquals(2, helper.getRowOf(12)); + assertEquals(2, helper.getRowOf(18)); + assertEquals(3, helper.getRowOf(19)); + } + + @SmallTest + public void testGetColumnOf() { + MonthDisplayHelper helper = new MonthDisplayHelper(2007, + Calendar.AUGUST, Calendar.SUNDAY); + + assertEquals(3, helper.getColumnOf(1)); + assertEquals(4, helper.getColumnOf(9)); + assertEquals(5, helper.getColumnOf(17)); + assertEquals(6, helper.getColumnOf(25)); + assertEquals(0, helper.getColumnOf(26)); + } + + @SmallTest + public void testWithinCurrentMonth() { + MonthDisplayHelper helper = new MonthDisplayHelper(2007, + Calendar.SEPTEMBER, Calendar.SUNDAY); + + // out of bounds + assertFalse(helper.isWithinCurrentMonth(-1, 3)); + assertFalse(helper.isWithinCurrentMonth(6, 3)); + assertFalse(helper.isWithinCurrentMonth(2, -1)); + assertFalse(helper.isWithinCurrentMonth(2, 7)); + + // last day of previous month + assertFalse(helper.isWithinCurrentMonth(0, 5)); + + // first day of next month + assertFalse(helper.isWithinCurrentMonth(5, 1)); + + // first day in month + assertTrue(helper.isWithinCurrentMonth(0, 6)); + + // last day in month + assertTrue(helper.isWithinCurrentMonth(5, 0)); + } + + private void assertArraysEqual(int[] expected, int[] actual) { + assertEquals("array length", expected.length, actual.length); + for (int i = 0; i < expected.length; i++) { + assertEquals("index " + i, + expected[i], actual[i]); + } + } + +} diff --git a/tests/CoreTests/android/util/StateSetTest.java b/tests/CoreTests/android/util/StateSetTest.java new file mode 100644 index 0000000000000000000000000000000000000000..e481ce04c82fff26501ad443fda18ce38bdf5c26 --- /dev/null +++ b/tests/CoreTests/android/util/StateSetTest.java @@ -0,0 +1,182 @@ +/* + * Copyright (C) 2007 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 android.util; + +import junit.framework.TestCase; +import android.test.suitebuilder.annotation.SmallTest; + +/** + * Tests for {@link StateSet} + */ + +public class StateSetTest extends TestCase { + + @SmallTest + public void testStateSetPositiveMatches() throws Exception { + int[] stateSpec = new int[2]; + int[] stateSet = new int[3]; + // Single states in both sets - match + stateSpec[0] = 1; + stateSet[0] = 1; + assertTrue(StateSet.stateSetMatches(stateSpec, stateSet)); + // Single states in both sets - non-match + stateSet[0] = 2; + assertFalse(StateSet.stateSetMatches(stateSpec, stateSet)); + // Add another state to the spec which the stateSet doesn't match + stateSpec[1] = 2; + assertFalse(StateSet.stateSetMatches(stateSpec, stateSet)); + // Add the missing matching element to the stateSet + stateSet[1] = 1; + assertTrue(StateSet.stateSetMatches(stateSpec, stateSet)); + // Add an irrelevent state to the stateSpec + stateSet[2] = 12345; + assertTrue(StateSet.stateSetMatches(stateSpec, stateSet)); + } + + @SmallTest + public void testStatesSetMatchMixEmUp() throws Exception { + int[] stateSpec = new int[2]; + int[] stateSet = new int[2]; + // One element in stateSpec which we must match and one which we must + // not match. stateSet only contains the match. + stateSpec[0] = 1; + stateSpec[1] = -2; + stateSet[0] = 1; + assertTrue(StateSet.stateSetMatches(stateSpec, stateSet)); + // stateSet now contains just the element we must not match + stateSet[0] = 2; + assertFalse(StateSet.stateSetMatches(stateSpec, stateSet)); + // Add another matching state to the the stateSet. We still fail + // because stateSet contains a must-not-match element + stateSet[1] = 1; + assertFalse(StateSet.stateSetMatches(stateSpec, stateSet)); + // Switch the must-not-match element in stateSet with a don't care + stateSet[0] = 12345; + assertTrue(StateSet.stateSetMatches(stateSpec, stateSet)); + } + + @SmallTest + public void testStateSetNegativeMatches() throws Exception { + int[] stateSpec = new int[2]; + int[] stateSet = new int[3]; + // Single states in both sets - match + stateSpec[0] = -1; + stateSet[0] = 2; + assertTrue(StateSet.stateSetMatches(stateSpec, stateSet)); + // Add another arrelevent state to the stateSet + stateSet[1] = 12345; + assertTrue(StateSet.stateSetMatches(stateSpec, stateSet)); + // Single states in both sets - non-match + stateSet[0] = 1; + assertFalse(StateSet.stateSetMatches(stateSpec, stateSet)); + // Add another state to the spec which the stateSet doesn't match + stateSpec[1] = -2; + assertFalse(StateSet.stateSetMatches(stateSpec, stateSet)); + // Add an irrelevent state to the stateSet + stateSet[2] = 12345; + assertFalse(StateSet.stateSetMatches(stateSpec, stateSet)); + } + + @SmallTest + public void testEmptySetMatchesNegtives() throws Exception { + int[] stateSpec = {-12345, -6789}; + int[] stateSet = new int[0]; + assertTrue(StateSet.stateSetMatches(stateSpec, stateSet)); + int[] stateSet2 = {0}; + assertTrue(StateSet.stateSetMatches(stateSpec, stateSet2)); + } + + @SmallTest + public void testEmptySetFailsPositives() throws Exception { + int[] stateSpec = {12345}; + int[] stateSet = new int[0]; + assertFalse(StateSet.stateSetMatches(stateSpec, stateSet)); + int[] stateSet2 = {0}; + assertFalse(StateSet.stateSetMatches(stateSpec, stateSet2)); + } + + @SmallTest + public void testEmptySetMatchesWildcard() throws Exception { + int[] stateSpec = StateSet.WILD_CARD; + int[] stateSet = new int[0]; + assertTrue(StateSet.stateSetMatches(stateSpec, stateSet)); + int[] stateSet2 = {0}; + assertTrue(StateSet.stateSetMatches(stateSpec, stateSet2)); + } + + @SmallTest + public void testSingleStatePositiveMatches() throws Exception { + int[] stateSpec = new int[2]; + int state; + // match + stateSpec[0] = 1; + state = 1; + assertTrue(StateSet.stateSetMatches(stateSpec, state)); + // non-match + state = 2; + assertFalse(StateSet.stateSetMatches(stateSpec, state)); + // add irrelevant must-not-match + stateSpec[1] = -12345; + assertFalse(StateSet.stateSetMatches(stateSpec, state)); + } + + @SmallTest + public void testSingleStateNegativeMatches() throws Exception { + int[] stateSpec = new int[2]; + int state; + // match + stateSpec[0] = -1; + state = 1; + assertFalse(StateSet.stateSetMatches(stateSpec, state)); + // non-match + state = 2; + assertTrue(StateSet.stateSetMatches(stateSpec, state)); + // add irrelevant must-not-match + stateSpec[1] = -12345; + assertTrue(StateSet.stateSetMatches(stateSpec, state)); + } + + @SmallTest + public void testZeroStateOnlyMatchesDefault() throws Exception { + int[] stateSpec = new int[3]; + int state = 0; + // non-match + stateSpec[0] = 1; + assertFalse(StateSet.stateSetMatches(stateSpec, state)); + // non-match + stateSpec[1] = -1; + assertFalse(StateSet.stateSetMatches(stateSpec, state)); + // match + stateSpec = StateSet.WILD_CARD; + assertTrue(StateSet.stateSetMatches(stateSpec, state)); + } + + @SmallTest + public void testNullStateOnlyMatchesDefault() throws Exception { + int[] stateSpec = new int[3]; + int[] stateSet = null; + // non-match + stateSpec[0] = 1; + assertFalse(StateSet.stateSetMatches(stateSpec, stateSet)); + // non-match + stateSpec[1] = -1; + assertFalse(StateSet.stateSetMatches(stateSpec, stateSet)); + // match + stateSpec = StateSet.WILD_CARD; + assertTrue(StateSet.stateSetMatches(stateSpec, stateSet)); + } +} diff --git a/tests/CoreTests/android/view/FocusFinderTest.java b/tests/CoreTests/android/view/FocusFinderTest.java new file mode 100644 index 0000000000000000000000000000000000000000..7ac8dfce6e916fb385a29a43e133eb451f032483 --- /dev/null +++ b/tests/CoreTests/android/view/FocusFinderTest.java @@ -0,0 +1,576 @@ +/* + * 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 android.view; + +import android.graphics.Rect; +import android.test.AndroidTestCase; +import android.test.suitebuilder.annotation.MediumTest; +import android.test.suitebuilder.annotation.SmallTest; + +public class FocusFinderTest extends AndroidTestCase { + + private FocusFinderHelper mFocusFinder; + + @Override + protected void setUp() throws Exception { + super.setUp(); + + mFocusFinder = new FocusFinderHelper(FocusFinder.getInstance()); + } + + @SmallTest + public void testPreconditions() { + assertNotNull("focus finder instance", mFocusFinder); + } + + @SmallTest + public void testBelowNotCandidateForDirectionUp() { + assertIsNotCandidate(View.FOCUS_UP, + new Rect(0, 30, 10, 40), // src (left, top, right, bottom) + new Rect(0, 50, 10, 60)); // dest (left, top, right, bottom) + } + + @SmallTest + public void testAboveShareEdgeEdgeOkForDirectionUp() { + final Rect src = new Rect(0, 30, 10, 40); + + final Rect dest = new Rect(src); + dest.offset(0, -src.height()); + assertEquals(src.top, dest.bottom); + + assertDirectionIsCandidate(View.FOCUS_UP, src, dest); + } + + @SmallTest + public void testCompletelyContainedNotCandidate() { + assertIsNotCandidate( + View.FOCUS_DOWN, + // L T R B + new Rect(0, 0, 50, 50), + new Rect(0, 1, 50, 49)); + } + + @SmallTest + public void testContinaedWithCommonBottomNotCandidate() { + assertIsNotCandidate( + View.FOCUS_DOWN, + // L T R B + new Rect(0, 0, 50, 50), + new Rect(0, 1, 50, 50)); + } + + @SmallTest + public void testOverlappingIsCandidateWhenBothEdgesAreInDirection() { + assertDirectionIsCandidate( + View.FOCUS_DOWN, + // L T R B + new Rect(0, 0, 50, 50), + new Rect(0, 1, 50, 51)); + } + + @SmallTest + public void testTopEdgeOfDestAtOrAboveTopOfSrcNotCandidateForDown() { + assertIsNotCandidate( + View.FOCUS_DOWN, + // L T R B + new Rect(0, 0, 50, 50), + new Rect(0, 0, 50, 51)); + assertIsNotCandidate( + View.FOCUS_DOWN, + // L T R B + new Rect(0, 0, 50, 50), + new Rect(0, -1, 50, 51)); + } + + @SmallTest + public void testSameRectBeamsOverlap() { + final Rect rect = new Rect(0, 0, 20, 20); + + assertBeamsOverlap(View.FOCUS_LEFT, rect, rect); + assertBeamsOverlap(View.FOCUS_RIGHT, rect, rect); + assertBeamsOverlap(View.FOCUS_UP, rect, rect); + assertBeamsOverlap(View.FOCUS_DOWN, rect, rect); + } + + @SmallTest + public void testOverlapBeamsRightLeftUpToEdge() { + final Rect rect1 = new Rect(0, 0, 20, 20); + final Rect rect2 = new Rect(rect1); + + // just below bottom edge + rect2.offset(0, rect1.height() - 1); + assertBeamsOverlap(View.FOCUS_LEFT, rect1, rect2); + assertBeamsOverlap(View.FOCUS_RIGHT, rect1, rect2); + + // at edge + rect2.offset(0, 1); + assertBeamsOverlap(View.FOCUS_LEFT, rect1, rect2); + assertBeamsOverlap(View.FOCUS_RIGHT, rect1, rect2); + + // just beyond + rect2.offset(0, 1); + assertBeamsDontOverlap(View.FOCUS_LEFT, rect1, rect2); + assertBeamsDontOverlap(View.FOCUS_RIGHT, rect1, rect2); + + // just below top edge + rect2.set(rect1); + rect2.offset(0, -(rect1.height() - 1)); + assertBeamsOverlap(View.FOCUS_LEFT, rect1, rect2); + assertBeamsOverlap(View.FOCUS_RIGHT, rect1, rect2); + + // at top edge + rect2.offset(0, -1); + assertBeamsOverlap(View.FOCUS_LEFT, rect1, rect2); + assertBeamsOverlap(View.FOCUS_RIGHT, rect1, rect2); + + // just beyond top edge + rect2.offset(0, -1); + assertBeamsDontOverlap(View.FOCUS_LEFT, rect1, rect2); + assertBeamsDontOverlap(View.FOCUS_RIGHT, rect1, rect2); + } + + @SmallTest + public void testOverlapBeamsUpDownUpToEdge() { + final Rect rect1 = new Rect(0, 0, 20, 20); + final Rect rect2 = new Rect(rect1); + + // just short of right edge + rect2.offset(rect1.width() - 1, 0); + assertBeamsOverlap(View.FOCUS_UP, rect1, rect2); + assertBeamsOverlap(View.FOCUS_DOWN, rect1, rect2); + + // at edge + rect2.offset(1, 0); + assertBeamsOverlap(View.FOCUS_UP, rect1, rect2); + assertBeamsOverlap(View.FOCUS_DOWN, rect1, rect2); + + // just beyond + rect2.offset(1, 0); + assertBeamsDontOverlap(View.FOCUS_UP, rect1, rect2); + assertBeamsDontOverlap(View.FOCUS_DOWN, rect1, rect2); + + // just short of left edge + rect2.set(rect1); + rect2.offset(-(rect1.width() - 1), 0); + assertBeamsOverlap(View.FOCUS_UP, rect1, rect2); + assertBeamsOverlap(View.FOCUS_DOWN, rect1, rect2); + + // at edge + rect2.offset(-1, 0); + assertBeamsOverlap(View.FOCUS_UP, rect1, rect2); + assertBeamsOverlap(View.FOCUS_DOWN, rect1, rect2); + + // just beyond edge + rect2.offset(-1, 0); + assertBeamsDontOverlap(View.FOCUS_UP, rect1, rect2); + assertBeamsDontOverlap(View.FOCUS_DOWN, rect1, rect2); + } + + @SmallTest + public void testDirectlyAboveTrumpsAboveLeft() { + Rect src = new Rect(0, 50, 20, 70); // src (left, top, right, bottom) + + Rect directlyAbove = new Rect(src); + directlyAbove.offset(0, -(1 + src.height())); + + Rect aboveLeft = new Rect(src); + aboveLeft.offset(-(1 + src.width()), -(1 + src.height())); + + assertBetterCandidate(View.FOCUS_UP, src, directlyAbove, aboveLeft); + } + + @SmallTest + public void testAboveInBeamTrumpsSlightlyCloserOutOfBeam() { + Rect src = new Rect(0, 50, 20, 70); // src (left, top, right, bottom) + + Rect directlyAbove = new Rect(src); + directlyAbove.offset(0, -(1 + src.height())); + + Rect aboveLeft = new Rect(src); + aboveLeft.offset(-(1 + src.width()), -(1 + src.height())); + + // offset directly above a little further up + directlyAbove.offset(0, -5); + assertBetterCandidate(View.FOCUS_UP, src, directlyAbove, aboveLeft); + } + + @SmallTest + public void testOutOfBeamBeatsInBeamUp() { + + Rect src = new Rect(0, 0, 50, 50); // (left, top, right, bottom) + + Rect aboveLeftOfBeam = new Rect(src); + aboveLeftOfBeam.offset(-(src.width() + 1), -src.height()); + assertBeamsDontOverlap(View.FOCUS_UP, src, aboveLeftOfBeam); + + Rect aboveInBeam = new Rect(src); + aboveInBeam.offset(0, -src.height()); + assertBeamsOverlap(View.FOCUS_UP, src, aboveInBeam); + + // in beam wins + assertBetterCandidate(View.FOCUS_UP, src, aboveInBeam, aboveLeftOfBeam); + + // still wins while aboveInBeam's bottom edge is < out of beams' top + aboveInBeam.offset(0, -(aboveLeftOfBeam.height() - 1)); + assertTrue("aboveInBeam.bottom > aboveLeftOfBeam.top", aboveInBeam.bottom > aboveLeftOfBeam.top); + assertBetterCandidate(View.FOCUS_UP, src, aboveInBeam, aboveLeftOfBeam); + + // cross the threshold: the out of beam prevails + aboveInBeam.offset(0, -1); + assertEquals(aboveInBeam.bottom, aboveLeftOfBeam.top); + assertBetterCandidate(View.FOCUS_UP, src, aboveLeftOfBeam, aboveInBeam); + } + + /** + * A non-candidate (even a much closer one) is always a worse choice + * than a real candidate. + */ + @MediumTest + public void testSomeCandidateBetterThanNonCandidate() { + Rect src = new Rect(0, 0, 50, 50); // (left, top, right, bottom) + + Rect nonCandidate = new Rect(src); + nonCandidate.offset(src.width() + 1, 0); + + assertIsNotCandidate(View.FOCUS_LEFT, src, nonCandidate); + + Rect candidate = new Rect(src); + candidate.offset(-(4 * src.width()), 0); + assertDirectionIsCandidate(View.FOCUS_LEFT, src, candidate); + + assertBetterCandidate(View.FOCUS_LEFT, src, candidate, nonCandidate); + } + + /** + * Grabbed from {@link com.android.frameworktest.focus.VerticalFocusSearchTest#testSearchFromMidLeft()} + */ + @SmallTest + public void testVerticalFocusSearchScenario() { + assertBetterCandidate(View.FOCUS_DOWN, + // L T R B + new Rect(0, 109, 153, 169), // src + new Rect(166, 169, 319, 229), // expectedbetter + new Rect(0, 229, 320, 289)); // expectedworse + + // failing test 4/10/2008, the values were tweaked somehow in functional + // test... + assertBetterCandidate(View.FOCUS_DOWN, + // L T R B + new Rect(0, 91, 153, 133), // src + new Rect(166, 133, 319, 175), // expectedbetter + new Rect(0, 175, 320, 217)); // expectedworse + + } + + /** + * Example: going down from a thin button all the way to the left of a + * screen where, just below, is a very wide button, and just below that, + * is an equally skinny button all the way to the left. want to make + * sure any minor axis factor doesn't override the fact that the one below + * in vertical beam should be next focus + */ + @SmallTest + public void testBeamsOverlapMajorAxisCloserMinorAxisFurther() { + assertBetterCandidate(View.FOCUS_DOWN, + // L T R B + new Rect(0, 0, 100, 100), // src + new Rect(0, 100, 480, 200), // expectedbetter + new Rect(0, 200, 100, 300)); // expectedworse + } + + /** + * Real scenario grabbed from song playback screen. + */ + @SmallTest + public void testMusicPlaybackScenario() { + assertBetterCandidate(View.FOCUS_LEFT, + // L T R B + new Rect(227, 185, 312, 231), // src + new Rect(195, 386, 266, 438), // expectedbetter + new Rect(124, 386, 195, 438)); // expectedworse + } + + /** + * more generalized version of {@link #testMusicPlaybackScenario()} + */ + @SmallTest + public void testOutOfBeamOverlapBeatsOutOfBeamFurtherOnMajorAxis() { + assertBetterCandidate(View.FOCUS_DOWN, + // L T R B + new Rect(0, 0, 50, 50), // src + new Rect(60, 40, 110, 90), // expectedbetter + new Rect(60, 70, 110, 120)); // expectedworse + } + + /** + * Make sure that going down prefers views that are actually + * down (and not those next to but still a candidate because + * they are overlapping on the major axis) + */ + @SmallTest + public void testInBeamTrumpsOutOfBeamOverlapping() { + assertBetterCandidate(View.FOCUS_DOWN, + // L T R B + new Rect(0, 0, 50, 50), // src + new Rect(0, 60, 50, 110), // expectedbetter + new Rect(51, 1, 101, 51)); // expectedworse + } + + @SmallTest + public void testOverlappingBeatsNonOverlapping() { + assertBetterCandidate(View.FOCUS_DOWN, + // L T R B + new Rect(0, 0, 50, 50), // src + new Rect(0, 40, 50, 90), // expectedbetter + new Rect(0, 75, 50, 125)); // expectedworse + } + + @SmallTest + public void testEditContactScenarioLeftFromDiscardChangesGoesToSaveContactInLandscape() { + assertBetterCandidate(View.FOCUS_LEFT, + // L T R B + new Rect(357, 258, 478, 318), // src + new Rect(2, 258, 100, 318), // better + new Rect(106, 120, 424, 184)); // worse + } + + /** + * A dial pad with 9 squares arranged in a grid. no padding, so + * the edges are equal. see {@link com.android.frameworktest.focus.LinearLayoutGrid} + */ + @SmallTest + public void testGridWithTouchingEdges() { + assertBetterCandidate(View.FOCUS_DOWN, + // L T R B + new Rect(106, 49, 212, 192), // src + new Rect(106, 192, 212, 335), // better + new Rect(0, 192, 106, 335)); // worse + + assertBetterCandidate(View.FOCUS_DOWN, + // L T R B + new Rect(106, 49, 212, 192), // src + new Rect(106, 192, 212, 335), // better + new Rect(212, 192, 318, 335)); // worse + } + + @SmallTest + public void testSearchFromEmptyRect() { + assertBetterCandidate(View.FOCUS_DOWN, + // L T R B + new Rect(0, 0, 0, 0), // src + new Rect(0, 0, 320, 45), // better + new Rect(0, 45, 320, 545)); // worse + } + + /** + * Reproduce bug 1124559, drilling down to actual bug + * (majorAxisDistance was wrong for direction left) + */ + @SmallTest + public void testGmailReplyButtonsScenario() { + assertBetterCandidate(View.FOCUS_LEFT, + // L T R B + new Rect(223, 380, 312, 417), // src + new Rect(102, 380, 210, 417), // better + new Rect(111, 443, 206, 480)); // worse + + assertBeamBeats(View.FOCUS_LEFT, + // L T R B + new Rect(223, 380, 312, 417), // src + new Rect(102, 380, 210, 417), // better + new Rect(111, 443, 206, 480)); // worse + + assertBeamsOverlap(View.FOCUS_LEFT, + // L T R B + new Rect(223, 380, 312, 417), + new Rect(102, 380, 210, 417)); + + assertBeamsDontOverlap(View.FOCUS_LEFT, + // L T R B + new Rect(223, 380, 312, 417), + new Rect(111, 443, 206, 480)); + + assertTrue( + "major axis distance less than major axis distance to " + + "far edge", + FocusFinderHelper.majorAxisDistance(View.FOCUS_LEFT, + // L T R B + new Rect(223, 380, 312, 417), + new Rect(102, 380, 210, 417)) < + FocusFinderHelper.majorAxisDistanceToFarEdge(View.FOCUS_LEFT, + // L T R B + new Rect(223, 380, 312, 417), + new Rect(111, 443, 206, 480))); + } + + @SmallTest + public void testGmailScenarioBug1203288() { + assertBetterCandidate(View.FOCUS_DOWN, + // L T R B + new Rect(0, 2, 480, 82), // src + new Rect(344, 87, 475, 124), // better + new Rect(0, 130, 480, 203)); // worse + } + + @SmallTest + public void testHomeShortcutScenarioBug1295354() { + assertBetterCandidate(View.FOCUS_RIGHT, + // L T R B + new Rect(3, 338, 77, 413), // src + new Rect(163, 338, 237, 413), // better + new Rect(83, 38, 157, 113)); // worse + } + + @SmallTest + public void testBeamAlwaysBeatsHoriz() { + assertBetterCandidate(View.FOCUS_RIGHT, + // L T R B + new Rect(0, 0, 50, 50), // src + new Rect(150, 0, 200, 50), // better, (way further, but in beam) + new Rect(60, 51, 110, 101)); // worse, even though it is closer + + assertBetterCandidate(View.FOCUS_LEFT, + // L T R B + new Rect(150, 0, 200, 50), // src + new Rect(0, 50, 50, 50), // better, (way further, but in beam) + new Rect(49, 99, 149, 101)); // worse, even though it is closer + } + + @SmallTest + public void testIsCandidateOverlappingEdgeFromEmptyRect() { + assertDirectionIsCandidate(View.FOCUS_DOWN, + // L T R B + new Rect(0, 0, 0, 0), // src + new Rect(0, 0, 20, 1)); // candidate + + assertDirectionIsCandidate(View.FOCUS_UP, + // L T R B + new Rect(0, 0, 0, 0), // src + new Rect(0, -1, 20, 0)); // candidate + + assertDirectionIsCandidate(View.FOCUS_LEFT, + // L T R B + new Rect(0, 0, 0, 0), // src + new Rect(-1, 0, 0, 20)); // candidate + + assertDirectionIsCandidate(View.FOCUS_RIGHT, + // L T R B + new Rect(0, 0, 0, 0), // src + new Rect(0, 0, 1, 20)); // candidate + } + + private void assertBeamsOverlap(int direction, Rect rect1, Rect rect2) { + String directionStr = validateAndGetStringFor(direction); + String assertMsg = String.format("Expected beams to overlap in direction %s " + + "for rectangles %s and %s", directionStr, rect1, rect2); + assertTrue(assertMsg, mFocusFinder.beamsOverlap(direction, rect1, rect2)); + } + + private void assertBeamsDontOverlap(int direction, Rect rect1, Rect rect2) { + String directionStr = validateAndGetStringFor(direction); + String assertMsg = String.format("Expected beams not to overlap in direction %s " + + "for rectangles %s and %s", directionStr, rect1, rect2); + assertFalse(assertMsg, mFocusFinder.beamsOverlap(direction, rect1, rect2)); + } + + /** + * Assert that particular rect is a better focus search candidate from a + * source rect than another. + * @param direction The direction of focus search. + * @param srcRect The src rectangle. + * @param expectedBetter The candidate that should be better. + * @param expectedWorse The candidate that should be worse. + */ + private void assertBetterCandidate(int direction, Rect srcRect, + Rect expectedBetter, Rect expectedWorse) { + + String directionStr = validateAndGetStringFor(direction); + String assertMsg = String.format( + "expected %s to be a better focus search candidate than " + + "%s when searching " + + "from %s in direction %s", + expectedBetter, expectedWorse, srcRect, directionStr); + + assertTrue(assertMsg, + mFocusFinder.isBetterCandidate(direction, srcRect, + expectedBetter, expectedWorse)); + + assertMsg = String.format( + "expected %s to not be a better focus search candidate than " + + "%s when searching " + + "from %s in direction %s", + expectedWorse, expectedBetter, srcRect, directionStr); + + assertFalse(assertMsg, + mFocusFinder.isBetterCandidate(direction, srcRect, + expectedWorse, expectedBetter)); + } + + private void assertIsNotCandidate(int direction, Rect src, Rect dest) { + String directionStr = validateAndGetStringFor(direction); + + final String assertMsg = String.format( + "expected going from %s to %s in direction %s to be an invalid " + + "focus search candidate", + src, dest, directionStr); + assertFalse(assertMsg, mFocusFinder.isCandidate(src, dest, direction)); + } + + private void assertBeamBeats(int direction, Rect srcRect, + Rect rect1, Rect rect2) { + + String directionStr = validateAndGetStringFor(direction); + String assertMsg = String.format( + "expecting %s to beam beat %s w.r.t %s in direction %s", + rect1, rect2, srcRect, directionStr); + assertTrue(assertMsg, mFocusFinder.beamBeats(direction, srcRect, rect1, rect2)); + } + + + private void assertDirectionIsCandidate(int direction, Rect src, Rect dest) { + String directionStr = validateAndGetStringFor(direction); + + final String assertMsg = String.format( + "expected going from %s to %s in direction %s to be a valid " + + "focus search candidate", + src, dest, directionStr); + assertTrue(assertMsg, mFocusFinder.isCandidate(src, dest, direction)); + } + + private String validateAndGetStringFor(int direction) { + String directionStr = "??"; + switch(direction) { + case View.FOCUS_UP: + directionStr = "FOCUS_UP"; + break; + case View.FOCUS_DOWN: + directionStr = "FOCUS_DOWN"; + break; + case View.FOCUS_LEFT: + directionStr = "FOCUS_LEFT"; + break; + case View.FOCUS_RIGHT: + directionStr = "FOCUS_RIGHT"; + break; + default: + fail("passed in unknown direction, ya blewit!"); + } + return directionStr; + } + + +} diff --git a/tests/CoreTests/android/view/MockView.java b/tests/CoreTests/android/view/MockView.java new file mode 100644 index 0000000000000000000000000000000000000000..1d416bde50ddb08e4dd9c78da85f681d6f73d709 --- /dev/null +++ b/tests/CoreTests/android/view/MockView.java @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2007 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 android.view; + +/** + * Mock View class for testing + */ + +public class MockView extends View{ + +} diff --git a/tests/CoreTests/android/view/ViewGroupAttributesTest.java b/tests/CoreTests/android/view/ViewGroupAttributesTest.java new file mode 100644 index 0000000000000000000000000000000000000000..b4ef0e7e76bd3f20598bfec91f8e70beac460deb --- /dev/null +++ b/tests/CoreTests/android/view/ViewGroupAttributesTest.java @@ -0,0 +1,83 @@ +/* + * 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 android.view; + +import android.content.Context; +import android.test.AndroidTestCase; +import android.test.suitebuilder.annotation.SmallTest; + +public class ViewGroupAttributesTest extends AndroidTestCase { + + private MyViewGroup mViewGroup; + + private static final class MyViewGroup extends ViewGroup { + + public MyViewGroup(Context context) { + super(context); + } + + @Override + protected void onLayout(boolean changed, int l, int t, int r, int b) { + } + + @Override + public boolean isChildrenDrawnWithCacheEnabled() { + return super.isChildrenDrawnWithCacheEnabled(); + } + } + + @Override + protected void setUp() throws Exception { + super.setUp(); + mViewGroup = new MyViewGroup(getContext()); + } + + @SmallTest + public void testDescendantFocusabilityEnum() { + assertEquals("expected ViewGroup.FOCUS_BEFORE_DESCENDANTS to be default", + ViewGroup.FOCUS_BEFORE_DESCENDANTS, mViewGroup.getDescendantFocusability()); + + // remember some state before we muck with flags + final boolean isAnimationCachEnabled = mViewGroup.isAnimationCacheEnabled(); + final boolean isAlwaysDrawnWithCacheEnabled = mViewGroup.isAlwaysDrawnWithCacheEnabled(); + final boolean isChildrenDrawnWithCacheEnabled = mViewGroup.isChildrenDrawnWithCacheEnabled(); + + mViewGroup.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS); + assertEquals(ViewGroup.FOCUS_AFTER_DESCENDANTS, mViewGroup.getDescendantFocusability()); + + mViewGroup.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS); + assertEquals(ViewGroup.FOCUS_BLOCK_DESCENDANTS, mViewGroup.getDescendantFocusability()); + + mViewGroup.setDescendantFocusability(ViewGroup.FOCUS_BEFORE_DESCENDANTS); + assertEquals(ViewGroup.FOCUS_BEFORE_DESCENDANTS, mViewGroup.getDescendantFocusability()); + + // verify we didn't change something unrelated + final String msg = "setDescendantFocusability messed with an unrelated flag"; + assertEquals(msg, isAnimationCachEnabled, mViewGroup.isAnimationCacheEnabled()); + assertEquals(msg, isAlwaysDrawnWithCacheEnabled, mViewGroup.isAlwaysDrawnWithCacheEnabled()); + assertEquals(msg, isChildrenDrawnWithCacheEnabled, mViewGroup.isChildrenDrawnWithCacheEnabled()); + } + + @SmallTest + public void testWrongIntSetForDescendantFocusabilityEnum() { + try { + mViewGroup.setDescendantFocusability(0); + fail("expected setting wrong flag to throw an exception"); + } catch (IllegalArgumentException expected) { + } + } +} diff --git a/tests/CoreTests/android/webkit/CookieTest.java b/tests/CoreTests/android/webkit/CookieTest.java new file mode 100644 index 0000000000000000000000000000000000000000..6844de724ba9cf03e9f0c0c092d4fe612aa077ec --- /dev/null +++ b/tests/CoreTests/android/webkit/CookieTest.java @@ -0,0 +1,184 @@ +/* + * 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 android.webkit; + +import android.content.Context; +import android.test.AndroidTestCase; +import android.util.Log; +import android.webkit.CookieManager; +import android.webkit.CookieSyncManager; + +public class CookieTest extends AndroidTestCase { + + /** + * To run these tests: $ mmm frameworks/base/tests/CoreTests/android && adb + * remount && adb sync $ adb shell am instrument -w \ -e class + * android.webkit.CookieTest \ + * android.core/android.test.InstrumentationTestRunner + */ + + private CookieManager mCookieManager; + + @Override + public void setContext(Context context) { + assertTrue(mContext == null); + super.setContext(context); + CookieSyncManager.createInstance(context); + mCookieManager = CookieManager.getInstance(); + mCookieManager.removeAllCookie(); + } + + public void testParse() { + mCookieManager.removeAllCookie(); + String url = "http://www.foo.com"; + + // basic + mCookieManager.setCookie(url, "a=b"); + String cookie = mCookieManager.getCookie(url); + assertTrue(cookie.equals("a=b")); + + // quoted + mCookieManager.setCookie(url, "c=\"d;\""); + cookie = mCookieManager.getCookie(url); + assertTrue(cookie.equals("a=b; c=\"d;\"")); + } + + public void testDomain() { + mCookieManager.removeAllCookie(); + String url = "http://www.foo.com"; + + // basic + mCookieManager.setCookie(url, "a=b"); + String cookie = mCookieManager.getCookie(url); + assertTrue(cookie.equals("a=b")); + + // no cross domain cookie + cookie = mCookieManager.getCookie("http://bar.com"); + assertTrue(cookie == null); + + // more than one cookie + mCookieManager.setCookie(url, "c=d; domain=.foo.com"); + cookie = mCookieManager.getCookie(url); + assertTrue(cookie.equals("a=b; c=d")); + + // host cookie should not be accessible from a sub-domain. + cookie = mCookieManager.getCookie("http://bar.www.foo.com"); + assertTrue(cookie.equals("c=d")); + + // test setting a domain= that doesn't start w/ a dot, should + // treat it as a domain cookie, as if there was a pre-pended dot. + mCookieManager.setCookie(url, "e=f; domain=www.foo.com"); + cookie = mCookieManager.getCookie(url); + assertTrue(cookie.equals("a=b; c=d; e=f")); + cookie = mCookieManager.getCookie("http://sub.www.foo.com"); + assertTrue(cookie.equals("c=d; e=f")); + cookie = mCookieManager.getCookie("http://foo.com"); + assertTrue(cookie.equals("c=d")); + } + + public void testSubDomain() { + mCookieManager.removeAllCookie(); + String url_abcd = "http://a.b.c.d.com"; + String url_bcd = "http://b.c.d.com"; + String url_cd = "http://c.d.com"; + String url_d = "http://d.com"; + + mCookieManager.setCookie(url_abcd, "a=1; domain=.a.b.c.d.com"); + mCookieManager.setCookie(url_abcd, "b=2; domain=.b.c.d.com"); + mCookieManager.setCookie(url_abcd, "c=3; domain=.c.d.com"); + mCookieManager.setCookie(url_abcd, "d=4; domain=.d.com"); + + String cookie = mCookieManager.getCookie(url_abcd); + assertTrue(cookie.equals("a=1; b=2; c=3; d=4")); + cookie = mCookieManager.getCookie(url_bcd); + assertTrue(cookie.equals("b=2; c=3; d=4")); + cookie = mCookieManager.getCookie(url_cd); + assertTrue(cookie.equals("c=3; d=4")); + cookie = mCookieManager.getCookie(url_d); + assertTrue(cookie.equals("d=4")); + + // check that the same cookie can exist on different sub-domains. + mCookieManager.setCookie(url_bcd, "x=bcd; domain=.b.c.d.com"); + mCookieManager.setCookie(url_bcd, "x=cd; domain=.c.d.com"); + cookie = mCookieManager.getCookie(url_bcd); + assertTrue(cookie.equals("b=2; c=3; d=4; x=bcd; x=cd")); + cookie = mCookieManager.getCookie(url_cd); + assertTrue(cookie.equals("c=3; d=4; x=cd")); + } + + public void testInvalidDomain() { + mCookieManager.removeAllCookie(); + String url = "http://foo.bar.com"; + + mCookieManager.setCookie(url, "a=1; domain=.yo.foo.bar.com"); + String cookie = mCookieManager.getCookie(url); + assertTrue(cookie == null); + + mCookieManager.setCookie(url, "b=2; domain=.foo.com"); + cookie = mCookieManager.getCookie(url); + assertTrue(cookie == null); + + mCookieManager.setCookie(url, "c=3; domain=.bar.foo.com"); + cookie = mCookieManager.getCookie(url); + assertTrue(cookie == null); + + mCookieManager.setCookie(url, "d=4; domain=.foo.bar.com.net"); + cookie = mCookieManager.getCookie(url); + assertTrue(cookie == null); + + mCookieManager.setCookie(url, "e=5; domain=.ar.com"); + cookie = mCookieManager.getCookie(url); + assertTrue(cookie == null); + + mCookieManager.setCookie(url, "f=6; domain=.com"); + cookie = mCookieManager.getCookie(url); + assertTrue(cookie == null); + + mCookieManager.setCookie(url, "g=7; domain=.co.uk"); + cookie = mCookieManager.getCookie(url); + assertTrue(cookie == null); + + mCookieManager.setCookie(url, "h=8; domain=.foo.bar.com.com"); + cookie = mCookieManager.getCookie(url); + assertTrue(cookie == null); + } + + public void testPath() { + mCookieManager.removeAllCookie(); + String url = "http://www.foo.com"; + + mCookieManager.setCookie(url, "a=b; path=/wee"); + String cookie = mCookieManager.getCookie(url + "/wee"); + assertTrue(cookie.equals("a=b")); + cookie = mCookieManager.getCookie(url + "/wee/"); + assertTrue(cookie.equals("a=b")); + cookie = mCookieManager.getCookie(url + "/wee/hee"); + assertTrue(cookie.equals("a=b")); + cookie = mCookieManager.getCookie(url + "/wee/hee/more"); + assertTrue(cookie.equals("a=b")); + cookie = mCookieManager.getCookie(url + "/weehee"); + assertTrue(cookie == null); + cookie = mCookieManager.getCookie(url); + assertTrue(cookie == null); + + mCookieManager.setCookie(url, "a=c; path="); + cookie = mCookieManager.getCookie(url + "/wee"); + assertTrue(cookie.equals("a=b; a=c")); + cookie = mCookieManager.getCookie(url); + assertTrue(cookie.equals("a=c")); + } +} diff --git a/tests/CoreTests/com/android/internal/telephony/ATResponseParserTest.java b/tests/CoreTests/com/android/internal/telephony/ATResponseParserTest.java new file mode 100644 index 0000000000000000000000000000000000000000..81727e4829616679d41db2ed8483273412691511 --- /dev/null +++ b/tests/CoreTests/com/android/internal/telephony/ATResponseParserTest.java @@ -0,0 +1,113 @@ +/* + * Copyright (C) 2006 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.android.internal.telephony; + +import junit.framework.TestCase; +import android.test.suitebuilder.annotation.SmallTest; + +public class ATResponseParserTest extends TestCase { + @SmallTest + public void testBasic() throws Exception { + ATResponseParser p = new ATResponseParser("+CREG: 0"); + + assertEquals(0, p.nextInt()); + + assertFalse(p.hasMore()); + + try { + p.nextInt(); + fail("exception expected"); + } catch (ATParseEx ex) { + //test pass + } + + p = new ATResponseParser("+CREG: 0,1"); + assertEquals(0, p.nextInt()); + assertEquals(1, p.nextInt()); + assertFalse(p.hasMore()); + + p = new ATResponseParser("+CREG: 0, 1"); + assertEquals(0, p.nextInt()); + assertEquals(1, p.nextInt()); + assertFalse(p.hasMore()); + + p = new ATResponseParser("+CREG: 0, 1,"); + assertEquals(0, p.nextInt()); + assertEquals(1, p.nextInt()); + // this seems odd but is probably OK + assertFalse(p.hasMore()); + try { + p.nextInt(); + fail("exception expected"); + } catch (ATParseEx ex) { + //test pass + } + + p = new ATResponseParser("+CREG: 0, 1 "); + assertEquals(0, p.nextInt()); + assertEquals(1, p.nextInt()); + assertFalse(p.hasMore()); + + p = new ATResponseParser("0, 1 "); + // no prefix -> exception + try { + p.nextInt(); + fail("exception expected"); + } catch (ATParseEx ex) { + //test pass + } + + p = new ATResponseParser("+CREG: 0, 1, 5"); + assertFalse(p.nextBoolean()); + assertTrue(p.nextBoolean()); + try { + // is this over-constraining? + p.nextBoolean(); + fail("exception expected"); + } catch (ATParseEx ex) { + //test pass + } + + p = new ATResponseParser("+CLCC: 1,0,2,0,0,\"+18005551212\",145"); + + assertEquals(1, p.nextInt()); + assertFalse(p.nextBoolean()); + assertEquals(2, p.nextInt()); + assertEquals(0, p.nextInt()); + assertEquals(0, p.nextInt()); + assertEquals("+18005551212", p.nextString()); + assertEquals(145, p.nextInt()); + assertFalse(p.hasMore()); + + p = new ATResponseParser("+CLCC: 1,0,2,0,0,\"+18005551212,145"); + + assertEquals(1, p.nextInt()); + assertFalse(p.nextBoolean()); + assertEquals(2, p.nextInt()); + assertEquals(0, p.nextInt()); + assertEquals(0, p.nextInt()); + try { + p.nextString(); + fail("expected ex"); + } catch (ATParseEx ex) { + //test pass + } + + p = new ATResponseParser("+FOO: \"\""); + assertEquals("", p.nextString()); + } +} diff --git a/tests/CoreTests/com/android/internal/telephony/PhoneNumberUtilsTest.java b/tests/CoreTests/com/android/internal/telephony/PhoneNumberUtilsTest.java new file mode 100644 index 0000000000000000000000000000000000000000..e8bd23999890b000525ae97f548775eeb183b26b --- /dev/null +++ b/tests/CoreTests/com/android/internal/telephony/PhoneNumberUtilsTest.java @@ -0,0 +1,326 @@ +/* + * Copyright (C) 2006 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.android.internal.telephony; + +import android.test.suitebuilder.annotation.SmallTest; +import android.text.SpannableStringBuilder; +import android.telephony.PhoneNumberUtils; + +import junit.framework.TestCase; + +public class PhoneNumberUtilsTest extends TestCase { + + @SmallTest + public void testA() throws Exception { + assertEquals( + "+17005554141", + PhoneNumberUtils.extractNetworkPortion("+17005554141") + ); + + assertEquals( + "+17005554141", + PhoneNumberUtils.extractNetworkPortion("+1 (700).555-4141") + ); + + assertEquals( + "17005554141", + PhoneNumberUtils.extractNetworkPortion("1 (700).555-4141") + ); + + // This may seem wrong, but it's probably ok + assertEquals( + "17005554141*#", + PhoneNumberUtils.extractNetworkPortion("1 (700).555-4141*#") + ); + + assertEquals( + "170055541NN", + PhoneNumberUtils.extractNetworkPortion("1 (700).555-41NN") + ); + + assertEquals( + "170055541NN", + PhoneNumberUtils.extractNetworkPortion("1 (700).555-41NN,1234") + ); + + assertEquals( + "170055541NN", + PhoneNumberUtils.extractNetworkPortion("1 (700).555-41NN;1234") + ); + + // An MMI string is unperterbed, even though it contains a + // (valid in this case) embedded + + assertEquals( + "**21**17005554141#", + PhoneNumberUtils.extractNetworkPortion("**21**+17005554141#") + //TODO this is the correct result, although the above + //result has been returned since change 31776 + //"**21**+17005554141#" + ); + + assertEquals("", PhoneNumberUtils.extractNetworkPortion("")); + + assertEquals("", PhoneNumberUtils.extractNetworkPortion(",1234")); + + byte [] b = new byte[20]; + b[0] = (byte) 0x81; b[1] = (byte) 0x71; b[2] = (byte) 0x00; b[3] = (byte) 0x55; + b[4] = (byte) 0x05; b[5] = (byte) 0x20; b[6] = (byte) 0xF0; + assertEquals("17005550020", + PhoneNumberUtils.calledPartyBCDToString(b, 0, 7)); + + b[0] = (byte) 0x91; b[1] = (byte) 0x71; b[2] = (byte) 0x00; b[3] = (byte) 0x55; + b[4] = (byte) 0x05; b[5] = (byte) 0x20; b[6] = (byte) 0xF0; + assertEquals("+17005550020", + PhoneNumberUtils.calledPartyBCDToString(b, 0, 7)); + + byte[] bRet = PhoneNumberUtils.networkPortionToCalledPartyBCD("+17005550020"); + assertEquals(7, bRet.length); + for (int i = 0; i < 7; i++) { + assertEquals(b[i], bRet[i]); + } + + bRet = PhoneNumberUtils.networkPortionToCalledPartyBCD("7005550020"); + assertEquals("7005550020", + PhoneNumberUtils.calledPartyBCDToString(bRet, 0, bRet.length)); + + b[0] = (byte) 0x81; b[1] = (byte) 0x71; b[2] = (byte) 0x00; b[3] = (byte) 0x55; + b[4] = (byte) 0x05; b[5] = (byte) 0x20; b[6] = (byte) 0xB0; + assertEquals("17005550020#", + PhoneNumberUtils.calledPartyBCDToString(b, 0, 7)); + + b[0] = (byte) 0x91; b[1] = (byte) 0x71; b[2] = (byte) 0x00; b[3] = (byte) 0x55; + b[4] = (byte) 0x05; b[5] = (byte) 0x20; b[6] = (byte) 0xB0; + assertEquals("+17005550020#", + PhoneNumberUtils.calledPartyBCDToString(b, 0, 7)); + + b[0] = (byte) 0x81; b[1] = (byte) 0x2A; b[2] = (byte) 0xB1; + assertEquals("*21#", + PhoneNumberUtils.calledPartyBCDToString(b, 0, 3)); + + b[0] = (byte) 0x81; b[1] = (byte) 0x2B; b[2] = (byte) 0xB1; + assertEquals("#21#", + PhoneNumberUtils.calledPartyBCDToString(b, 0, 3)); + + b[0] = (byte) 0x91; b[1] = (byte) 0x2A; b[2] = (byte) 0xB1; + assertEquals("*21#+", + PhoneNumberUtils.calledPartyBCDToString(b, 0, 3)); + + b[0] = (byte) 0x81; b[1] = (byte) 0xAA; b[2] = (byte) 0x12; b[3] = (byte) 0xFB; + assertEquals("**21#", + PhoneNumberUtils.calledPartyBCDToString(b, 0, 4)); + + b[0] = (byte) 0x91; b[1] = (byte) 0xAA; b[2] = (byte) 0x12; b[3] = (byte) 0xFB; + assertEquals("**21#+", + PhoneNumberUtils.calledPartyBCDToString(b, 0, 4)); + + b[0] = (byte) 0x81; b[1] = (byte) 0x9A; b[2] = (byte) 0xA9; b[3] = (byte) 0x71; + b[4] = (byte) 0x00; b[5] = (byte) 0x55; b[6] = (byte) 0x05; b[7] = (byte) 0x20; + b[8] = (byte) 0xB0; + assertEquals("*99*17005550020#", + PhoneNumberUtils.calledPartyBCDToString(b, 0, 9)); + + b[0] = (byte) 0x91; b[1] = (byte) 0x9A; b[2] = (byte) 0xA9; b[3] = (byte) 0x71; + b[4] = (byte) 0x00; b[5] = (byte) 0x55; b[6] = (byte) 0x05; b[7] = (byte) 0x20; + b[8] = (byte) 0xB0; + assertEquals("*99*+17005550020#", + PhoneNumberUtils.calledPartyBCDToString(b, 0, 9)); + + b[0] = (byte) 0x81; b[1] = (byte) 0xAA; b[2] = (byte) 0x12; b[3] = (byte) 0x1A; + b[4] = (byte) 0x07; b[5] = (byte) 0x50; b[6] = (byte) 0x55; b[7] = (byte) 0x00; + b[8] = (byte) 0x02; b[9] = (byte) 0xFB; + assertEquals("**21*17005550020#", + PhoneNumberUtils.calledPartyBCDToString(b, 0, 10)); + + b[0] = (byte) 0x91; b[1] = (byte) 0xAA; b[2] = (byte) 0x12; b[3] = (byte) 0x1A; + b[4] = (byte) 0x07; b[5] = (byte) 0x50; b[6] = (byte) 0x55; b[7] = (byte) 0x00; + b[8] = (byte) 0x02; b[9] = (byte) 0xFB; + assertEquals("**21*+17005550020#", + PhoneNumberUtils.calledPartyBCDToString(b, 0, 10)); + + b[0] = (byte) 0x81; b[1] = (byte) 0x2A; b[2] = (byte) 0xA1; b[3] = (byte) 0x71; + b[4] = (byte) 0x00; b[5] = (byte) 0x55; b[6] = (byte) 0x05; b[7] = (byte) 0x20; + b[8] = (byte) 0xF0; + assertEquals("*21*17005550020", + PhoneNumberUtils.calledPartyBCDToString(b, 0, 9)); + + b[0] = (byte) 0x91; b[1] = (byte) 0x2A; b[2] = (byte) 0xB1; b[3] = (byte) 0x71; + b[4] = (byte) 0x00; b[5] = (byte) 0x55; b[6] = (byte) 0x05; b[7] = (byte) 0x20; + b[8] = (byte) 0xF0; + assertEquals("*21#+17005550020", + PhoneNumberUtils.calledPartyBCDToString(b, 0, 9)); + + assertNull(PhoneNumberUtils.extractNetworkPortion(null)); + assertNull(PhoneNumberUtils.extractPostDialPortion(null)); + assertTrue(PhoneNumberUtils.compare(null, null)); + assertFalse(PhoneNumberUtils.compare(null, "123")); + assertFalse(PhoneNumberUtils.compare("123", null)); + assertNull(PhoneNumberUtils.toCallerIDMinMatch(null)); + assertNull(PhoneNumberUtils.getStrippedReversed(null)); + assertNull(PhoneNumberUtils.stringFromStringAndTOA(null, 1)); + } + + @SmallTest + public void testB() throws Exception { + assertEquals("", PhoneNumberUtils.extractPostDialPortion("+17005554141")); + assertEquals("", PhoneNumberUtils.extractPostDialPortion("+1 (700).555-4141")); + assertEquals("", PhoneNumberUtils.extractPostDialPortion("+1 (700).555-41NN")); + assertEquals(",1234", PhoneNumberUtils.extractPostDialPortion("+1 (700).555-41NN,1234")); + assertEquals(";1234", PhoneNumberUtils.extractPostDialPortion("+1 (700).555-41NN;1234")); + assertEquals(";1234,;N", + PhoneNumberUtils.extractPostDialPortion("+1 (700).555-41NN;1-2.34 ,;N")); + } + + @SmallTest + public void testCompare() throws Exception { + // this is odd + assertFalse(PhoneNumberUtils.compare("", "")); + + assertTrue(PhoneNumberUtils.compare("911", "911")); + assertFalse(PhoneNumberUtils.compare("911", "18005550911")); + assertTrue(PhoneNumberUtils.compare("5555", "5555")); + assertFalse(PhoneNumberUtils.compare("5555", "180055555555")); + + assertTrue(PhoneNumberUtils.compare("+17005554141", "+17005554141")); + assertTrue(PhoneNumberUtils.compare("+17005554141", "+1 (700).555-4141")); + assertTrue(PhoneNumberUtils.compare("+17005554141", "+1 (700).555-4141,1234")); + assertTrue(PhoneNumberUtils.compare("+17005554141", "17005554141")); + assertTrue(PhoneNumberUtils.compare("+17005554141", "7005554141")); + assertTrue(PhoneNumberUtils.compare("+17005554141", "5554141")); + assertTrue(PhoneNumberUtils.compare("17005554141", "5554141")); + assertTrue(PhoneNumberUtils.compare("+17005554141", "01117005554141")); + assertTrue(PhoneNumberUtils.compare("+17005554141", "0017005554141")); + assertTrue(PhoneNumberUtils.compare("17005554141", "0017005554141")); + + + assertTrue(PhoneNumberUtils.compare("+17005554141", "**31#+17005554141")); + + assertFalse(PhoneNumberUtils.compare("+1 999 7005554141", "+1 7005554141")); + assertTrue(PhoneNumberUtils.compare("011 1 7005554141", "7005554141")); + + assertFalse(PhoneNumberUtils.compare("011 11 7005554141", "+17005554141")); + + assertFalse(PhoneNumberUtils.compare("+17005554141", "7085882300")); + + assertTrue(PhoneNumberUtils.compare("+44 207 792 3490", "0 207 792 3490")); + + assertFalse(PhoneNumberUtils.compare("+44 207 792 3490", "00 207 792 3490")); + assertFalse(PhoneNumberUtils.compare("+44 207 792 3490", "011 207 792 3490")); + + /***** FIXME's ******/ + // + // MMI header should be ignored + assertFalse(PhoneNumberUtils.compare("+17005554141", "**31#17005554141")); + + // It's too bad this is false + // +44 (0) 207 792 3490 is not a dialable number + // but it is commonly how European phone numbers are written + assertFalse(PhoneNumberUtils.compare("+44 207 792 3490", "+44 (0) 207 792 3490")); + + // The japanese international prefix, for example, messes us up + // But who uses a GSM phone in Japan? + assertFalse(PhoneNumberUtils.compare("+44 207 792 3490", "010 44 207 792 3490")); + + // The Australian one messes us up too + assertFalse(PhoneNumberUtils.compare("+44 207 792 3490", "0011 44 207 792 3490")); + + // The Russian trunk prefix messes us up, as does current + // Russian area codes (which bein with 0) + + assertFalse(PhoneNumberUtils.compare("+7(095)9100766", "8(095)9100766")); + + // 444 is not a valid country code, but + // matchIntlPrefixAndCC doesnt know this + assertTrue(PhoneNumberUtils.compare("+444 207 792 3490", "0 207 792 3490")); + } + + + @SmallTest + public void testToCallerIDIndexable() throws Exception { + assertEquals("14145", PhoneNumberUtils.toCallerIDMinMatch("17005554141")); + assertEquals("14145", PhoneNumberUtils.toCallerIDMinMatch("1-700-555-4141")); + assertEquals("14145", PhoneNumberUtils.toCallerIDMinMatch("1-700-555-4141,1234")); + assertEquals("14145", PhoneNumberUtils.toCallerIDMinMatch("1-700-555-4141;1234")); + + //this seems wrong, or at least useless + assertEquals("NN145", PhoneNumberUtils.toCallerIDMinMatch("1-700-555-41NN")); + + // -- these are all not useful, but not terribly wrong + assertEquals("", PhoneNumberUtils.toCallerIDMinMatch("")); + assertEquals("0032", PhoneNumberUtils.toCallerIDMinMatch("2300")); + assertEquals("0032+", PhoneNumberUtils.toCallerIDMinMatch("+2300")); + assertEquals("#130#", PhoneNumberUtils.toCallerIDMinMatch("*#031#")); + } + + @SmallTest + public void testGetIndexable() throws Exception { + assertEquals("14145550071", PhoneNumberUtils.getStrippedReversed("1-700-555-4141")); + assertEquals("14145550071", PhoneNumberUtils.getStrippedReversed("1-700-555-4141,1234")); + assertEquals("14145550071", PhoneNumberUtils.getStrippedReversed("1-700-555-4141;1234")); + + //this seems wrong, or at least useless + assertEquals("NN145550071", PhoneNumberUtils.getStrippedReversed("1-700-555-41NN")); + + // -- these are all not useful, but not terribly wrong + assertEquals("", PhoneNumberUtils.getStrippedReversed("")); + assertEquals("0032", PhoneNumberUtils.getStrippedReversed("2300")); + assertEquals("0032+", PhoneNumberUtils.getStrippedReversed("+2300")); + assertEquals("#130#*", PhoneNumberUtils.getStrippedReversed("*#031#")); + } + + @SmallTest + public void testNanpFormatting() { + SpannableStringBuilder number = new SpannableStringBuilder(); + number.append("8005551212"); + PhoneNumberUtils.formatNanpNumber(number); + assertEquals("800-555-1212", number.toString()); + + number.clear(); + number.append("800555121"); + PhoneNumberUtils.formatNanpNumber(number); + assertEquals("800-555-121", number.toString()); + + number.clear(); + number.append("555-1212"); + PhoneNumberUtils.formatNanpNumber(number); + assertEquals("555-1212", number.toString()); + + number.clear(); + number.append("800-55512"); + PhoneNumberUtils.formatNanpNumber(number); + assertEquals("800-555-12", number.toString()); + } + + @SmallTest + public void testConvertKeypadLettersToDigits() { + assertEquals("1-800-4664-411", + PhoneNumberUtils.convertKeypadLettersToDigits("1-800-GOOG-411")); + assertEquals("18004664411", + PhoneNumberUtils.convertKeypadLettersToDigits("1800GOOG411")); + assertEquals("1-800-466-4411", + PhoneNumberUtils.convertKeypadLettersToDigits("1-800-466-4411")); + assertEquals("18004664411", + PhoneNumberUtils.convertKeypadLettersToDigits("18004664411")); + assertEquals("222-333-444-555-666-7777-888-9999", + PhoneNumberUtils.convertKeypadLettersToDigits( + "ABC-DEF-GHI-JKL-MNO-PQRS-TUV-WXYZ")); + assertEquals("222-333-444-555-666-7777-888-9999", + PhoneNumberUtils.convertKeypadLettersToDigits( + "abc-def-ghi-jkl-mno-pqrs-tuv-wxyz")); + assertEquals("(800) 222-3334", + PhoneNumberUtils.convertKeypadLettersToDigits("(800) ABC-DEFG")); + } +} diff --git a/tests/CoreTests/com/android/internal/telephony/PhoneNumberWatcherTest.java b/tests/CoreTests/com/android/internal/telephony/PhoneNumberWatcherTest.java new file mode 100644 index 0000000000000000000000000000000000000000..88eaecd5e5caaccbd74159a71dfff8d5630b6b40 --- /dev/null +++ b/tests/CoreTests/com/android/internal/telephony/PhoneNumberWatcherTest.java @@ -0,0 +1,65 @@ +/* + * 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.android.internal.telephony; + +import android.telephony.PhoneNumberFormattingTextWatcher; +import android.test.suitebuilder.annotation.SmallTest; +import android.text.Selection; +import android.text.SpannableStringBuilder; +import android.text.TextWatcher; + +import junit.framework.TestCase; + +public class PhoneNumberWatcherTest extends TestCase { + @SmallTest + public void testHyphenation() throws Exception { + SpannableStringBuilder number = new SpannableStringBuilder(); + TextWatcher tw = new PhoneNumberFormattingTextWatcher(); + number.append("555-1212"); + // Move the cursor to the left edge + Selection.setSelection(number, 0); + tw.beforeTextChanged(number, 0, 0, 1); + // Insert an 8 at the beginning + number.insert(0, "8"); + tw.afterTextChanged(number); + assertEquals("855-512-12", number.toString()); + } + + @SmallTest + public void testHyphenDeletion() throws Exception { + SpannableStringBuilder number = new SpannableStringBuilder(); + TextWatcher tw = new PhoneNumberFormattingTextWatcher(); + number.append("555-1212"); + // Move the cursor to after the hyphen + Selection.setSelection(number, 4); + // Delete the hyphen + tw.beforeTextChanged(number, 3, 1, 0); + number.delete(3, 4); + tw.afterTextChanged(number); + // Make sure that it deleted the character before the hyphen + assertEquals("551-212", number.toString()); + + // Make sure it deals with left edge boundary case + number.insert(0, "-"); + Selection.setSelection(number, 1); + tw.beforeTextChanged(number, 0, 1, 0); + number.delete(0, 1); + tw.afterTextChanged(number); + // Make sure that it deleted the character before the hyphen + assertEquals("551-212", number.toString()); + } +} diff --git a/tests/CoreTests/com/android/internal/telephony/TelephonyTests.java b/tests/CoreTests/com/android/internal/telephony/TelephonyTests.java new file mode 100644 index 0000000000000000000000000000000000000000..eb2bd23ad7b417bfead66303b85c370999418514 --- /dev/null +++ b/tests/CoreTests/com/android/internal/telephony/TelephonyTests.java @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2006 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.android.internal.telephony; + +import com.android.internal.telephony.gsm.AdnRecordTest; +import com.android.internal.telephony.gsm.GSMPhoneTest; +import com.android.internal.telephony.gsm.GsmAlphabetTest; +import com.android.internal.telephony.gsm.SMSDispatcherTest; +import com.android.internal.telephony.gsm.SimPhoneBookTest; +import com.android.internal.telephony.gsm.SimSmsTest; +import com.android.internal.telephony.gsm.SimUtilsTest; + +import junit.framework.TestSuite; + +/** + * To run these tests: + * $ mmm java/tests && adb sync + * $ adb shell am instrument -w \ + * -e class com.android.internal.telephony.TelephonyTests \ + * android.core/android.test.InstrumentationTestRunner + */ +public class TelephonyTests { + public static TestSuite suite() { + TestSuite suite = new TestSuite(TelephonyTests.class.getName()); + + suite.addTestSuite(PhoneNumberWatcherTest.class); + suite.addTestSuite(ATResponseParserTest.class); + suite.addTestSuite(PhoneNumberUtilsTest.class); + suite.addTestSuite(SMSDispatcherTest.class); + //suite.addTestSuite(GSMPhoneTest.class); + suite.addTestSuite(AdnRecordTest.class); + suite.addTestSuite(GsmAlphabetTest.class); + suite.addTestSuite(SimUtilsTest.class); + suite.addTestSuite(SimPhoneBookTest.class); + suite.addTestSuite(SimSmsTest.class); + + return suite; + } +} diff --git a/tests/CoreTests/com/android/internal/telephony/TestPhoneNotifier.java b/tests/CoreTests/com/android/internal/telephony/TestPhoneNotifier.java new file mode 100644 index 0000000000000000000000000000000000000000..427795b0a9add8aba2cf94546cc8bf72b76b0ea1 --- /dev/null +++ b/tests/CoreTests/com/android/internal/telephony/TestPhoneNotifier.java @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2006 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.android.internal.telephony; + +/** + * Stub class used for unit tests + */ + +public class TestPhoneNotifier implements PhoneNotifier { + public TestPhoneNotifier() { + } + + public void notifyPhoneState(Phone sender) { + } + + public void notifyServiceState(Phone sender) { + } + + public void notifyCellLocation(Phone sender) { + } + + public void notifySignalStrength(Phone sender) { + } + + public void notifyMessageWaitingChanged(Phone sender) { + } + + public void notifyCallForwardingChanged(Phone sender) { + } + + public void notifyDataConnection(Phone sender, String reason) { + } + + public void notifyDataConnectionFailed(Phone sender, String reason) { + } + + public void notifyDataActivity(Phone sender) { + } +} diff --git a/tests/CoreTests/com/android/internal/telephony/gsm/AdnRecordTest.java b/tests/CoreTests/com/android/internal/telephony/gsm/AdnRecordTest.java new file mode 100644 index 0000000000000000000000000000000000000000..6cafdf0a8cd7edf5618c4cbe8bc067305e44a257 --- /dev/null +++ b/tests/CoreTests/com/android/internal/telephony/gsm/AdnRecordTest.java @@ -0,0 +1,176 @@ +/* + * Copyright (C) 2006 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.android.internal.telephony.gsm; + +import junit.framework.TestCase; +import android.test.suitebuilder.annotation.SmallTest; + +/** + * {@hide} + */ +public class AdnRecordTest extends TestCase { + + @SmallTest + public void testBasic() throws Exception { + AdnRecord adn; + + // + // Typical record + // + adn = new AdnRecord( + SimUtils.hexStringToBytes("566F696365204D61696C07918150367742F3FFFFFFFFFFFF")); + + assertEquals("Voice Mail", adn.getAlphaTag()); + assertEquals("+18056377243", adn.getNumber()); + assertFalse(adn.isEmpty()); + + // + // Empty records, empty strings + // + adn = new AdnRecord( + SimUtils.hexStringToBytes("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF")); + + assertEquals("", adn.getAlphaTag()); + assertEquals("", adn.getNumber()); + assertTrue(adn.isEmpty()); + + // + // Record too short + // + adn = new AdnRecord(SimUtils.hexStringToBytes( "FF")); + + assertEquals("", adn.getAlphaTag()); + assertEquals("", adn.getNumber()); + assertTrue(adn.isEmpty()); + + // + // TOA = 0xff ("control string") + // + adn = new AdnRecord( + SimUtils.hexStringToBytes("566F696365204D61696C07FF8150367742F3FFFFFFFFFFFF")); + + assertEquals("Voice Mail", adn.getAlphaTag()); + assertEquals("18056377243", adn.getNumber()); + assertFalse(adn.isEmpty()); + + // + // TOA = 0x81 (unknown) + // + adn = new AdnRecord( + SimUtils.hexStringToBytes("566F696365204D61696C07818150367742F3FFFFFFFFFFFF")); + + assertEquals("Voice Mail", adn.getAlphaTag()); + assertEquals("18056377243", adn.getNumber()); + assertFalse(adn.isEmpty()); + + // + // Number Length is too long + // + adn = new AdnRecord( + SimUtils.hexStringToBytes("566F696365204D61696C0F918150367742F3FFFFFFFFFFFF")); + + assertEquals("Voice Mail", adn.getAlphaTag()); + assertEquals("", adn.getNumber()); + assertFalse(adn.isEmpty()); + + // + // Number Length is zero (invalid) + // + adn = new AdnRecord( + SimUtils.hexStringToBytes("566F696365204D61696C00918150367742F3FFFFFFFFFFFF")); + + assertEquals("Voice Mail", adn.getAlphaTag()); + assertEquals("", adn.getNumber()); + assertFalse(adn.isEmpty()); + + // + // Number Length is 2, first number byte is FF, TOA is international + // + adn = new AdnRecord( + SimUtils.hexStringToBytes("566F696365204D61696C0291FF50367742F3FFFFFFFFFFFF")); + + assertEquals("Voice Mail", adn.getAlphaTag()); + assertEquals("", adn.getNumber()); + assertFalse(adn.isEmpty()); + + // + // Number Length is 2, first number digit is valid, TOA is international + // + adn = new AdnRecord( + SimUtils.hexStringToBytes("566F696365204D61696C0291F150367742F3FFFFFFFFFFFF")); + + assertEquals("Voice Mail", adn.getAlphaTag()); + assertEquals("+1", adn.getNumber()); + assertFalse(adn.isEmpty()); + + // + // An extended record + // + adn = new AdnRecord( + SimUtils.hexStringToBytes( + "4164676A6DFFFFFFFFFFFFFFFFFFFFFF0B918188551512C221436587FF01")); + + assertEquals("Adgjm", adn.getAlphaTag()); + assertEquals("+18885551212,12345678", adn.getNumber()); + assertFalse(adn.isEmpty()); + assertTrue(adn.hasExtendedRecord()); + + adn.appendExtRecord(SimUtils.hexStringToBytes("0206092143658709ffffffffff")); + + assertEquals("Adgjm", adn.getAlphaTag()); + assertEquals("+18885551212,12345678901234567890", adn.getNumber()); + assertFalse(adn.isEmpty()); + + // + // An extended record with an invalid extension + // + adn = new AdnRecord( + SimUtils.hexStringToBytes( + "4164676A6DFFFFFFFFFFFFFFFFFFFFFF0B918188551512C221436587FF01")); + + assertEquals("Adgjm", adn.getAlphaTag()); + assertEquals("+18885551212,12345678", adn.getNumber()); + assertFalse(adn.isEmpty()); + assertTrue(adn.hasExtendedRecord()); + + adn.appendExtRecord(SimUtils.hexStringToBytes("0106092143658709ffffffffff")); + + assertEquals("Adgjm", adn.getAlphaTag()); + assertEquals("+18885551212,12345678", adn.getNumber()); + assertFalse(adn.isEmpty()); + + // + // An extended record with an invalid extension + // + adn = new AdnRecord( + SimUtils.hexStringToBytes( + "4164676A6DFFFFFFFFFFFFFFFFFFFFFF0B918188551512C221436587FF01")); + + assertEquals("Adgjm", adn.getAlphaTag()); + assertEquals("+18885551212,12345678", adn.getNumber()); + assertFalse(adn.isEmpty()); + assertTrue(adn.hasExtendedRecord()); + + adn.appendExtRecord(SimUtils.hexStringToBytes("020B092143658709ffffffffff")); + + assertEquals("Adgjm", adn.getAlphaTag()); + assertEquals("+18885551212,12345678", adn.getNumber()); + assertFalse(adn.isEmpty()); + } +} + + diff --git a/tests/CoreTests/com/android/internal/telephony/gsm/GSMPhoneTest.java b/tests/CoreTests/com/android/internal/telephony/gsm/GSMPhoneTest.java new file mode 100644 index 0000000000000000000000000000000000000000..ec9b3ef90d76a076f9ca63f83ddeade5167ccad3 --- /dev/null +++ b/tests/CoreTests/com/android/internal/telephony/gsm/GSMPhoneTest.java @@ -0,0 +1,2024 @@ +/* + * Copyright (C) 2007 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.android.internal.telephony.gsm; + +import android.core.TestHandler; +import android.os.AsyncResult; +import android.os.Message; +import android.telephony.ServiceState; +import android.test.AndroidTestCase; +import android.test.PerformanceTestCase; + +import com.android.internal.telephony.Call; +import com.android.internal.telephony.CallStateException; +import com.android.internal.telephony.Connection; +import com.android.internal.telephony.MmiCode; +import com.android.internal.telephony.Phone; +import com.android.internal.telephony.TestPhoneNotifier; +import com.android.internal.telephony.test.SimulatedCommands; +import com.android.internal.telephony.test.SimulatedRadioControl; + +import java.util.List; + +public class GSMPhoneTest extends AndroidTestCase implements PerformanceTestCase { + private SimulatedRadioControl mRadioControl; + private TestHandler mTestHandler; + private GSMPhone mGSMPhone; + + private static final int EVENT_PHONE_STATE_CHANGED = 1; + private static final int EVENT_DISCONNECT = 2; + private static final int EVENT_RINGING = 3; + private static final int EVENT_CHANNEL_OPENED = 4; + private static final int EVENT_POST_DIAL = 5; + private static final int EVENT_DONE = 6; + private static final int EVENT_SSN = 7; + private static final int EVENT_MMI_INITIATE = 8; + private static final int EVENT_MMI_COMPLETE = 9; + private static final int EVENT_IN_SERVICE = 10; + private static final int SUPP_SERVICE_FAILED = 11; + private static final int SERVICE_STATE_CHANGED = 12; + + private static final int FAIL_TIMEOUT_MILLIS = 5 * 1000; + + @Override + protected void setUp() throws Exception { + super.setUp(); + + mTestHandler = TestHandler.create("GSMPhoneTest TestHandler", + new Runnable() { + public void run() { + SimulatedCommands sc = new SimulatedCommands(); + mRadioControl = sc; + mGSMPhone = new GSMPhone( + mContext, sc, + new TestPhoneNotifier(), + true); + + } + } + ); + + mTestHandler.setFailTimeoutMillis(FAIL_TIMEOUT_MILLIS); + mGSMPhone.registerForPhoneStateChanged(mTestHandler.hh, EVENT_PHONE_STATE_CHANGED, null); + mGSMPhone.registerForNewRingingConnection(mTestHandler.hh, EVENT_RINGING, null); + mGSMPhone.registerForDisconnect(mTestHandler.hh, EVENT_DISCONNECT, null); + + mGSMPhone.setOnPostDialCharacter(mTestHandler.hh, EVENT_POST_DIAL, null); + + mGSMPhone.registerForSuppServiceNotification(mTestHandler.hh, EVENT_SSN, null); + mGSMPhone.registerForMmiInitiate(mTestHandler.hh, EVENT_MMI_INITIATE, null); + mGSMPhone.registerForMmiComplete(mTestHandler.hh, EVENT_MMI_COMPLETE, null); + mGSMPhone.registerForSuppServiceFailed(mTestHandler.hh, SUPP_SERVICE_FAILED, null); + + mGSMPhone.registerForServiceStateChanged(mTestHandler.hh, SERVICE_STATE_CHANGED, null); + + // wait until we get phone in both voice and data service + Message msg; + ServiceState state; + do { + do { + msg = mTestHandler.getNextMessage(); + } while (msg.what != SERVICE_STATE_CHANGED); + state = (ServiceState) ((AsyncResult) msg.obj).result; + } while (state.getState() != ServiceState.STATE_IN_SERVICE); + + } + + @Override + protected void tearDown() throws Exception { + mGSMPhone.unregisterForPhoneStateChanged(mTestHandler.hh); + mGSMPhone.unregisterForNewRingingConnection(mTestHandler.hh); + mGSMPhone.unregisterForDisconnect(mTestHandler.hh); + mGSMPhone.setOnPostDialCharacter(null, 0, null); + mGSMPhone.unregisterForSuppServiceNotification(mTestHandler.hh); + mGSMPhone.unregisterForMmiInitiate(mTestHandler.hh); + mGSMPhone.unregisterForMmiComplete(mTestHandler.hh); + + mRadioControl.shutdown(); + + mTestHandler.hh.sendMessage(mTestHandler.hh.obtainMessage(EVENT_DONE)); + + Message msg; + + do { + msg = mTestHandler.getNextMessage(); + } while (msg.what != EVENT_DONE); + + mTestHandler.looper.quit(); + + mGSMPhone = null; + mRadioControl = null; + mTestHandler = null; + + super.tearDown(); + } + + // These test can only be run once. + public int startPerformance(Intermediates intermediates) { + return 1; + } + + public boolean isPerformanceOnly() { + return false; + } + + + //This test is causing the emulator screen to turn off. I don't understand + //why, but I'm removing it until we can figure it out. + public void brokenTestGeneral() throws Exception { + Connection cn; + Message msg; + AsyncResult ar; + + // IDLE state + + assertEquals(Phone.State.IDLE, mGSMPhone.getState()); + assertEquals(0, mGSMPhone.getRingingCall().getConnections().size()); + assertEquals(0, mGSMPhone.getForegroundCall().getConnections().size()); + assertEquals(0, mGSMPhone.getBackgroundCall().getConnections().size()); + + assertEquals(Call.State.IDLE, mGSMPhone.getRingingCall().getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); + + assertEquals(0, mGSMPhone.getForegroundCall().getEarliestCreateTime()); + assertEquals(0, mGSMPhone.getForegroundCall().getEarliestConnectTime()); + assertFalse(mGSMPhone.canConference()); + + // One DIALING connection + + mRadioControl.setAutoProgressConnectingCall(false); + + mGSMPhone.dial("+13125551212"); + + assertEquals(Phone.State.OFFHOOK, mGSMPhone.getState()); + + do { + msg = mTestHandler.getNextMessage(); + } while (msg.what != EVENT_PHONE_STATE_CHANGED); + + assertEquals(Phone.State.OFFHOOK, mGSMPhone.getState()); + assertEquals(Call.State.DIALING, mGSMPhone.getForegroundCall().getState()); + assertTrue(mGSMPhone.getForegroundCall().isDialingOrAlerting()); + + /* + do { + th.getNextMessage(); + } while (phone.getForegroundCall().getConnections().size() == 0); + */ + + assertEquals(0, mGSMPhone.getRingingCall().getConnections().size()); + assertEquals(1, mGSMPhone.getForegroundCall().getConnections().size()); + assertEquals(0, mGSMPhone.getBackgroundCall().getConnections().size()); + + assertEquals(Call.State.IDLE, mGSMPhone.getRingingCall().getState()); + assertEquals(Call.State.DIALING, + mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); + + assertTrue(mGSMPhone.getForegroundCall().getEarliestCreateTime() > 0); + assertEquals(0, mGSMPhone.getForegroundCall().getEarliestConnectTime()); + + cn = mGSMPhone.getForegroundCall().getConnections().get(0); + assertTrue(!cn.isIncoming()); + assertEquals(Connection.PostDialState.NOT_STARTED, cn.getPostDialState()); + + assertEquals(Connection.DisconnectCause.NOT_DISCONNECTED, cn.getDisconnectCause()); + + assertFalse(mGSMPhone.canConference()); + + // One ALERTING connection + + mRadioControl.progressConnectingCallState(); + + do { + mTestHandler.getNextMessage(); + } + while (mGSMPhone.getForegroundCall().getState() != Call.State.ALERTING); + + assertEquals(Phone.State.OFFHOOK, mGSMPhone.getState()); + assertTrue(mGSMPhone.getForegroundCall().isDialingOrAlerting()); + + assertEquals(0, mGSMPhone.getRingingCall().getConnections().size()); + assertEquals(1, mGSMPhone.getForegroundCall().getConnections().size()); + assertEquals(0, mGSMPhone.getBackgroundCall().getConnections().size()); + + assertEquals(Call.State.IDLE, mGSMPhone.getRingingCall().getState()); + assertEquals(Call.State.ALERTING, mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); + + assertTrue(mGSMPhone.getForegroundCall().getEarliestCreateTime() > 0); + assertEquals(0, mGSMPhone.getForegroundCall().getEarliestConnectTime()); + + cn = mGSMPhone.getForegroundCall().getConnections().get(0); + assertTrue(!cn.isIncoming()); + assertEquals(Connection.PostDialState.NOT_STARTED, cn.getPostDialState()); + assertFalse(mGSMPhone.canConference()); + + // One ACTIVE connection + + mRadioControl.progressConnectingCallState(); + + do { + mTestHandler.getNextMessage(); + } while (mGSMPhone.getForegroundCall().getState() != Call.State.ACTIVE); + + assertEquals(Phone.State.OFFHOOK, mGSMPhone.getState()); + assertFalse(mGSMPhone.getForegroundCall().isDialingOrAlerting()); + + assertEquals(0, mGSMPhone.getRingingCall().getConnections().size()); + assertEquals(1, mGSMPhone.getForegroundCall().getConnections().size()); + assertEquals(0, mGSMPhone.getBackgroundCall().getConnections().size()); + + assertEquals(Call.State.IDLE, mGSMPhone.getRingingCall().getState()); + assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); + + assertTrue(mGSMPhone.getForegroundCall().getEarliestCreateTime() > 0); + assertTrue(mGSMPhone.getForegroundCall().getEarliestConnectTime() > 0); + + cn = mGSMPhone.getForegroundCall().getConnections().get(0); + assertTrue(!cn.isIncoming()); + assertEquals(Connection.PostDialState.COMPLETE, cn.getPostDialState()); + assertFalse(mGSMPhone.canConference()); + + // One disconnected connection + mGSMPhone.getForegroundCall().hangup(); + + do { + msg = mTestHandler.getNextMessage(); + } while (msg.what != EVENT_DISCONNECT); + + assertEquals(Phone.State.IDLE, mGSMPhone.getState()); + assertFalse(mGSMPhone.getForegroundCall().isDialingOrAlerting()); + + assertEquals(0, mGSMPhone.getRingingCall().getConnections().size()); + assertEquals(1, mGSMPhone.getForegroundCall().getConnections().size()); + assertEquals(0, mGSMPhone.getBackgroundCall().getConnections().size()); + + assertEquals(Call.State.IDLE, mGSMPhone.getRingingCall().getState()); + assertEquals(Call.State.DISCONNECTED, mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); + + assertTrue(mGSMPhone.getForegroundCall().getEarliestCreateTime() > 0); + assertTrue(mGSMPhone.getForegroundCall().getEarliestConnectTime() > 0); + + assertFalse(mGSMPhone.canConference()); + + cn = mGSMPhone.getForegroundCall().getEarliestConnection(); + + assertEquals(Call.State.DISCONNECTED, cn.getState()); + + // Back to idle state + + mGSMPhone.clearDisconnected(); + + assertEquals(Phone.State.IDLE, mGSMPhone.getState()); + assertFalse(mGSMPhone.getForegroundCall().isDialingOrAlerting()); + + assertEquals(0, mGSMPhone.getRingingCall().getConnections().size()); + assertEquals(0, mGSMPhone.getForegroundCall().getConnections().size()); + assertEquals(0, mGSMPhone.getBackgroundCall().getConnections().size()); + + assertEquals(Call.State.IDLE, mGSMPhone.getRingingCall().getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); + + assertEquals(0, mGSMPhone.getForegroundCall().getEarliestCreateTime()); + assertEquals(0, mGSMPhone.getForegroundCall().getEarliestConnectTime()); + + assertFalse(mGSMPhone.canConference()); + + // cn left over from before phone.clearDisconnected(); + + assertEquals(Call.State.DISCONNECTED, cn.getState()); + + // One ringing (INCOMING) call + + mRadioControl.triggerRing("18005551212"); + + do { + msg = mTestHandler.getNextMessage(); + } while (msg.what != EVENT_RINGING); + + assertEquals(Phone.State.RINGING, mGSMPhone.getState()); + assertTrue(mGSMPhone.getRingingCall().isRinging()); + + ar = (AsyncResult) msg.obj; + cn = (Connection) ar.result; + assertTrue(cn.isRinging()); + assertEquals(mGSMPhone.getRingingCall(), cn.getCall()); + + assertEquals(1, mGSMPhone.getRingingCall().getConnections().size()); + assertEquals(0, mGSMPhone.getForegroundCall().getConnections().size()); + assertEquals(0, mGSMPhone.getBackgroundCall().getConnections().size()); + + assertEquals(Call.State.INCOMING, mGSMPhone.getRingingCall().getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); + + assertTrue(mGSMPhone.getRingingCall().getEarliestCreateTime() > 0); + assertEquals(0, mGSMPhone.getRingingCall().getEarliestConnectTime()); + + assertEquals(0, mGSMPhone.getForegroundCall().getEarliestCreateTime()); + assertEquals(0, mGSMPhone.getForegroundCall().getEarliestConnectTime()); + + cn = mGSMPhone.getRingingCall().getConnections().get(0); + assertTrue(cn.isIncoming()); + assertEquals(Connection.PostDialState.NOT_STARTED, cn.getPostDialState()); + + assertFalse(mGSMPhone.canConference()); + + // One mobile terminated active call + mGSMPhone.acceptCall(); + + do { + mTestHandler.getNextMessage(); + } while (mGSMPhone.getRingingCall().getConnections().size() == 1); + + assertEquals(Phone.State.OFFHOOK, mGSMPhone.getState()); + assertFalse(mGSMPhone.getRingingCall().isRinging()); + + assertEquals(0, mGSMPhone.getRingingCall().getConnections().size()); + assertEquals(1, mGSMPhone.getForegroundCall().getConnections().size()); + assertEquals(0, mGSMPhone.getBackgroundCall().getConnections().size()); + + assertEquals(Call.State.IDLE, mGSMPhone.getRingingCall().getState()); + assertEquals(Call.State.ACTIVE, + mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); + + assertTrue(mGSMPhone.getForegroundCall().getEarliestCreateTime() > 0); + assertTrue(mGSMPhone.getForegroundCall().getEarliestConnectTime() > 0); + + cn = mGSMPhone.getForegroundCall().getConnections().get(0); + assertTrue(cn.isIncoming()); + assertEquals(Connection.PostDialState.NOT_STARTED, cn.getPostDialState()); + + assertFalse(mGSMPhone.canConference()); + + // One disconnected (local hangup) call + + try { + Connection conn; + conn = mGSMPhone.getForegroundCall().getConnections().get(0); + conn.hangup(); + } catch (CallStateException ex) { + ex.printStackTrace(); + fail("unexpected ex"); + } + + do { + msg = mTestHandler.getNextMessage(); + } while (msg.what != EVENT_DISCONNECT); + + + assertEquals(Phone.State.IDLE, mGSMPhone.getState()); + assertFalse(mGSMPhone.getForegroundCall().isDialingOrAlerting()); + assertFalse(mGSMPhone.getRingingCall().isRinging()); + + assertEquals(0, mGSMPhone.getRingingCall().getConnections().size()); + assertEquals(1, mGSMPhone.getForegroundCall().getConnections().size()); + assertEquals(0, mGSMPhone.getBackgroundCall().getConnections().size()); + + assertEquals(Call.State.IDLE, mGSMPhone.getRingingCall().getState()); + assertEquals(Call.State.DISCONNECTED, + mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); + + assertTrue(mGSMPhone.getForegroundCall().getEarliestCreateTime() > 0); + assertTrue(mGSMPhone.getForegroundCall().getEarliestConnectTime() > 0); + + cn = mGSMPhone.getForegroundCall().getEarliestConnection(); + + assertEquals(Call.State.DISCONNECTED, cn.getState()); + + assertEquals(Connection.DisconnectCause.LOCAL, cn.getDisconnectCause()); + + assertFalse(mGSMPhone.canConference()); + + // Back to idle state + + mGSMPhone.clearDisconnected(); + + assertFalse(mGSMPhone.getForegroundCall().isDialingOrAlerting()); + assertFalse(mGSMPhone.getRingingCall().isRinging()); + + assertEquals(Connection.DisconnectCause.LOCAL, cn.getDisconnectCause()); + assertEquals(0, mGSMPhone.getForegroundCall().getConnections().size()); + assertEquals(Phone.State.IDLE, mGSMPhone.getState()); + + assertEquals(0, mGSMPhone.getRingingCall().getConnections().size()); + assertEquals(0, mGSMPhone.getForegroundCall().getConnections().size()); + assertEquals(0, mGSMPhone.getBackgroundCall().getConnections().size()); + + assertEquals(Call.State.IDLE, mGSMPhone.getRingingCall().getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); + + assertEquals(0, mGSMPhone.getForegroundCall().getEarliestCreateTime()); + assertEquals(0, mGSMPhone.getForegroundCall().getEarliestConnectTime()); + + assertFalse(mGSMPhone.canConference()); + + // cn left over from before phone.clearDisconnected(); + + assertEquals(Call.State.DISCONNECTED, cn.getState()); + + // One ringing call + + mRadioControl.triggerRing("18005551212"); + + do { + mTestHandler.getNextMessage(); + } while (mGSMPhone.getRingingCall().getConnections().isEmpty()); + + assertEquals(Phone.State.RINGING, mGSMPhone.getState()); + assertFalse(mGSMPhone.getForegroundCall().isDialingOrAlerting()); + assertTrue(mGSMPhone.getRingingCall().isRinging()); + + assertEquals(1, mGSMPhone.getRingingCall().getConnections().size()); + assertEquals(0, mGSMPhone.getForegroundCall().getConnections().size()); + assertEquals(0, mGSMPhone.getBackgroundCall().getConnections().size()); + + assertEquals(Call.State.INCOMING, mGSMPhone.getRingingCall().getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); + + assertTrue(mGSMPhone.getRingingCall().getEarliestCreateTime() > 0); + assertEquals(0, mGSMPhone.getRingingCall().getEarliestConnectTime()); + + assertEquals(0, mGSMPhone.getForegroundCall().getEarliestCreateTime()); + assertEquals(0, mGSMPhone.getForegroundCall().getEarliestConnectTime()); + + assertFalse(mGSMPhone.canConference()); + + // One rejected call + mGSMPhone.rejectCall(); + + do { + mTestHandler.getNextMessage(); + } while (mGSMPhone.getState() != Phone.State.IDLE); + + assertFalse(mGSMPhone.getForegroundCall().isDialingOrAlerting()); + assertFalse(mGSMPhone.getRingingCall().isRinging()); + + assertEquals(1, mGSMPhone.getRingingCall().getConnections().size()); + assertEquals(0, mGSMPhone.getForegroundCall().getConnections().size()); + assertEquals(0, mGSMPhone.getBackgroundCall().getConnections().size()); + + assertEquals(Call.State.DISCONNECTED, mGSMPhone.getRingingCall().getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); + + assertTrue(mGSMPhone.getRingingCall().getEarliestCreateTime() > 0); + assertEquals(0, mGSMPhone.getRingingCall().getEarliestConnectTime()); + + assertEquals(0, mGSMPhone.getForegroundCall().getEarliestCreateTime()); + assertEquals(0, mGSMPhone.getForegroundCall().getEarliestConnectTime()); + + cn = mGSMPhone.getRingingCall().getEarliestConnection(); + assertEquals(Call.State.DISCONNECTED, cn.getState()); + + assertEquals(Connection.DisconnectCause.INCOMING_MISSED, cn.getDisconnectCause()); + + assertFalse(mGSMPhone.canConference()); + + // Back to idle state + + mGSMPhone.clearDisconnected(); + + assertEquals(Connection.DisconnectCause.INCOMING_MISSED, cn.getDisconnectCause()); + assertEquals(0, mGSMPhone.getForegroundCall().getConnections().size()); + assertEquals(Phone.State.IDLE, mGSMPhone.getState()); + + assertEquals(0, mGSMPhone.getRingingCall().getConnections().size()); + assertEquals(0, mGSMPhone.getForegroundCall().getConnections().size()); + assertEquals(0, mGSMPhone.getBackgroundCall().getConnections().size()); + + assertEquals(Call.State.IDLE, mGSMPhone.getRingingCall().getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); + + assertEquals(0, mGSMPhone.getForegroundCall().getEarliestCreateTime()); + assertEquals(0, mGSMPhone.getForegroundCall().getEarliestConnectTime()); + + assertFalse(mGSMPhone.canConference()); + assertEquals(Call.State.DISCONNECTED, cn.getState()); + + // One ringing call + + mRadioControl.triggerRing("18005551212"); + + do { + mTestHandler.getNextMessage(); + } while (mGSMPhone.getRingingCall().getConnections().isEmpty()); + + assertEquals(Phone.State.RINGING, mGSMPhone.getState()); + assertFalse(mGSMPhone.getForegroundCall().isDialingOrAlerting()); + assertTrue(mGSMPhone.getRingingCall().isRinging()); + + cn = mGSMPhone.getRingingCall().getEarliestConnection(); + + // Ringing call disconnects + + mRadioControl.triggerHangupForeground(); + + do { + mTestHandler.getNextMessage(); + } while (mGSMPhone.getState() != Phone.State.IDLE); + + assertEquals(Connection.DisconnectCause.INCOMING_MISSED, cn.getDisconnectCause()); + + // One Ringing Call + + mRadioControl.triggerRing("18005551212"); + + do { + mTestHandler.getNextMessage(); + } while (mGSMPhone.getState() != Phone.State.RINGING); + + + cn = mGSMPhone.getRingingCall().getEarliestConnection(); + + // One answered call + mGSMPhone.acceptCall(); + + do { + mTestHandler.getNextMessage(); + } while (mGSMPhone.getState() != Phone.State.OFFHOOK); + + assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); + + // one holding call + mGSMPhone.switchHoldingAndActive(); + + do { + mTestHandler.getNextMessage(); + } while (mGSMPhone.getBackgroundCall().getState() == Call.State.IDLE); + + + assertEquals(Call.State.IDLE, mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.HOLDING, mGSMPhone.getBackgroundCall().getState()); + + // one active call + mGSMPhone.switchHoldingAndActive(); + + do { + mTestHandler.getNextMessage(); + } + while (mGSMPhone.getBackgroundCall().getState() == Call.State.HOLDING); + + assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); + + // One disconnected call in the foreground slot + + mRadioControl.triggerHangupAll(); + + do { + mTestHandler.getNextMessage(); + } while (mGSMPhone.getState() != Phone.State.IDLE); + + assertEquals(Call.State.DISCONNECTED, mGSMPhone.getForegroundCall().getState()); + assertEquals(Connection.DisconnectCause.NORMAL, cn.getDisconnectCause()); + + // Test missed calls + + mRadioControl.triggerRing("18005551212"); + + do { + mTestHandler.getNextMessage(); + } while (mGSMPhone.getState() != Phone.State.RINGING); + + mGSMPhone.rejectCall(); + + do { + msg = mTestHandler.getNextMessage(); + } while (msg.what != EVENT_DISCONNECT); + + ar = (AsyncResult) msg.obj; + cn = (Connection) ar.result; + + assertEquals(Connection.DisconnectCause.INCOMING_MISSED, cn.getDisconnectCause()); + assertEquals(Phone.State.IDLE, mGSMPhone.getState()); + assertEquals(Call.State.DISCONNECTED, mGSMPhone.getRingingCall().getState()); + + // Test incoming not missed calls + + mRadioControl.triggerRing("18005551212"); + + do { + mTestHandler.getNextMessage(); + } while (mGSMPhone.getState() != Phone.State.RINGING); + + cn = mGSMPhone.getRingingCall().getEarliestConnection(); + + mGSMPhone.acceptCall(); + + do { + mTestHandler.getNextMessage(); + } while (mGSMPhone.getState() != Phone.State.OFFHOOK); + + assertEquals(Connection.DisconnectCause.NOT_DISCONNECTED, cn.getDisconnectCause()); + assertEquals(Call.State.IDLE, mGSMPhone.getRingingCall().getState()); + assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); + + try { + mGSMPhone.getForegroundCall().hangup(); + } catch (CallStateException ex) { + ex.printStackTrace(); + fail("unexpected ex"); + } + + do { + mTestHandler.getNextMessage(); + } while (mGSMPhone.getForegroundCall().getState() + != Call.State.DISCONNECTED); + + assertEquals(Connection.DisconnectCause.LOCAL, cn.getDisconnectCause()); + + // + // Test held and hangup held calls + // + + // One ALERTING call + mGSMPhone.dial("+13125551212"); + + do { + mTestHandler.getNextMessage(); + } while (mGSMPhone.getState() != Phone.State.OFFHOOK); + + assertTrue(mGSMPhone.getForegroundCall().isDialingOrAlerting()); + + mRadioControl.progressConnectingCallState(); + mRadioControl.progressConnectingCallState(); + + // One ACTIVE call + + do { + mTestHandler.getNextMessage(); + } while (mGSMPhone.getForegroundCall().getState() != Call.State.ACTIVE); + + assertFalse(mGSMPhone.getForegroundCall().isDialingOrAlerting()); + + // One ACTIVE call, one ringing call + + mRadioControl.triggerRing("18005551212"); + + do { + mTestHandler.getNextMessage(); + } while (mGSMPhone.getState() != Phone.State.RINGING); + + assertFalse(mGSMPhone.getForegroundCall().isDialingOrAlerting()); + assertTrue(mGSMPhone.getRingingCall().isRinging()); + + // One HOLDING call, one ACTIVE call + mGSMPhone.acceptCall(); + + do { + mTestHandler.getNextMessage(); + } while (mGSMPhone.getState() != Phone.State.OFFHOOK); + + assertFalse(mGSMPhone.getForegroundCall().isDialingOrAlerting()); + + assertEquals(Call.State.IDLE, mGSMPhone.getRingingCall().getState()); + assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.HOLDING, mGSMPhone.getBackgroundCall().getState()); + assertTrue(mGSMPhone.canConference()); + + // Conference the two + mGSMPhone.conference(); + + do { + mTestHandler.getNextMessage(); + } while (mGSMPhone.getBackgroundCall().getState() != Call.State.IDLE); + + assertFalse(mGSMPhone.getForegroundCall().isDialingOrAlerting()); + + assertEquals(Call.State.IDLE, mGSMPhone.getRingingCall().getState()); + assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); + assertTrue(mGSMPhone.getForegroundCall().isMultiparty()); + assertFalse(mGSMPhone.canConference()); + + // Hold the multiparty call + mGSMPhone.switchHoldingAndActive(); + + do { + mTestHandler.getNextMessage(); + } + while (mGSMPhone.getBackgroundCall().getState() != Call.State.HOLDING); + + assertEquals(Call.State.IDLE, mGSMPhone.getRingingCall().getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getForegroundCall().getState()); + assertTrue(mGSMPhone.getBackgroundCall().isMultiparty()); + assertFalse(mGSMPhone.canConference()); + + // Multiparty call on hold, call waiting added + + mRadioControl.triggerRing("18005558355"); + + do { + mTestHandler.getNextMessage(); + } while (mGSMPhone.getState() != Phone.State.RINGING); + + assertFalse(mGSMPhone.getForegroundCall().isDialingOrAlerting()); + assertTrue(mGSMPhone.getRingingCall().isRinging()); + + assertEquals(Call.State.IDLE, mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.HOLDING, mGSMPhone.getBackgroundCall().getState()); + assertTrue(mGSMPhone.getBackgroundCall().isMultiparty()); + assertEquals(Call.State.WAITING, mGSMPhone.getRingingCall().getState()); + assertFalse(mGSMPhone.canConference()); + + // Hangup conference call, ringing call still around + mGSMPhone.getBackgroundCall().hangup(); + + do { + mTestHandler.getNextMessage(); + } while (mGSMPhone.getBackgroundCall().getState() != Call.State.DISCONNECTED); + + assertEquals(Phone.State.RINGING, mGSMPhone.getState()); + assertEquals(Call.State.DISCONNECTED, mGSMPhone.getBackgroundCall().getState()); + + assertFalse(mGSMPhone.getForegroundCall().isDialingOrAlerting()); + assertTrue(mGSMPhone.getRingingCall().isRinging()); + + // Reject waiting call + mGSMPhone.rejectCall(); + + do { + mTestHandler.getNextMessage(); + } while (mGSMPhone.getState() != Phone.State.IDLE); + + assertFalse(mGSMPhone.getForegroundCall().isDialingOrAlerting()); + assertFalse(mGSMPhone.getRingingCall().isRinging()); + } + + public void testOutgoingCallFailImmediately() throws Exception { + Message msg; + + // Test outgoing call fail-immediately edge case + // This happens when a call terminated before ever appearing in a + // call list + // This should land the immediately-failing call in the + // ForegroundCall list as an IDLE call + mRadioControl.setNextDialFailImmediately(true); + + Connection cn = mGSMPhone.dial("+13125551212"); + + do { + msg = mTestHandler.getNextMessage(); + } while (msg.what != EVENT_DISCONNECT); + + assertEquals(Phone.State.IDLE, mGSMPhone.getState()); + + assertEquals(Connection.DisconnectCause.NORMAL, cn.getDisconnectCause()); + + assertEquals(0, mGSMPhone.getRingingCall().getConnections().size()); + assertEquals(1, mGSMPhone.getForegroundCall().getConnections().size()); + assertEquals(0, mGSMPhone.getBackgroundCall().getConnections().size()); + + assertEquals(Call.State.IDLE, mGSMPhone.getRingingCall().getState()); + assertEquals(Call.State.DISCONNECTED, mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); + + assertTrue(mGSMPhone.getForegroundCall().getEarliestCreateTime() > 0); + assertEquals(0, mGSMPhone.getForegroundCall().getEarliestConnectTime()); + } + + public void testHangupOnOutgoing() throws Exception { + Connection cn; + Message msg; + + mRadioControl.setAutoProgressConnectingCall(false); + + // Test 1: local hangup in "DIALING" state + mGSMPhone.dial("+13125551212"); + + do { + mTestHandler.getNextMessage(); + } + while (mGSMPhone.getForegroundCall().getState() != Call.State.DIALING); + + cn = mGSMPhone.getForegroundCall().getEarliestConnection(); + + mGSMPhone.getForegroundCall().hangup(); + + do { + msg = mTestHandler.getNextMessage(); + } while (msg.what != EVENT_DISCONNECT); + + assertEquals(Phone.State.IDLE, mGSMPhone.getState()); + + assertEquals(Call.State.DISCONNECTED, mGSMPhone.getForegroundCall().getState()); + assertEquals(Connection.DisconnectCause.LOCAL, cn.getDisconnectCause()); + + // Test 2: local hangup in "ALERTING" state + mGSMPhone.dial("+13125551212"); + + do { + mTestHandler.getNextMessage(); + } while (mGSMPhone.getState() != Phone.State.OFFHOOK); + + mRadioControl.progressConnectingCallState(); + + do { + mTestHandler.getNextMessage(); + } + while (mGSMPhone.getForegroundCall().getState() != Call.State.ALERTING); + + cn = mGSMPhone.getForegroundCall().getEarliestConnection(); + + mGSMPhone.getForegroundCall().hangup(); + + do { + msg = mTestHandler.getNextMessage(); + } while (msg.what != EVENT_DISCONNECT); + + assertEquals(Phone.State.IDLE, mGSMPhone.getState()); + + assertEquals(Call.State.DISCONNECTED, mGSMPhone.getForegroundCall().getState()); + assertEquals(Connection.DisconnectCause.LOCAL, cn.getDisconnectCause()); + + // Test 3: local immediate hangup before GSM index is + // assigned (CallTracker.hangupPendingMO case) + + mRadioControl.pauseResponses(); + + cn = mGSMPhone.dial("+13125551212"); + + cn.hangup(); + + mRadioControl.resumeResponses(); + + do { + msg = mTestHandler.getNextMessage(); + } while (msg.what != EVENT_DISCONNECT); + + assertEquals(Phone.State.IDLE, mGSMPhone.getState()); + + assertEquals(Call.State.DISCONNECTED, mGSMPhone.getForegroundCall().getState()); + + assertEquals(Connection.DisconnectCause.LOCAL, + mGSMPhone.getForegroundCall().getEarliestConnection().getDisconnectCause()); + } + + public void testHangupOnChannelClose() throws Exception { + mGSMPhone.dial("+13125551212"); + + do { + mTestHandler.getNextMessage(); + } while (mGSMPhone.getForegroundCall().getConnections().isEmpty()); + + mRadioControl.shutdown(); + + do { + mTestHandler.getNextMessage(); + mGSMPhone.clearDisconnected(); + } while (!mGSMPhone.getForegroundCall().getConnections().isEmpty()); + } + + public void testIncallMmiCallDeflection() throws Exception { + Message msg; + + // establish an active call + mGSMPhone.dial("+13125551212"); + + do { + mRadioControl.progressConnectingCallState(); + mTestHandler.getNextMessage(); + } while (mGSMPhone.getForegroundCall().getState() != Call.State.ACTIVE); + + assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); + + // establish a ringing (WAITING) call + + mRadioControl.triggerRing("18005551212"); + + do { + msg = mTestHandler.getNextMessage(); + } while (msg.what != EVENT_RINGING); + + assertEquals(Phone.State.RINGING, mGSMPhone.getState()); + assertTrue(mGSMPhone.getRingingCall().isRinging()); + assertEquals(Call.State.WAITING, mGSMPhone.getRingingCall().getState()); + assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); + + // Simulate entering 0 followed by SEND: release all held calls + // or sets UDUB for a waiting call. + mGSMPhone.handleInCallMmiCommands("0"); + + do { + mTestHandler.getNextMessage(); + } while (mGSMPhone.getRingingCall().getState() == Call.State.WAITING); + + assertEquals(Phone.State.OFFHOOK, mGSMPhone.getState()); + assertFalse(mGSMPhone.getRingingCall().isRinging()); + assertEquals(Call.State.DISCONNECTED, mGSMPhone.getRingingCall().getState()); + assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); + + // change the active call to holding call + mGSMPhone.switchHoldingAndActive(); + + do { + mTestHandler.getNextMessage(); + } while (mGSMPhone.getBackgroundCall().getState() == Call.State.IDLE); + + + assertEquals(Call.State.IDLE, mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.HOLDING, mGSMPhone.getBackgroundCall().getState()); + + // Simulate entering 0 followed by SEND: release all held calls + // or sets UDUB for a waiting call. + mGSMPhone.handleInCallMmiCommands("0"); + + do { + mTestHandler.getNextMessage(); + } while (mGSMPhone.getBackgroundCall().getState() == Call.State.HOLDING); + + assertEquals(Phone.State.IDLE, mGSMPhone.getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.DISCONNECTED, mGSMPhone.getBackgroundCall().getState()); + } + + public void testIncallMmiCallWaiting() throws Exception { + Message msg; + + // establish an active call + mGSMPhone.dial("+13125551212"); + + do { + mRadioControl.progressConnectingCallState(); + mTestHandler.getNextMessage(); + } while (mGSMPhone.getForegroundCall().getState() != Call.State.ACTIVE); + + assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); + + // establish a ringing (WAITING) call + + mRadioControl.triggerRing("18005551212"); + + do { + msg = mTestHandler.getNextMessage(); + } while (msg.what != EVENT_RINGING); + + assertEquals(Phone.State.RINGING, mGSMPhone.getState()); + assertTrue(mGSMPhone.getRingingCall().isRinging()); + assertEquals(Call.State.WAITING, mGSMPhone.getRingingCall().getState()); + assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); + + // Simulate entering 1 followed by SEND: release all active calls + // (if any exist) and accepts the other (held or waiting) call. + + mGSMPhone.handleInCallMmiCommands("1"); + + do { + mTestHandler.getNextMessage(); + } while (mGSMPhone.getRingingCall().getState() == Call.State.WAITING); + + assertEquals(Phone.State.OFFHOOK, mGSMPhone.getState()); + assertFalse(mGSMPhone.getRingingCall().isRinging()); + assertEquals(Call.State.IDLE, mGSMPhone.getRingingCall().getState()); + assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); + assertEquals("18005551212", + mGSMPhone.getForegroundCall().getConnections().get(0).getAddress()); + + // change the active call to holding call + mGSMPhone.switchHoldingAndActive(); + + do { + mTestHandler.getNextMessage(); + } while (mGSMPhone.getBackgroundCall().getState() == Call.State.IDLE); + + assertEquals(Call.State.IDLE, mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.HOLDING, mGSMPhone.getBackgroundCall().getState()); + + // Simulate entering 1 followed by SEND: release all active calls + // (if any exist) and accepts the other (held or waiting) call. + mGSMPhone.handleInCallMmiCommands("1"); + + do { + mTestHandler.getNextMessage(); + } while (mGSMPhone.getBackgroundCall().getState() != Call.State.IDLE); + + assertEquals(Phone.State.OFFHOOK, mGSMPhone.getState()); + assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); + assertEquals("18005551212", + mGSMPhone.getForegroundCall().getConnections().get(0).getAddress()); + + // at this point, the active call with number==18005551212 should + // have the gsm index of 2 + + mRadioControl.triggerRing("16505550100"); + + do { + msg = mTestHandler.getNextMessage(); + } while (msg.what != EVENT_RINGING); + + assertEquals(Phone.State.RINGING, mGSMPhone.getState()); + assertTrue(mGSMPhone.getRingingCall().isRinging()); + assertEquals(Call.State.WAITING, mGSMPhone.getRingingCall().getState()); + assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); + + // Simulate entering "12" followed by SEND: release the call with + // gsm index equals to 2. + mGSMPhone.handleInCallMmiCommands("12"); + + do { + mTestHandler.getNextMessage(); + } while (mGSMPhone.getForegroundCall().getState() == Call.State.ACTIVE); + + assertEquals(Phone.State.RINGING, mGSMPhone.getState()); + assertTrue(mGSMPhone.getRingingCall().isRinging()); + assertEquals(Call.State.WAITING, mGSMPhone.getRingingCall().getState()); + assertEquals(Call.State.DISCONNECTED, mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); + + mGSMPhone.acceptCall(); + + do { + mTestHandler.getNextMessage(); + } while (mGSMPhone.getState() != Phone.State.OFFHOOK); + + assertEquals(Phone.State.OFFHOOK, mGSMPhone.getState()); + assertFalse(mGSMPhone.getRingingCall().isRinging()); + assertEquals(Call.State.IDLE, mGSMPhone.getRingingCall().getState()); + assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); + + // at this point, the call with number==16505550100 should + // have the gsm index of 1 + mGSMPhone.dial("+13125551212"); + + do { + mRadioControl.progressConnectingCallState(); + mTestHandler.getNextMessage(); + } while (mGSMPhone.getForegroundCall().getState() != Call.State.ACTIVE || + mGSMPhone.getBackgroundCall().getState() != Call.State.HOLDING); + + assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.HOLDING, mGSMPhone.getBackgroundCall().getState()); + + // at this point, the active call with number==13125551212 should + // have the gsm index of 2 + + // Simulate entering "11" followed by SEND: release the call with + // gsm index equals to 1. This should not be allowed, and a + // Supplementary Service notification must be received. + mGSMPhone.handleInCallMmiCommands("11"); + do { + msg = mTestHandler.getNextMessage(); + } while (msg != null && msg.what != SUPP_SERVICE_FAILED); + assertFalse("IncallMmiCallWaiting: command should not work on holding call", msg == null); + + // Simulate entering "12" followed by SEND: release the call with + // gsm index equals to 2. + mGSMPhone.handleInCallMmiCommands("12"); + + do { + mTestHandler.getNextMessage(); + } while (mGSMPhone.getForegroundCall().getState() == Call.State.ACTIVE); + + assertEquals(Call.State.DISCONNECTED, mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.HOLDING, mGSMPhone.getBackgroundCall().getState()); + + // Simulate entering 1 followed by SEND: release all active calls + // (if any exist) and accepts the other (held or waiting) call. + mGSMPhone.handleInCallMmiCommands("1"); + + do { + mTestHandler.getNextMessage(); + } while (mGSMPhone.getBackgroundCall().getState() != Call.State.IDLE); + + assertEquals(Phone.State.OFFHOOK, mGSMPhone.getState()); + assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); + assertEquals("16505550100", + mGSMPhone.getForegroundCall().getConnections().get(0).getAddress()); + + // Simulate entering "11" followed by SEND: release the call with + // gsm index equals to 1. + mGSMPhone.handleInCallMmiCommands("11"); + + do { + mTestHandler.getNextMessage(); + } while (mGSMPhone.getForegroundCall().getState() == Call.State.ACTIVE); + + assertEquals(Call.State.DISCONNECTED, mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); + } + + public void testIncallMmiCallHold() throws Exception { + Message msg; + + // establish an active call + mGSMPhone.dial("13125551212"); + + do { + mRadioControl.progressConnectingCallState(); + mTestHandler.getNextMessage(); + } while (mGSMPhone.getForegroundCall().getState() != Call.State.ACTIVE); + + assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); + + // establish a ringing (WAITING) call + + mRadioControl.triggerRing("18005551212"); + + do { + msg = mTestHandler.getNextMessage(); + } while (msg.what != EVENT_RINGING); + + assertEquals(Phone.State.RINGING, mGSMPhone.getState()); + assertTrue(mGSMPhone.getRingingCall().isRinging()); + assertEquals(Call.State.WAITING, mGSMPhone.getRingingCall().getState()); + assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); + + // simulate entering 2 followed by SEND: place all active calls + // (if any exist) on hold and accepts the other (held or waiting) + // call + + mGSMPhone.handleInCallMmiCommands("2"); + + do { + mTestHandler.getNextMessage(); + } while (mGSMPhone.getRingingCall().getState() == Call.State.WAITING); + + + assertFalse(mGSMPhone.getRingingCall().isRinging()); + assertEquals(Phone.State.OFFHOOK, mGSMPhone.getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getRingingCall().getState()); + assertEquals(Call.State.ACTIVE, + mGSMPhone.getForegroundCall().getState()); + assertEquals("18005551212", + mGSMPhone.getForegroundCall().getConnections().get(0).getAddress()); + assertEquals(Call.State.HOLDING, mGSMPhone.getBackgroundCall().getState()); + assertEquals("13125551212", + mGSMPhone.getBackgroundCall().getConnections().get(0).getAddress()); + + // swap the active and holding calls + mGSMPhone.handleInCallMmiCommands("2"); + + do { + msg = mTestHandler.getNextMessage(); + } while (msg.what != EVENT_PHONE_STATE_CHANGED); + + assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); + assertEquals("13125551212", + mGSMPhone.getForegroundCall().getConnections().get(0).getAddress()); + assertEquals(Call.State.HOLDING, mGSMPhone.getBackgroundCall().getState()); + assertEquals("18005551212", + mGSMPhone.getBackgroundCall().getConnections().get(0).getAddress()); + + // merge the calls + mGSMPhone.conference(); + + do { + mTestHandler.getNextMessage(); + } while (mGSMPhone.getBackgroundCall().getState() != Call.State.IDLE); + + assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); + assertEquals(2, mGSMPhone.getForegroundCall().getConnections().size()); + + // at this point, we have an active conference call, with + // call(1) = 13125551212 and call(2) = 18005551212 + + // Simulate entering "23" followed by SEND: places all active call + // on hold except call 3. This should fail and a supplementary service + // failed notification should be received. + + mGSMPhone.handleInCallMmiCommands("23"); + + do { + msg = mTestHandler.getNextMessage(); + } while (msg != null && msg.what != SUPP_SERVICE_FAILED); + assertFalse("IncallMmiCallHold: separate should have failed!", msg == null); + + // Simulate entering "21" followed by SEND: places all active call + // on hold except call 1. + mGSMPhone.handleInCallMmiCommands("21"); + + do { + mTestHandler.getNextMessage(); + } while (mGSMPhone.getBackgroundCall().getState() == Call.State.IDLE); + + assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); + assertEquals("13125551212", + mGSMPhone.getForegroundCall().getConnections().get(0).getAddress()); + assertEquals(Call.State.HOLDING, mGSMPhone.getBackgroundCall().getState()); + assertEquals("18005551212", + mGSMPhone.getBackgroundCall().getConnections().get(0).getAddress()); + } + + public void testIncallMmiMultipartyServices() throws Exception { + // establish an active call + mGSMPhone.dial("13125551212"); + + do { + mRadioControl.progressConnectingCallState(); + mTestHandler.getNextMessage(); + } while (mGSMPhone.getForegroundCall().getState() != Call.State.ACTIVE); + + assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); + + // dial another call + mGSMPhone.dial("18005551212"); + + do { + mRadioControl.progressConnectingCallState(); + mTestHandler.getNextMessage(); + } while (mGSMPhone.getForegroundCall().getState() != Call.State.ACTIVE); + + assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.HOLDING, mGSMPhone.getBackgroundCall().getState()); + + mGSMPhone.handleInCallMmiCommands("3"); + + do { + mTestHandler.getNextMessage(); + } while (mGSMPhone.getBackgroundCall().getState() != Call.State.IDLE); + + assertEquals(Phone.State.OFFHOOK, mGSMPhone.getState()); + assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); + assertEquals("18005551212", + mGSMPhone.getForegroundCall().getConnections().get(0).getAddress()); + assertEquals("13125551212", + mGSMPhone.getForegroundCall().getConnections().get(1).getAddress()); + assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); + } + + public void testCallIndex() throws Exception { + Message msg; + + // establish the first call + mGSMPhone.dial("16505550100"); + + do { + mRadioControl.progressConnectingCallState(); + mTestHandler.getNextMessage(); + } while (mGSMPhone.getForegroundCall().getState() != Call.State.ACTIVE); + + assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); + + String baseNumber = "1650555010"; + + for (int i = 1; i < 6; i++) { + String number = baseNumber + i; + + mGSMPhone.dial(number); + + do { + mRadioControl.progressConnectingCallState(); + mTestHandler.getNextMessage(); + } while (mGSMPhone.getForegroundCall().getState() != Call.State.ACTIVE); + + assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.HOLDING, mGSMPhone.getBackgroundCall().getState()); + + if (mGSMPhone.getBackgroundCall().getConnections().size() >= 5) { + break; + } + + mGSMPhone.conference(); + + do { + mTestHandler.getNextMessage(); + } while (mGSMPhone.getBackgroundCall().getState() != Call.State.IDLE); + + assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); + } + + assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); + assertEquals("16505550105", + mGSMPhone.getForegroundCall().getConnections().get(0).getAddress()); + assertEquals(Call.State.HOLDING, mGSMPhone.getBackgroundCall().getState()); + + // create an incoming call, this call should have the call index + // of 7 + mRadioControl.triggerRing("18005551212"); + + do { + msg = mTestHandler.getNextMessage(); + } while (msg.what != EVENT_RINGING); + + assertEquals(Phone.State.RINGING, mGSMPhone.getState()); + assertTrue(mGSMPhone.getRingingCall().isRinging()); + assertEquals(Call.State.WAITING, mGSMPhone.getRingingCall().getState()); + assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.HOLDING, mGSMPhone.getBackgroundCall().getState()); + + // hangup the background call and accept the ringing call + mGSMPhone.getBackgroundCall().hangup(); + mGSMPhone.acceptCall(); + + do { + mTestHandler.getNextMessage(); + } while (mGSMPhone.getRingingCall().getState() != Call.State.IDLE); + + assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); + assertEquals("18005551212", + mGSMPhone.getForegroundCall().getConnections().get(0).getAddress()); + assertEquals(Call.State.HOLDING, mGSMPhone.getBackgroundCall().getState()); + assertEquals("16505550105", + mGSMPhone.getBackgroundCall().getConnections().get(0).getAddress()); + + mGSMPhone.handleInCallMmiCommands("17"); + + do { + mTestHandler.getNextMessage(); + } while (mGSMPhone.getForegroundCall().getState() == Call.State.ACTIVE); + + assertEquals(Call.State.DISCONNECTED, mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.HOLDING, mGSMPhone.getBackgroundCall().getState()); + assertEquals("16505550105", + mGSMPhone.getBackgroundCall().getConnections().get(0). + getAddress()); + + mGSMPhone.handleInCallMmiCommands("1"); + + do { + mTestHandler.getNextMessage(); + } while (mGSMPhone.getForegroundCall().getState() != Call.State.ACTIVE); + + assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); + + mGSMPhone.handleInCallMmiCommands("16"); + + do { + mTestHandler.getNextMessage(); + } while (mGSMPhone.getForegroundCall().getState() == Call.State.ACTIVE); + + assertEquals(Call.State.DISCONNECTED, mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); + } + + public void testPostDialSequences() throws Exception { + Message msg; + AsyncResult ar; + Connection cn; + + mGSMPhone.dial("+13125551212,1234;5N8xx"); + + do { + msg = mTestHandler.getNextMessage(); + mRadioControl.progressConnectingToActive(); + } while (msg.what != EVENT_POST_DIAL); + + ar = (AsyncResult) (msg.obj); + cn = (Connection) (ar.result); + assertEquals(',', msg.arg1); + assertEquals("1234;5N8", cn.getRemainingPostDialString()); + + + do { + msg = mTestHandler.getNextMessage(); + } while (msg.what != EVENT_POST_DIAL); + + assertEquals('1', msg.arg1); + ar = (AsyncResult) (msg.obj); + assertEquals(Connection.PostDialState.STARTED, ar.userObj); + + do { + msg = mTestHandler.getNextMessage(); + } while (msg.what != EVENT_POST_DIAL); + + assertEquals('2', msg.arg1); + ar = (AsyncResult) (msg.obj); + assertEquals(Connection.PostDialState.STARTED, ar.userObj); + + do { + msg = mTestHandler.getNextMessage(); + } while (msg.what != EVENT_POST_DIAL); + + assertEquals('3', msg.arg1); + ar = (AsyncResult) (msg.obj); + assertEquals(Connection.PostDialState.STARTED, ar.userObj); + + do { + msg = mTestHandler.getNextMessage(); + } while (msg.what != EVENT_POST_DIAL); + + assertEquals('4', msg.arg1); + ar = (AsyncResult) (msg.obj); + assertEquals(Connection.PostDialState.STARTED, ar.userObj); + + do { + msg = mTestHandler.getNextMessage(); + } while (msg.what != EVENT_POST_DIAL); + + assertEquals(';', msg.arg1); + ar = (AsyncResult) (msg.obj); + cn = (Connection) (ar.result); + assertEquals(Connection.PostDialState.WAIT, cn.getPostDialState()); + assertEquals(Connection.PostDialState.WAIT, ar.userObj); + cn.proceedAfterWaitChar(); + + do { + msg = mTestHandler.getNextMessage(); + } while (msg.what != EVENT_POST_DIAL); + + assertEquals('5', msg.arg1); + ar = (AsyncResult) (msg.obj); + assertEquals(Connection.PostDialState.STARTED, ar.userObj); + + do { + msg = mTestHandler.getNextMessage(); + } while (msg.what != EVENT_POST_DIAL); + + assertEquals('N', msg.arg1); + ar = (AsyncResult) (msg.obj); + cn = (Connection) (ar.result); + assertEquals(Connection.PostDialState.WILD, cn.getPostDialState()); + assertEquals(Connection.PostDialState.WILD, ar.userObj); + cn.proceedAfterWildChar(",6;7"); + + do { + msg = mTestHandler.getNextMessage(); + } while (msg.what != EVENT_POST_DIAL); + + ar = (AsyncResult) (msg.obj); + cn = (Connection) (ar.result); + assertEquals(',', msg.arg1); + assertEquals("6;78", cn.getRemainingPostDialString()); + + do { + msg = mTestHandler.getNextMessage(); + } while (msg.what != EVENT_POST_DIAL); + + assertEquals('6', msg.arg1); + ar = (AsyncResult) (msg.obj); + assertEquals(Connection.PostDialState.STARTED, ar.userObj); + + do { + msg = mTestHandler.getNextMessage(); + } while (msg.what != EVENT_POST_DIAL); + + assertEquals(';', msg.arg1); + ar = (AsyncResult) (msg.obj); + cn = (Connection) (ar.result); + assertEquals(Connection.PostDialState.WAIT, cn.getPostDialState()); + assertEquals(Connection.PostDialState.WAIT, ar.userObj); + cn.proceedAfterWaitChar(); + + do { + msg = mTestHandler.getNextMessage(); + } while (msg.what != EVENT_POST_DIAL); + + assertEquals('7', msg.arg1); + ar = (AsyncResult) (msg.obj); + assertEquals(Connection.PostDialState.STARTED, ar.userObj); + + do { + msg = mTestHandler.getNextMessage(); + } while (msg.what != EVENT_POST_DIAL); + + assertEquals('8', msg.arg1); + ar = (AsyncResult) (msg.obj); + assertEquals(Connection.PostDialState.STARTED, ar.userObj); + + // Bogus chars at end should be ignored + + do { + msg = mTestHandler.getNextMessage(); + } while (msg.what != EVENT_POST_DIAL); + + assertEquals(0, msg.arg1); + ar = (AsyncResult) (msg.obj); + cn = (Connection) (ar.result); + assertEquals(Connection.PostDialState.COMPLETE, + cn.getPostDialState()); + assertEquals(Connection.PostDialState.COMPLETE, ar.userObj); + } + + public void testPostDialCancel() throws Exception { + Message msg; + AsyncResult ar; + Connection cn; + + mGSMPhone.dial("+13125551212,N"); + mRadioControl.progressConnectingToActive(); + + mRadioControl.progressConnectingToActive(); + + do { + msg = mTestHandler.getNextMessage(); + } while (msg.what != EVENT_POST_DIAL); + + assertEquals(',', msg.arg1); + + do { + msg = mTestHandler.getNextMessage(); + } while (msg.what != EVENT_POST_DIAL); + + assertEquals('N', msg.arg1); + ar = (AsyncResult) (msg.obj); + cn = (Connection) (ar.result); + assertEquals(Connection.PostDialState.WILD, cn.getPostDialState()); + cn.cancelPostDial(); + + assertEquals(Connection.PostDialState.CANCELLED, cn.getPostDialState()); + } + + public void testOutgoingCallFail() throws Exception { + Message msg; + /* + * normal clearing + */ + + mRadioControl.setNextCallFailCause(CallFailCause.NORMAL_CLEARING); + mRadioControl.setAutoProgressConnectingCall(false); + + Connection cn = mGSMPhone.dial("+13125551212"); + + mRadioControl.progressConnectingCallState(); + + // I'm just progressing the call state to + // ensure getCurrentCalls() gets processed... + // Normally these failure conditions would happen in DIALING + // not ALERTING + do { + mTestHandler.getNextMessage(); + } while (cn.getState() == Call.State.DIALING); + + + mRadioControl.triggerHangupAll(); + + do { + msg = mTestHandler.getNextMessage(); + } while (msg.what != EVENT_DISCONNECT); + + assertEquals(Phone.State.IDLE, mGSMPhone.getState()); + + assertEquals(Connection.DisconnectCause.NORMAL, cn.getDisconnectCause()); + + assertEquals(0, mGSMPhone.getRingingCall().getConnections().size()); + assertEquals(1, mGSMPhone.getForegroundCall().getConnections().size()); + assertEquals(0, mGSMPhone.getBackgroundCall().getConnections().size()); + + assertEquals(Call.State.IDLE, mGSMPhone.getRingingCall().getState()); + assertEquals(Call.State.DISCONNECTED, mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); + + assertTrue(mGSMPhone.getForegroundCall().getEarliestCreateTime() > 0); + assertEquals(0, mGSMPhone.getForegroundCall().getEarliestConnectTime()); + + /* + * busy + */ + + mRadioControl.setNextCallFailCause(CallFailCause.USER_BUSY); + mRadioControl.setAutoProgressConnectingCall(false); + + cn = mGSMPhone.dial("+13125551212"); + + mRadioControl.progressConnectingCallState(); + + // I'm just progressing the call state to + // ensure getCurrentCalls() gets processed... + // Normally these failure conditions would happen in DIALING + // not ALERTING + do { + mTestHandler.getNextMessage(); + } while (cn.getState() == Call.State.DIALING); + + + mRadioControl.triggerHangupAll(); + + do { + msg = mTestHandler.getNextMessage(); + } while (msg.what != EVENT_DISCONNECT); + + assertEquals(Phone.State.IDLE, mGSMPhone.getState()); + + assertEquals(Connection.DisconnectCause.BUSY, cn.getDisconnectCause()); + + assertEquals(0, mGSMPhone.getRingingCall().getConnections().size()); + assertEquals(1, mGSMPhone.getForegroundCall().getConnections().size()); + assertEquals(0, mGSMPhone.getBackgroundCall().getConnections().size()); + + assertEquals(Call.State.IDLE, mGSMPhone.getRingingCall().getState()); + assertEquals(Call.State.DISCONNECTED, + mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); + + assertTrue(mGSMPhone.getForegroundCall().getEarliestCreateTime() > 0); + assertEquals(0, mGSMPhone.getForegroundCall().getEarliestConnectTime()); + + /* + * congestion + */ + + mRadioControl.setNextCallFailCause(CallFailCause.NO_CIRCUIT_AVAIL); + mRadioControl.setAutoProgressConnectingCall(false); + + cn = mGSMPhone.dial("+13125551212"); + + mRadioControl.progressConnectingCallState(); + + // I'm just progressing the call state to + // ensure getCurrentCalls() gets processed... + // Normally these failure conditions would happen in DIALING + // not ALERTING + do { + mTestHandler.getNextMessage(); + } while (cn.getState() == Call.State.DIALING); + + + mRadioControl.triggerHangupAll(); + + // Unlike the while loops above, this one waits + // for a "phone state changed" message back to "idle" + do { + msg = mTestHandler.getNextMessage(); + } while (!(msg.what == EVENT_PHONE_STATE_CHANGED + && mGSMPhone.getState() == Phone.State.IDLE)); + + assertEquals(Phone.State.IDLE, mGSMPhone.getState()); + + assertEquals(Connection.DisconnectCause.CONGESTION, cn.getDisconnectCause()); + + assertEquals(0, mGSMPhone.getRingingCall().getConnections().size()); + assertEquals(1, mGSMPhone.getForegroundCall().getConnections().size()); + assertEquals(0, mGSMPhone.getBackgroundCall().getConnections().size()); + + assertEquals(Call.State.IDLE, mGSMPhone.getRingingCall().getState()); + assertEquals(Call.State.DISCONNECTED, mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); + + assertTrue(mGSMPhone.getForegroundCall().getEarliestCreateTime() > 0); + assertEquals(0, mGSMPhone.getForegroundCall().getEarliestConnectTime()); + } + + public void testSSNotification() throws Exception { + // MO + runTest(0, SuppServiceNotification.MO_CODE_UNCONDITIONAL_CF_ACTIVE); + runTest(0, SuppServiceNotification.MO_CODE_CALL_IS_WAITING); + runTest(0, SuppServiceNotification.MO_CODE_CALL_DEFLECTED); + + // MT + runTest(1, SuppServiceNotification.MT_CODE_FORWARDED_CALL); + runTest(1, SuppServiceNotification.MT_CODE_CALL_CONNECTED_ECT); + runTest(1, SuppServiceNotification.MT_CODE_ADDITIONAL_CALL_FORWARDED); + } + + private void runTest(int type, int code) { + Message msg; + + mRadioControl.triggerSsn(type, code); + + do { + msg = mTestHandler.getNextMessage(); + } while (msg.what != EVENT_SSN); + + AsyncResult ar = (AsyncResult) msg.obj; + + assertNull(ar.exception); + + SuppServiceNotification notification = + (SuppServiceNotification) ar.result; + + assertEquals(type, notification.notificationType); + assertEquals(code, notification.code); + } + + public void testUssd() throws Exception { + // Quick hack to work around a race condition in this test: + // We may initiate a USSD MMI before GSMPhone receives its initial + // EVENT_RADIO_OFF_OR_NOT_AVAILABLE event. When the phone sees this + // event, it will cancel the just issued USSD MMI, which we don't + // want. So sleep a little first. + try { + Thread.sleep(1000); + } catch (InterruptedException ex) { + // do nothing + } + + verifyNormal(); + verifyCancel(); + varifyNetworkInitiated(); + } + + private void varifyNetworkInitiated() { + Message msg; + AsyncResult ar; + MmiCode mmi; + + // Receive an incoming NOTIFY + mRadioControl.triggerIncomingUssd("0", "NOTIFY message"); + do { + msg = mTestHandler.getNextMessage(); + } while (msg.what != EVENT_MMI_COMPLETE); + + ar = (AsyncResult) msg.obj; + mmi = (MmiCode) ar.result; + + assertFalse(mmi.isUssdRequest()); + + // Receive a REQUEST and send response + mRadioControl.triggerIncomingUssd("1", "REQUEST Message"); + do { + msg = mTestHandler.getNextMessage(); + } while (msg.what != EVENT_MMI_COMPLETE); + ar = (AsyncResult) msg.obj; + mmi = (MmiCode) ar.result; + + assertTrue(mmi.isUssdRequest()); + + mGSMPhone.sendUssdResponse("## TEST: TEST_GSMPhone responding..."); + do { + msg = mTestHandler.getNextMessage(); + } while (msg.what != EVENT_MMI_INITIATE); + + ar = (AsyncResult) msg.obj; + mmi = (MmiCode) ar.result; + + GsmMmiCode gsmMmi = (GsmMmiCode) mmi; + assertTrue(gsmMmi.isPendingUSSD()); + + do { + msg = mTestHandler.getNextMessage(); + } while (msg.what != EVENT_MMI_COMPLETE); + + ar = (AsyncResult) msg.obj; + mmi = (MmiCode) ar.result; + + assertNull(ar.exception); + assertFalse(mmi.isUssdRequest()); + + // Receive a REQUEST and cancel + mRadioControl.triggerIncomingUssd("1", "REQUEST Message"); + do { + msg = mTestHandler.getNextMessage(); + } while (msg.what != EVENT_MMI_COMPLETE); + ar = (AsyncResult) msg.obj; + mmi = (MmiCode) ar.result; + + assertTrue(mmi.isUssdRequest()); + + mmi.cancel(); + + do { + msg = mTestHandler.getNextMessage(); + } while (msg.what != EVENT_MMI_COMPLETE); + + ar = (AsyncResult) msg.obj; + mmi = (MmiCode) ar.result; + + assertNull(ar.exception); + assertEquals(MmiCode.State.CANCELLED, mmi.getState()); + + List mmiList = mGSMPhone.getPendingMmiCodes(); + assertEquals(0, mmiList.size()); + } + + private void verifyNormal() throws CallStateException { + Message msg; + AsyncResult ar; + MmiCode mmi; + + mGSMPhone.dial("#646#"); + + do { + msg = mTestHandler.getNextMessage(); + } while (msg.what != EVENT_MMI_INITIATE); + + do { + msg = mTestHandler.getNextMessage(); + } while (msg.what != EVENT_MMI_COMPLETE); + + ar = (AsyncResult) msg.obj; + mmi = (MmiCode) ar.result; + assertEquals(MmiCode.State.COMPLETE, mmi.getState()); + } + + + private void verifyCancel() throws CallStateException { + /** + * This case makes an assumption that dial() will add the USSD + * to the "pending MMI codes" list before it returns. This seems + * like reasonable semantics. It also assumes that the USSD + * request in question won't complete until we get back to the + * event loop, thus cancel() is safe. + */ + Message msg; + + mGSMPhone.dial("#646#"); + + List pendingMmis = mGSMPhone.getPendingMmiCodes(); + + assertEquals(1, pendingMmis.size()); + + MmiCode mmi = pendingMmis.get(0); + assertTrue(mmi.isCancelable()); + mmi.cancel(); + + do { + msg = mTestHandler.getNextMessage(); + } while (msg.what != EVENT_MMI_INITIATE); + + do { + msg = mTestHandler.getNextMessage(); + } while (msg.what != EVENT_MMI_COMPLETE); + + AsyncResult ar = (AsyncResult) msg.obj; + mmi = (MmiCode) ar.result; + + assertEquals(MmiCode.State.CANCELLED, mmi.getState()); + } + + public void testRilHooks() throws Exception { + // + // These test cases all assume the RIL OEM hooks + // just echo back their input + // + + Message msg; + AsyncResult ar; + + // null byte array + + mGSMPhone.invokeOemRilRequestRaw(null, mTestHandler.hh.obtainMessage(999)); + + do { + msg = mTestHandler.getNextMessage(); + } while (!(msg.what == 999)); + + ar = ((AsyncResult) msg.obj); + + assertNull(ar.result); + assertNull(ar.exception); + + // empty byte array + + mGSMPhone.invokeOemRilRequestRaw(new byte[0], mTestHandler.hh.obtainMessage(999)); + + do { + msg = mTestHandler.getNextMessage(); + } while (!(msg.what == 999)); + + ar = ((AsyncResult) msg.obj); + + assertEquals(0, ((byte[]) (ar.result)).length); + assertNull(ar.exception); + + // byte array with data + + mGSMPhone.invokeOemRilRequestRaw("Hello".getBytes("utf-8"), + mTestHandler.hh.obtainMessage(999)); + + do { + msg = mTestHandler.getNextMessage(); + } while (!(msg.what == 999)); + + ar = ((AsyncResult) msg.obj); + + assertEquals("Hello", new String(((byte[]) (ar.result)), "utf-8")); + assertNull(ar.exception); + + // null strings + + mGSMPhone.invokeOemRilRequestStrings(null, mTestHandler.hh.obtainMessage(999)); + + do { + msg = mTestHandler.getNextMessage(); + } while (!(msg.what == 999)); + + ar = ((AsyncResult) msg.obj); + + assertNull(ar.result); + assertNull(ar.exception); + + // empty byte array + + mGSMPhone.invokeOemRilRequestStrings(new String[0], + mTestHandler.hh.obtainMessage(999)); + + do { + msg = mTestHandler.getNextMessage(); + } while (!(msg.what == 999)); + + ar = ((AsyncResult) msg.obj); + + assertEquals(0, ((String[]) (ar.result)).length); + assertNull(ar.exception); + + // Strings with data + + String s[] = new String[1]; + + s[0] = "Hello"; + + mGSMPhone.invokeOemRilRequestStrings(s, mTestHandler.hh.obtainMessage(999)); + + do { + msg = mTestHandler.getNextMessage(); + } while (!(msg.what == 999)); + + ar = ((AsyncResult) msg.obj); + + assertEquals("Hello", ((String[]) (ar.result))[0]); + assertEquals(1, ((String[]) (ar.result)).length); + assertNull(ar.exception); + } + + public void testMmi() throws Exception { + mRadioControl.setAutoProgressConnectingCall(false); + + // "valid" MMI sequences + runValidMmi("*#67#", false); + runValidMmi("##43*11#", false); + runValidMmi("#33*1234*11#", false); + runValidMmi("*21*6505551234**5#", false); + runValidMmi("**03**1234*4321*4321#", false); + // pound string + runValidMmi("5308234092307540923#", true); + // short code + runValidMmi("22", true); + // as part of call setup + runValidMmiWithConnect("*31#6505551234"); + + // invalid MMI sequences + runNotMmi("6505551234"); + runNotMmi("1234#*12#34566654"); + runNotMmi("*#*#12#*"); + } + + private void runValidMmi(String dialString, boolean cancelable) throws CallStateException { + Connection c = mGSMPhone.dial(dialString); + assertNull(c); + + Message msg; + do { + msg = mTestHandler.getNextMessage(); + } while (msg.what != EVENT_MMI_INITIATE); + + // Should not be cancelable. + AsyncResult ar = (AsyncResult) msg.obj; + MmiCode mmi = (MmiCode) ar.result; + assertEquals(cancelable, mmi.isCancelable()); + + do { + msg = mTestHandler.getNextMessage(); + } while (msg.what != EVENT_MMI_COMPLETE); + + } + + private void runValidMmiWithConnect(String dialString) throws CallStateException { + mRadioControl.pauseResponses(); + + Connection c = mGSMPhone.dial(dialString); + assertNotNull(c); + + hangup(c); + } + + private void hangup(Connection cn) throws CallStateException { + cn.hangup(); + + mRadioControl.resumeResponses(); + + Message msg; + do { + msg = mTestHandler.getNextMessage(); + } while (msg.what != EVENT_DISCONNECT); + } + + private void runNotMmi(String dialString) throws CallStateException { + mRadioControl.pauseResponses(); + + Connection c = mGSMPhone.dial(dialString); + assertNotNull(c); + + hangup(c); + } +} diff --git a/tests/CoreTests/com/android/internal/telephony/gsm/GsmAlphabetTest.java b/tests/CoreTests/com/android/internal/telephony/gsm/GsmAlphabetTest.java new file mode 100644 index 0000000000000000000000000000000000000000..f36d96bba8111de94fab5a4a1cc2bdfdb2c3c4ca --- /dev/null +++ b/tests/CoreTests/com/android/internal/telephony/gsm/GsmAlphabetTest.java @@ -0,0 +1,309 @@ +/* + * Copyright (C) 2006 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.android.internal.telephony.gsm; + +import junit.framework.TestCase; + +import android.test.suitebuilder.annotation.LargeTest; +import android.test.suitebuilder.annotation.SmallTest; +import android.test.suitebuilder.annotation.Suppress; + +public class GsmAlphabetTest extends TestCase { + + private static final String sGsmExtendedChars = "{|}\\[~]\f\u20ac"; + + @SmallTest + public void test7bitWithHeader() throws Exception { + byte[] data = new byte[3]; + data[0] = (byte) 1; + data[1] = (byte) 2; + data[2] = (byte) 2; + SmsHeader header = new SmsHeader(); + header.add(new SmsHeader.Element(SmsHeader.CONCATENATED_8_BIT_REFERENCE, data)); + + String message = "aaaaaaaaaabbbbbbbbbbcccccccccc"; + byte[] userData = GsmAlphabet.stringToGsm7BitPackedWithHeader(message, header.toByteArray()); + int septetCount = GsmAlphabet.countGsmSeptets(message, false); + String parsedMessage = GsmAlphabet.gsm7BitPackedToString( + userData, header.toByteArray().length+1, septetCount, 1); + assertEquals(message, parsedMessage); + } + + // TODO: This method should *really* be a series of individual test methods. + @LargeTest + public void testBasic() throws Exception { + // '@' maps to char 0 + assertEquals(0, GsmAlphabet.charToGsm('@')); + + // `a (a with grave accent) maps to last GSM charater + assertEquals(0x7f, GsmAlphabet.charToGsm('\u00e0')); + + // + // These are the extended chars + // They should all return GsmAlphabet.GSM_EXTENDED_ESCAPE + // + + for (int i = 0, s = sGsmExtendedChars.length(); i < s; i++) { + assertEquals(GsmAlphabet.GSM_EXTENDED_ESCAPE, + GsmAlphabet.charToGsm(sGsmExtendedChars.charAt(i))); + + } + + // euro symbol + assertEquals(GsmAlphabet.GSM_EXTENDED_ESCAPE, + GsmAlphabet.charToGsm('\u20ac')); + + // An unmappable char (the 'cent' char) maps to a space + assertEquals(GsmAlphabet.charToGsm(' '), + GsmAlphabet.charToGsm('\u00a2')); + + // unmappable = space = 1 septet + assertEquals(1, GsmAlphabet.countGsmSeptets('\u00a2')); + + // + // Test extended table + // + + for (int i = 0, s = sGsmExtendedChars.length(); i < s; i++) { + assertEquals(sGsmExtendedChars.charAt(i), + GsmAlphabet.gsmExtendedToChar( + GsmAlphabet.charToGsmExtended(sGsmExtendedChars.charAt(i)))); + + } + + // Unmappable extended char + assertEquals(GsmAlphabet.charToGsm(' '), + GsmAlphabet.charToGsmExtended('@')); + + // + // gsmToChar() + // + + assertEquals('@', GsmAlphabet.gsmToChar(0)); + + // `a (a with grave accent) maps to last GSM charater + assertEquals('\u00e0', GsmAlphabet.gsmToChar(0x7f)); + + assertEquals('\uffff', + GsmAlphabet.gsmToChar(GsmAlphabet.GSM_EXTENDED_ESCAPE)); + + // Out-of-range/unmappable value + assertEquals(' ', GsmAlphabet.gsmToChar(0x80)); + + // + // gsmExtendedToChar() + // + + assertEquals('{', GsmAlphabet.gsmExtendedToChar(0x28)); + + // No double-escapes + assertEquals(' ', GsmAlphabet.gsmExtendedToChar( + GsmAlphabet.GSM_EXTENDED_ESCAPE)); + + // Unmappable + assertEquals(' ', GsmAlphabet.gsmExtendedToChar(0)); + + // + // stringTo7BitPacked, gsm7BitPackedToString + // + + byte[] packed; + StringBuilder testString = new StringBuilder(300); + + // Check all alignment cases + for (int i = 0; i < 9; i++, testString.append('@')) { + packed = GsmAlphabet.stringToGsm7BitPacked(testString.toString()); + assertEquals(testString.toString(), + GsmAlphabet.gsm7BitPackedToString(packed, 1, 0xff & packed[0])); + } + + // Check full non-extended alphabet + for (int i = 0; i < 0x80; i++) { + char c; + + if (i == GsmAlphabet.GSM_EXTENDED_ESCAPE) { + continue; + } + + c = GsmAlphabet.gsmToChar(i); + testString.append(c); + + // These are all non-extended chars, so it should be + // one septet per char + assertEquals(1, GsmAlphabet.countGsmSeptets(c)); + } + + packed = GsmAlphabet.stringToGsm7BitPacked(testString.toString()); + assertEquals(testString.toString(), + GsmAlphabet.gsm7BitPackedToString(packed, 1, 0xff & packed[0])); + + // Test extended chars too + + testString.append(sGsmExtendedChars); + + for (int i = 0, s = sGsmExtendedChars.length(); i < s; i++) { + // These are all extended chars, so it should be + // two septets per char + assertEquals(2, GsmAlphabet.countGsmSeptets(sGsmExtendedChars.charAt(i))); + + } + + packed = GsmAlphabet.stringToGsm7BitPacked(testString.toString()); + assertEquals(testString.toString(), + GsmAlphabet.gsm7BitPackedToString(packed, 1, 0xff & packed[0])); + + // stringTo7BitPacked handles up to 255 septets + + testString.setLength(0); + for (int i = 0; i < 255; i++) { + testString.append('@'); + } + + packed = GsmAlphabet.stringToGsm7BitPacked(testString.toString()); + assertEquals(testString.toString(), + GsmAlphabet.gsm7BitPackedToString(packed, 1, 0xff & packed[0])); + + // > 255 septets throws runtime exception + testString.append('@'); + + try { + GsmAlphabet.stringToGsm7BitPacked(testString.toString()); + fail("expected exception"); + } catch (EncodeException ex) { + // exception expected + } + + // Try 254 septets with 127 extended chars + + testString.setLength(0); + for (int i = 0; i < (255 / 2); i++) { + testString.append('{'); + } + + packed = GsmAlphabet.stringToGsm7BitPacked(testString.toString()); + assertEquals(testString.toString(), + GsmAlphabet.gsm7BitPackedToString(packed, 1, 0xff & packed[0])); + + // > 255 septets throws runtime exception + testString.append('{'); + + try { + GsmAlphabet.stringToGsm7BitPacked(testString.toString()); + fail("expected exception"); + } catch (EncodeException ex) { + // exception expected + } + + // + // 8 bit unpacked format + // + // Note: we compare hex strings here + // because Assert doesnt have array-comparisons + + byte unpacked[]; + + unpacked = SimUtils.hexStringToBytes("566F696365204D61696C"); + assertEquals("Voice Mail", + GsmAlphabet.gsm8BitUnpackedToString(unpacked, 0, unpacked.length)); + + assertEquals(SimUtils.bytesToHexString(unpacked), + SimUtils.bytesToHexString( + GsmAlphabet.stringToGsm8BitPacked("Voice Mail"))); + + unpacked = GsmAlphabet.stringToGsm8BitPacked(sGsmExtendedChars); + // two bytes for every extended char + assertEquals(2 * sGsmExtendedChars.length(), unpacked.length); + assertEquals(sGsmExtendedChars, + GsmAlphabet.gsm8BitUnpackedToString(unpacked, 0, unpacked.length)); + + // should be two bytes per extended char + assertEquals(2 * sGsmExtendedChars.length(), unpacked.length); + + // Test truncation of unaligned extended chars + unpacked = new byte[3]; + GsmAlphabet.stringToGsm8BitUnpackedField(sGsmExtendedChars, unpacked, + 0, unpacked.length); + + // Should be one extended char and an 0xff at the end + + assertEquals(0xff, 0xff & unpacked[2]); + assertEquals(sGsmExtendedChars.substring(0, 1), + GsmAlphabet.gsm8BitUnpackedToString(unpacked, 0, unpacked.length)); + + // Test truncation of normal chars + unpacked = new byte[3]; + GsmAlphabet.stringToGsm8BitUnpackedField("abcd", unpacked, + 0, unpacked.length); + + assertEquals("abc", + GsmAlphabet.gsm8BitUnpackedToString(unpacked, 0, unpacked.length)); + + // Test truncation of mixed normal and extended chars + unpacked = new byte[3]; + GsmAlphabet.stringToGsm8BitUnpackedField("a{cd", unpacked, + 0, unpacked.length); + + assertEquals("a{", + GsmAlphabet.gsm8BitUnpackedToString(unpacked, 0, unpacked.length)); + + // Test padding after normal char + unpacked = new byte[3]; + GsmAlphabet.stringToGsm8BitUnpackedField("a", unpacked, + 0, unpacked.length); + + assertEquals("a", + GsmAlphabet.gsm8BitUnpackedToString(unpacked, 0, unpacked.length)); + + assertEquals(0xff, 0xff & unpacked[1]); + assertEquals(0xff, 0xff & unpacked[2]); + + // Test malformed input -- escape char followed by end of field + unpacked[0] = 0; + unpacked[1] = 0; + unpacked[2] = GsmAlphabet.GSM_EXTENDED_ESCAPE; + + assertEquals("@@", + GsmAlphabet.gsm8BitUnpackedToString(unpacked, 0, unpacked.length)); + + // non-zero offset + assertEquals("@", + GsmAlphabet.gsm8BitUnpackedToString(unpacked, 1, unpacked.length - 1)); + + // test non-zero offset + unpacked[0] = 0; + GsmAlphabet.stringToGsm8BitUnpackedField("abcd", unpacked, + 1, unpacked.length - 1); + + + assertEquals(0, unpacked[0]); + + assertEquals("ab", + GsmAlphabet.gsm8BitUnpackedToString(unpacked, 1, unpacked.length - 1)); + + // test non-zero offset with truncated extended char + unpacked[0] = 0; + + GsmAlphabet.stringToGsm8BitUnpackedField("a{", unpacked, + 1, unpacked.length - 1); + + assertEquals(0, unpacked[0]); + + assertEquals("a", + GsmAlphabet.gsm8BitUnpackedToString(unpacked, 1, unpacked.length - 1)); + } +} + diff --git a/tests/CoreTests/com/android/internal/telephony/gsm/SMSDispatcherTest.java b/tests/CoreTests/com/android/internal/telephony/gsm/SMSDispatcherTest.java new file mode 100644 index 0000000000000000000000000000000000000000..84974ef4e2e5ee3c3790337c145dcd369ed7a8d2 --- /dev/null +++ b/tests/CoreTests/com/android/internal/telephony/gsm/SMSDispatcherTest.java @@ -0,0 +1,98 @@ +/* + * Copyright (C) 2007 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.android.internal.telephony.gsm; + +import android.core.TestHandler; +import android.test.suitebuilder.annotation.MediumTest; +import com.android.internal.telephony.TestPhoneNotifier; +import com.android.internal.telephony.test.SimulatedCommands; +import com.android.internal.telephony.test.SimulatedRadioControl; +import android.test.AndroidTestCase; +import android.test.suitebuilder.annotation.Suppress; +import android.telephony.gsm.SmsMessage; + +import java.util.Iterator; + +/** + * {@hide} + */ +public class SMSDispatcherTest extends AndroidTestCase { + @MediumTest + public void testCMT1() throws Exception { + SmsMessage sms; + SmsHeader header; + Iterator elements; + + String[] lines = new String[2]; + + lines[0] = "+CMT: ,158"; + lines[1] = "07914140279510F6440A8111110301003BF56080426101748A8C0B05040B" + + "8423F000035502010106276170706C69636174696F6E2F766E642E776170" + + "2E6D6D732D6D65737361676500AF848D0185B4848C8298524F347839776F" + + "7547514D4141424C3641414141536741415A4B554141414141008D908918" + + "802B31363530323438363137392F545950453D504C4D4E008A808E028000" + + "88058103093A8083687474703A2F2F36"; + + sms = SmsMessage.newFromCMT(lines); + header = sms.getUserDataHeader(); + assertNotNull(header); + assertNotNull(sms.getUserData()); + + elements = header.getElements().iterator(); + assertNotNull(elements); + } + + @MediumTest + public void testCMT2() throws Exception { + SmsMessage sms; + SmsHeader header; + Iterator elements; + + String[] lines = new String[2]; + + + lines[0] = "+CMT: ,77"; + lines[1] = "07914140279510F6440A8111110301003BF56080426101848A3B0B05040B8423F" + + "00003550202362E3130322E3137312E3135302F524F347839776F7547514D4141" + + "424C3641414141536741415A4B55414141414100"; + + sms = SmsMessage.newFromCMT(lines); + header = sms.getUserDataHeader(); + System.out.println("header = " + header); + assertNotNull(header); + assertNotNull(sms.getUserData()); + + elements = header.getElements().iterator(); + assertNotNull(elements); + } + + @MediumTest + public void testEfRecord() throws Exception { + SmsMessage sms; + + String s = "03029111000c9194981492631000f269206190022000a053e4534a05358bd3" + + "69f05804259da0219418a40641536a110a0aea408080604028180e888462c1" + + "50341c0f484432a1542c174c46b3e1743c9f9068442a994ea8946ac56ab95e" + + "b0986c46abd96eb89c6ec7ebf97ec0a070482c1a8fc8a472c96c3a9fd0a874" + + "4aad5aafd8ac76cbed7abfe0b0784c2e9bcfe8b47acd6ebbdff0b87c4eafdb" + + "eff8bc7ecfeffbffffffffffffffffffffffffffff"; + byte[] data = SimUtils.hexStringToBytes(s); + + sms = SmsMessage.createFromEfRecord(1, data); + assertNotNull(sms.getMessageBody()); + } +} diff --git a/tests/CoreTests/com/android/internal/telephony/gsm/SimPhoneBookTest.java b/tests/CoreTests/com/android/internal/telephony/gsm/SimPhoneBookTest.java new file mode 100644 index 0000000000000000000000000000000000000000..53fdd51ba6c265be7e19c7fb1c36bf2b29a2c111 --- /dev/null +++ b/tests/CoreTests/com/android/internal/telephony/gsm/SimPhoneBookTest.java @@ -0,0 +1,107 @@ +/* + * Copyright (C) 2006 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.android.internal.telephony.gsm; + +import android.core.TestHandler; +import android.os.ServiceManager; +import android.test.suitebuilder.annotation.Suppress; + +import java.util.List; + +import junit.framework.TestCase; + +@Suppress +public class SimPhoneBookTest extends TestCase { + + public void testBasic() throws Exception { + ISimPhoneBook simPhoneBook = + ISimPhoneBook.Stub.asInterface(ServiceManager.getService("simphonebook")); + assertNotNull(simPhoneBook); + + int size[] = simPhoneBook.getAdnRecordsSize(SimConstants.EF_ADN); + assertNotNull(size); + assertEquals(3, size.length); + assertEquals(size[0] * size[2], size[1]); + assertTrue(size[2] >= 100); + + List adnRecordList = simPhoneBook.getAdnRecordsInEf(SimConstants.EF_ADN); + // do it twice cause the second time shall read from cache only + adnRecordList = simPhoneBook.getAdnRecordsInEf(SimConstants.EF_ADN); + assertNotNull(adnRecordList); + + // Test for phone book update + int adnIndex, listIndex = 0; + AdnRecord originalAdn = null; + // We need to maintain the state of the SIM before and after the test. + // Since this test doesn't mock the SIM we try to get a valid ADN record, + // for 3 tries and if this fails, we bail out. + for (adnIndex = 3 ; adnIndex >= 1; adnIndex--) { + listIndex = adnIndex - 1; // listIndex is zero based. + originalAdn = adnRecordList.get(listIndex); + assertNotNull("Original Adn is Null.", originalAdn); + assertNotNull("Original Adn alpha tag is null.", originalAdn.getAlphaTag()); + assertNotNull("Original Adn number is null.", originalAdn.getNumber()); + + if (originalAdn.getNumber().length() > 0 && + originalAdn.getAlphaTag().length() > 0) { + break; + } + } + if (adnIndex == 0) return; + + AdnRecord emptyAdn = new AdnRecord("", ""); + AdnRecord firstAdn = new AdnRecord("John", "4085550101"); + AdnRecord secondAdn = new AdnRecord("Andy", "6505550102"); + String pin2 = null; + + // udpate by index + boolean success = simPhoneBook.updateAdnRecordsInEfByIndex(SimConstants.EF_ADN, + firstAdn.getAlphaTag(), firstAdn.getNumber(), adnIndex, pin2); + adnRecordList = simPhoneBook.getAdnRecordsInEf(SimConstants.EF_ADN); + AdnRecord tmpAdn = adnRecordList.get(listIndex); + assertTrue(success); + assertTrue(firstAdn.isEqual(tmpAdn)); + + // replace by search + success = simPhoneBook.updateAdnRecordsInEfBySearch(SimConstants.EF_ADN, + firstAdn.getAlphaTag(), firstAdn.getNumber(), + secondAdn.getAlphaTag(), secondAdn.getNumber(), pin2); + adnRecordList = simPhoneBook.getAdnRecordsInEf(SimConstants.EF_ADN); + tmpAdn = adnRecordList.get(listIndex); + assertTrue(success); + assertFalse(firstAdn.isEqual(tmpAdn)); + assertTrue(secondAdn.isEqual(tmpAdn)); + + // erase be search + success = simPhoneBook.updateAdnRecordsInEfBySearch(SimConstants.EF_ADN, + secondAdn.getAlphaTag(), secondAdn.getNumber(), + emptyAdn.getAlphaTag(), emptyAdn.getNumber(), pin2); + adnRecordList = simPhoneBook.getAdnRecordsInEf(SimConstants.EF_ADN); + tmpAdn = adnRecordList.get(listIndex); + assertTrue(success); + assertTrue(tmpAdn.isEmpty()); + + // restore the orginial adn + success = simPhoneBook.updateAdnRecordsInEfByIndex(SimConstants.EF_ADN, + originalAdn.getAlphaTag(), originalAdn.getNumber(), adnIndex, + pin2); + adnRecordList = simPhoneBook.getAdnRecordsInEf(SimConstants.EF_ADN); + tmpAdn = adnRecordList.get(listIndex); + assertTrue(success); + assertTrue(originalAdn.isEqual(tmpAdn)); + } +} diff --git a/tests/CoreTests/com/android/internal/telephony/gsm/SimSmsTest.java b/tests/CoreTests/com/android/internal/telephony/gsm/SimSmsTest.java new file mode 100644 index 0000000000000000000000000000000000000000..6ced23d7a4d626c597f91f7c49d1384cd1e10de4 --- /dev/null +++ b/tests/CoreTests/com/android/internal/telephony/gsm/SimSmsTest.java @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2006 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.android.internal.telephony.gsm; + +import android.os.ServiceManager; +import android.test.suitebuilder.annotation.MediumTest; +import android.test.suitebuilder.annotation.Suppress; + +import java.util.List; + +import junit.framework.TestCase; + +public class SimSmsTest extends TestCase { + + @MediumTest + @Suppress // TODO: suppress this test for now since it doesn't work on the emulator + public void testBasic() throws Exception { + + ISms sms = ISms.Stub.asInterface(ServiceManager.getService("isms")); + assertNotNull(sms); + + List records = sms.getAllMessagesFromSimEf(); + assertNotNull(records); + assertTrue(records.size() >= 0); + + int firstNullIndex = -1; + int firstValidIndex = -1; + byte[] pdu = null; + for (int i = 0; i < records.size(); i++) { + SmsRawData data = records.get(i); + if (data != null && firstValidIndex == -1) { + firstValidIndex = i; + pdu = data.getBytes(); + } + if (data == null && firstNullIndex == -1) { + firstNullIndex = i; + } + if (firstNullIndex != -1 && firstValidIndex != -1) { + break; + } + } + if (firstNullIndex == -1 || firstValidIndex == -1) + return; + assertNotNull(pdu); + } +} diff --git a/tests/CoreTests/com/android/internal/telephony/gsm/SimUtilsTest.java b/tests/CoreTests/com/android/internal/telephony/gsm/SimUtilsTest.java new file mode 100644 index 0000000000000000000000000000000000000000..3fbc8f52f4e2f85eb4b8fd6ad379ba308da78c2f --- /dev/null +++ b/tests/CoreTests/com/android/internal/telephony/gsm/SimUtilsTest.java @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2006 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.android.internal.telephony.gsm; + +import com.android.internal.telephony.gsm.SimTlv; +import com.android.internal.telephony.gsm.SimUtils; +import junit.framework.TestCase; +import android.test.suitebuilder.annotation.SmallTest; + + +public class SimUtilsTest extends TestCase { + + @SmallTest + public void testBasic() throws Exception { + byte[] data, data2; + + /* + * bcdToString() + */ + + // An EF[ICCID] record + data = SimUtils.hexStringToBytes("981062400510444868f2"); + assertEquals("8901260450014484862", SimUtils.bcdToString(data, 0, data.length)); + + // skip the first and last bytes + assertEquals("0126045001448486", SimUtils.bcdToString(data, 1, data.length - 2)); + + // Stops on invalid BCD value + data = SimUtils.hexStringToBytes("98F062400510444868f2"); + assertEquals("890", SimUtils.bcdToString(data, 0, data.length)); + + /* + * bcdByteToInt() + */ + + assertEquals(98, SimUtils.bcdByteToInt((byte) 0x89)); + + // Out of range is treated as 0 + assertEquals(8, SimUtils.bcdByteToInt((byte) 0x8c)); + + /* + * adnStringFieldToString() + */ + + + data = SimUtils.hexStringToBytes("00566f696365204d61696c07918150367742f3ffffffffffff"); + // Again, skip prepended 0 + // (this is an EF[ADN] record) + assertEquals("Voice Mail", SimUtils.adnStringFieldToString(data, 1, data.length - 15)); + + data = SimUtils.hexStringToBytes("809673539A5764002F004DFFFFFFFFFF"); + // (this is from an EF[ADN] record) + assertEquals("\u9673\u539A\u5764/M", SimUtils.adnStringFieldToString(data, 0, data.length)); + + data = SimUtils.hexStringToBytes("810A01566fec6365204de0696cFFFFFF"); + // (this is made up to test since I don't have a real one) + assertEquals("Vo\u00ECce M\u00E0il", SimUtils.adnStringFieldToString(data, 0, data.length)); + + data = SimUtils.hexStringToBytes("820505302D82d32d31"); + // Example from 3GPP TS 11.11 V18.1.3.0 annex B + assertEquals("-\u0532\u0583-1", SimUtils.adnStringFieldToString(data, 0, data.length)); + } + +} + diff --git a/tests/CoreTests/com/android/internal/util/PredicatesTest.java b/tests/CoreTests/com/android/internal/util/PredicatesTest.java new file mode 100644 index 0000000000000000000000000000000000000000..c46ff051dd335d66d52ef89fa5d13d3ad370bfd7 --- /dev/null +++ b/tests/CoreTests/com/android/internal/util/PredicatesTest.java @@ -0,0 +1,74 @@ +/* + * 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.android.internal.util; + +import junit.framework.TestCase; + +import java.util.ArrayList; +import java.util.Collections; + +public class PredicatesTest extends TestCase { + + private static final Predicate TRUE = new Predicate() { + public boolean apply(Object o) { + return true; + } + }; + + private static final Predicate FALSE = new Predicate() { + public boolean apply(Object o) { + return false; + } + }; + + public void testAndPredicate_AllConditionsTrue() throws Exception { + assertTrue(Predicates.and(newArrayList(TRUE)).apply(null)); + assertTrue(Predicates.and(newArrayList(TRUE, TRUE)).apply(null)); + } + + public void testAndPredicate_AtLeastOneConditionIsFalse() throws Exception { + assertFalse(Predicates.and(newArrayList(FALSE, TRUE, TRUE)).apply(null)); + assertFalse(Predicates.and(newArrayList(TRUE, FALSE, TRUE)).apply(null)); + assertFalse(Predicates.and(newArrayList(TRUE, TRUE, FALSE)).apply(null)); + } + + public void testOrPredicate_AllConditionsTrue() throws Exception { + assertTrue(Predicates.or(newArrayList(TRUE, TRUE, TRUE)).apply(null)); + } + + public void testOrPredicate_AllConditionsFalse() throws Exception { + assertFalse(Predicates.or(newArrayList(FALSE, FALSE, FALSE)).apply(null)); + } + + public void testOrPredicate_AtLeastOneConditionIsTrue() throws Exception { + assertTrue(Predicates.or(newArrayList(TRUE, FALSE, FALSE)).apply(null)); + assertTrue(Predicates.or(newArrayList(FALSE, TRUE, FALSE)).apply(null)); + assertTrue(Predicates.or(newArrayList(FALSE, FALSE, TRUE)).apply(null)); + } + + public void testNotPredicate() throws Exception { + assertTrue(Predicates.not(FALSE).apply(null)); + assertFalse(Predicates.not(TRUE).apply(null)); + } + + private static ArrayList newArrayList(E... elements) { + ArrayList list = new ArrayList(); + Collections.addAll(list, elements); + return list; + } + +} diff --git a/tests/CoreTests/run_core_test.sh b/tests/CoreTests/run_core_test.sh new file mode 100755 index 0000000000000000000000000000000000000000..1fc33483b17f8a8811176ec6f60a57a545afab09 --- /dev/null +++ b/tests/CoreTests/run_core_test.sh @@ -0,0 +1,4 @@ +framework=/system/framework +bpath=$framework/core.jar:$framework/ext.jar:$framework/framework.jar:$framework/android.test.runner.jar +adb shell exec dalvikvm -Xbootclasspath:$bpath -cp system/app/CoreTests.apk \ + com.android.internal.util.WithFramework junit.textui.TestRunner $* diff --git a/tests/CoreTests/run_junit.sh b/tests/CoreTests/run_junit.sh new file mode 100755 index 0000000000000000000000000000000000000000..b77794df2f74b8efcdec7a954d6200a487fef6d2 --- /dev/null +++ b/tests/CoreTests/run_junit.sh @@ -0,0 +1,9 @@ +# runs unit tests over adb shell using dalvikvm. The value added is setting the classpath for you +# and pointing to the junit textui test runner. +# +# the normal usage might be: +# (make MoreJavaTests) +# $ adb sync +# $ java/tests/run_junit.sh android.util.MyTest + +adb shell exec dalvikvm -cp system/app/MoreTests.apk junit.textui.TestRunner $* diff --git a/tests/DumpRenderTree/Android.mk b/tests/DumpRenderTree/Android.mk new file mode 100644 index 0000000000000000000000000000000000000000..505a436420d1d7e4b997d502163ab12075e0da73 --- /dev/null +++ b/tests/DumpRenderTree/Android.mk @@ -0,0 +1,12 @@ +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_MODULE_TAGS := tests + +LOCAL_SRC_FILES := $(call all-subdir-java-files) + +LOCAL_JAVA_LIBRARIES := android.test.runner + +LOCAL_PACKAGE_NAME := DumpRenderTree + +include $(BUILD_PACKAGE) diff --git a/tests/DumpRenderTree/AndroidManifest.xml b/tests/DumpRenderTree/AndroidManifest.xml new file mode 100644 index 0000000000000000000000000000000000000000..8e06cc83228e2f98e442c5ef6231a9bcd1665dc5 --- /dev/null +++ b/tests/DumpRenderTree/AndroidManifest.xml @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + + + + + diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/CallbackProxy.java b/tests/DumpRenderTree/src/com/android/dumprendertree/CallbackProxy.java new file mode 100644 index 0000000000000000000000000000000000000000..a3894612100bf9de57f8fbce78c0206a33b23828 --- /dev/null +++ b/tests/DumpRenderTree/src/com/android/dumprendertree/CallbackProxy.java @@ -0,0 +1,328 @@ +/* + * Copyright (C) 2007 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.android.dumprendertree; + +import android.os.Handler; +import android.os.Message; + +import java.util.HashMap; + +public class CallbackProxy extends Handler implements EventSender, LayoutTestController { + + private EventSender mEventSender; + private LayoutTestController mLayoutTestController; + + private static final int EVENT_DOM_LOG = 1; + private static final int EVENT_FIRE_KBD = 2; + private static final int EVENT_KEY_DOWN_1 = 3; + private static final int EVENT_KEY_DOWN_2 = 4; + private static final int EVENT_LEAP = 5; + private static final int EVENT_MOUSE_CLICK = 6; + private static final int EVENT_MOUSE_DOWN = 7; + private static final int EVENT_MOUSE_MOVE = 8; + private static final int EVENT_MOUSE_UP = 9; + + private static final int LAYOUT_CLEAR_LIST = 20; + private static final int LAYOUT_DISPLAY = 21; + private static final int LAYOUT_DUMP_TEXT = 22; + private static final int LAYOUT_DUMP_HISTORY = 23; + private static final int LAYOUT_DUMP_CHILD_SCROLL = 24; + private static final int LAYOUT_DUMP_EDIT_CB = 25; + private static final int LAYOUT_DUMP_SEL_RECT = 26; + private static final int LAYOUT_DUMP_TITLE_CHANGES = 27; + private static final int LAYOUT_KEEP_WEB_HISTORY = 28; + private static final int LAYOUT_NOTIFY_DONE = 29; + private static final int LAYOUT_QUEUE_BACK_NAV = 30; + private static final int LAYOUT_QUEUE_FWD_NAV = 31; + private static final int LAYOUT_QUEUE_LOAD = 32; + private static final int LAYOUT_QUEUE_RELOAD = 33; + private static final int LAYOUT_QUEUE_SCRIPT = 34; + private static final int LAYOUT_REPAINT_HORZ = 35; + private static final int LAYOUT_SET_ACCEPT_EDIT = 36; + private static final int LAYOUT_MAIN_FIRST_RESP = 37; + private static final int LAYOUT_SET_WINDOW_KEY = 38; + private static final int LAYOUT_TEST_REPAINT = 39; + private static final int LAYOUT_WAIT_UNTIL_DONE = 40; + + CallbackProxy(EventSender eventSender, + LayoutTestController layoutTestController) { + mEventSender = eventSender; + mLayoutTestController = layoutTestController; + } + + public void handleMessage(Message msg) { + switch (msg.what) { + case EVENT_DOM_LOG: + mEventSender.enableDOMUIEventLogging(msg.arg1); + break; + case EVENT_FIRE_KBD: + mEventSender.fireKeyboardEventsToElement(msg.arg1); + break; + case EVENT_KEY_DOWN_1: + HashMap map = (HashMap) msg.obj; + mEventSender.keyDown((String) map.get("character"), + (String[]) map.get("withModifiers")); + break; + + case EVENT_KEY_DOWN_2: + mEventSender.keyDown((String)msg.obj); + break; + + case EVENT_LEAP: + mEventSender.leapForward(msg.arg1); + break; + + case EVENT_MOUSE_CLICK: + mEventSender.mouseClick(); + break; + + case EVENT_MOUSE_DOWN: + mEventSender.mouseDown(); + break; + + case EVENT_MOUSE_MOVE: + mEventSender.mouseMoveTo(msg.arg1, msg.arg2); + break; + + case EVENT_MOUSE_UP: + mEventSender.mouseUp(); + break; + + case LAYOUT_CLEAR_LIST: + mLayoutTestController.clearBackForwardList(); + break; + + case LAYOUT_DISPLAY: + mLayoutTestController.display(); + break; + + case LAYOUT_DUMP_TEXT: + mLayoutTestController.dumpAsText(); + break; + + case LAYOUT_DUMP_HISTORY: + mLayoutTestController.dumpBackForwardList(); + break; + + case LAYOUT_DUMP_CHILD_SCROLL: + mLayoutTestController.dumpChildFrameScrollPositions(); + break; + + case LAYOUT_DUMP_EDIT_CB: + mLayoutTestController.dumpEditingCallbacks(); + break; + + case LAYOUT_DUMP_SEL_RECT: + mLayoutTestController.dumpSelectionRect(); + break; + + case LAYOUT_DUMP_TITLE_CHANGES: + mLayoutTestController.dumpTitleChanges(); + break; + + case LAYOUT_KEEP_WEB_HISTORY: + mLayoutTestController.keepWebHistory(); + break; + + case LAYOUT_NOTIFY_DONE: + mLayoutTestController.notifyDone(); + break; + + case LAYOUT_QUEUE_BACK_NAV: + mLayoutTestController.queueBackNavigation(msg.arg1); + break; + + case LAYOUT_QUEUE_FWD_NAV: + mLayoutTestController.queueForwardNavigation(msg.arg1); + break; + + case LAYOUT_QUEUE_LOAD: + HashMap loadMap = + (HashMap) msg.obj; + mLayoutTestController.queueLoad(loadMap.get("Url"), + loadMap.get("frameTarget")); + break; + + case LAYOUT_QUEUE_RELOAD: + mLayoutTestController.queueReload(); + break; + + case LAYOUT_QUEUE_SCRIPT: + mLayoutTestController.queueScript((String)msg.obj); + break; + + case LAYOUT_REPAINT_HORZ: + mLayoutTestController.repaintSweepHorizontally(); + break; + + case LAYOUT_SET_ACCEPT_EDIT: + mLayoutTestController.setAcceptsEditing( + msg.arg1 == 1 ? true : false); + break; + case LAYOUT_MAIN_FIRST_RESP: + mLayoutTestController.setMainFrameIsFirstResponder( + msg.arg1 == 1 ? true : false); + break; + + case LAYOUT_SET_WINDOW_KEY: + mLayoutTestController.setWindowIsKey( + msg.arg1 == 1 ? true : false); + break; + + case LAYOUT_TEST_REPAINT: + mLayoutTestController.testRepaint(); + break; + + case LAYOUT_WAIT_UNTIL_DONE: + mLayoutTestController.waitUntilDone(); + break; + } + } + + // EventSender Methods + + public void enableDOMUIEventLogging(int DOMNode) { + obtainMessage(EVENT_DOM_LOG, DOMNode, 0).sendToTarget(); + } + + public void fireKeyboardEventsToElement(int DOMNode) { + obtainMessage(EVENT_FIRE_KBD, DOMNode, 0).sendToTarget(); + } + + public void keyDown(String character, String[] withModifiers) { + // TODO Auto-generated method stub + HashMap map = new HashMap(); + map.put("character", character); + map.put("withModifiers", withModifiers); + obtainMessage(EVENT_KEY_DOWN_1, map).sendToTarget(); + } + + public void keyDown(String character) { + obtainMessage(EVENT_KEY_DOWN_2, character).sendToTarget(); + } + + public void leapForward(int milliseconds) { + obtainMessage(EVENT_LEAP, milliseconds, 0).sendToTarget(); + } + + public void mouseClick() { + obtainMessage(EVENT_MOUSE_CLICK).sendToTarget(); + } + + public void mouseDown() { + obtainMessage(EVENT_MOUSE_DOWN).sendToTarget(); + } + + public void mouseMoveTo(int X, int Y) { + obtainMessage(EVENT_MOUSE_MOVE, X, Y).sendToTarget(); + } + + public void mouseUp() { + obtainMessage(EVENT_MOUSE_UP).sendToTarget(); + } + + // LayoutTestController Methods + + public void clearBackForwardList() { + obtainMessage(LAYOUT_CLEAR_LIST).sendToTarget(); + } + + public void display() { + obtainMessage(LAYOUT_DISPLAY).sendToTarget(); + } + + public void dumpAsText() { + obtainMessage(LAYOUT_DUMP_TEXT).sendToTarget(); + } + + public void dumpBackForwardList() { + obtainMessage(LAYOUT_DUMP_HISTORY).sendToTarget(); + } + + public void dumpChildFrameScrollPositions() { + obtainMessage(LAYOUT_DUMP_CHILD_SCROLL).sendToTarget(); + } + + public void dumpEditingCallbacks() { + obtainMessage(LAYOUT_DUMP_EDIT_CB).sendToTarget(); + } + + public void dumpSelectionRect() { + obtainMessage(LAYOUT_DUMP_SEL_RECT).sendToTarget(); + } + + public void dumpTitleChanges() { + obtainMessage(LAYOUT_DUMP_TITLE_CHANGES).sendToTarget(); + } + + public void keepWebHistory() { + obtainMessage(LAYOUT_KEEP_WEB_HISTORY).sendToTarget(); + } + + public void notifyDone() { + obtainMessage(LAYOUT_NOTIFY_DONE).sendToTarget(); + } + + public void queueBackNavigation(int howfar) { + obtainMessage(LAYOUT_QUEUE_BACK_NAV, howfar, 0).sendToTarget(); + } + + public void queueForwardNavigation(int howfar) { + obtainMessage(LAYOUT_QUEUE_FWD_NAV, howfar, 0).sendToTarget(); + } + + public void queueLoad(String Url, String frameTarget) { + HashMap map = new HashMap(); + map.put("Url", Url); + map.put("frameTarget", frameTarget); + obtainMessage(LAYOUT_QUEUE_LOAD, map).sendToTarget(); + } + + public void queueReload() { + obtainMessage(LAYOUT_QUEUE_RELOAD).sendToTarget(); + } + + public void queueScript(String scriptToRunInCurrentContext) { + obtainMessage(LAYOUT_QUEUE_SCRIPT, + scriptToRunInCurrentContext).sendToTarget(); + } + + public void repaintSweepHorizontally() { + obtainMessage(LAYOUT_REPAINT_HORZ).sendToTarget(); + } + + public void setAcceptsEditing(boolean b) { + obtainMessage(LAYOUT_SET_ACCEPT_EDIT, b ? 1 : 0, 0).sendToTarget(); + } + + public void setMainFrameIsFirstResponder(boolean b) { + obtainMessage(LAYOUT_MAIN_FIRST_RESP, b ? 1 : 0, 0).sendToTarget(); + } + + public void setWindowIsKey(boolean b) { + obtainMessage(LAYOUT_SET_WINDOW_KEY,b ? 1 : 0, 0).sendToTarget(); + } + + public void testRepaint() { + obtainMessage(LAYOUT_TEST_REPAINT).sendToTarget(); + } + + public void waitUntilDone() { + obtainMessage(LAYOUT_WAIT_UNTIL_DONE).sendToTarget(); + } + +} diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/EventSender.java b/tests/DumpRenderTree/src/com/android/dumprendertree/EventSender.java new file mode 100644 index 0000000000000000000000000000000000000000..82fd8d8d61de01a16d2fe19163567944c4fdfa31 --- /dev/null +++ b/tests/DumpRenderTree/src/com/android/dumprendertree/EventSender.java @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2007 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.android.dumprendertree; + +public interface EventSender { + public void mouseDown(); + public void mouseUp(); + public void mouseClick(); + public void mouseMoveTo(int X, int Y); + public void leapForward(int milliseconds); + public void keyDown (String character, String[] withModifiers); + public void keyDown (String character); + public void enableDOMUIEventLogging(int DOMNode); + public void fireKeyboardEventsToElement(int DOMNode); +} diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/FileFilter.java b/tests/DumpRenderTree/src/com/android/dumprendertree/FileFilter.java new file mode 100644 index 0000000000000000000000000000000000000000..5a73759af6949cc15d54077e303c7d5bf901deee --- /dev/null +++ b/tests/DumpRenderTree/src/com/android/dumprendertree/FileFilter.java @@ -0,0 +1,242 @@ +/* + * Copyright (C) 2007 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.android.dumprendertree; + +import java.util.HashSet; +import java.util.Hashtable; +import android.util.*; + +public class FileFilter { + + public static boolean ignoreTest(String file) { + // treat files like directories for the time being. + int size = ignoreTestList.length; + for (int i = 0; i < size; i ++) { + if (file.startsWith(ignoreTestList[i])) { + Log.e("FileFilter", "File path in IgnoreTest: " + file); + return true; + } + } + return false; + } + + public static boolean ignoreResults(String file) { + int index = file.indexOf("fast"); + if (index != -1) { + String sub = file.substring(index); + if (ignoreResultList.contains(sub)) + return true; + } + return false; + + } + + public static String isKnownBug(String file) { + int index = file.indexOf("fast"); + if (index != -1) { + String sub = file.substring(index); + // Log.e("FileFilter", "Looking for:"+sub); + if (bugList.containsKey(sub)) + return bugList.get(sub); + } + return null; + } + + final static HashSet ignoreResultList = new HashSet(); + final static Hashtable bugList = + new Hashtable(); + + static { + fillIgnoreResultSet(); + fillBugTable(); + } + + static final String [] ignoreTestList = { + ".", // ignore hidden directories and files + "resources", // ignore resource directories + "AppleScript", // AppleScript not supported + "xpath", // xpath requires libxml2, not supported + "xsl", //xsl requires libxml2 & libxslt, not sup. + "kde", // don't run kde tests. + ".svn", // don't run anything under .svn folder + "gradients", //known crash + "toString-stack-overflow.html", // Crashes #606688 + "frame-limit.html", // generates too many GREFs + "css-insert-import-rule.html", // Crashes, #717414 + "input-text-enter.html", // Crashes. #735088 + "text-shadow-extreme-value.html", // Crashes #571671 + "001.html", + "reflection-masks.html", + "frame-creation-removal.html", + "large-expressions.html", + "null-page-show-modal-dialog-crash.html", + "font-face-implicit-local-font.html", + "font-face-locally-installed.html", + "beforeSelectorOnCodeElement.html", + "cssTarget-crash.html" + }; + + static void fillIgnoreResultSet() { + // need test plugin + ignoreResultList.add("fast/dom/Window/Plug-ins.html"); + // pixel depth + ignoreResultList.add("fast/dom/Window/window-screen-properties.html"); + // missing space in textrun, ok as text is wrapped. ignore. #714933 + ignoreResultList.add("fast/events/onload-webkit-before-webcore.html"); + // missing support for textInputController.makeAttributedString() + ignoreResultList.add("fast/forms/attributed-strings.html"); + // charset convert. #516936 ignore, won't fix + ignoreResultList.add("fast/forms/form-data-encoding-2.html"); + // charset convert. #516936 ignore, won't fix + ignoreResultList.add("fast/forms/form-data-encoding.html"); + // execCommand "insertText" not supported + ignoreResultList.add("fast/forms/input-appearance-maxlength.html"); + // Copy&Paste commands not supported + ignoreResultList.add("fast/forms/input-truncate-newline.html"); + ignoreResultList.add("fast/forms/textarea-paste-newline.html"); + // requires eventSender.mouseMoveTo, mouseDown & mouseUp and + // abs. position of mouse to select a word. ignore, won't fix #716583 + ignoreResultList.add("fast/forms/onselect-textarea.html"); + // requires eventSender.mouseMoveTo, mouseDown & mouseUp and + // abs. position of mouse to select a word. ignore, won't fix #716583 + ignoreResultList.add("fast/forms/onselect-textfield.html"); + // not implemented queryCommandEnabled:BackColor, Undo & Redo + ignoreResultList.add("fast/forms/plaintext-mode-1.html"); + // Our text areas are a little thinner than Apples. Also RTL test failes + ignoreResultList.add("fast/forms/textarea-appearance-wrap.html"); + // Our text areas are a little thinner than Apples + ignoreResultList.add("fast/forms/textarea-hard-linewrap.html"); + // screen width&height are different + ignoreResultList.add("fast/frames/frameElement-widthheight.html"); + ignoreResultList.add("fast/frames/frame-js-url-clientWidth.html"); + // requires JS test API, textInputController + ignoreResultList.add("fast/text/attributed-substring-from-range.html"); + ignoreResultList.add("fast/text/attributed-substring-from-range-001.html"); + // will not fix #619707 + ignoreResultList.add("fast/css/case-transform.html"); + // different platform defaults for font and different screen size + ignoreResultList.add("fast/css/computed-style.html"); + // different screen size result in extra spaces in Apple compared to us + ignoreResultList.add("fast/dom/Element/offsetLeft-offsetTop-body-quirk.html"); + // xslt and xpath elements missing from property list + ignoreResultList.add("fast/dom/Window/window-properties.html"); + // requires textInputController.characterIndexForPoint + ignoreResultList.add("fast/dom/character-index-for-point.html"); + // requires xpath support + ignoreResultList.add("fast/dom/gc-9.html"); + // requires xslt and xpath support + ignoreResultList.add("fast/dom/global-constructors.html"); + // dynamic plugins not supported + ignoreResultList.add("fast/dom/object-embed-plugin-scripting.html"); + ignoreResultList.add("fast/js/navigator-mimeTypes-length.html"); + // there is extra spacing in the file due to multiple input boxes + // fitting on one line on Apple, ours are wrapped. Space at line ends + // are stripped. + ignoreResultList.add("fast/dom/tabindex-clamp.html"); + + // requires eventSender.mouseDown(),mouseUp() + ignoreResultList.add("fast/dom/Window/window-xy-properties.html"); + ignoreResultList.add("fast/events/window-events-bubble.html"); + ignoreResultList.add("fast/events/window-events-bubble2.html"); + ignoreResultList.add("fast/events/window-events-capture.html"); + ignoreResultList.add("fast/forms/select-empty-list.html"); + ignoreResultList.add("fast/replaced/image-map.html"); + ignoreResultList.add("fast/events/capture-on-target.html"); + ignoreResultList.add("fast/events/dblclick-addEventListener.html"); + ignoreResultList.add("fast/events/drag-in-frames.html"); + ignoreResultList.add("fast/events/drag-outside-window.html"); + ignoreResultList.add("fast/events/event-sender-mouse-click.html"); + ignoreResultList.add("fast/events/event-view-toString.html"); + ignoreResultList.add("fast/events/frame-click-focus.html"); + ignoreResultList.add("fast/events/input-image-scrolled-x-y.html"); + ignoreResultList.add("fast/events/anchor-image-scrolled-x-y.html"); + ignoreResultList.add("fast/events/mouseclick-target-and-positioning.html"); + ignoreResultList.add("fast/events/mouseover-mouseout.html"); + ignoreResultList.add("fast/events/mouseover-mouseout2.html"); + ignoreResultList.add("fast/events/mouseup-outside-button.html"); + ignoreResultList.add("fast/events/mouseup-outside-document.html"); + ignoreResultList.add("fast/events/onclick-list-marker.html"); + ignoreResultList.add("fast/events/ondragenter.html"); + ignoreResultList.add("fast/forms/drag-into-textarea.html"); + ignoreResultList.add("fast/forms/input-select-on-click.html"); + ignoreResultList.add("fast/forms/listbox-onchange.html"); + ignoreResultList.add("fast/forms/search-cancel-button-mouseup.html"); + ignoreResultList.add("fast/forms/textarea-scrolled-endline-caret.html"); + + // there is extra spacing in the file due to multiple frame boxes + // fitting on one line on Apple, ours are wrapped. Space at line ends + // are stripped. + ignoreResultList.add("fast/events/iframe-object-onload.html"); + // eventSender.mouseDown(), mouseUp() and objc API missing + ignoreResultList.add("fast/events/mouseup-outside-document.html"); + ignoreResultList.add("fast/events/objc-keyboard-event-creation.html"); + ignoreResultList.add("fast/events/objc-event-api.html"); + // not capturing the console messages + ignoreResultList.add("fast/forms/selected-index-assert.html"); + ignoreResultList.add("fast/parser/script-tag-with-trailing-slash.html"); + // there is extra spacing as the text areas and input boxes fit next + // to each other on Apple, but are wrapped on our screen. + ignoreResultList.add("fast/forms/selection-functions.html"); + // Text selection done differently on our platform. When a inputbox + // gets focus, the entire block is selected. + ignoreResultList.add("fast/forms/textarea-initial-caret-position.html"); + ignoreResultList.add("fast/forms/textarea-no-scroll-on-blur.html"); + // Requires LayoutTests to exist at /tmp/LayoutTests + ignoreResultList.add("fast/loader/local-JavaScript-from-local.html"); + ignoreResultList.add("fast/loader/local-iFrame-source-from-local.html"); + // extra spacing because iFrames rendered next to each other on Apple + ignoreResultList.add("fast/loader/opaque-base-url.html"); + ignoreResultList.add("fast/text/plain-text-line-breaks.html"); + + + } + + static void fillBugTable() { + bugList.put("fast/forms/check-box-enter-key.html", "716715"); + bugList.put("fast/forms/focus-control-to-page.html", "716638"); + bugList.put("fast/html/tab-order.html", "719289"); + bugList.put("fast/dom/attribute-namespaces-get-set.html", "733229"); + bugList.put("fast/dom/location-hash.html", "733822"); + bugList.put("fast/dom/set-innerHTML.html", "733823"); + bugList.put("fast/dom/xmlhttprequest-get.html", "733846"); + bugList.put("fast/encoding/css-charset-default.html", "733856"); + bugList.put("fast/encoding/default-xhtml-encoding.html", "733882"); + bugList.put("fast/encoding/meta-in-xhtml.html", "733882"); + bugList.put("fast/events/frame-tab-focus.html", "734308"); + bugList.put("fast/events/keydown-keypress-focus-change.html", "653224"); + bugList.put("fast/events/keypress-focus-change.html", "653224"); + bugList.put("fast/events/option-tab.html", "734308"); + bugList.put("fast/forms/focus2.html", "735111"); + bugList.put("fast/forms/listbox-selection.html", "735116"); + bugList.put("fast/forms/search-event-delay.html", "735120"); + bugList.put("fast/frames/iframe-window-focus.html", "735140"); + bugList.put("fast/innerHTML/004.html", "733882"); + bugList.put("fast/js/date-DST-time-cusps.html", "735144"); + bugList.put("fast/js/string-capitalization.html", "516936"); + bugList.put("fast/js/string-concatenate-outofmemory.html","735152"); + bugList.put("fast/parser/external-entities.html", "735176"); + bugList.put("fast/events/div-focus.html", "735185"); + bugList.put("fast/overflow/scroll-vertical-not-horizontal.html", "735196"); + bugList.put("fast/events/arrow-navigation.html", "735233"); + bugList.put("fast/forms/select-type-ahead-non-latin.html", "735244"); + bugList.put("fast/events/js-keyboard-event-creation.html", "735255"); + + } + + + +} diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/FileList.java b/tests/DumpRenderTree/src/com/android/dumprendertree/FileList.java new file mode 100644 index 0000000000000000000000000000000000000000..8b33d16a7806bd3823b626feafa62b92d442a028 --- /dev/null +++ b/tests/DumpRenderTree/src/com/android/dumprendertree/FileList.java @@ -0,0 +1,160 @@ +/* + * Copyright (C) 2007 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.android.dumprendertree; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.io.File; + +import android.app.ListActivity; +import android.view.KeyEvent; +import android.view.View; +import android.widget.ListView; +import android.widget.SimpleAdapter; +import android.os.Bundle; + + +public abstract class FileList extends ListActivity +{ + public boolean onKeyDown(int keyCode, KeyEvent event) { + switch (keyCode) + { + case KeyEvent.KEYCODE_DPAD_LEFT: + if (mPath.length() > mBaseLength) { + File f = new File(mPath); + mFocusFile = f.getName(); + mFocusIndex = 0; + f = f.getParentFile(); + mPath = f.getPath(); + updateList(); + return true; + } + break; + + case KeyEvent.KEYCODE_DPAD_RIGHT: + { + Map map = (Map) getListView().getItemAtPosition(getListView().getSelectedItemPosition()); + String path = (String)map.get("path"); + if ((new File(path)).isDirectory()) { + mPath = path; + mFocusFile = null; + updateList(); + } else { + processFile(path, false); + } + return true; + } + + default: + break; + } + return super.onKeyDown(keyCode, event); + } + + public void onCreate(Bundle icicle) + { + super.onCreate(icicle); + setupPath(); + updateList(); + } + + protected List getData() + { + List myData = new ArrayList(); + + File f = new File(mPath); + if (!f.exists()) { + addItem(myData, "!LayoutTests path missing!", ""); + return myData; + } + String[] files = f.list(); + + for (int i = 0; i < files.length; i++) { + StringBuilder sb = new StringBuilder(mPath); + sb.append(File.separatorChar); + sb.append(files[i]); + String path = sb.toString(); + File c = new File(path); + if (fileFilter(c)) { + if (c.isDirectory()) { + addItem(myData, "<"+files[i]+">", path); + if (mFocusFile != null && mFocusFile.equals(files[i])) + mFocusIndex = myData.size()-1; + } + else + addItem(myData, files[i], path); + } + } + + return myData; + } + + protected void addItem(List data, String name, String path) + { + HashMap temp = new HashMap(); + temp.put("title", name); + temp.put("path", path); + data.add(temp); + } + + protected void onListItemClick(ListView l, View v, int position, long id) + { + Map map = (Map) l.getItemAtPosition(position); + String path = (String)map.get("path"); + if (path.length() > 0) + processFile(path, true); + + } + + /* + * This function is called when the user has selected a file in the + * file list. The selected file could be a file or a directory. + * The flag indicates if this was from a selection or not. + */ + abstract void processFile(String filename, boolean selection); + + /* + * This function is called when the file list is being built. Return + * true if the file is to be added to the file list. + */ + abstract boolean fileFilter(File f); + + protected void updateList() { + setListAdapter(new SimpleAdapter(this, + getData(), + android.R.layout.simple_list_item_1, + new String[] {"title"}, + new int[] {android.R.id.text1})); + String title = mPath; //.substring(mBaseLength-11); // show the word LayoutTests + setTitle(title); + getListView().setSelection(mFocusIndex); + } + + protected void setupPath() + { + mPath = "/sdcard"; + mBaseLength = mPath.length(); + } + + protected String mPath; + protected int mBaseLength; + protected String mFocusFile; + protected int mFocusIndex; + +} diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/HTMLHostActivity.java b/tests/DumpRenderTree/src/com/android/dumprendertree/HTMLHostActivity.java new file mode 100644 index 0000000000000000000000000000000000000000..9521f8038656ff58fa4976408d39a74ef079f5ec --- /dev/null +++ b/tests/DumpRenderTree/src/com/android/dumprendertree/HTMLHostActivity.java @@ -0,0 +1,607 @@ +/* + * Copyright (C) 2007 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.android.dumprendertree; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.BufferedOutputStream; +import java.io.FileInputStream; +import java.io.IOException; +import java.util.Vector; +import java.util.Stack; + +import android.app.Activity; +import android.content.Intent; +import android.os.Bundle; +import android.util.Log; +import android.view.KeyEvent; +import android.view.ViewGroup; +import android.webkit.JsPromptResult; +import android.webkit.JsResult; +import android.webkit.WebChromeClient; +import android.webkit.WebSettings; +import android.webkit.WebView; +import android.widget.LinearLayout; +import android.os.*; +import android.test.TestRecorder; + +// SQLite3 in android has a bunch of bugs which +// is causing TestRecorder to not record the results +// properly. This class is a wrapper around it and records +// results in a file as well. +class TestRecorderV2 extends TestRecorder { + @Override + public void passed(String layout_file) { + try { + mBufferedOutputPassedStream.write(layout_file.getBytes()); + mBufferedOutputPassedStream.write('\n'); + mBufferedOutputPassedStream.flush(); + } catch(Exception e) { + e.printStackTrace(); + } + super.passed(layout_file); + } + + @Override + public void failed(String layout_file, String reason) { + try { + mBufferedOutputFailedStream.write(layout_file.getBytes()); + mBufferedOutputFailedStream.write('\n'); + mBufferedOutputFailedStream.flush(); + } catch(Exception e) { + e.printStackTrace(); + } + super.failed(layout_file, reason); + } + + public TestRecorderV2() { + super(); + try { + File resultsPassedFile = new File("/sdcard/layout_test_presults.txt"); + File resultsFailedFile = new File("/sdcard/layout_test_fresults.txt"); + + mBufferedOutputPassedStream = + new BufferedOutputStream(new FileOutputStream(resultsPassedFile, true)); + mBufferedOutputFailedStream = + new BufferedOutputStream(new FileOutputStream(resultsFailedFile, true)); + + } catch (Exception e) { + e.printStackTrace(); + } + } + + protected void finalize() throws Throwable { + mBufferedOutputPassedStream.flush(); + mBufferedOutputFailedStream.flush(); + mBufferedOutputPassedStream.close(); + mBufferedOutputFailedStream.close(); + } + + private static BufferedOutputStream mBufferedOutputPassedStream; + private static BufferedOutputStream mBufferedOutputFailedStream; +} + +public class HTMLHostActivity extends Activity + implements LayoutTestController { + + private TestRecorderV2 mResultRecorder = new TestRecorderV2(); + private HTMLHostCallbackInterface mCallback = null; + private CallbackProxy mCallbackProxy; + + public class FileEntry { + public FileEntry(String path, int index) { + mPath = path; mIndex=index; + } + String mPath; + int mIndex; + } + + public class AsyncHandler extends Handler { + @Override + public void handleMessage(Message msg) { + if (msg.what == MSG_DUMP) { + this.removeMessages(MSG_TIMEOUT); + mTimedOut = false; + requestWebKitData(); + return; + } else if (msg.what == MSG_TIMEOUT) { + mTimedOut = true; + requestWebKitData(); + return; + } else if (msg.what == MSG_WEBKIT_DATA) { + HTMLHostActivity.this.dump(mTimedOut, (String)msg.obj); + return; + } + + super.handleMessage(msg); + } + + void requestWebKitData() { + Message callback = obtainMessage(MSG_WEBKIT_DATA); + if (dumpAsText) { + mWebView.documentAsText(callback); + } else { + mWebView.externalRepresentation(callback); + } + } + + } + + // Activity methods + public void onCreate(Bundle icicle) { + super.onCreate(icicle); + + LinearLayout contentView = new LinearLayout(this); + contentView.setOrientation(LinearLayout.VERTICAL); + setContentView(contentView); + + mWebView = new WebView(this); + mWebView.getSettings().setJavaScriptEnabled(true); + mWebView.setWebChromeClient(mChromeClient); + eventSender = new WebViewEventSender(mWebView); + mCallbackProxy = new CallbackProxy(eventSender, this); + + mWebView.addJavascriptInterface(mCallbackProxy, "layoutTestController"); + mWebView.addJavascriptInterface(mCallbackProxy, "eventSender"); + contentView.addView(mWebView, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.FILL_PARENT, 0.0f)); + + mHandler = new AsyncHandler(); + } + + @Override + protected void onRestoreInstanceState(Bundle savedInstanceState) { + super.onRestoreInstanceState(savedInstanceState); + } + + protected void onResume() { + super.onResume(); + if (mProcessStack == null || mProcessStack.isEmpty() ) { + mOutstandingLoads = 0; + dumpAsText = false; + pageComplete = false; + + mWebView.getSettings().setLayoutAlgorithm(WebSettings.LayoutAlgorithm.NORMAL); + + mFinishedStack = new Stack(); + + Intent intent = getIntent(); + if (intent.getData() != null) { + File f = new File(intent.getData().toString()); + + if (f.isDirectory()) { + mProcessStack = new Vector(); + mProcessStack.add(new FileEntry(intent.getData().toString(), 0)); + Log.v(LOGTAG, "Initial dir: "+intent.getData().toString()); + loadNextPage(); + } else { + mCurrentFile = intent.getData().toString(); + mWebView.loadUrl("file://"+intent.getData().toString()); + } + + } + else + mWebView.loadUrl("about:"); + } + } + + protected void onStop() { + super.onStop(); + mWebView.stopLoading(); + } + + protected void onDestroy() { + super.onDestroy(); + mWebView.destroy(); + mWebView = null; + } + + public boolean dispatchKeyEvent(KeyEvent event) { + // Log key strokes as they don't seem to be matched + //Log.e(LOGTAG, "Event: "+event); + return super.dispatchKeyEvent(event); + } + + // Functions + + protected void loadNextPage() { + dumpAsText = false; + pageComplete = false; + dumpTitleChanges = false; + eventSender.resetMouse(); + while (!mProcessStack.isEmpty()) { + FileEntry fe = (FileEntry)mProcessStack.remove(0); + if (fe.mIndex == 0) { + System.out.println(); + System.out.print(fe.mPath); + } + Log.v(LOGTAG, "Processing dir: "+fe.mPath+" size: "+mProcessStack.size()); + File f = new File(fe.mPath); + String [] files = f.list(); + for (int i = fe.mIndex; i < files.length; i++) { + if (FileFilter.ignoreTest(files[i])) { + continue; + } + File c = new File(f.getPath(), files[i]); + if (c.isDirectory()) { + Log.v(LOGTAG, "Adding dir: "+fe.mPath+"/"+files[i]); + mProcessStack.add(new FileEntry(fe.mPath+"/"+files[i], 0)); + } else if (files[i].toLowerCase().endsWith("ml")) { + mProcessStack.add(0, new FileEntry(fe.mPath, i+1)); + mCurrentFile = fe.mPath+"/"+files[i]; + Log.e(LOGTAG, "Processing: "+mCurrentFile); + mWebView.loadUrl("file://"+mCurrentFile); + + // Create a timeout timer + Message m = mHandler.obtainMessage(MSG_TIMEOUT); + // Some tests can take up to 5secs to run. + mHandler.sendMessageDelayed(m, 6000); + return; + } + } + Log.v(LOGTAG, "Finished dir: "+fe.mPath+" size: "+mProcessStack.size()); + } + // If we got to here, then we must have finished completely + finished(); + } + + public void scheduleDump() { + // Only schedule if we really are ready + if (waitToDump || mOutstandingLoads > 0 || mDumpRequested) { + return; + } + mDumpRequested = true; + mHandler.obtainMessage(MSG_DUMP).sendToTarget(); + } + + // Dump the page + public void dump(boolean timeout, String webkitData) { + mDumpRequested = false; + System.out.print('.'); + + // remove the extension + String resultFile = mCurrentFile.substring(0, mCurrentFile.lastIndexOf('.')); + + // store the finished file on the stack so that we can do a diff at the end. + mFinishedStack.push(resultFile); + + // dumpAsText version can be directly compared to expected results + if (dumpAsText) { + resultFile += "-results.txt"; + } else { + resultFile += "-android-results.txt"; + } + try { + FileOutputStream os = new FileOutputStream(resultFile); + if (timeout) { + Log.i("Layout test: Timeout", resultFile); + os.write("**Test timeout\n".getBytes()); + } + if (dumpTitleChanges) + os.write(mTitleChanges.toString().getBytes()); + if (mDialogStrings != null) + os.write(mDialogStrings.toString().getBytes()); + mDialogStrings = null; + os.write(webkitData.getBytes()); + os.flush(); + os.close(); + } catch (FileNotFoundException ex) { + ex.printStackTrace(); + } catch (IOException ex) { + ex.printStackTrace(); + } + + if (mProcessStack != null) + loadNextPage(); + else + finished(); + } + + // Wrap up + public void failedCase(String file, String reason) { + Log.i("Layout test:", file + " failed" + reason); + mResultRecorder.failed(file, reason); + + file = file + ".html"; + String bugNumber = FileFilter.isKnownBug(file); + if (bugNumber != null) { + System.out.println("FAIL known:"+bugNumber+ " "+file+reason); + return; + } + if (FileFilter.ignoreResults(file)) { + return; + } + System.out.println("FAIL: "+file+reason); + } + + public void passedCase(String file) { + // Add the result to the sqlite database + Log.i("Layout test:", file + " passed"); + mResultRecorder.passed(file); + + file = file + ".html"; + String bugNumber = FileFilter.isKnownBug(file); + if (bugNumber != null) { + System.out.println("Bug Fixed: "+bugNumber+ " "+file); + return; + } + + if (FileFilter.ignoreResults(file)) { + System.out.println("Ignored test passed: "+file); + return; + } + } + + public void setCallback(HTMLHostCallbackInterface callback) { + mCallback = callback; + } + + public void finished() { + int passed = 0; + while (!mFinishedStack.empty()) { + Log.v(LOGTAG, "Comparing dump and reference"); + String file = (String)mFinishedStack.pop(); + + // Only check results that we can check, ie dumpAsText results + String dumpFile = file + "-results.txt"; + File f = new File(dumpFile); + if (f.exists()) { + try { + FileInputStream fr = new FileInputStream(file+"-results.txt"); + FileInputStream fe = new FileInputStream(file+"-expected.txt"); + + mResultRecorder.started(file); + + // If the length is different then they are different + int diff = fe.available() - fr.available(); + if (diff > 1 || diff < 0) { + failedCase(file, " different length"); + fr.close(); + fe.close(); + + mResultRecorder.finished(file); + continue; + } + byte[] br = new byte[fr.available()]; + byte[] be = new byte[fe.available()]; + fr.read(br); + fe.read(be); + boolean fail = false; + for (int i = 0; i < br.length; i++) { + if (br[i] != be[i]) { + failedCase(file, " @offset: "+i); + fail = true; + break; + } + } + if (br.length != be.length && be[be.length-1] == '\n') { + Log.d(LOGTAG, "Extra new line being ignore:" + file); + } + fr.close(); + fe.close(); + if (!fail) { + passed++; + passedCase(file); + } + } catch (FileNotFoundException ex) { + // TODO do something here + } catch (IOException ex) { + // Failed on available() or read() + } + mResultRecorder.finished(file); + } + } + + if (mCallback != null) { + mCallback.waitForFinish(); + } + + finish(); + } + + // LayoutTestController Functions + public void dumpAsText() { + dumpAsText = true; + String url = mWebView.getUrl(); + Log.v(LOGTAG, "dumpAsText called:"+url); + if (url.length() > 60) + url = url.substring(60); + } + + public void waitUntilDone() { + waitToDump = true; + } + public void notifyDone() { + waitToDump = false; + mChromeClient.onProgressChanged(mWebView, 100); + } + public void display() { + mWebView.invalidate(); + } + + public void clearBackForwardList() { + mWebView.clearHistory(); + + } + + public void dumpBackForwardList() { + //printf("\n============== Back Forward List ==============\n"); + // mWebHistory + //printf("===============================================\n"); + + } + + public void dumpChildFrameScrollPositions() { + // TODO Auto-generated method stub + + } + + public void dumpEditingCallbacks() { + // TODO Auto-generated method stub + + } + + public void dumpSelectionRect() { + // TODO Auto-generated method stub + + } + + public void dumpTitleChanges() { + if (!dumpTitleChanges) { + mTitleChanges = new StringBuffer(); + } + dumpTitleChanges = true; + } + + public void keepWebHistory() { + if (!keepWebHistory) { + mWebHistory = new Vector(); + } + keepWebHistory = true; + + } + + public void queueBackNavigation(int howfar) { + // TODO Auto-generated method stub + + } + + public void queueForwardNavigation(int howfar) { + // TODO Auto-generated method stub + + } + + public void queueLoad(String Url, String frameTarget) { + // TODO Auto-generated method stub + + } + + public void queueReload() { + mWebView.reload(); + } + + public void queueScript(String scriptToRunInCurrentContext) { + mWebView.loadUrl("javascript:"+scriptToRunInCurrentContext); + } + + public void repaintSweepHorizontally() { + // TODO Auto-generated method stub + + } + + public void setAcceptsEditing(boolean b) { + // TODO Auto-generated method stub + + } + + public void setMainFrameIsFirstResponder(boolean b) { + // TODO Auto-generated method stub + + } + + public void setWindowIsKey(boolean b) { + // This is meant to show/hide the window. The best I can find + // is setEnabled() + mWebView.setEnabled(b); + } + + public void testRepaint() { + mWebView.invalidate(); + } + + // Instrumentation calls this to find + // if the activity has finished running the layout tests + public boolean hasFinishedRunning() { + if( mProcessStack == null || mFinishedStack == null) + return false; + + if (mProcessStack.isEmpty() && mFinishedStack.empty()) { + return true; + } + + return false; + } + + private final WebChromeClient mChromeClient = new WebChromeClient() { + @Override + public void onProgressChanged(WebView view, int newProgress) { + if (newProgress == 100) { + pageComplete = true; + String url = mWebView.getUrl(); + if (url != null) { + Log.v(LOGTAG, "Finished: "+ url); + if (url.length() > 60) + url = url.substring(60); + scheduleDump(); + } + } + } + + @Override + public void onReceivedTitle(WebView view, String title) { + if (title.length() > 30) + title = "..."+title.substring(title.length()-30); + setTitle(title); + if (dumpTitleChanges) { + mTitleChanges.append("TITLE CHANGED: "); + mTitleChanges.append(title); + mTitleChanges.append("\n"); + } + } + + @Override + public boolean onJsAlert(WebView view, String url, String message, + JsResult result) { + if (mDialogStrings == null) { + mDialogStrings = new StringBuffer(); + } + mDialogStrings.append("ALERT: "); + mDialogStrings.append(message); + mDialogStrings.append('\n'); + return false; + } + }; + + private WebView mWebView; + private WebViewEventSender eventSender; + private Vector mProcessStack; + private Stack mFinishedStack; + static final String LOGTAG="DumpRenderTree"; + private String mCurrentFile; + private int mOutstandingLoads; + private AsyncHandler mHandler; + private boolean mDumpRequested; + + private boolean dumpAsText; + private boolean waitToDump; + private boolean pageComplete; + + private boolean dumpTitleChanges; + private StringBuffer mTitleChanges; + + private StringBuffer mDialogStrings; + + private boolean keepWebHistory; + private Vector mWebHistory; + + private boolean mTimedOut; + + static final int MSG_DUMP = 0; + static final int MSG_TIMEOUT = 1; + static final int MSG_WEBKIT_DATA = 2; + +} diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/HTMLHostApp.java b/tests/DumpRenderTree/src/com/android/dumprendertree/HTMLHostApp.java new file mode 100644 index 0000000000000000000000000000000000000000..f610f5a2f433ed3efbb7371f624ebd46dfcf3d35 --- /dev/null +++ b/tests/DumpRenderTree/src/com/android/dumprendertree/HTMLHostApp.java @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2007 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.android.dumprendertree; + +import android.app.Application; + +public class HTMLHostApp extends Application { + + public HTMLHostApp() { + } + + public void onCreate() { + } + + public void onTerminate() { + } + +} + diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/HTMLHostCallbackInterface.java b/tests/DumpRenderTree/src/com/android/dumprendertree/HTMLHostCallbackInterface.java new file mode 100644 index 0000000000000000000000000000000000000000..60a2915fbc55b1de09f3bdd68ca294731e2a7d64 --- /dev/null +++ b/tests/DumpRenderTree/src/com/android/dumprendertree/HTMLHostCallbackInterface.java @@ -0,0 +1,21 @@ +/* + * Copyright (C) 2007 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.android.dumprendertree; + +public interface HTMLHostCallbackInterface { + public void waitForFinish(); +} diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestController.java b/tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestController.java new file mode 100644 index 0000000000000000000000000000000000000000..6166dd0f94b80943559e0e743f3a3eb8aabe7d8b --- /dev/null +++ b/tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestController.java @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2007 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.android.dumprendertree; + +public interface LayoutTestController { + + public void dumpAsText(); + public void waitUntilDone(); + public void notifyDone(); + + // Force a redraw of the page + public void display(); + // Used with pixel dumps of content + public void testRepaint(); + + // If the page title changes, add the information to the output. + public void dumpTitleChanges(); + public void dumpBackForwardList(); + public void dumpChildFrameScrollPositions(); + public void dumpEditingCallbacks(); + + // Show/Hide window for window.onBlur() testing + public void setWindowIsKey(boolean b); + // Mac function, used to disable events going to the window + public void setMainFrameIsFirstResponder(boolean b); + + public void dumpSelectionRect(); + + // invalidate and draw one line at a time of the web view. + public void repaintSweepHorizontally(); + + // History testing functions + public void keepWebHistory(); + public void clearBackForwardList(); + // navigate after page load has finished + public void queueBackNavigation(int howfar); + public void queueForwardNavigation(int howfar); + + // Reload when the page load has finished + public void queueReload(); + // Execute the provided script in current context when page load has finished. + public void queueScript(String scriptToRunInCurrentContext); + // Load the provided URL into the provided frame + public void queueLoad(String Url, String frameTarget); + + public void setAcceptsEditing(boolean b); + +} diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestsAutoRunner.java b/tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestsAutoRunner.java new file mode 100755 index 0000000000000000000000000000000000000000..e0e535e356b1d29477ab829f0e20ea6a90c2e9e5 --- /dev/null +++ b/tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestsAutoRunner.java @@ -0,0 +1,48 @@ +/* + * 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.android.dumprendertree; + +import junit.framework.TestSuite; +import com.android.dumprendertree.LayoutTestsAutoTest; + +import android.test.InstrumentationTestRunner; +import android.test.InstrumentationTestSuite; + + +/** + * Instrumentation Test Runner for all MediaPlayer tests. + * + * Running all tests: + * + * adb shell am instrument \ + * -w com.android.dumprendertree.LayoutTestsAutoRunner + */ + +public class LayoutTestsAutoRunner extends InstrumentationTestRunner { + @Override + public TestSuite getAllTests() { + TestSuite suite = new InstrumentationTestSuite(this); + suite.addTestSuite(LayoutTestsAutoTest.class); + return suite; + } + + @Override + public ClassLoader getLoader() { + return LayoutTestsAutoRunner.class.getClassLoader(); + } +} + diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestsAutoTest.java b/tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestsAutoTest.java new file mode 100644 index 0000000000000000000000000000000000000000..f46b263bfc7ce92318652b20060ea606c21b45e6 --- /dev/null +++ b/tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestsAutoTest.java @@ -0,0 +1,157 @@ +/* + * 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.android.dumprendertree; + +import android.app.Instrumentation; +import android.app.Instrumentation.ActivityMonitor; +import android.content.ContentResolver; +import android.content.ContentValues; +import android.util.Log; +import android.view.KeyEvent; + +import android.test.ActivityInstrumentationTestCase; +import android.test.AndroidTestCase; +import android.test.suitebuilder.annotation.LargeTest; + +import com.android.dumprendertree.HTMLHostActivity; + +public class LayoutTestsAutoTest extends ActivityInstrumentationTestCase { + + private final static String LOGTAG = "LayoutTests"; + private final static String LAYOUT_TESTS_ROOT = "/sdcard/android/layout_tests/"; + + public LayoutTestsAutoTest() { + super("com.android.dumprendertree", Menu.class); + } + + // Invokes running of layout tests + // and waits till it has finished running. + public void executeLayoutTests(String folder) { + Instrumentation inst = getInstrumentation(); + getActivity().processFile(folder, true); + + ActivityMonitor htmlHostActivityMonitor = + inst.addMonitor("com.android.dumprendertree.HTMLHostActivity", null, false); + HTMLHostActivity activity = + (HTMLHostActivity) htmlHostActivityMonitor.waitForActivityWithTimeout(6000); + + while (!activity.hasFinishedRunning()) { + // Poll every 5 seconds to determine if the layout + // tests have finished running + try {Thread.sleep(5000); } catch(Exception e){} + } + + // Wait few more seconds so that results are + // flushed to the /sdcard + try {Thread.sleep(5000); } catch(Exception e){} + + return ; + } + + // Running all the layout tests at once sometimes + // causes the dumprendertree to run out of memory. + // So, additional tests are added to run the tests + // in chunks. + @LargeTest + public void testAllLayoutTests() { + executeLayoutTests(LAYOUT_TESTS_ROOT + "fast"); + } + + @LargeTest + public void testLayoutSubset1() { + executeLayoutTests(LAYOUT_TESTS_ROOT + "fast/backgrounds"); + executeLayoutTests(LAYOUT_TESTS_ROOT + "fast/borders"); + executeLayoutTests(LAYOUT_TESTS_ROOT + "fast/box-shadow"); + executeLayoutTests(LAYOUT_TESTS_ROOT + "fast/box-sizing"); + executeLayoutTests(LAYOUT_TESTS_ROOT + "fast/canvas"); + } + + @LargeTest + public void testLayoutSubset2() { + executeLayoutTests(LAYOUT_TESTS_ROOT + "fast/clip"); + executeLayoutTests(LAYOUT_TESTS_ROOT + "fast/compact"); + executeLayoutTests(LAYOUT_TESTS_ROOT + "fast/cookies"); + executeLayoutTests(LAYOUT_TESTS_ROOT + "fast/css"); + executeLayoutTests(LAYOUT_TESTS_ROOT + "fast/css-generated-content"); + executeLayoutTests(LAYOUT_TESTS_ROOT + "fast/doctypes"); + } + + @LargeTest + public void testLayoutSubset3() { + executeLayoutTests(LAYOUT_TESTS_ROOT + "fast/dom"); + executeLayoutTests(LAYOUT_TESTS_ROOT + "fast/dynamic"); + executeLayoutTests(LAYOUT_TESTS_ROOT + "fast/encoding"); + executeLayoutTests(LAYOUT_TESTS_ROOT + "fast/events"); + executeLayoutTests(LAYOUT_TESTS_ROOT + "fast/flexbox"); + } + + @LargeTest + public void testLayoutSubset4() { + executeLayoutTests(LAYOUT_TESTS_ROOT + "fast/forms"); + executeLayoutTests(LAYOUT_TESTS_ROOT + "fast/frames"); + executeLayoutTests(LAYOUT_TESTS_ROOT + "fast/gradients"); + executeLayoutTests(LAYOUT_TESTS_ROOT + "fast/history"); + executeLayoutTests(LAYOUT_TESTS_ROOT + "fast/html"); + } + + @LargeTest + public void testLayoutSubset5() { + executeLayoutTests(LAYOUT_TESTS_ROOT + "fast/images"); + executeLayoutTests(LAYOUT_TESTS_ROOT + "fast/inline"); + executeLayoutTests(LAYOUT_TESTS_ROOT + "fast/inline-block"); + executeLayoutTests(LAYOUT_TESTS_ROOT + "fast/innerHTML"); + executeLayoutTests(LAYOUT_TESTS_ROOT + "fast/invalid"); + } + + @LargeTest + public void testLayoutSubset6() { + executeLayoutTests(LAYOUT_TESTS_ROOT + "fast/js"); + executeLayoutTests(LAYOUT_TESTS_ROOT + "fast/layers"); + executeLayoutTests(LAYOUT_TESTS_ROOT + "fast/leaks"); + executeLayoutTests(LAYOUT_TESTS_ROOT + "fast/lists"); + executeLayoutTests(LAYOUT_TESTS_ROOT + "fast/loader"); + executeLayoutTests(LAYOUT_TESTS_ROOT + "fast/media"); + } + + @LargeTest + public void testLayoutSubset7() { + executeLayoutTests(LAYOUT_TESTS_ROOT + "fast/multicol"); + executeLayoutTests(LAYOUT_TESTS_ROOT + "fast/overflow"); + executeLayoutTests(LAYOUT_TESTS_ROOT + "fast/parser"); + executeLayoutTests(LAYOUT_TESTS_ROOT + "fast/profiler"); + executeLayoutTests(LAYOUT_TESTS_ROOT + "fast/reflections"); + executeLayoutTests(LAYOUT_TESTS_ROOT + "fast/regex"); + } + + @LargeTest + public void testLayoutSubset8() { + executeLayoutTests(LAYOUT_TESTS_ROOT + "fast/repaint"); + executeLayoutTests(LAYOUT_TESTS_ROOT + "fast/replaced"); + executeLayoutTests(LAYOUT_TESTS_ROOT + "fast/runin"); + executeLayoutTests(LAYOUT_TESTS_ROOT + "fast/selectors"); + executeLayoutTests(LAYOUT_TESTS_ROOT + "fast/table"); + executeLayoutTests(LAYOUT_TESTS_ROOT + "fast/text"); + } + + @LargeTest + public void testLayoutSubset9() { + executeLayoutTests(LAYOUT_TESTS_ROOT + "fast/tokenizer"); + executeLayoutTests(LAYOUT_TESTS_ROOT + "fast/transforms"); + executeLayoutTests(LAYOUT_TESTS_ROOT + "fast/xpath"); + executeLayoutTests(LAYOUT_TESTS_ROOT + "fast/xsl"); + } +} diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/Menu.java b/tests/DumpRenderTree/src/com/android/dumprendertree/Menu.java new file mode 100644 index 0000000000000000000000000000000000000000..2def8f353e3e9454cf5370535f1a7a60feb363ea --- /dev/null +++ b/tests/DumpRenderTree/src/com/android/dumprendertree/Menu.java @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2007 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.android.dumprendertree; + +import android.content.Intent; +import android.net.Uri; +import android.os.Bundle; + +import java.io.File; + +public class Menu extends FileList { + + public void onCreate(Bundle icicle) + { + super.onCreate(icicle); + } + + boolean fileFilter(File f) { + if (f.getName().startsWith(".")) + return false; + if (f.getName().equalsIgnoreCase("resources")) + return false; + if (f.isDirectory()) + return true; + if (f.getPath().toLowerCase().endsWith("ml")) + return true; + return false; + } + + void processFile(String filename, boolean selection) + { + Intent result = new Intent(null, Uri.parse(filename)); + result.setClass(this, HTMLHostActivity.class); + result.putExtra("ReturnWhenFinished", selection); + startActivity(result); + } + +} + diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/WebViewEventSender.java b/tests/DumpRenderTree/src/com/android/dumprendertree/WebViewEventSender.java new file mode 100644 index 0000000000000000000000000000000000000000..eea63463697835af6c52d670d457b79e21516e22 --- /dev/null +++ b/tests/DumpRenderTree/src/com/android/dumprendertree/WebViewEventSender.java @@ -0,0 +1,194 @@ +/* + * Copyright (C) 2007 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.android.dumprendertree; + +import android.webkit.WebView; +import android.view.KeyEvent; +import android.util.*; + +import java.util.Arrays; + +public class WebViewEventSender implements EventSender { + + WebViewEventSender(WebView webView) { + mWebView = webView; + } + + public void resetMouse() { + mouseX = mouseY = 0; + } + + public void enableDOMUIEventLogging(int DOMNode) { + // TODO Auto-generated method stub + + } + + public void fireKeyboardEventsToElement(int DOMNode) { + // TODO Auto-generated method stub + + } + + public void keyDown(String character, String[] withModifiers) { + Log.e("EventSender", "KeyDown: " + character + "(" + + character.getBytes()[0] + ") Modifiers: " + + Arrays.toString(withModifiers)); + KeyEvent modifier = null; + if (withModifiers != null && withModifiers.length > 0) { + for (int i = 0; i < withModifiers.length; i++) { + int keyCode = modifierMapper(withModifiers[i]); + modifier = new KeyEvent(KeyEvent.ACTION_DOWN, keyCode); + mWebView.onKeyDown(modifier.getKeyCode(), modifier); + } + } + int keyCode = keyMapper(character.toLowerCase().toCharArray()[0]); + KeyEvent event = new KeyEvent(KeyEvent.ACTION_DOWN, keyCode); + mWebView.onKeyDown(event.getKeyCode(), event); + + } + + public void keyDown(String character) { + keyDown(character, null); + } + + public void leapForward(int milliseconds) { + // TODO Auto-generated method stub + + } + + public void mouseClick() { + mouseDown(); + mouseUp(); + } + + public void mouseDown() { + /* KeyEvent event = new KeyEvent( + KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_CENTER); + mWebView.onKeyDown(event.getKeyCode(), event); */ + } + + public void mouseMoveTo(int X, int Y) { + if (X > mouseX) { + KeyEvent event = new KeyEvent( + KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_RIGHT); + mWebView.onKeyDown(event.getKeyCode(), event); + mWebView.onKeyUp(event.getKeyCode(), event); + } else if ( X < mouseX ) { + KeyEvent event = new KeyEvent( + KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_LEFT); + mWebView.onKeyDown(event.getKeyCode(), event); + mWebView.onKeyUp(event.getKeyCode(), event); + } + if (Y > mouseY) { + KeyEvent event = new KeyEvent( + KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_DOWN); + mWebView.onKeyDown(event.getKeyCode(), event); + mWebView.onKeyUp(event.getKeyCode(), event); + } else if (Y < mouseY ) { + KeyEvent event = new KeyEvent( + KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_UP); + mWebView.onKeyDown(event.getKeyCode(), event); + mWebView.onKeyUp(event.getKeyCode(), event); + } + mouseX= X; + mouseY= Y; + + } + + public void mouseUp() { + /* KeyEvent event = new KeyEvent( + KeyEvent.ACTION_UP, KeyEvent.KEYCODE_DPAD_CENTER); + mWebView.onKeyDown(event.getKeyCode(), event);*/ + + } + + // Assumes lowercase chars, case needs to be + // handled by calling function. + static int keyMapper(char c) { + // handle numbers + if (c >= '0' && c<= '9') { + int offset = c - '0'; + return KeyEvent.KEYCODE_0 + offset; + } + + // handle characters + if (c >= 'a' && c <= 'z') { + int offset = c - 'a'; + return KeyEvent.KEYCODE_A + offset; + } + + // handle all others + switch (c) { + case '*': + return KeyEvent.KEYCODE_STAR; + case '#': + return KeyEvent.KEYCODE_POUND; + case ',': + return KeyEvent.KEYCODE_COMMA; + case '.': + return KeyEvent.KEYCODE_PERIOD; + case '\t': + return KeyEvent.KEYCODE_TAB; + case ' ': + return KeyEvent.KEYCODE_SPACE; + case '\n': + return KeyEvent.KEYCODE_ENTER; + case '\b': + case 0x7F: + return KeyEvent.KEYCODE_DEL; + case '~': + return KeyEvent.KEYCODE_GRAVE; + case '-': + return KeyEvent.KEYCODE_MINUS; + case '=': + return KeyEvent.KEYCODE_EQUALS; + case '(': + return KeyEvent.KEYCODE_LEFT_BRACKET; + case ')': + return KeyEvent.KEYCODE_RIGHT_BRACKET; + case '\\': + return KeyEvent.KEYCODE_BACKSLASH; + case ';': + return KeyEvent.KEYCODE_SEMICOLON; + case '\'': + return KeyEvent.KEYCODE_APOSTROPHE; + case '/': + return KeyEvent.KEYCODE_SLASH; + default: + break; + } + + return c; + } + + static int modifierMapper(String modifier) { + if (modifier.equals("ctrlKey")) { + return KeyEvent.KEYCODE_ALT_LEFT; + } else if (modifier.equals("shiftKey")) { + return KeyEvent.KEYCODE_SHIFT_LEFT; + } else if (modifier.equals("altKey")) { + return KeyEvent.KEYCODE_SYM; + } else if (modifier.equals("metaKey")) { + return KeyEvent.KEYCODE_UNKNOWN; + } + return KeyEvent.KEYCODE_UNKNOWN; + } + + private WebView mWebView = null; + private int mouseX; + private int mouseY; + +} diff --git a/tests/FrameworkTest/Android.mk b/tests/FrameworkTest/Android.mk new file mode 100644 index 0000000000000000000000000000000000000000..61cdbfa5617eb3b0bab586545564e07c014780a1 --- /dev/null +++ b/tests/FrameworkTest/Android.mk @@ -0,0 +1,15 @@ +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_MODULE_TAGS := tests + +# Only compile source java files in this apk. +LOCAL_SRC_FILES := $(call all-java-files-under, src) + +LOCAL_JAVA_LIBRARIES := android.test.runner + +LOCAL_PACKAGE_NAME := FrameworkTest + +include $(BUILD_PACKAGE) +# Use the following include to make our test apk. +include $(call all-makefiles-under,$(LOCAL_PATH)) diff --git a/tests/FrameworkTest/AndroidManifest.xml b/tests/FrameworkTest/AndroidManifest.xml new file mode 100644 index 0000000000000000000000000000000000000000..9913bfc7e6b6b9ffe252a65d4e6492c1c0e7768b --- /dev/null +++ b/tests/FrameworkTest/AndroidManifest.xml @@ -0,0 +1,929 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + V + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/FrameworkTest/README b/tests/FrameworkTest/README new file mode 100644 index 0000000000000000000000000000000000000000..d6d0042605c5dc396c886e2ca847b6164427fe55 --- /dev/null +++ b/tests/FrameworkTest/README @@ -0,0 +1,8 @@ +FrameworkTestApplication should hold snippets of functionality that are +helpful for testing the UI framework code, but not appropriate for +sample code. For instance, a layout contrived to exercise an edge case +of scrolling behavior. + +InstrumentationTestCases should be added under tests and added to the +list of tests in FrameworkInstrumentationTestRunner. + diff --git a/tests/FrameworkTest/res/drawable/big_drawable_background.9.png b/tests/FrameworkTest/res/drawable/big_drawable_background.9.png new file mode 100644 index 0000000000000000000000000000000000000000..aded635ca569a79e8b406c34702633ac4902e92b Binary files /dev/null and b/tests/FrameworkTest/res/drawable/big_drawable_background.9.png differ diff --git a/tests/FrameworkTest/res/drawable/bitmap_drawable.xml b/tests/FrameworkTest/res/drawable/bitmap_drawable.xml new file mode 100644 index 0000000000000000000000000000000000000000..35673ec0ef4a501588ec93a8100b31e2cdfd5da8 --- /dev/null +++ b/tests/FrameworkTest/res/drawable/bitmap_drawable.xml @@ -0,0 +1,19 @@ + + + + diff --git a/tests/FrameworkTest/res/drawable/black_square.png b/tests/FrameworkTest/res/drawable/black_square.png new file mode 100644 index 0000000000000000000000000000000000000000..1bfe0a2501f77602785918445c2e7b8f19e2ecf1 Binary files /dev/null and b/tests/FrameworkTest/res/drawable/black_square.png differ diff --git a/tests/FrameworkTest/res/drawable/black_square_stretchable.9.png b/tests/FrameworkTest/res/drawable/black_square_stretchable.9.png new file mode 100644 index 0000000000000000000000000000000000000000..1fcbeb1f82d12b0271edcb906b77595d3fb9e41b Binary files /dev/null and b/tests/FrameworkTest/res/drawable/black_square_stretchable.9.png differ diff --git a/tests/FrameworkTest/res/drawable/box.xml b/tests/FrameworkTest/res/drawable/box.xml new file mode 100644 index 0000000000000000000000000000000000000000..6849bd34689d5baaafa03d371fd20419278d6539 --- /dev/null +++ b/tests/FrameworkTest/res/drawable/box.xml @@ -0,0 +1,26 @@ + + + + + + + + diff --git a/tests/FrameworkTest/res/drawable/drawable_background.9.png b/tests/FrameworkTest/res/drawable/drawable_background.9.png new file mode 100644 index 0000000000000000000000000000000000000000..1337ba978bb73c5a08cd5d44bee58d4314342fb8 Binary files /dev/null and b/tests/FrameworkTest/res/drawable/drawable_background.9.png differ diff --git a/tests/FrameworkTest/res/drawable/sym_now_playing_pause_1.png b/tests/FrameworkTest/res/drawable/sym_now_playing_pause_1.png new file mode 100644 index 0000000000000000000000000000000000000000..2f19d082b689dcf092e104cbe6159abdbecce1b5 Binary files /dev/null and b/tests/FrameworkTest/res/drawable/sym_now_playing_pause_1.png differ diff --git a/tests/FrameworkTest/res/drawable/sym_now_playing_skip_backward_1.png b/tests/FrameworkTest/res/drawable/sym_now_playing_skip_backward_1.png new file mode 100644 index 0000000000000000000000000000000000000000..f945a8190c8d368d94a2fef6ecf4569ec9b8b311 Binary files /dev/null and b/tests/FrameworkTest/res/drawable/sym_now_playing_skip_backward_1.png differ diff --git a/tests/FrameworkTest/res/drawable/sym_now_playing_skip_forward_1.png b/tests/FrameworkTest/res/drawable/sym_now_playing_skip_forward_1.png new file mode 100644 index 0000000000000000000000000000000000000000..da9361a34bd5bf660890c4dc42b733c4a0463be3 Binary files /dev/null and b/tests/FrameworkTest/res/drawable/sym_now_playing_skip_forward_1.png differ diff --git a/tests/FrameworkTest/res/layout/add_column_in_table.xml b/tests/FrameworkTest/res/layout/add_column_in_table.xml new file mode 100644 index 0000000000000000000000000000000000000000..62c27f31023a7fed6f4b5b7aca8af66d1523010a --- /dev/null +++ b/tests/FrameworkTest/res/layout/add_column_in_table.xml @@ -0,0 +1,46 @@ + + + + + + + + + + + + + + + +